Building and Using an IR Library for AV Integration

I have broken through on several fronts working with Global Cache devices, sending IR codes. Some hard won progress.

Now I need to create appropriate structure for lots of various IR codes that need to be stored, and accessed both by single function buttons, but also by multi-function buttons (meaning that a single button click will activate a whole series of IR commands (which are implemented as TCP and HTTP POST nodes.

What is a good pattern for structure? I am not sure the best way to store the strings and/or JSON so that I have one "database" flow that can be utilized by multiple initiating nodes.

I have been assuming subflows might be a way, but there is very little documentation on subflows, and I can't even replicate examples (see http://noderedguide.com/node-red-lecture-5-the-node-red-programming-model/#h.wzpvxd7hsc7g) because I can't find the generic "input' and "output" nodes shown there. How do you hook inputs and outputs to a subflow?

But of course, should I even use subflows at all? Is there a better way?

Good question. I will try to help with the question:

I prepared an animated gif to illustrate how to transform a nice gate function into a subflow (it is possible to do it in a shorter way, so this is only for the sake of understanding). The original function is found here: Simple gate to switch on and off a flow

My first thought is to build a "map" of IR code names to the internal code number (or bytes, buffers, whatever). This could be a simple CSV file with 2 columns, that is read at startup and parsed into a JS object and stored into Global context. Then, whenever you need to interpret a code, pass the code name to a change node that does the lookup from your Global context variable. As Andrei shows, it's then pretty simple to place that lookup node into a subflow so you can keep your flows DRY ("don't repeat yourself").

If this approach sounds like it makes sense for your use case, could you post an example "table" of a few of your name-to-code mappings (simple and compound codes)? It would help me create a sample flow to show what I mean...

These are great recommendations. Here is an example of single IR codes based on your feedback.

ZETTAGUARD-ZW410,[IN 1],{"frequency":37735,"irCode":"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,21,22,21,22,63,22,21,22,21,22,21,22,63,22,21,22,63,22,63,22,21,22,63,22,63,22,63,22,1512,343,85,22,3700","preamble":"","repeat":1}
ZETTAGUARD-ZW410,[IN 2],{"frequency":41450,"irCode":"344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100","preamble":"","repeat":1}
ZETTAGUARD-ZW410,[IN 3],{"frequency":37914,"irCode":"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,63,22,63,22,63,22,21,22,21,22,21,22,63,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,1519,343,85,22,3700","preamble":"","repeat":1}
ZETTAGUARD-ZW410,[IN 4],{"frequency":37825,"irCode":"345,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,63,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,1516,343,85,22,3649,343,85,22,3649,343,85,22,3700","preamble":"","repeat":1}

Format:
DeviceID,[IR Function],{JSON Code for driving IR through Global Cache Flex adapter}

I am still figuring out how to get compound codes to work on the bench. For example, using the remote, the AV matrix switcher I need to drive is controlled by sending a sequence of 1) Destination IR command, and 2) Source IR command. I haven't gotten this to physically work yet on the bench, but I have to assume it would be just 2 sequential codes in rapid succession.

Look forward to seeing your idea of a sample flow. I've learned a lot the last couple of weeks working with node red and iOT devices, and feel I am approaching ability to be productive in my new systems integration business.

Interesting -- in order to make the csv/json text more readable, please click the "pencil" icon on that last post, and put a line containing only 3 backtics like ``` before and after your sample text.

I understand the Device ID in col #1 -- can you explain what the IR Function in col #2 means? In javascript the square brackets represent an array, so when you show "[IN 4]" is that just a string that represents input from Key 4? Are there output keys or events as well?

Valid JSON strings are not easy to maintain as plain text inside a spreadsheet, so my approach would be to split its internal fields into separate CSV columns. Then assemble the requested single (or multiple) IR codes into a buffer when it's time to transmit them. Does the JSON structure always have those 4 fields: frequency, preamble, repeat, and irCode? Are there extra/optional fields used in other transmission types or with different manufacturers or device types?

shrickus,

Here is the format that I put together that separates keys from actual data:
DeviceID,IRFunction,{JSON Code for driving IR through Global Cache Flex adapter}

DeviceID = unique identifier I made up as a primary key to the device to be controlled
IR Function = secondary key to the specific function offered up by the device to be controlled
JSON .... = the exact string that must be sent to the Flex (which is the IR emitting device), via http, for the specific IR Function for that DeviceID. When Flex receives it, it drives the appropriate IR emitter to control the device (in this case a 1x4 HDMI switch).

This is essentially the same structure of data that will be needed for every function on every device, of which there are ~ a dozen devices with dozens of functions per device that need to be sent these types of commands.

Based on your feedback, I removed square brackets, and reduced the number of fields in the format, by combining device and function into one field so there is only a primary key. As for the JSON, it would be best if I don't have to store it in a different format than that which is needed by the device. For this type of control adapter (Global Cache Flex), the number of JSON fields is always the same, but the number of integers/string characters varies widely. One function might involve 40 numbers comma separated, another might be 75, another might be 8.

The other IR controller device (GC-100) uses TCP strings instead of JSON for driving the commands. But it is essentially the same command content - some number of fields that contain strings and numbers.

Saving the info below is convenient in that the actual configuration is a function of the flows, but the data needed for driving the IR commands won't change, unless the device being controlled switches to an IR controller that uses TCP instead of HTTP.

ZG-ZW410-IN-1,{"frequency":37735,"irCode":"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,21,22,21,22,63,22,21,22,21,22,21,22,63,22,21,22,63,22,63,22,21,22,63,22,63,22,63,22,1512,343,85,22,3700","preamble":"","repeat":1}
ZG-ZW410-IN-2,{"frequency":41450,"irCode":"344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100","preamble":"","repeat":1}
ZG-ZW410-IN-3,{"frequency":37914,"irCode":"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,63,22,63,22,63,22,21,22,21,22,21,22,63,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,1519,343,85,22,3700","preamble":"","repeat":1}
ZG-ZW410-IN-4,{"frequency":37825,"irCode":"345,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,63,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,1516,343,85,22,3649,343,85,22,3649,343,85,22,3700","preamble":"","repeat":1}

Andrei - I figured it was something simple, but hours of staring at node red screens and trying to interpret peoples' online written tutorials did not lead me to the concept that you show, which is how to add inputs and outputs. By pressing the faintly colored controls at the top of the workspace.

So that works and gets me past another hurdle in the path to good, modular design.

Thank you!

1 Like

shrickus,

I am now studying the best way to store and retrieve the IR codes from a file. I wonder if I should use JSON rather than CSV - then I can easily parse the JSON and not worry about using CSV and the overhead of accommodating JSON in CSV format.

Seems like if I do this, then I just need to add the DEVICE-FUNCTION key as a new field inside the JSON that needs to be sent the make the IR command happen.

I am not a JSON expert, but it seems that a JSON Collection might be a way to build one IR file that has all JSON in it for driving IR commands. Then I would just need to learn node red way of selecting a JSON string by the collection (zero in on device) and the function (e.g. Power On).

Here is one way to store the IR mapping data as a CSV spreadsheet:

DeviceID,IRFunction,IRType,IRCode,frequency,preamble,repeat
ZG-ZW410,IN-1,JSON,"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,21,22,21,22,63,22,21,22,21,22,21,22,63,22,21,22,63,22,63,22,21,22,63,22,63,22,63,22,1512,343,85,22,3700",37735,,1
ZG-ZW410,IN-2,JSON,"344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100",41450,,1
ZG-ZW410,IN-3,JSON,"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,63,22,63,22,63,22,21,22,21,22,21,22,63,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,1519,343,85,22,3700",37914,,1
ZG-ZW410,IN-4,JSON,"345,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,63,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,1516,343,85,22,3649,343,85,22,3649,343,85,22,3700",37825,,1

And here is what it looks like when parsed into a JS Array of objects:

[
  {
    "DeviceID": "ZG-ZW410",
    "IRFunction": "IN-1",
    "IRType": "JSON",
    "IRCode": "343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,21,22,21,22,63,22,21,22,21,22,21,22,63,22,21,22,63,22,63,22,21,22,63,22,63,22,63,22,1512,343,85,22,3700",
    "frequency": 37735,
    "repeat": 1
  },
  {
    "DeviceID": "ZG-ZW410",
    "IRFunction": "IN-2",
    "IRType": "JSON",
    "IRCode": "344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100",
    "frequency": 41450,
    "repeat": 1
  },
  {
    "DeviceID": "ZG-ZW410",
    "IRFunction": "IN-3",
    "IRType": "JSON",
    "IRCode": "343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,63,22,63,22,63,22,21,22,21,22,21,22,63,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,1519,343,85,22,3700",
    "frequency": 37914,
    "repeat": 1
  },
  {
    "DeviceID": "ZG-ZW410",
    "IRFunction": "IN-4",
    "IRType": "JSON",
    "IRCode": "345,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,63,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,1516,343,85,22,3649,343,85,22,3649,343,85,22,3700",
    "frequency": 37825,
    "repeat": 1
  }
]

Not to throw another spanner in the gears, but I'm growing to like the YAML format even more:

- DeviceID: ZG-ZW410
  IRFunction: IN-1
  IRType: JSON
  IRCode: >-
    343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,21,22,21,22,63,22,21,22,21,22,21,22,63,22,21,22,63,22,63,22,21,22,63,22,63,22,63,22,1512,343,85,22,3700
  frequency: 37735
  preamble: ''
  repeat: 1
- DeviceID: ZG-ZW410
  IRFunction: IN-2
  IRType: JSON
  IRCode: >-
    344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100
  frequency: 41450
  preamble: ''
  repeat: 1
- DeviceID: ZG-ZW410
  IRFunction: IN-3
  IRType: JSON
  IRCode: >-
    343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,63,22,63,22,63,22,21,22,21,22,21,22,63,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,1519,343,85,22,3700
  frequency: 37914
  preamble: ''
  repeat: 1
- DeviceID: ZG-ZW410
  IRFunction: IN-4
  IRType: JSON
  IRCode: >-
    345,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,63,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,1516,343,85,22,3649,343,85,22,3649,343,85,22,3700
  frequency: 37825
  preamble: ''
  repeat: 1

It's a superset of JSON, without all the punctuation and restrictions on embedded newlines.

Here is a set of flows that show how to convert your data into either csv or yaml files. Using an inject node, it then reads those files, converts the data into the JS objects that will later need to be sent to the gateway, and stores them indexed by DeviceID and IRFunction into a flow variable called "IRCodeMap". This process only needs to be done once at startup, so the code map is available to the other flows.

[{"id":"1c8a64c7.1f718b","type":"yaml","z":"f9a2eec9.c2e26","property":"payload","name":"","x":510,"y":1520,"wires":[["6e7f6048.2bf41","d662fa6d.6027b8"]]},{"id":"b6c1d99.3e55228","type":"csv","z":"f9a2eec9.c2e26","name":"","sep":",","hdrin":true,"hdrout":"","multi":"mult","ret":"\\n","temp":"","skip":"0","x":510,"y":1480,"wires":[["d662fa6d.6027b8"]]},{"id":"dd4fc694.791198","type":"file in","z":"f9a2eec9.c2e26","name":"","filename":"irCodes.yaml","format":"utf8","chunk":false,"sendError":false,"x":310,"y":1520,"wires":[["1c8a64c7.1f718b"]]},{"id":"a348ee2e.03fa3","type":"file in","z":"f9a2eec9.c2e26","name":"","filename":"irCodes.csv","format":"utf8","chunk":false,"sendError":false,"x":310,"y":1480,"wires":[["b6c1d99.3e55228"]]},{"id":"5b3f1f1b.00d64","type":"inject","z":"f9a2eec9.c2e26","name":"","topic":"csv","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":110,"y":1480,"wires":[["a348ee2e.03fa3"]]},{"id":"ecfca482.237b88","type":"inject","z":"f9a2eec9.c2e26","name":"","topic":"yaml","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":120,"y":1520,"wires":[["dd4fc694.791198"]]},{"id":"642ee161.c812","type":"comment","z":"f9a2eec9.c2e26","name":"Build IR Code mapping files","info":"","x":180,"y":1340,"wires":[]},{"id":"d662fa6d.6027b8","type":"debug","z":"f9a2eec9.c2e26","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":690,"y":1480,"wires":[]},{"id":"d5db4ceb.e224c","type":"inject","z":"f9a2eec9.c2e26","name":"irCodes.json","topic":"json","payload":"{\"ZG-ZW410/IN-1\":{\"frequency\":37735,\"irCode\":\"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,21,22,21,22,63,22,21,22,21,22,21,22,63,22,21,22,63,22,63,22,21,22,63,22,63,22,63,22,1512,343,85,22,3700\",\"preamble\":\"\",\"repeat\":1},\"ZG-ZW410/IN-2\":{\"frequency\":41450,\"irCode\":\"344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100\",\"preamble\":\"\",\"repeat\":1},\"ZG-ZW410/IN-3\":{\"frequency\":37914,\"irCode\":\"343,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,21,22,63,22,63,22,63,22,63,22,21,22,21,22,21,22,63,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,1519,343,85,22,3700\",\"preamble\":\"\",\"repeat\":1},\"ZG-ZW410/IN-4\":{\"frequency\":37825,\"irCode\":\"345,171,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,21,22,63,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,21,22,63,22,63,22,63,22,63,22,63,22,63,22,63,22,1516,343,85,22,3649,343,85,22,3649,343,85,22,3700\",\"preamble\":\"\",\"repeat\":1}}","payloadType":"json","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":1380,"wires":[["89c0e126.325a6"]]},{"id":"ceeb2110.8bb41","type":"csv","z":"f9a2eec9.c2e26","name":"","sep":",","hdrin":"","hdrout":true,"multi":"one","ret":"\\n","temp":"DeviceID,IRFunction,IRType,IRCode,frequency,preamble,repeat","skip":"0","x":510,"y":1360,"wires":[["819667ca.861ba8"]]},{"id":"c46ff270.aa17","type":"yaml","z":"f9a2eec9.c2e26","property":"payload","name":"","x":510,"y":1400,"wires":[["77f80ad7.8685c4"]]},{"id":"89c0e126.325a6","type":"change","z":"f9a2eec9.c2e26","name":"parse into array","rules":[{"t":"set","p":"payload","pt":"msg","to":"$spread(payload).(\t  $key := $keys($)[0];\t  $dev := $.*;\t  {\t    \"DeviceID\": $substringBefore($key, \"/\"),\t    \"IRFunction\": $substringAfter($key, \"/\"),\t    \"IRType\": \"JSON\",\t    \"IRCode\": $dev.irCode,\t    \"frequency\": $dev.frequency,\t    \"preamble\": $dev.preamble,\t    \"repeat\": $dev.repeat\t  }\t)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":320,"y":1380,"wires":[["ceeb2110.8bb41","c46ff270.aa17"]]},{"id":"819667ca.861ba8","type":"file","z":"f9a2eec9.c2e26","name":"","filename":"irCodes.csv","appendNewline":true,"createDir":false,"overwriteFile":"true","x":690,"y":1360,"wires":[]},{"id":"77f80ad7.8685c4","type":"file","z":"f9a2eec9.c2e26","name":"","filename":"irCodes.yaml","appendNewline":true,"createDir":false,"overwriteFile":"true","x":690,"y":1400,"wires":[]},{"id":"6e7f6048.2bf41","type":"change","z":"f9a2eec9.c2e26","name":"","rules":[{"t":"set","p":"IRCodeMap","pt":"flow","to":"payload {\t  $.DeviceID: $.{\t    IRFunction:\t      IRType = \"JSON\" ?\t        {\t          \"frequency\": frequency,\t          \"irCode\": IRCode,\t          \"preamble\": preamble,\t          \"repeat\": repeat\t        } :\t      IRType = \"TCP\" ?\t        {\t          \"tcpCode\": TCPCode,\t          \"preamble\": preamble,\t          \"repeat\": repeat\t        } :\t      \"Invalid type: \" & IRType    \t  } ~> $merge()\t}","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":720,"y":1520,"wires":[[]]},{"id":"f263829b.d9e78","type":"inject","z":"f9a2eec9.c2e26","name":"","topic":"ZG-ZW410","payload":"IN-1","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":1660,"wires":[["7a41d875.ce8e88"]]},{"id":"f85553c7.3c2e5","type":"inject","z":"f9a2eec9.c2e26","name":"","topic":"ZG-ZW410","payload":"IN-2","payloadType":"str","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":1700,"wires":[["7a41d875.ce8e88"]]},{"id":"7a41d875.ce8e88","type":"change","z":"f9a2eec9.c2e26","name":"lookup IRCode data","rules":[{"t":"set","p":"json","pt":"msg","to":"$flowContext(\"IRCodeMap\")\t ~> $lookup($$.topic)\t ~> $lookup($$.payload)","tot":"jsonata"},{"t":"set","p":"topic","pt":"msg","to":"topic & \"/\" & payload","tot":"jsonata"},{"t":"move","p":"json","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":420,"y":1680,"wires":[["ccb39610.0d5368"]]},{"id":"ccb39610.0d5368","type":"debug","z":"f9a2eec9.c2e26","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":690,"y":1680,"wires":[]},{"id":"caeba302.2a3e3","type":"inject","z":"f9a2eec9.c2e26","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":1620,"wires":[["938ed2e8.559a2"]]},{"id":"938ed2e8.559a2","type":"change","z":"f9a2eec9.c2e26","name":"verify IRCodeMap","rules":[{"t":"set","p":"payload","pt":"msg","to":"$flowContext(\"IRCodeMap\")","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":410,"y":1620,"wires":[["ccb39610.0d5368"]]},{"id":"1797c703.3d0569","type":"comment","z":"f9a2eec9.c2e26","name":"Check IR Code mapping files","info":"","x":180,"y":1440,"wires":[]},{"id":"fe5a4ff2.25c44","type":"comment","z":"f9a2eec9.c2e26","name":"Lookup IR Codes from topic/payload","info":"","x":200,"y":1580,"wires":[]}]

The last flow injects a msg like { "topic": "ZG-ZW410", "payload": "IN-2" } -- this is wired to a change node that uses the flow context to lookup the json data to be sent to the device, sending the original data structure that you requested:

{"frequency":41450,"irCode":"344,187,22,23,22,23,22,23,22,23,22,23,22,23,22,23,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,69,22,23,22,23,22,69,22,23,22,69,22,69,22,23,22,23,22,23,22,69,22,23,22,69,22,23,22,23,22,69,22,69,22,69,22,1661,343,93,22,3999,343,93,22,4100","preamble":"","repeat":1}

--Steve

1 Like

This is turning into a quite valuable thread (to me at least)!

What I have ended up doing for my current project (at least the beta version) is to store my IR library in JSON format to begin with. As a second order of business after my current deadline, I am going to look into your recommendation to use Excel to manage the database.

I haven't fully thought this through yet, but I can envision a system that does the following:

  1. pull IR codes from various sources, in various formats, using PowerQuery (in Excel 2016+)
  2. Massage based on source/format to common format that saves nicely to Excel sheet and is easy to convert to JSON in post-processing
  3. Save file in that format
  4. Convert to json IR library format, yielding a single JSON file that has all my IR codes
  5. using node red or any other control program, consume the JSON by converting to object and referencing the various fields needed to drive IR (and then serial as well) commands.

Step 4 would presumably be a utility that I could create, maybe even in node red.

Given that I am into AV systems as a business, I need to accommodate the following requirements:

  1. I want one library stored in a single, self-describing, easily human readable format that accumulates over time, and is easily consumed by node red and other programs,
  2. At some point I will put the library in a SQL database most likely.
  3. Workflow for projects must be very efficient and extensible using Agile methology
  4. Accommodate the reality that there are lots of sources of IR codes, in various formats
  5. Accommodate the reality that in some cases IR codes must be learned manually using the actual remote control, and manually edited/stored (I am currently using global cache iLearn utility, which supports supports several output formats including JSON)

I am on deadline right now and I thank you all for the great ideas and help.

Next week I will add another entry here detailing what I ended up with as solution so that technique is available to others. i have benefitted mightily from online forums and will give back, especially to share the biggest roadblocks I ran into learning node red (many). I now am gaining momentum and get more impressed with node red and the people using it, the more I learn. Happy to be a new member of the community.

Stephen

1 Like

As it is such a valuable thread, please consider changing the original topic title to better reflect what this covers, as I think it has strayed somewhat from the best practice modularity/subflow topic. That will make it easier for others to find in the future.