Bad idea to use function node instead of separate flow nodes?

I have sonoff RF receiver which I have take payload and put it to separate switch nodes.

Then, there was too many switch nodes, and I try to replace them with only one function node, containting all 'translations' of incoming messages from RF to single mqtt publish node., with following code:

var a = msg.payload.RfReceived.Data;
//var a=msg.payload;
var b=null;

// motion sensor MS01 @ ENTRY DOOR
if (a=='EC2D8E') {msg.topic='stat/terasa/MS01'; msg.payload='ON';}

// motion sensor MS03 @ RADIONA
if (a=='EBC35E') {msg.topic='stat/terasa/MS03'; msg.payload='ON';}


// door senzor TERASA
if (a=='2BB30A') {msg.topic='stat/DS01'; msg.payload='ON';}
if (a=='2BB30E') {msg.topic='stat/DS01'; msg.payload='OFF';}
if (a=='2BB306') {msg.topic='stat/DS01'; msg.payload='BATT';}

// door senzor TEST SENZOR NA STOLU
if (a=='93B60A') {msg.topic='stat/DESK'; msg.payload='ON';}
if (a=='93B60E') {msg.topic='stat/DESK'; msg.payload='OFF';}
if (a=='93B606') {msg.topic='stat/DESK'; msg.payload='BATT';}

// door senzor STUBIĹ TE DONJA VRATA
if (a=='D8FE0A') {msg.topic='stat/DS07'; msg.payload='ON';}
if (a=='D8FE0E') {msg.topic='stat/DS07'; msg.payload='OFF';}
if (a=='D8FE06') {msg.topic='stat/DS07'; msg.payload='BATT';}

// door senzor ULAZNA VRATA
if (a=='32760A') {msg.topic='stat/DS02'; msg.payload='ON';}
if (a=='32760E') {msg.topic='stat/DS02'; msg.payload='OFF';}
if (a=='327606') {msg.topic='stat/DS02'; msg.payload='BATT';}

// door senzor GARAŽA POLO
if (a=='31A40A') {msg.topic='stat/DS03'; msg.payload='ON';}
if (a=='31A40E') {msg.topic='stat/DS03'; msg.payload='OFF';}
if (a=='31A406') {msg.topic='stat/DS03'; msg.payload='BATT';}

// door senzor GARAŽA AUDI
if (a=='347A0A') {msg.topic='stat/DS04'; msg.payload='ON';}
if (a=='347A0E') {msg.topic='stat/DS04'; msg.payload='OFF';}
if (a=='347A06') {msg.topic='stat/DS04'; msg.payload='BATT';}

// door senzor GARAŽA RADIONA
if (a=='32020A') {msg.topic='stat/DS05'; msg.payload='ON';}
if (a=='32020E') {msg.topic='stat/DS05'; msg.payload='OFF';}
if (a=='320206') {msg.topic='stat/DS05'; msg.payload='BATT';}

// door senzor POŠTANSKI SANDUČIĆ
if (a=='33900A') {msg.topic='stat/DS06'; msg.payload='ON';}
if (a=='33900E') {msg.topic='stat/DS06'; msg.payload='OFF';}
if (a=='339006') {msg.topic='stat/DS06'; msg.payload='BATT';}

// door senzor KAPIJA DOOBR BELL
if (a=='C5FD05') {msg.topic='stat/GATE/db01'; msg.payload='ON';}



// RF TIPKALA

    // TIPKALO 1
    if (a=='013C94') {msg.topic='cmnd/RS_LED1/POWER'; msg.payload='TOGGLE';}
    if (a=='013C92') {msg.topic='cmnd/SOF001/POWER';  msg.payload='TOGGLE';}
    if (a=='013C91') {msg.topic='cmnd/DOF003/POWER';  msg.payload='TOGGLE';}

    // TIPKALO 2
    if (a=='0A1B91') {msg.topic='cmnd/RS_LED1/POWER'; msg.payload='TOGGLE';}
    if (a=='0A1B98') {msg.topic='cmnd/SOF001/POWER';  msg.payload='TOGGLE';}
    if (a=='0A1B92') {msg.topic='cmnd/SOF003/POWER';  msg.payload='TOGGLE';}



return msg;

Works fine, but slower ?

It seams that sometimes I loose some of the input messages.

Is this approach worse then send payload to separate switch nodes ??

do you need to evaluate all the if's, or just till one is true?

https://www.w3schools.com/js/js_if_else.asp

It may also be quicker to use a dictionary/object of 'a' keys and values

var ids = {"1000298253": 146,
           "10009fc033": 153,
           "10008186bb": 154
}
msg.topic = ids[a]
return msg;

Whenever you are looking at lots of if's like that, a switch/case statement is almost always going to be better. Though I've no idea whether it is more performant in this case.

Possibly even better in this case would be to maintain a global variable for a lookup table. You could probably replace most of that code with 1 or 2 statements. Again though, no idea whether it would be more efficient - almost certainly easier to maintain though. (Oops, I see that @E1cid beat me to that idea though I'd put it in a global var so that you can use other processes/flows to maintain it).

Can't think why that code might be failing to process input messages. Are you counting the input and output messages? Also, how fast are you trying to process inputs and on what platform? What else does the platform have running on it?

Yes i thought global to, but i'm new to javascript and could not be bothered to check syntaxs. Please feel free to add anything i missed. i was horrified at the number of if's.

In your function:
if incoming payload is something you haven't defined in your if statements, then it returns original message.
This may be OK but also it is something you can look as a risk of failure.

For this little the function does for you, I doubt there will be noticeable performance losses. Of course, it can be optimized.
For example in every if statement, return msg immediately as there is no need to compare the input with anything else if it is already found.

1 Like

Many months ago, I created a solution that you may find useful. Although it was designed to integrate a Sonoff RF Bridge with Home Assistant, the approach I used is based on MQTT so Home Assistant is not required.

The solution was initially realized in python but I also created a Node-Red version. It's described here (where you will also find the flow's listing):

The function node called demultiplexer does all the work. I've modified it to use your data and to accommodate your topic structure:

var d = { 'EC2D8E':['stat/terasa/MS01','ON','false'],
          'EBC35E':['stat/terasa/MS03','ON','false'],
          '2BB30A':['stat/DS01','ON','false'],
          '2BB30E':['stat/DS01','OFF','false'],
          '2BB306':['stat/DS01','BATT','false'],
          '93B60A':['stat/DESK','ON','false'],
          '93B60E':['stat/DESK','OFF','false'],
          '93B606':['stat/DESK','BATT','false'],
          'D8FE0A':['stat/DS07','ON','false'],
          'D8FE0E':['stat/DS07','OFF','false'],
          'D8FE06':['stat/DS07','BATT','false'],
          '32760A':['stat/DS02','ON','false'],
          '32760E':['stat/DS02','OFF','false'],
          '327606':['stat/DS02','BATT','false'],
          '31A40A':['stat/DS03','ON','false'],
          '31A40E':['stat/DS03','OFF','false'],
          '31A406':['stat/DS03','BATT','false'],
          '347A0A':['stat/DS04','ON','false'],
          '347A0E':['stat/DS04','OFF','false'],
          '347A06':['stat/DS04','BATT','false'],
          '32020A':['stat/DS05','ON','false'],
          '32020E':['stat/DS05','OFF','false'],
          '320206':['stat/DS05','BATT','false'],
          '33900A':['stat/DS06','ON','false'],
          '33900E':['stat/DS06','OFF','false'],
          '339006':['stat/DS06','BATT','false'],
          'C5FD05':['stat/GATE/db01','ON','false'],
          '32760E':['stat/DS02','OFF','false'],
          '327606':['stat/DS02','BATT','false'],
          '013C94':['cmnd/RS_LED1/POWER','TOGGLE','false'],
          '013C92':['cmnd/SOF001/POWER','TOGGLE','false'],
          '013C91':['cmnd/DOF003/POWER','TOGGLE','false'],
          '0A1B91':['cmnd/RS_LED1/POWER','TOGGLE','false'],
          '0A1B98':['cmnd/SOF001/POWER','TOGGLE','false'],
          '0A1B92':['cmnd/DOF003/POWER','TOGGLE','false']
        };

var p = msg.payload.RfReceived.Data;

if (p in d) {
  msg.topic = d[p][0];
  msg.payload = d[p][1];
  msg.retain = d[p][2];
  msg.qos = 1;
}
else {
  msg.topic = "stat/unknown";
  msg.payload = p;
  msg.retain = "false";
  msg.qos = 1;
}

return msg;

The data's format is straightforward:

'rfcode':['topic','payload','retain']

Although I set all of the retain fields to false, if there are topics whose payloads you wish to have retained, just set their retain field to true.

1 Like

I do something similar to assign roles and MQTT topics to my ESP8266 nodes, but with the added step of reading the table from a file. The read is triggered from a one-shot on start-up, deploy or a button click, and the file converted from CSV and saved in global context. This means that :

a) the data is available for multiple uses
b) it's easy to edit the file, and
c) the function nodes are a lot less cluttered.

Using column names in the CSV format also allows accessing the fields by name, e.g.

if (nodeids[idx].NodeID == msg.payload)
{
    nodeTopic = nodeids[idx].Topic;
}
2 Likes

Wow, what a good community here :=)
I thought that kind of cooperation died with usnet newsgroups.

Back to topic.
Above solution(s) works great, even handles some potential threats which I didn't think of.

I tried measure which is faster with Date.now() timestamps. There was no visible difference. Difference of Date.now() before and after run of both functions is 0 or 1 ms. Both more less same. But for some other reason probably, my function was returning many cycles on payload.msg. Not sure why. Never mind now, I like you solutions better.

Btw. I run this automation on Raspberry Pi 3. It's used only for node red with dashboard. Just motions sensors over RF bridge, and commands to lights. Exception is one photo taken from camera taken each 5 sec. Nothing else on this device. But configuration gets quite large now. Over 5000 lines when I export it (formated export of all nodes from nodered).

Tnx..

Ah well, perhaps it helps that some of us still remember those heady days :rofl:

2 Likes

There is also process.hrtime for a higher resolution timer - see https://nodejs.org/api/process.html#process_process_hrtime_time
can't recall is we add process to the global scope in a function already or if you would need to add it via settings.js, but it can be useful.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.