Sending an email from node red flow : based on integer table status

I am new to node red and JavaScript. I would appreciate help on something I need to get working. I want to send an email to notify me of an alarm condition, based on the status of an I 32 table from my S2. i.e. if value is 1 alarm conditon, 0 no alarm. Please see the attached flow. I have a function block in to simulate my snap pac read node just for simplicity for now.
The only problem i have is that i dont know how to only send the email once, and not every time the flow is injected when an alarm is active.
Any ideas, much appreciation for help on this.

[{"id":"fae1c9a.3fe49b8","type":"inject","z":"c97af0fa.6fb9","name":"","topic":"","payload":"","payloadType":"num","repeat":"3600","crontab":"","once":false,"onceDelay":0.1,"x":288,"y":258,"wires":[["a84d3449.af0e88"]]},{"id":"85f79ab7.071c58","type":"debug","z":"c97af0fa.6fb9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","x":429,"y":498,"wires":[]},{"id":"a84d3449.af0e88","type":"function","z":"c97af0fa.6fb9","name":"simulate I 32 from SNAP S-2","func":"\n//mimmic the Opto 22 msg.payload\n//set all events to trigger = of zero\nmsg.payload = \n[\n    0,\n    0,\n    1,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0,\n    0\n];\n\nreturn msg;\n","outputs":1,"noerr":0,"x":347,"y":318,"wires":[["8052cd35.8b6aa8"]]},{"id":"ce24e154.f29cf8","type":"function","z":"c97af0fa.6fb9","name":"build email","func":"//Build the email message:\nvar LowAlm = msg.payload; //the I 32 alarm table copied from the Opto controller\nvar R1indextxt = []; //array holding the text for the alarm messages\nvar R1indextxt_final = []; //array holding the alarms that are active\nvar Rindextxt_finalload = []; //array holding the alamrs with the null removed\n\nR1indextxt[0] = \"T1000 low alarm active\"\nR1indextxt[1] = \"T1001 low alarm active\"\nR1indextxt[2] = \"T1002 low alarm active\"\nR1indextxt[3] = \"T1003 low alarm active\"\nR1indextxt[4] = \"T1004 low alarm active and whatever\"\nR1indextxt[5] = \"T1005 low alarm active\"\nR1indextxt[10] = \"T1015 low alarm active and more text\"\n//and so on... up to element 100 or whatever is needed\n\n//map the array to match the read in I 32 table alarm condition to the proper text field\n var format_LowAlm =, index_number) =>{\n    //Check the Value of each index and assign a text alarm if equals one\n    if (element === 1) \n    {\n        R1indextxt_final[index_number] = R1indextxt[index_number];\n    }\n});\n\n//get rid of the null elements \nR1indextxt_finalload = R1indextxt_final.filter(function(i){return i !== null; });\n\n//msg.payload - the content inside the email\nmsg.payload = \"PPXX Process Alarm ||\" + R1indextxt_finalload.join(\" // \");\n//msg.topic - subject line of the email\nmsg.topic = 'PPXX Process Alarm'\n\n//this can be set in the email node\ = []\n//msg.includes = Alarm_active;\ = msg.payload;\n// = Alarm_active;\n\nreturn msg;","outputs":1,"noerr":0,"x":448,"y":434,"wires":[["85f79ab7.071c58","fa4b7c4.ad20b8","d9aa46ab.94a198"]]},{"id":"8052cd35.8b6aa8","type":"function","z":"c97af0fa.6fb9","name":"evaluate array","func":"//evaluate alarm array: does an email need to be sent?\nfunction isOne(One) {\n    return One === 1;\n}\n\nvar LowAlm = msg.payload; //the I 32 alarm table copied from the Opto controller\nvar Alarm_active; //boolean to hold status of alarm state: if email should be sent\n\nAlarm_active = LowAlm.some(isOne);\ = Alarm_active;\nmsg.payload = LowAlm;\n\nreturn msg;","outputs":1,"noerr":0,"x":311,"y":378,"wires":[["58e52cc1.67958c"]]},{"id":"58e52cc1.67958c","type":"switch","z":"c97af0fa.6fb9","name":"","property":"active","propertyType":"msg","rules":[{"t":"true"},{"t":"false"}],"checkall":"true","repair":false,"outputs":2,"x":297,"y":440,"wires":[["ce24e154.f29cf8"],["85f79ab7.071c58"]]},{"id":"fa4b7c4.ad20b8","type":"e-mail","z":"c97af0fa.6fb9","server":"","port":"465","secure":true,"name":"","dname":"","x":677,"y":434,"wires":[]},{"id":"d9aa46ab.94a198","type":"debug","z":"c97af0fa.6fb9","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":696,"y":491,"wires":[]}]

I think the easiest way to get the functionality you’re describing would be to add a report by exception (RBE) node right after the SNAP read node. By default the RBE node will “block unless value changes” which means any duplicate messages are dumped, but any time an array comes in with a different value it is allowed to continue through the flow.

This way you don’t get duplicate emails for the same alarm, but when the alarm condition changes (becomes active) it is allowed through and you get an email. Then, if the alarm condition changes back (becomes inactive) your current switch node should catch it and not send an email.

Let me know if that works for you or if you have any other questions!

Also, welcome to the forum!

Thanks a lot that works excellent and does exactly what I needed.

Here is a follow up question to this node red flow. In the function block, an alarm text field is coded to a specific array element for the email payload body. Another option, is that I could use a string persistent table in the S-2 controller and read the table using the snap read node. I would have a string table of a length as high as 500 and width of 48. Would this be too much memory usage. A downside I see would be whenever new firmware is installed I would lose these values.
What are your thoughts on this? thanks,

Looking at the PAC-S2 controller memory map… We can see that you have around 16mb for your strategy.

In other words, no, a table of that size is not going to be any problem at all (assuming you don’t have a massive strategy).

As for backing it up before you do a firmware update, you should be using OptoTagPreserve as a matter of course when doing the update process.
Read a little more about it here;