# How to create an Modbus-TCP alarm status dashboard

**URL:** <https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041>\
**Category:** Industrial\
**Created:** [22 March 2021 19:59 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041 "2021-03-22T19:59:23Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [22 March 2021 19:59 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/1 "2021-03-22T19:59:24Z")

</div>

My goal is to motorize 350 addresses of a PLC over a modebus-tcp, and if any of the values are different then 0 (zero) to display on a dashboard those address, the corresponding status (based on the value reported) and the trigger time.  
In other words to create an alarm dashboard that shows in real time the PLC status.

Some clarification:

- The flow only pulls modbus-tcp data (every second) no need to send any commands (values)
- Each address can report only the following values:  
- "0" - normal state (value not displayed)  
- "2" - not acknowledge alarm (display in red)  
- "1027" - acknowledge alarm (display in yellow)  
- "1088" - sensor fail (sensor fail)
- Each address is associated with a certain area of the system (ex. 0001 = valve 1; 0002 = light1; 0003 = main computer .....) on the dashboard I want to display the associated name of each address too.
- beside the real time dashboard I want to create an alarm log (a database with all reported alarms as they occur)

I need some help with he following:

- how to display the initial triggered alarm time (on my flow time refreshes with every data pull)
- how to separate the triggered alarms from the modbus-read array and to use a database to associate the names of the triggered address (for all 350 of them)
- how to separate the triggered alarms from the modbus-read array to be logged to a database

Any help is much appreciated.

Here is a print screen of my dashboard and the flow I have so far:

 ![image1](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/c/accd009708efb180dfc617124d05c2459810d634.jpeg)

```auto
[{"id":"e36f3a9f.a38dd8","type":"ui_table","z":"74d8f714.ab8378","group":"81dd3718.b97888","name":"Alarm","order":1,"width":"12","height":"8","columns":[{"field":"Time","title":"<center>Time</>","width":"25%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Register","title":"<center>Channel</>","width":"10%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Notes","title":"<center>Alarm Message</>","width":"50%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}},{"field":"Alarm","title":"<center>Status</>","width":"15%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":850,"y":1460,"wires":[]},{"id":"80183847.7650d8","type":"modbus-read","z":"74d8f714.ab8378","name":"","topic":"","showStatusActivities":true,"logIOActivities":false,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"0","quantity":"100","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c6527b9f.17c448","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":170,"y":1480,"wires":[["c37bbf47.cf40d8","6cd67e6f.8345f8","55ab041b.5d0f3c","2856eb17.df3bb4","bb3c74a1.d7b4c","74cfddeb.27a7e4","7fbc0c6f.1603dc","345beee5.52173a"],[]]},{"id":"6cd67e6f.8345f8","type":"function","z":"74d8f714.ab8378","name":"1-100 test all alarms code","func":"\nvar t = new Date();\nt = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + ' / ' + ('00' + (t.getMonth()+1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());\n\n//var i=0;\nfor (var i=0; i < msg.payload.length ; i++) {\n\nif (msg.payload[i]!==0) {\n if (i<9) {\n if (msg.payload[i]===2) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"0000\" + (i+1),\n \"Alarm\": \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1027) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"0000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1028) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"0000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1029) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"0000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n } \n if (msg.payload[i]===1088) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"0000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n } \n }\n if (i>=9 && i<99) {\n if (msg.payload[i]===2) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"000\" + (i+1),\n \"Alarm\": \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1027) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1028) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1029) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n } \n if (msg.payload[i]===1088) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"000\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n } \n }\n if (i==99) {\n if (msg.payload[i]===2) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"00\" + (i+1),\n \"Alarm\": \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1027) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"00\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1028) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"00\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n }\n if (msg.payload[i]===1029) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"00\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n } \n if (msg.payload[i]===1088) {\n msg.payload.push(\n {\n \"Time\": t,\n \"Register\":\"00\" + (i+1),\n \"Alarm\": \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\",\n \"Notes\": \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i+1) +\"</div>\"\n })\n } \n }\n}\n}\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":430,"y":1460,"wires":[["8bb0330c.318e2","42560203.14ce24","a8504d6b.fc97f","5285815a.bef9b","f4cbbe3f.7cd658"]]},{"id":"42560203.14ce24","type":"function","z":"74d8f714.ab8378","name":"","func":"\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":1460,"wires":[["e36f3a9f.a38dd8"]]},{"id":"81dd3718.b97888","type":"ui_group","name":"Active Alarms","tab":"4e11db25.239e94","order":1,"disp":true,"width":"12","collapse":true},{"id":"c6527b9f.17c448","type":"modbus-client","name":"","clienttype":"tcp","bufferCommands":false,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"192.168.1.120","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":1,"commandDelay":1,"clientTimeout":1000,"reconnectOnTimeout":true,"reconnectTimeout":2000,"parallelUnitIdsAllowed":true},{"id":"4e11db25.239e94","type":"ui_tab","name":"Alarms Monitiring","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 March 2021 21:20 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/2 "2021-03-22T21:20:41Z")

</div>

Essentially, store the modbus array (payload) in context & check its value is different before generating an alarm entry. Also, store the table rows array in context and add/remove/update the rows depending on the change from current to previous value.

e.g...

```auto

var t = new Date();
t = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + ' / ' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());

var previous = context.get("previous") || [];
var current = [...msg.payload];
var table = context.get("table") || [];

for (var i = 0; i < msg.payload.length; i++) {
    var register = ("" + (i + 1)).padStart(5,"0");
    
    //has value changed?
    if (previous[i] !== current[i]) {
        var row = table.find(e => e.Register == register);

        if (!row) {
            if (current[i] === 0)
                continue; //dont add this one (its 0)
            
            row = {
                "Register": register,
                "Alarm": "",
                "Notes": ""
            }            
            table.push(row);
        } else {
            //there is a row in the table...
            if (current[i] === 0) {
                ///remove it because its now 0
                table = table.filter(e => e.Register !== register);
                continue;
            }
        }

        row.Time = t;//update the time
        if (current[i] === 2) {
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + "ALARM" + "</div>";
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>";
        } else if (current[i] === 1027) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>";
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>";
        } else if (current[i] === 1028) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>",
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>"
        } else if (current[i] === 1029) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>",
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>"
        } else if (current[i] === 1088) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "SENSOR FAIL" + "</div>",
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>"
        }        
    }
}

context.set("previous", current);
context.set("table", table);

msg.payload = table;
return msg;

```

Here is a demo flow...

```auto
[{"id":"e36f3a9f.a38dd8","type":"ui_table","z":"b872cb4b.5a6448","group":"81dd3718.b97888","name":"Alarm","order":1,"width":"12","height":"8","columns":[{"field":"Time","title":"<center>Time</>","width":"25%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Register","title":"<center>Channel</>","width":"10%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Notes","title":"<center>Alarm Message</>","width":"50%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}},{"field":"Alarm","title":"<center>Status</>","width":"15%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":1310,"y":1000,"wires":[]},{"id":"6cd67e6f.8345f8","type":"function","z":"b872cb4b.5a6448","name":"generate alarm table","func":"\nvar t = new Date();\nt = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + ' / ' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());\n\nvar previous = context.get(\"previous\") || [];\nvar current = [...msg.payload];\nvar table = context.get(\"table\") || [];\nfor (var i = 0; i < msg.payload.length; i++) {\n var register = (\"\" + (i + 1)).padStart(5,\"0\");\n \n //has value changed?\n if (previous[i] !== current[i]) {\n var row = table.find(e => e.Register == register);\n\n if (!row) {\n if (current[i] === 0)\n continue; //dont add this one (its 0)\n \n row = {\n \"Register\": register,\n \"Alarm\": \"\",\n \"Notes\": \"\"\n } \n table.push(row);\n } else {\n //there is a row in the table...\n if (current[i] === 0) {\n ///remove it because its now 0\n table = table.filter(e => e.Register !== register);\n continue;\n }\n }\n\n row.Time = t;//update the time\n if (current[i] === 2) {\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\";\n row.Notes = \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i + 1) + \"</div>\";\n } else if (current[i] === 1027) {\n row.Alarm = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Notes = \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i + 1) + \"</div>\";\n } else if (current[i] === 1028) {\n row.Alarm = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n row.Notes = \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i + 1) + \"</div>\"\n } else if (current[i] === 1029) {\n row.Alarm = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\",\n row.Notes = \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i + 1) + \"</div>\"\n } else if (current[i] === 1088) {\n row.Alarm = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\",\n row.Notes = \"<div style='background-color: red; width:100%; color:white'>\" + \"NO COMM. ON MAIN NETWORK\" + (i + 1) + \"</div>\"\n } \n }\n}\n\ncontext.set(\"previous\", current);\ncontext.set(\"table\", table);\n\nmsg.payload = table;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1120,"y":1000,"wires":[["e36f3a9f.a38dd8"]]},{"id":"4cb90eb.e1c59f","type":"inject","z":"b872cb4b.5a6448","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[0,0,0,0,0]","payloadType":"json","x":790,"y":1000,"wires":[["6cd67e6f.8345f8"]]},{"id":"d525bd3.ce2364","type":"inject","z":"b872cb4b.5a6448","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[0,0,0,0,2]","payloadType":"json","x":800,"y":1040,"wires":[["6cd67e6f.8345f8"]]},{"id":"1e32cbd0.0b6174","type":"inject","z":"b872cb4b.5a6448","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[0,2,0,0,2]","payloadType":"json","x":800,"y":1080,"wires":[["6cd67e6f.8345f8"]]},{"id":"5fa3b332.bb05dc","type":"inject","z":"b872cb4b.5a6448","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[0,1027,0,0,2]","payloadType":"json","x":810,"y":1120,"wires":[["6cd67e6f.8345f8"]]},{"id":"7b341dc5.0d6854","type":"inject","z":"b872cb4b.5a6448","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[1028,1027,0,0,2]","payloadType":"json","x":820,"y":1160,"wires":[["6cd67e6f.8345f8"]]},{"id":"81dd3718.b97888","type":"ui_group","name":"Active Alarms","tab":"4e11db25.239e94","order":1,"disp":true,"width":"12","collapse":true},{"id":"4e11db25.239e94","type":"ui_tab","name":"Alarms Monitiring","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 March 2021 21:24 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/3 "2021-03-22T21:24:22Z")

</div>

> [@lucibuz](#):
>
> Each address is associated with a certain area of the system (ex. 0001 = valve 1; 0002 = light1; 0003 = main computer .....) on the dashboard I want to display the associated name of each address too.

For this part, use a lookup...

```auto
var lookup = {
  1: "Door Sensor",
  2: "Window Sensor"
}
var sensorNo = 1;
var sensorName = lookup[sensorNo] || ("Unknown " + sensorNo);

```

proof....  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/8/c82939cfb632dcb270f7696a825fefd9c9d09929.png)

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [22 March 2021 21:26 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/4 "2021-03-22T21:26:08Z")

</div>

> [@lucibuz](#):
>
> beside the real time dashboard I want to create an alarm log (a database with all reported alarms as they occur)

Do you know SQL and databases?

what database?

There are hundreds of examples of INSERTing data into SQL databases.

I suggest you start with separate demo flows (using injects) to get it node-red --\> database working THEN try to integrate with your flow.

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [22 March 2021 21:33 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/5 "2021-03-22T21:33:02Z")

</div>

Thanks for your quick reply,  
I'll check your suggestions and get back with the results.

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [23 March 2021 10:58 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/6 "2021-03-23T10:58:14Z")

</div>

Thanks for sharing the above code examples, they worked great and the result in the Alarm Dashboard is as I want it.

For the alarms log I want to use a SQlite database, I've seen some examples that how to create a table and how to insert data, but I don't know how to extract each objects from the generated alarms array.

I adapt an example to my flow but I don't know how to extract those payloads.

```auto
msg.topic = "INSERT INTO accesslog (time,register,alarm,notes) " +
        "VALUES ('"+msg.payload.time+"','"+msg.payload.register+"','"+msg.payload.alarm+"','"+msg.payload.notes+"')";

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [23 March 2021 11:14 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/7 "2021-03-23T11:14:25Z")

</div>

> [@lucibuz](#):
>
> I adapt an example to my flow but I don't know how to extract those payloads.
> 
> ```auto
> msg.topic = "INSERT INTO accesslog (time,register,alarm,notes) " +
> "VALUES ('"+msg.payload.time+"','"+msg.payload.register+"','"+msg.payload.a
> 
> ```

first things first, JavaScript is case sensitive (e.g. `msg.payload.time` is different to `msg.payload.Time`)

* * *

Am I right in thinking that you want the "detected alarm changes (the adds and updates)" to be sent to SQLite database?

Then you could simply send a `msg` from the function that updates the alarm table. For this you use node.send() and if you use an array you can send out of different outputs on the function. Port 1 could be for the final table data, port 2 for sending to SQLite

e.g...  
set the function to output 2 outputs then return the table out of output 1 (at the end of the function) and node.send the "update/insert" messages out of output 2 (in the middle of the loop as changes are detected)...

```auto
var t = new Date();
t = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + ' / ' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());

var previous = context.get("previous") || [];
var current = [...msg.payload];
var table = context.get("table") || [];

for (var i = 0; i < msg.payload.length; i++) {
    var register = ("" + (i + 1)).padStart(5,"0");
    var update_or_insert = "";

    //has value changed?
    if (previous[i] !== current[i]) {
        var row = table.find(e => e.Register == register);

        if (!row) {
            if (current[i] === 0)
                continue; //dont add this one (its 0)
            
            row = {
                "Register": register,
                "Alarm": "",
                "Notes": ""
            }            
            update_or_insert = "insert";
            table.push(row);
        } else {
            //there is a row in the table...
            if (current[i] === 0) {
                ///remove it because its now 0
                table = table.filter(e => e.Register !== register);
                continue;
            }
            update_or_insert = "update";
        }

        row.Time = t;//update the time
        if (current[i] === 2) {
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + "ALARM" + "</div>";
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>";
        } else if (current[i] === 1027) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>";
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>";
        } else if (current[i] === 1028) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>",
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>"
        } else if (current[i] === 1029) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>",
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>"
        } else if (current[i] === 1088) {
            row.Alarm = "<div style='background-color: yellow; width:100%; color:red'>" + "SENSOR FAIL" + "</div>",
            row.Notes = "<div style='background-color: red; width:100%; color:white'>" + "NO COMM. ON MAIN NETWORK" + (i + 1) + "</div>"
        }       
        //TODO: 
        // You can create the SQL here and send it in the topic OR send an object with 
        // the clean alarm and notes info (i.e. no HTML) then build a SQL query in the next node 
        node.send( [null, {topic:update_or_insert,payload:row}] ); //Send the updated ROW out of output 2
    }
}

context.set("previous", current);
context.set("table", table);

msg.payload = table;
return [msg, null]; //Return table to function output 1;

```

* * *

NOTE: Read the TODO in the code.

NOTE2: Read this: There’s a great page in the docs that will explain how to use the debug panel to find the right path to any data item. [Working with messages : Node-RED](https://nodered.org/docs/user-guide/messages)

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [23 March 2021 11:33 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/8 "2021-03-23T11:33:15Z")

</div>

> [@Steve-Mcl](#):
>
> Am I right in thinking that you want the "detected alarm changes (the adds and updates)" to be sent to SQLite database?

I believe so, I have to try it to see how data is logged.

I'll give it a try and get back with the results.

Thanks again, much appreciated your help.

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [24 March 2021 19:25 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/9 "2021-03-24T19:25:50Z")

</div>

Hello,  
I manage to create the SQLite database and to inset the triggered alarms into the database log as suggested above.

Here is the code I adapted up to my knowledge:

```auto

var previous = context.get("previous") || [];
var current = [...msg.payload];
var table = context.get("table") || [];
for (var i = 0; i < msg.payload.length; i++) {
    var channel = ("" + (i + 1)).padStart(5,"0");
    var sensorNo = (i + 1);
    var sensorName = lookup[sensorNo] || ("Unknown " + sensorNo);
    //has value changed?
    if (previous[i] !== current[i]) {
        var row = table.find(e => e.Channel == channel);

        if (!row) {
            if (current[i] === 0)
                continue; //dont add this one (its 0)
            
            row = {
                "Time":t,
                "Channel": channel,
                "Alarm": "",                
                "Status": "",
                "Alarmlog": "",                
                "Statuslog": ""                
            }            
            table.push(row);
        } else {
            //there is a row in the table...
            if (current[i] === 0) {
                ///remove it because its now 0
                table = table.filter(e => e.Channel !== channel);
                continue;
            }
        }

        row.Time = t;//update the time
        if (current[i] === 2) {
            row.Status = "<div style='background-color: red; width:100%; color:white'>" + "ALARM" + "</div>";
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + sensorName + "</div>";
            row.Statuslog = "ALARM !";
            row.Alarmlog = sensorName ;            
        } else if (current[i] === 1027) {
            row.Status = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>";
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + sensorName + "</div>";
            row.Statuslog = "ALARM";
            row.Alarmlog = sensorName ;            
        } else if (current[i] === 1028) {
            row.Status = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>";
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + sensorName + "</div>";
            row.Statuslog = "ALARM";
            row.Alarmlog = sensorName ;
        } else if (current[i] === 1029) {
            row.Status = "<div style='background-color: yellow; width:100%; color:red'>" + "ALARM" + "</div>";
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + sensorName + "</div>";
            row.Statuslog = "ALARM";
            row.Alarmlog = sensorName ;
        } else if (current[i] === 1088) {
            row.Status = "<div style='background-color: yellow; width:100%; color:red'>" + "SENSOR FAIL" + "</div>";
            row.Alarm = "<div style='background-color: red; width:100%; color:white'>" + sensorName + "</div>";
            row.Statuslog = "SENSOR FAIL";
            row.Alarmlog = sensorName ;
        }
                //TODO: 
        // You can create the SQL here and send it in the topic OR send an object with 
        // the clean alarm and notes info (i.e. no HTML) then build a SQL query in the next node 
        node.send( [null, { topic: ("INSERT INTO alarmlog (Time,Channel,Alarm,Status) " +
        "VALUES ('"+row.Time+"','"+row.Channel+"','"+row.Alarmlog+"','"+row.Statuslog+"')")}] ); //Send the SQL query out of output 2
    }
}

context.set("previous", current);
context.set("table", table);

msg.payload = table;
return [msg, null]; //Return table to function output 1;

```

and the flow:

```auto
[{"id":"80183847.7650d8","type":"modbus-read","z":"74d8f714.ab8378","name":"","topic":"","showStatusActivities":true,"logIOActivities":false,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"0","quantity":"115","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c6527b9f.17c448","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":250,"y":1460,"wires":[["c37bbf47.cf40d8","b50640ea.4fca38","115b2abd.6fd2fd"],[]]},{"id":"115b2abd.6fd2fd","type":"function","z":"74d8f714.ab8378","name":"generate alarm table","func":"\nvar t = new Date();\nt = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + '/' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());\n\nvar lookup = {\n 1: \"NO COMM. ON MAIN NETWORK\",\n 2: \"NO COMM. ON BACKUP NETWORK\",\n 3: \"MAIN SERVER OUT OF ORDER\",\n 4: \"BACKUP SERVER OUT OF ORDER\",\n 5: \"NO COMM. MAIN SERVER ON MAIN NETWORK\",\n 6: \"NO COMM. MAIN SERVER ON BACKUP NETWORK\",\n 7: \"NO COMM. BACKUP SERVER ON MAIN NETWORK\",\n 8: \"NO COMM. BACKUP SERVER ON BACKUP NETWORK\",\n 9: \"MAXIMUM DISKSPACE USED. LOGGING STOPPED\",\n 10: \"ALARMLOG: FILE CAN NOT BE WRITTEN\",\n 11: \"MTUS PORT: RD4 COM PORT FAILURE\",\n 12: \"MTUS PORT: RD4 NO COMMUNICATION\",\n 13: \"MTUS PORT: RD4 ERROR IN COMMUNICATION\",\n 14: \"MTUS STBD: RD5 COM PORT FAILURE\",\n 15: \"MTUS STBD: RD5 NO COMMUNICATION\",\n 16: \"MTUS STBD: RD5 ERROR IN COMMUNICATION\",\n 17: \"X101 NOT PRESENT\",\n 18: \"X102 NOT PRESENT\",\n 19: \"X103 NOT PRESENT\",\n 20: \"X104 NOT PRESENT\",\n 21: \"X109 NOT PRESENT\",\n 22: \"X110 NOT PRESENT\",\n 23: \"X111 NOT PRESENT\",\n 24: \"X117 NOT PRESENT\",\n 25: \"X118 NOT PRESENT\",\n 26: \"X119 NOT PRESENT\",\n 27: \"X125 NOT PRESENT\",\n 28: \"X126 NOT PRESENT\",\n 29: \"X127 NOT PRESENT\",\n 30: \"X128 NOT PRESENT\",\n 31: \"XP101 MAIN LINK NOT PRESENT\",\n 32: \"XP109 MAIN LINK NOT PRESENT\",\n 33: \"XP117 MAIN LINK NOT PRESENT\",\n 34: \"XP125 MAIN LINK NOT PRESENT\",\n 35: \"XP101 BACKUP LINK NOT PRESENT\",\n 36: \"XP109 BACKUP LINK NOT PRESENT\",\n 37: \"XP117 BACKUP LINK NOT PRESENT\",\n 38: \"XP125 BACKUP LINK NOT PRESENT\",\n 39: \"X101 INVALID BOARD TYPE\",\n 40: \"X102 INVALID BOARD TYPE\",\n 41: \"X103 INVALID BOARD TYPE\",\n 42: \"X104 INVALID BOARD TYPE\",\n 43: \"X109 INVALID BOARD TYPE\",\n 44: \"X110 INVALID BOARD TYPE\",\n 45: \"X111 INVALID BOARD TYPE\",\n 46: \"X117 INVALID BOARD TYPE\",\n 47: \"X118 INVALID BOARD TYPE\",\n 48: \"X119 INVALID BOARD TYPE\",\n 49: \"X125 INVALID BOARD TYPE\",\n 50: \"X126 INVALID BOARD TYPE\",\n 51: \"X127 INVALID BOARD TYPE\",\n 52: \"X128 INVALID BOARD TYPE\",\n 53: \"MBS_TCP: RD18 TCP/IP Socket Error\",\n 54: \"MBS_TCP: RD18 No Communication\",\n 55: \"MAIN SERVER IO SERVER NOT FOUND\",\n 56: \"BACKUP SERVER IO SERVER NOT FOUND\",\n 57: \"FB1 MAIN LINK NO COMMUNICATION\",\n 58: \"FB1 BACKUP LINK NO COMMUNICATION\",\n 59: \"FB2 MAIN LINK NO COMMUNICATION\",\n 60: \"X201 NOT PRESENT\",\n 61: \"X202 NOT PRESENT\",\n 62: \"X203 NOT PRESENT\",\n 63: \"X204 NOT PRESENT\",\n 64: \"X209 NOT PRESENT\",\n 65: \"X210 NOT PRESENT\",\n 66: \"X211 NOT PRESENT\",\n 67: \"X217 NOT PRESENT\",\n 68: \"X218 NOT PRESENT\",\n 69: \"X219 NOT PRESENT\",\n 70: \"X220 NOT PRESENT\",\n 71: \"FB2 BACKUP LINK NO COMMUNICATION\",\n 72: \"XP201 MAIN LINK NOT PRESENT\",\n 73: \"XP209 MAIN LINK NOT PRESENT\",\n 74: \"XP217 MAIN LINK NOT PRESENT\",\n 75: \"XP201 BACKUP LINK NOT PRESENT\",\n 76: \"XP209 BACKUP LINK NOT PRESENT\",\n 77: \"XP217 BACKUP LINK NOT PRESENT\",\n 78: \"X202 INVALID BOARD TYPE\",\n 79: \"X203 INVALID BOARD TYPE\",\n 80: \"X204 INVALID BOARD TYPE\",\n 81: \"X210 INVALID BOARD TYPE\",\n 82: \"X211 INVALID BOARD TYPE\",\n 83: \"X212 INVALID BOARD TYPE\",\n 84: \"X218 INVALID BOARD TYPE\",\n 85: \"X219 INVALID BOARD TYPE\",\n 86: \"X220 INVALID BOARD TYPE\",\n 87: \"X301 NOT PRESENT\",\n 88: \"X302 NOT PRESENT\",\n 89: \"X303 NOT PRESENT\",\n 90: \"X304 NOT PRESENT\",\n 91: \"X309 NOT PRESENT\",\n 92: \"XP301 MAIN LINK NOT PRESENT\",\n 93: \"XP309 MAIN LINK NOT PRESENT\",\n 94: \"XP301 BACKUP LINK NOT PRESENT\",\n 95: \"FB3 MAIN LINK NO COMMUNICATION\",\n 96: \"FB3 BACKUP LINK NO COMMUNICATION\",\n 97: \"FB3 PROC301 IEC-1131 CONFIG NOT LOADED\",\n 98: \"FB3 PROC301 IEC-1131 PROGRAM NOT RUNNING\",\n 99: \"NMEA_WIND: RD6 COM PORT ERROR\",\n 100: \"NMEA_WIND: RD6 NO COMMUNICATION\",\n 101: \"FB3 PROC309 IEC-1131 CONFIG NOT LOADED\",\n 102: \"FB3 PROC309 IEC-1131 PROGRAM NOT RUNNING\",\n 103: \"X301 INVALID BOARD TYPE\",\n 104: \"X302 INVALID BOARD TYPE\",\n 105: \"X303 INVALID BOARD TYPE\",\n 106: \"X304 INVALID BOARD TYPE\",\n 107: \"X309 INVALID BOARD TYPE\",\n 108: \"FB4 MAIN LINK NO COMMUNICATION\",\n 109: \"FB4 BACKUP LINK NO COMMUNICATION\", \n 110: \"FB4 LOP MESS NOT PRESENT\",\n 111: \"FB4 LOP ENGINEER NOT PRESENT\",\n 112: \"FB4 LOP 1ST MATE NOT PRESENT\",\n 113: \"FB4 LOP ALARMPANEL ENGINEROOM\",\n 114: \"ALARM PANEL E.R. POWER FAIL\",\n 115: \"ALARM PANEL E.R. EARTH FAULT\",\n 116: \"WATERTIGHT DOORS POWER FAILURE\",\n 117: \"WATERTIGHT DOORS BATTERY LOW\",\n 118: \"BILGE FORE PEAK LEVEL HIGH\",\n 119: \"BILGE BOW THRUSTER ROOM LEVEL HIGH\",\n 120: \"BILGE COFFERDAM LEVEL HIGH\"\n}\n\n\n\nvar previous = context.get(\"previous\") || [];\nvar current = [...msg.payload];\nvar table = context.get(\"table\") || [];\nfor (var i = 0; i < msg.payload.length; i++) {\n var channel = (\"\" + (i + 1)).padStart(5,\"0\");\n var sensorNo = (i + 1);\n var sensorName = lookup[sensorNo] || (\"Unknown \" + sensorNo);\n //has value changed?\n if (previous[i] !== current[i]) {\n var row = table.find(e => e.Channel == channel);\n\n if (!row) {\n if (current[i] === 0)\n continue; //dont add this one (its 0)\n \n row = {\n \"Time\":t,\n \"Channel\": channel,\n \"Alarm\": \"\", \n \"Status\": \"\",\n \"Alarmlog\": \"\", \n \"Statuslog\": \"\" \n } \n table.push(row);\n } else {\n //there is a row in the table...\n if (current[i] === 0) {\n ///remove it because its now 0\n table = table.filter(e => e.Channel !== channel);\n continue;\n }\n }\n\n row.Time = t;//update the time\n if (current[i] === 2) {\n row.Status = \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM !\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1027) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1028) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1029) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1088) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"SENSOR FAIL\";\n row.Alarmlog = sensorName ;\n }\n //TODO: \n // You can create the SQL here and send it in the topic OR send an object with \n // the clean alarm and notes info (i.e. no HTML) then build a SQL query in the next node \n node.send( [null, { topic: (\"INSERT INTO alarmlog (Time,Channel,Alarm,Status) \" +\n \"VALUES ('\"+row.Time+\"','\"+row.Channel+\"','\"+row.Alarmlog+\"','\"+row.Statuslog+\"')\")}] ); //Send the SQL query out of output 2\n }\n}\n\ncontext.set(\"previous\", current);\ncontext.set(\"table\", table);\n\nmsg.payload = table;\nreturn [msg, null]; //Return table to function output 1;","outputs":2,"noerr":0,"initialize":"","finalize":"","x":460,"y":1460,"wires":[["1caa8632.9ffda2","e36f3a9f.a38dd8"],["33eac830.bf165","25ea02b9.be8eee"]]},{"id":"e36f3a9f.a38dd8","type":"ui_table","z":"74d8f714.ab8378","group":"81dd3718.b97888","name":"Alarm List","order":1,"width":13,"height":8,"columns":[{"field":"Time","title":"<center>Time</>","width":"23%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Channel","title":"<center>Channel</>","width":"10%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Alarm","title":"<center>Alarm Message</>","width":"52%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}},{"field":"Status","title":"<center>Status</>","width":"15%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":680,"y":1440,"wires":[]},{"id":"33eac830.bf165","type":"sqlite","z":"74d8f714.ab8378","mydb":"27e5ab9a.4c829c","sqlquery":"msg.topic","sql":"","name":"Alarm Log","x":690,"y":1480,"wires":[["a37080a.2ef5","b91eacf3.d6a2b8"]]},{"id":"84f739ae.91b518","type":"ui_button","z":"74d8f714.ab8378","name":"","group":"783af07a.d61d58","order":2,"width":3,"height":1,"passthru":true,"label":"View Alarm Log","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"date","topic":"","topicType":"str","x":500,"y":1600,"wires":[["25ea02b9.be8eee"]]},{"id":"c17826fc.b4e2","type":"inject","z":"74d8f714.ab8378","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":520,"y":1640,"wires":[["25ea02b9.be8eee"]]},{"id":"25ea02b9.be8eee","type":"delay","z":"74d8f714.ab8378","name":"","pauseType":"delay","timeout":"500","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":690,"y":1620,"wires":[["83bb0a3b.56c4d8"]]},{"id":"83bb0a3b.56c4d8","type":"change","z":"74d8f714.ab8378","name":"Last 10 events","rules":[{"t":"set","p":"topic","pt":"msg","to":"SELECT * FROM alarmlog ORDER BY timestamp DESC LIMIT 10","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":860,"y":1620,"wires":[["927b5032.7c45e8"]]},{"id":"927b5032.7c45e8","type":"sqlite","z":"74d8f714.ab8378","mydb":"27e5ab9a.4c829c","sqlquery":"msg.topic","sql":"","name":"Alarm Log","x":1030,"y":1620,"wires":[["6c2561ae.43481","761d8c23.1ca984"]]},{"id":"761d8c23.1ca984","type":"template","z":"74d8f714.ab8378","name":"Format","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<table>\n \n <tr><th> Time </th><th> Channel </th><th> Alarm Message </th><th> Status </th><th>\n {{#payload}}\n <tr class=\"\">\n <td><center>{{Time}}</td>\n <td><center>{{Channel}}</td>\n <td><center>{{Alarm}}</td>\n <td><center>{{Status}}</td>\n </tr>\n {{/payload}}\n</table>\n","output":"str","x":1200,"y":1620,"wires":[["1cf08fea.b4b38"]]},{"id":"1cf08fea.b4b38","type":"ui_template","z":"74d8f714.ab8378","group":"783af07a.d61d58","name":"Alarm Log","order":4,"width":13,"height":8,"format":"<div ng-bind-html=\"msg.payload\" height=\"600\" style=\"height: 600px;\"></div>","storeOutMessages":true,"fwdInMessages":true,"resendOnRefresh":false,"templateScope":"local","x":1350,"y":1620,"wires":[[]]},{"id":"27d0e60a.18dc62","type":"inject","z":"74d8f714.ab8378","name":"create database","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"CREATE TABLE 'alarmlog' ('id' INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 'Time' TEXT, 'Channel' TEXT, 'Alarm' TEXT, 'Status' TEXT, 'timestamp' INTEGER DEFAULT CURRENT_TIMESTAMP)","payload":"","payloadType":"date","x":260,"y":1760,"wires":[["a896741a.d61798"]]},{"id":"a896741a.d61798","type":"sqlite","z":"74d8f714.ab8378","mydb":"27e5ab9a.4c829c","sqlquery":"msg.topic","sql":"","name":"Alarm Log","x":430,"y":1760,"wires":[["741330e7.ba891"]]},{"id":"741330e7.ba891","type":"debug","z":"74d8f714.ab8378","name":"","active":false,"tosidebar":true,"console":true,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":600,"y":1760,"wires":[]},{"id":"c6527b9f.17c448","type":"modbus-client","name":"","clienttype":"tcp","bufferCommands":false,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"192.168.1.120","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":1,"commandDelay":1,"clientTimeout":1000,"reconnectOnTimeout":true,"reconnectTimeout":2000,"parallelUnitIdsAllowed":true},{"id":"81dd3718.b97888","type":"ui_group","name":"Active Alarms","tab":"4e11db25.239e94","order":1,"disp":true,"width":13,"collapse":true},{"id":"27e5ab9a.4c829c","type":"sqlitedb","db":"nodered.db","mode":"RWC"},{"id":"783af07a.d61d58","type":"ui_group","name":"Alarm Log","tab":"4e11db25.239e94","order":4,"disp":false,"width":"13","collapse":false},{"id":"4e11db25.239e94","type":"ui_tab","name":"Alarms Monitiring","icon":"dashboard","order":1,"disabled":false,"hidden":false}]

```

There are few things that I want to improve:

- when the modebus connection is lost the Alarm List table is still showing the last alarms, better way is to create a dashboard element showing the connection state and to clear the table
- the Alarm log HTML view, maybe to add some button to have a filter the log entries by 24hours, 1 week, 1 month.

Thanks for all your help.

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [26 March 2021 20:29 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/10 "2021-03-26T20:29:13Z")

</div>

Hello,  
I have a question in regards with the Modbus read node.  
As I mention before I want to pull 350 addresses from my PLC, but the reported array has just 94 values.  
 ![Screenshot_2021-03-26 Node-RED 172 16 10 12(1)](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/e/f/ef2d77ba54ae906493d0a3e40beb67f0a375e93e.png)  
 ![Screenshot_2021-03-26 Node-RED 172 16 10 12](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/3/d31da8b3083dbd869835f5f3cdf2b420f41fb644.png)

It's something that I miss in configuration? how can I fix this?  
Thanks in advance for your help.

---

<div class="post-metadata">

**Author:** ![UnborN](https://avatars.discourse-cdn.com/v4/letter/u/4491bb/32.png) [@UnborN](https://discourse.nodered.org/u/UnborN)\
**Post date:** [26 March 2021 22:46 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/11 "2021-03-26T22:46:52Z")

</div>

> [@lucibuz](#):
>
> I want to pull 350 addresses from my PLC, but the reported array has just 94 values

Hi .. a similar question regarding the amount of registers you can read,  
was asked on the developer's github page for the modbus node.

> <https://github.com/BiancoRoyal/node-red-contrib-modbus/issues/233>
>
> AS #211 is still not solved for me, I tried a different approach: I want to read… all the necessary registers at once and split the buffer afterwords in Node-RED to select the few values I need.
> 
> The necessary amount is 334 (registers starting at 30535 up to 30869). But when I try this with a read node, there is no result. Only after entering 96 instead of 334 as an amount there is a result.
> 
> Is there really a limit for the amount, or is this problem related to my solar inverter?
> 
> Another question, if this does not work properly: can I use a flex getter node to get more than one register back? At the moment I feed the flex getter node with just one register like so:
> \`\`\`
> msg.payload = { 
> 'fc': 3,
> 'unitid': 3, 
> 'address': 30867 , 
> 'quantity': 2 }; 
> return msg;
> \`\`\`
> 
> Is there a syntax to feed in more objects then this single register?

Possibly it could be a limitation on your device how many registers you can poll at once.

One workaround is to read them in chunks.

I do something similar reading from some Energy meters by chaining the nodes and then using a Join node to join the read values.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/f/3/f34ee8d2ad5b1be46a6f404345d3b88ed81335c9.png)

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [27 March 2021 00:02 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/12 "2021-03-27T00:02:02Z")

</div>

Funny thing - using a modbus slave emulator, if i request over 127 items, i start getting strange length responses in the debug output from node-red-contrib-modbus

The slave application seems to send all the data that i request. For example, I requested 150 items & the slave responded with the right amount of data...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/3/c/3c0ee84ed21627f602b3ebdbf8a1291f48ed12ea.png)

but the modbus flex getter only shows me the first 22 items...  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/c/0/c0722996291545988a031eb6c3b996067ab8e565.png)

Another oddity is Wireshark doesn't correctly recognise the response...

Normal wireshark response (127 items)...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/f/a/fa62d610c647323505ab0ab6f0fe9ccceb92535f.png)

When i request 150 items...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/5/d5c04babe84336c504d91efdb871b98a25f5e2bb.png)

And this [online modbus packet parser](https://rapidscada.net/modbus/ModbusParser.aspx) doesnt like the response.

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/7/7/7750e15ec6b55c78f09ecf00d11d3a66242e5bb6.png)  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/e/0/e06f79012e21dacaaa8869058e1abca992618d7d.png)

... which leads me to think ...

- The response is actually NG or out of spec?
- The wireshark filter and the web site checker tool is old / limited / broken?

I dont have the energy to scour the modbus spec so if anyone familiar with the modbus tcp specification wants to analyse the following request and response packets please do...

node-red --\> slave

```auto
000100000006010300000096

```

slave --\> node-red

```auto
00010000012f01032c00010002000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005f0060000000000000000000000000000000000000000000000000000000000000007c007d007e007f00800081000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

```

  
  

### Possible work arounds...

1. Do 4 sequential requests for 0~99 then 100~199 then 200~299 then 300~349 (you could do it in 3 reads but aligning to the 0, 100, 200 and 300 mark will make parsing simpler)
2. DIY it - send `00010000000601030000015e` over TCP to your slave & parse the result yourself

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/b/ab4093569285503c547c78b237b18ff2eb8449a2.png)

Demo DIY modbus TCP flow...  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/2/d/2d45f970c3e3cd2ffa7e7cdbb2f5c7ca93ba6335.png)

Results...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/a/d/ad14085e3d557ee5cd8aa0d43790313ab049313e.png)

flow...

```auto
[{"id":"81661067.26948","type":"tcp request","z":"5e6c8b.7f38b374","server":"192.168.1.59","port":"502","out":"sit","splitc":" ","name":"","x":1908,"y":208,"wires":[["edb7a472.6eebc8"]]},{"id":"f77e01bf.42f16","type":"inject","z":"5e6c8b.7f38b374","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"00010000000601030000015e","payloadType":"str","x":1872,"y":144,"wires":[["50df09a0.9d44e8"]]},{"id":"50df09a0.9d44e8","type":"buffer-maker","z":"5e6c8b.7f38b374","name":"","specification":"spec","specificationType":"ui","items":[{"name":"item1","type":"hex","length":-1,"dataType":"msg","data":"payload"}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","x":2054,"y":144,"wires":[["cef58d63.4cb6","81661067.26948"]]},{"id":"f662fe41.9f3f3","type":"debug","z":"5e6c8b.7f38b374","name":"modbus response","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2282,"y":208,"wires":[]},{"id":"cef58d63.4cb6","type":"debug","z":"5e6c8b.7f38b374","name":"modbus request","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2272,"y":144,"wires":[]},{"id":"edb7a472.6eebc8","type":"buffer-parser","z":"5e6c8b.7f38b374","name":"","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"uint16be","name":"data","offset":9,"length":-1,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"buffer","offset":9,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":2102,"y":208,"wires":[["f662fe41.9f3f3"]]}]

```

NOTE: Here be dragons. The above flow does not check headers, does not do any error checking & i have no idea how it will handle disconnections. Feel free to use it or not but i would recommend at least checking the modbus headers and response data length at minimum before accepting the data as good

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [27 March 2021 00:07 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/13 "2021-03-27T00:07:17Z")

</div>

> [@UnborN](#):
>
> Possibly it could be a limitation on your device how many registers you can poll at once.

I'm unsure that is the real problem (see my post above).

some time ago, I was looking at nodejs modbus implementation and it had a bug whereby it would crash after a certain request size. I seem to remember something to do with it using a byte in a buffer to represent the request length (or the response length) so when a response \> 255 bytes arrived, the "size" byte was rolled over (or the node crashed - i forget - it was quite some time ago))

I am no modbus specification expert and i really dont have the energy to debug it and check the spec but if you want to update your repo issue with the above info, feel free.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [27 March 2021 01:11 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/14 "2021-03-27T01:11:28Z")

</div>

Slight update: Added header checks - works quite nicely reading 350 registers...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/1/8/18a8221432b090eab6ad6910b3becdb103df8c9b.png)

```auto
[{"id":"f77e01bf.42f16","type":"inject","z":"5e6c8b.7f38b374","name":"FC4: Read 50 from address 100","props":[{"p":"topic","vt":"str"},{"p":"sid","v":"1","vt":"num"},{"p":"pid","v":"0","vt":"num"},{"p":"len","v":"6","vt":"num"},{"p":"uid","v":"1","vt":"num"},{"p":"fc","v":"4","vt":"num"},{"p":"address","v":"100","vt":"num"},{"p":"registerCount","v":"50","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1602,"y":64,"wires":[["4e227fe.b16e08"]]},{"id":"f662fe41.9f3f3","type":"debug","z":"5e6c8b.7f38b374","name":"modbus response","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":2282,"y":240,"wires":[]},{"id":"cef58d63.4cb6","type":"debug","z":"5e6c8b.7f38b374","name":"modbus request","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2272,"y":112,"wires":[]},{"id":"edb7a472.6eebc8","type":"buffer-parser","z":"5e6c8b.7f38b374","name":"Parse Response","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"int16be","name":"header=>sid","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int16be","name":"header=>pid","offset":2,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"int16be","name":"header=>len","offset":4,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"header=>uid","offset":6,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"header=>fc","offset":7,"length":1,"offsetbit":0,"scale":"1","mask":"0x7F"},{"type":"uint8","name":"header=>byteCount","offset":8,"length":1,"offsetbit":0,"scale":"1","mask":"0x7F"},{"type":"uint16be","name":"data","offset":9,"length":-1,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"buffer","offset":9,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":2048,"y":176,"wires":[["79e4497c.3006e8"]]},{"id":"4e227fe.b16e08","type":"function","z":"5e6c8b.7f38b374","name":"inc SID","func":"var sid = context.get(\"sid\") || 0;\nsid++;\nif(sid > 250) sid = 0;\ncontext.set(\"sid\", sid) \nmsg.sid = sid;\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1852,"y":112,"wires":[["a85ac5f2.9be538"]]},{"id":"a85ac5f2.9be538","type":"buffer-maker","z":"5e6c8b.7f38b374","name":"build MB Request","specification":"spec","specificationType":"ui","items":[{"name":"sid","type":"uint16be","length":1,"dataType":"msg","data":"sid"},{"name":"pid","type":"uint16be","length":1,"dataType":"msg","data":"pid"},{"name":"len","type":"uint16be","length":1,"dataType":"msg","data":"len"},{"name":"uid","type":"byte","length":1,"dataType":"msg","data":"uid"},{"name":"fc","type":"byte","length":1,"dataType":"msg","data":"fc"},{"name":"address","type":"uint16be","length":1,"dataType":"msg","data":"address"},{"name":"registerCount","type":"uint16be","length":1,"dataType":"msg","data":"registerCount"}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","x":2058,"y":112,"wires":[["cef58d63.4cb6","81661067.26948"]]},{"id":"79e4497c.3006e8","type":"function","z":"5e6c8b.7f38b374","name":"check response","func":"var header = msg.payload.header || {};\nvar sidOK = msg.sid == header.sid;\nvar pidOK = msg.pid == header.pid;\nvar uidOK = msg.uid == header.uid;\nvar fcOK = msg.fc == header.fc;\nvar countOK = msg.registerCount == (header.byteCount/2);\nif(!countOK && msg.registerCount > 127) {\n countOK = msg.registerCount == msg.payload.data.length;\n}\n\nvar statText = \"\";\nif(!sidOK) {\n statText = \"SID does not match. Sent: ${msg.sid}, Received: ${header.sid}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!pidOK) {\n statText = \"PID does not match. Sent: ${msg.pid}, Received: ${header.pid}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!uidOK) {\n statText = \"Unit ID does not match. Sent: ${msg.uid}, Received: ${header.uid}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!fcOK) {\n statText = \"FC does not match. Sent: ${msg.fc}, Received: ${header.fc}\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nif(!countOK) {\n statText = \"Response register count does not match requested count\";\n node.error(statText, msg);\n node.status({text:statText});\n return null;\n}\nstatText = `OK. FC: ${msg.fc}, Addr: ${msg.address}[${msg.registerCount}], SID: (${msg.sid}) : Got ${msg.payload.data.length} register(s)` ;\nnode.status({text:statText});\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":2048,"y":240,"wires":[["f662fe41.9f3f3"]]},{"id":"d821be47.eb35a","type":"inject","z":"5e6c8b.7f38b374","name":"FC3: Read 350 from address 0","props":[{"p":"topic","vt":"str"},{"p":"sid","v":"1","vt":"num"},{"p":"pid","v":"0","vt":"num"},{"p":"len","v":"6","vt":"num"},{"p":"uid","v":"1","vt":"num"},{"p":"fc","v":"3","vt":"num"},{"p":"address","v":"0","vt":"num"},{"p":"registerCount","v":"350","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":1602,"y":112,"wires":[["4e227fe.b16e08"]]},{"id":"81661067.26948","type":"tcp request","z":"5e6c8b.7f38b374","server":"192.168.1.59","port":"502","out":"sit","splitc":" ","name":"","x":1812,"y":176,"wires":[["edb7a472.6eebc8"]]}]

```

And you can now set the `fc`, `address` and `registerCount` in the inject.

LIMITATIONS: only fc3 and fc4 are handled (more work required to read coils or write to modbus - but it is possible - feel free to make a modbus (kinda) contrib out of it)

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [27 March 2021 07:18 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/15 "2021-03-27T07:18:14Z")

</div>

Thanks,  
I'll look into the work around that was presented and see what's the easiest solution in my case.

Strange enough, if I'll pull request for 350 coils (FC1) I'm getting 352 values into the array.  
I have to mention that for now I'm using a modbus simulator not the actual PLC.

![Screenshot_2021-03-27 Node-RED 172 16 10 12(1)](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/b/dbb4fc88fb83ef6a6887024f8a4946eb93bb0876.png)  
 ![Screenshot_2021-03-27 Node-RED 172 16 10 12](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/3/9/395133ad09d4ddd4d35a70081de2544c3aeb7bab.png)

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [27 March 2021 08:32 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/16 "2021-03-27T08:32:04Z")

</div>

> [@lucibuz](#):
>
> I'm using a modbus simulator

Which one? Can you share a link please?

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [27 March 2021 08:34 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/17 "2021-03-27T08:34:40Z")

</div>

> [@lucibuz](#):
>
> Strange enough, if I'll pull request for 350 coils (FC1) I'm getting 352 values into the array.

That one is easily explained. The bools are probably packed in 8 or 16 bits. 352÷16=22 WORDS.

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [27 March 2021 08:58 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/18 "2021-03-27T08:58:43Z")

</div>

I find 2 simulators:

> **[Modbus simulator](https://sourceforge.net/projects/modrssim/)**
>
> Download Modbus simulator for free. Modbus RTU and TCP/IP slave simulator. For Testing, Training or Learning these protocols - includes an AllenBradley DF1 master and a slave mode.

> **[ModRSsim2](https://sourceforge.net/projects/modrssim2/)**
>
> Download ModRSsim2 for free. mod\_RSsim Fork with Updates. Modbus Simulator for RS-232 and TCP/IP. Fork of mod\_RSsim (https://sourceforge.net/projects/modrssim).

I'm using modrssim, for some reason modrssim2 doesn't work on my w10.

---

<div class="post-metadata">

**Author:** ![lucibuz](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/lucibuz/32/39131_2.png) [@lucibuz](https://discourse.nodered.org/u/lucibuz)\
**Post date:** [27 March 2021 15:48 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/19 "2021-03-27T15:48:18Z")

</div>

Hello,

I'm trying solve this by spiting the reading for the modbus addresses in 100's ... but I can't get settings to a merge array.  
Can you please help,  
thanks.

 ![Screenshot_2021-03-27 Node-RED 172 16 10 226](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/4/5/459afd3285fcedf0e7bf658272347d1bdea96d09.png)

```auto
[{"id":"2d82b2f9.ef879e","type":"modbus-read","z":"74d8f714.ab8378","name":"","topic":"","showStatusActivities":true,"logIOActivities":false,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"0","quantity":"99","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"2979eedb.de0842","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":250,"y":1460,"wires":[["5c7c274b.fce7f","115b2abd.6fd2fd"],[]]},{"id":"a993c182.d1aaf8","type":"modbus-read","z":"74d8f714.ab8378","name":"","topic":"","showStatusActivities":true,"logIOActivities":false,"showErrors":true,"unitid":"","dataType":"HoldingRegister","adr":"100","quantity":"199","rate":"5","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"2979eedb.de0842","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"x":250,"y":1500,"wires":[["c5cd73e8.ab98a"],[]]},{"id":"c5cd73e8.ab98a","type":"function","z":"74d8f714.ab8378","name":"generate alarm table","func":"\nvar t = new Date();\nt = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + '/' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());\n\nvar lookup = {\n 1: \"NO COMM. ON MAIN NETWORK\",\n 2: \"NO COMM. ON BACKUP NETWORK\",\n 3: \"MAIN SERVER OUT OF ORDER\",\n 4: \"BACKUP SERVER OUT OF ORDER\",\n 5: \"NO COMM. MAIN SERVER ON MAIN NETWORK\",\n 6: \"NO COMM. MAIN SERVER ON BACKUP NETWORK\",\n 7: \"NO COMM. BACKUP SERVER ON MAIN NETWORK\",\n 8: \"NO COMM. BACKUP SERVER ON BACKUP NETWORK\",\n 9: \"MAXIMUM DISKSPACE USED. LOGGING STOPPED\",\n 10: \"ALARMLOG: FILE CAN NOT BE WRITTEN\",\n 11: \"MTUS PORT: RD4 COM PORT FAILURE\",\n 12: \"MTUS PORT: RD4 NO COMMUNICATION\",\n 13: \"MTUS PORT: RD4 ERROR IN COMMUNICATION\",\n 14: \"MTUS STBD: RD5 COM PORT FAILURE\",\n 15: \"MTUS STBD: RD5 NO COMMUNICATION\",\n 16: \"MTUS STBD: RD5 ERROR IN COMMUNICATION\",\n 17: \"X101 NOT PRESENT\",\n 18: \"X102 NOT PRESENT\",\n 19: \"X103 NOT PRESENT\",\n 20: \"X104 NOT PRESENT\",\n 21: \"X109 NOT PRESENT\",\n 22: \"X110 NOT PRESENT\",\n 23: \"X111 NOT PRESENT\",\n 24: \"X117 NOT PRESENT\",\n 25: \"X118 NOT PRESENT\",\n 26: \"X119 NOT PRESENT\",\n 27: \"X125 NOT PRESENT\",\n 28: \"X126 NOT PRESENT\",\n 29: \"X127 NOT PRESENT\",\n 30: \"X128 NOT PRESENT\",\n 31: \"XP101 MAIN LINK NOT PRESENT\",\n 32: \"XP109 MAIN LINK NOT PRESENT\",\n 33: \"XP117 MAIN LINK NOT PRESENT\",\n 34: \"XP125 MAIN LINK NOT PRESENT\",\n 35: \"XP101 BACKUP LINK NOT PRESENT\",\n 36: \"XP109 BACKUP LINK NOT PRESENT\",\n 37: \"XP117 BACKUP LINK NOT PRESENT\",\n 38: \"XP125 BACKUP LINK NOT PRESENT\",\n 39: \"X101 INVALID BOARD TYPE\",\n 40: \"X102 INVALID BOARD TYPE\",\n 41: \"X103 INVALID BOARD TYPE\",\n 42: \"X104 INVALID BOARD TYPE\",\n 43: \"X109 INVALID BOARD TYPE\",\n 44: \"X110 INVALID BOARD TYPE\",\n 45: \"X111 INVALID BOARD TYPE\",\n 46: \"X117 INVALID BOARD TYPE\",\n 47: \"X118 INVALID BOARD TYPE\",\n 48: \"X119 INVALID BOARD TYPE\",\n 49: \"X125 INVALID BOARD TYPE\",\n 50: \"X126 INVALID BOARD TYPE\",\n 51: \"X127 INVALID BOARD TYPE\",\n 52: \"X128 INVALID BOARD TYPE\",\n 53: \"MBS_TCP: RD18 TCP/IP Socket Error\",\n 54: \"MBS_TCP: RD18 No Communication\",\n 55: \"MAIN SERVER IO SERVER NOT FOUND\",\n 56: \"BACKUP SERVER IO SERVER NOT FOUND\",\n 57: \"FB1 MAIN LINK NO COMMUNICATION\",\n 58: \"FB1 BACKUP LINK NO COMMUNICATION\",\n 59: \"FB2 MAIN LINK NO COMMUNICATION\",\n 60: \"X201 NOT PRESENT\",\n 61: \"X202 NOT PRESENT\",\n 62: \"X203 NOT PRESENT\",\n 63: \"X204 NOT PRESENT\",\n 64: \"X209 NOT PRESENT\",\n 65: \"X210 NOT PRESENT\",\n 66: \"X211 NOT PRESENT\",\n 67: \"X217 NOT PRESENT\",\n 68: \"X218 NOT PRESENT\",\n 69: \"X219 NOT PRESENT\",\n 70: \"X220 NOT PRESENT\",\n 71: \"FB2 BACKUP LINK NO COMMUNICATION\",\n 72: \"XP201 MAIN LINK NOT PRESENT\",\n 73: \"XP209 MAIN LINK NOT PRESENT\",\n 74: \"XP217 MAIN LINK NOT PRESENT\",\n 75: \"XP201 BACKUP LINK NOT PRESENT\",\n 76: \"XP209 BACKUP LINK NOT PRESENT\",\n 77: \"XP217 BACKUP LINK NOT PRESENT\",\n 78: \"X202 INVALID BOARD TYPE\",\n 79: \"X203 INVALID BOARD TYPE\",\n 80: \"X204 INVALID BOARD TYPE\",\n 81: \"X210 INVALID BOARD TYPE\",\n 82: \"X211 INVALID BOARD TYPE\",\n 83: \"X212 INVALID BOARD TYPE\",\n 84: \"X218 INVALID BOARD TYPE\",\n 85: \"X219 INVALID BOARD TYPE\",\n 86: \"X220 INVALID BOARD TYPE\",\n 87: \"X301 NOT PRESENT\",\n 88: \"X302 NOT PRESENT\",\n 89: \"X303 NOT PRESENT\",\n 90: \"X304 NOT PRESENT\",\n 91: \"X309 NOT PRESENT\",\n 92: \"XP301 MAIN LINK NOT PRESENT\",\n 93: \"XP309 MAIN LINK NOT PRESENT\",\n 94: \"XP301 BACKUP LINK NOT PRESENT\",\n 95: \"FB3 MAIN LINK NO COMMUNICATION\",\n 96: \"FB3 BACKUP LINK NO COMMUNICATION\",\n 97: \"FB3 PROC301 IEC-1131 CONFIG NOT LOADED\",\n 98: \"FB3 PROC301 IEC-1131 PROGRAM NOT RUNNING\",\n 99: \"NMEA_WIND: RD6 COM PORT ERROR\",\n 100: \"NMEA_WIND: RD6 NO COMMUNICATION\",\n 101: \"FB3 PROC309 IEC-1131 CONFIG NOT LOADED\",\n 102: \"FB3 PROC309 IEC-1131 PROGRAM NOT RUNNING\",\n 103: \"X301 INVALID BOARD TYPE\",\n 104: \"X302 INVALID BOARD TYPE\",\n 105: \"X303 INVALID BOARD TYPE\",\n 106: \"X304 INVALID BOARD TYPE\",\n 107: \"X309 INVALID BOARD TYPE\",\n 108: \"FB4 MAIN LINK NO COMMUNICATION\",\n 109: \"FB4 BACKUP LINK NO COMMUNICATION\", \n 110: \"FB4 LOP MESS NOT PRESENT\",\n 111: \"FB4 LOP ENGINEER NOT PRESENT\",\n 112: \"FB4 LOP 1ST MATE NOT PRESENT\",\n 113: \"FB4 LOP ALARMPANEL ENGINEROOM\",\n 114: \"ALARM PANEL E.R. POWER FAIL\",\n 115: \"ALARM PANEL E.R. EARTH FAULT\",\n 116: \"WATERTIGHT DOORS POWER FAILURE\",\n 117: \"WATERTIGHT DOORS BATTERY LOW\",\n 118: \"BILGE FORE PEAK LEVEL HIGH\",\n 119: \"BILGE BOW THRUSTER ROOM LEVEL HIGH\",\n 120: \"BILGE COFFERDAM LEVEL HIGH\"\n}\n\n\n\nvar previous = context.get(\"previous\") || [];\nvar current = [...msg.payload];\nvar table = context.get(\"table\") || [];\nfor (var i = 0; i < msg.payload.length; i++) {\n var channel = (\"\" + (i + 100)).padStart(5,\"0\");\n var sensorNo = (i + 100);\n var sensorName = lookup[sensorNo] || (\"Unknown \" + sensorNo);\n //has value changed?\n if (previous[i] !== current[i]) {\n var row = table.find(e => e.Channel == channel);\n\n if (!row) {\n if (current[i] === 0)\n continue; //dont add this one (its 0)\n \n row = {\n \"Time\":t,\n \"Channel\": channel,\n \"Alarm\": \"\", \n \"Status\": \"\",\n \"Alarmlog\": \"\", \n \"Statuslog\": \"\" \n } \n table.push(row);\n } else {\n //there is a row in the table...\n if (current[i] === 0) {\n ///remove it because its now 0\n table = table.filter(e => e.Channel !== channel);\n continue;\n }\n }\n\n row.Time = t;//update the time\n if (current[i] === 2) {\n row.Status = \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM !\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1027) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1028) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1029) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1088) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"SENSOR FAIL\";\n row.Alarmlog = sensorName ;\n }\n //TODO: \n // You can create the SQL here and send it in the topic OR send an object with \n // the clean alarm and notes info (i.e. no HTML) then build a SQL query in the next node \n node.send( [null, { topic: (\"INSERT INTO alarmlog (Time,Channel,Alarm,Status) \" +\n \"VALUES ('\"+row.Time+\"','\"+row.Channel+\"','\"+row.Alarmlog+\"','\"+row.Statuslog+\"')\")}] ); //Send the SQL query out of output 2\n }\n}\n\ncontext.set(\"previous\", current);\ncontext.set(\"table\", table);\n\nmsg.payload = table;\nreturn [msg, null]; //Return table to function output 1;","outputs":2,"noerr":0,"initialize":"","finalize":"","x":460,"y":1500,"wires":[["b59febd3.ec7848","be345f3e.1a55f"],["84fb433e.b0a2f8"]]},{"id":"115b2abd.6fd2fd","type":"function","z":"74d8f714.ab8378","name":"generate alarm table","func":"\nvar t = new Date();\nt = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + '/' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());\n\nvar lookup = {\n 1: \"NO COMM. ON MAIN NETWORK\",\n 2: \"NO COMM. ON BACKUP NETWORK\",\n 3: \"MAIN SERVER OUT OF ORDER\",\n 4: \"BACKUP SERVER OUT OF ORDER\",\n 5: \"NO COMM. MAIN SERVER ON MAIN NETWORK\",\n 6: \"NO COMM. MAIN SERVER ON BACKUP NETWORK\",\n 7: \"NO COMM. BACKUP SERVER ON MAIN NETWORK\",\n 8: \"NO COMM. BACKUP SERVER ON BACKUP NETWORK\",\n 9: \"MAXIMUM DISKSPACE USED. LOGGING STOPPED\",\n 10: \"ALARMLOG: FILE CAN NOT BE WRITTEN\",\n 11: \"MTUS PORT: RD4 COM PORT FAILURE\",\n 12: \"MTUS PORT: RD4 NO COMMUNICATION\",\n 13: \"MTUS PORT: RD4 ERROR IN COMMUNICATION\",\n 14: \"MTUS STBD: RD5 COM PORT FAILURE\",\n 15: \"MTUS STBD: RD5 NO COMMUNICATION\",\n 16: \"MTUS STBD: RD5 ERROR IN COMMUNICATION\",\n 17: \"X101 NOT PRESENT\",\n 18: \"X102 NOT PRESENT\",\n 19: \"X103 NOT PRESENT\",\n 20: \"X104 NOT PRESENT\",\n 21: \"X109 NOT PRESENT\",\n 22: \"X110 NOT PRESENT\",\n 23: \"X111 NOT PRESENT\",\n 24: \"X117 NOT PRESENT\",\n 25: \"X118 NOT PRESENT\",\n 26: \"X119 NOT PRESENT\",\n 27: \"X125 NOT PRESENT\",\n 28: \"X126 NOT PRESENT\",\n 29: \"X127 NOT PRESENT\",\n 30: \"X128 NOT PRESENT\",\n 31: \"XP101 MAIN LINK NOT PRESENT\",\n 32: \"XP109 MAIN LINK NOT PRESENT\",\n 33: \"XP117 MAIN LINK NOT PRESENT\",\n 34: \"XP125 MAIN LINK NOT PRESENT\",\n 35: \"XP101 BACKUP LINK NOT PRESENT\",\n 36: \"XP109 BACKUP LINK NOT PRESENT\",\n 37: \"XP117 BACKUP LINK NOT PRESENT\",\n 38: \"XP125 BACKUP LINK NOT PRESENT\",\n 39: \"X101 INVALID BOARD TYPE\",\n 40: \"X102 INVALID BOARD TYPE\",\n 41: \"X103 INVALID BOARD TYPE\",\n 42: \"X104 INVALID BOARD TYPE\",\n 43: \"X109 INVALID BOARD TYPE\",\n 44: \"X110 INVALID BOARD TYPE\",\n 45: \"X111 INVALID BOARD TYPE\",\n 46: \"X117 INVALID BOARD TYPE\",\n 47: \"X118 INVALID BOARD TYPE\",\n 48: \"X119 INVALID BOARD TYPE\",\n 49: \"X125 INVALID BOARD TYPE\",\n 50: \"X126 INVALID BOARD TYPE\",\n 51: \"X127 INVALID BOARD TYPE\",\n 52: \"X128 INVALID BOARD TYPE\",\n 53: \"MBS_TCP: RD18 TCP/IP Socket Error\",\n 54: \"MBS_TCP: RD18 No Communication\",\n 55: \"MAIN SERVER IO SERVER NOT FOUND\",\n 56: \"BACKUP SERVER IO SERVER NOT FOUND\",\n 57: \"FB1 MAIN LINK NO COMMUNICATION\",\n 58: \"FB1 BACKUP LINK NO COMMUNICATION\",\n 59: \"FB2 MAIN LINK NO COMMUNICATION\",\n 60: \"X201 NOT PRESENT\",\n 61: \"X202 NOT PRESENT\",\n 62: \"X203 NOT PRESENT\",\n 63: \"X204 NOT PRESENT\",\n 64: \"X209 NOT PRESENT\",\n 65: \"X210 NOT PRESENT\",\n 66: \"X211 NOT PRESENT\",\n 67: \"X217 NOT PRESENT\",\n 68: \"X218 NOT PRESENT\",\n 69: \"X219 NOT PRESENT\",\n 70: \"X220 NOT PRESENT\",\n 71: \"FB2 BACKUP LINK NO COMMUNICATION\",\n 72: \"XP201 MAIN LINK NOT PRESENT\",\n 73: \"XP209 MAIN LINK NOT PRESENT\",\n 74: \"XP217 MAIN LINK NOT PRESENT\",\n 75: \"XP201 BACKUP LINK NOT PRESENT\",\n 76: \"XP209 BACKUP LINK NOT PRESENT\",\n 77: \"XP217 BACKUP LINK NOT PRESENT\",\n 78: \"X202 INVALID BOARD TYPE\",\n 79: \"X203 INVALID BOARD TYPE\",\n 80: \"X204 INVALID BOARD TYPE\",\n 81: \"X210 INVALID BOARD TYPE\",\n 82: \"X211 INVALID BOARD TYPE\",\n 83: \"X212 INVALID BOARD TYPE\",\n 84: \"X218 INVALID BOARD TYPE\",\n 85: \"X219 INVALID BOARD TYPE\",\n 86: \"X220 INVALID BOARD TYPE\",\n 87: \"X301 NOT PRESENT\",\n 88: \"X302 NOT PRESENT\",\n 89: \"X303 NOT PRESENT\",\n 90: \"X304 NOT PRESENT\",\n 91: \"X309 NOT PRESENT\",\n 92: \"XP301 MAIN LINK NOT PRESENT\",\n 93: \"XP309 MAIN LINK NOT PRESENT\",\n 94: \"XP301 BACKUP LINK NOT PRESENT\",\n 95: \"FB3 MAIN LINK NO COMMUNICATION\",\n 96: \"FB3 BACKUP LINK NO COMMUNICATION\",\n 97: \"FB3 PROC301 IEC-1131 CONFIG NOT LOADED\",\n 98: \"FB3 PROC301 IEC-1131 PROGRAM NOT RUNNING\",\n 99: \"NMEA_WIND: RD6 COM PORT ERROR\",\n 100: \"NMEA_WIND: RD6 NO COMMUNICATION\",\n 101: \"FB3 PROC309 IEC-1131 CONFIG NOT LOADED\",\n 102: \"FB3 PROC309 IEC-1131 PROGRAM NOT RUNNING\",\n 103: \"X301 INVALID BOARD TYPE\",\n 104: \"X302 INVALID BOARD TYPE\",\n 105: \"X303 INVALID BOARD TYPE\",\n 106: \"X304 INVALID BOARD TYPE\",\n 107: \"X309 INVALID BOARD TYPE\",\n 108: \"FB4 MAIN LINK NO COMMUNICATION\",\n 109: \"FB4 BACKUP LINK NO COMMUNICATION\", \n 110: \"FB4 LOP MESS NOT PRESENT\",\n 111: \"FB4 LOP ENGINEER NOT PRESENT\",\n 112: \"FB4 LOP 1ST MATE NOT PRESENT\",\n 113: \"FB4 LOP ALARMPANEL ENGINEROOM\",\n 114: \"ALARM PANEL E.R. POWER FAIL\",\n 115: \"ALARM PANEL E.R. EARTH FAULT\",\n 116: \"WATERTIGHT DOORS POWER FAILURE\",\n 117: \"WATERTIGHT DOORS BATTERY LOW\",\n 118: \"BILGE FORE PEAK LEVEL HIGH\",\n 119: \"BILGE BOW THRUSTER ROOM LEVEL HIGH\",\n 120: \"BILGE COFFERDAM LEVEL HIGH\"\n}\n\n\n\nvar previous = context.get(\"previous\") || [];\nvar current = [...msg.payload];\nvar table = context.get(\"table\") || [];\nfor (var i = 0; i < msg.payload.length; i++) {\n var channel = (\"\" + (i + 1)).padStart(5,\"0\");\n var sensorNo = (i + 1);\n var sensorName = lookup[sensorNo] || (\"Unknown \" + sensorNo);\n //has value changed?\n if (previous[i] !== current[i]) {\n var row = table.find(e => e.Channel == channel);\n\n if (!row) {\n if (current[i] === 0)\n continue; //dont add this one (its 0)\n \n row = {\n \"Time\":t,\n \"Channel\": channel,\n \"Alarm\": \"\", \n \"Status\": \"\",\n \"Alarmlog\": \"\", \n \"Statuslog\": \"\" \n } \n table.push(row);\n } else {\n //there is a row in the table...\n if (current[i] === 0) {\n ///remove it because its now 0\n table = table.filter(e => e.Channel !== channel);\n continue;\n }\n }\n\n row.Time = t;//update the time\n if (current[i] === 2) {\n row.Status = \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM !\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1027) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1028) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1029) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1088) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"SENSOR FAIL\";\n row.Alarmlog = sensorName ;\n }\n //TODO: \n // You can create the SQL here and send it in the topic OR send an object with \n // the clean alarm and notes info (i.e. no HTML) then build a SQL query in the next node \n node.send( [null, { topic: (\"INSERT INTO alarmlog (Time,Channel,Alarm,Status) \" +\n \"VALUES ('\"+row.Time+\"','\"+row.Channel+\"','\"+row.Alarmlog+\"','\"+row.Statuslog+\"')\")}] ); //Send the SQL query out of output 2\n }\n}\n\ncontext.set(\"previous\", current);\ncontext.set(\"table\", table);\n\nmsg.payload = table;\nreturn [msg, null]; //Return table to function output 1;","outputs":2,"noerr":0,"initialize":"","finalize":"","x":460,"y":1460,"wires":[["1caa8632.9ffda2","be345f3e.1a55f"],["33eac830.bf165","25ea02b9.be8eee"]]},{"id":"be345f3e.1a55f","type":"join","z":"74d8f714.ab8378","name":"","mode":"custom","build":"array","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"4","count":"","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":680,"y":1500,"wires":[["e36f3a9f.a38dd8"]]},{"id":"e36f3a9f.a38dd8","type":"ui_table","z":"74d8f714.ab8378","group":"81dd3718.b97888","name":"Alarm List","order":1,"width":13,"height":8,"columns":[{"field":"Time","title":"<center>Time</>","width":"23%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Channel","title":"<center>Channel</>","width":"10%","align":"center","formatter":"plaintext","formatterParams":{"target":"_blank"}},{"field":"Alarm","title":"<center>Alarm Message</>","width":"52%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}},{"field":"Status","title":"<center>Status</>","width":"15%","align":"center","formatter":"html","formatterParams":{"target":"_blank"}}],"outputs":0,"cts":false,"x":900,"y":1440,"wires":[]},{"id":"2979eedb.de0842","type":"modbus-client","name":"","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"172.16.10.71","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true},{"id":"81dd3718.b97888","type":"ui_group","name":"Active Alarms","tab":"4e11db25.239e94","order":1,"disp":true,"width":13,"collapse":true},{"id":"4e11db25.239e94","type":"ui_tab","name":"Alarms Monitiring","icon":"dashboard","order":1,"disabled":false,"hidden":false}]
```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [27 March 2021 16:10 UTC](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041/20 "2021-03-27T16:10:28Z")

</div>

Try this...

the key to this is to fire the reads sequentially. (PS, you will need to chose your modbus config in the modbus nodes)

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/5/d54d83c0bdb097ea9ae9d0753501c166d28ede64.png)

```auto
[{"id":"e65eb5ea.4fa858","type":"modbus-getter","z":"5e6c8b.7f38b374","name":"0 ~ 99","showStatusActivities":false,"showErrors":false,"logIOActivities":false,"unitid":"1","dataType":"HoldingRegister","adr":"0","quantity":"100","server":"d1841b37.604628","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":false,"x":1584,"y":960,"wires":[["63c6d18f.950c8"],[]]},{"id":"2cc804d5.2e33bc","type":"modbus-getter","z":"5e6c8b.7f38b374","name":"100 ~ 199","showStatusActivities":false,"showErrors":false,"logIOActivities":false,"unitid":"1","dataType":"HoldingRegister","adr":"100","quantity":"100","server":"d1841b37.604628","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":true,"x":1596,"y":1024,"wires":[["9a94f150.5222"],[]]},{"id":"63c6d18f.950c8","type":"change","z":"5e6c8b.7f38b374","name":"","rules":[{"t":"set","p":"data1","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1776,"y":960,"wires":[["4fb126bd.00d5f8","2cc804d5.2e33bc"]]},{"id":"85684a01.bfd1f8","type":"inject","z":"5e6c8b.7f38b374","name":"","props":[{"p":"topic","vt":"str"},{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"true","payloadType":"bool","x":1442,"y":960,"wires":[["e65eb5ea.4fa858"]]},{"id":"9a94f150.5222","type":"change","z":"5e6c8b.7f38b374","name":"","rules":[{"t":"set","p":"data2","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1776,"y":1024,"wires":[["196ffb.89463005","ffc09dbd.9bc89"]]},{"id":"196ffb.89463005","type":"modbus-getter","z":"5e6c8b.7f38b374","name":"200 ~ 299","showStatusActivities":false,"showErrors":false,"logIOActivities":false,"unitid":"1","dataType":"HoldingRegister","adr":"100","quantity":"100","server":"d1841b37.604628","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":true,"x":1596,"y":1088,"wires":[["72d2709e.14a7d"],[]]},{"id":"72d2709e.14a7d","type":"change","z":"5e6c8b.7f38b374","name":"","rules":[{"t":"set","p":"data3","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1776,"y":1088,"wires":[["d5a57cd.c815d8","c18e20a2.23a71"]]},{"id":"d5a57cd.c815d8","type":"function","z":"5e6c8b.7f38b374","name":"Make 1 array","func":"msg.payload = [msg.data1.map(e => e), msg.data2.map(e => e), msg.data3.map(e => e)]\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":1686,"y":1168,"wires":[["cf84ffc3.151ed","58fd7ace.0eb404"]]},{"id":"cf84ffc3.151ed","type":"function","z":"5e6c8b.7f38b374","name":"generate alarm table","func":"\nvar t = new Date();\nt = (('00' + t.getHours()).slice(-2) + ':' + ('00' + t.getMinutes()).slice(-2) + ':' + ('00' + t.getSeconds()).slice(-2) + '/' + ('00' + (t.getMonth() + 1)).slice(-2) + '.' + ('00' + t.getDate()).slice(-2) + '.' + t.getFullYear());\n\nvar lookup = {\n 1: \"NO COMM. ON MAIN NETWORK\",\n 2: \"NO COMM. ON BACKUP NETWORK\",\n 3: \"MAIN SERVER OUT OF ORDER\",\n 4: \"BACKUP SERVER OUT OF ORDER\",\n 5: \"NO COMM. MAIN SERVER ON MAIN NETWORK\",\n 6: \"NO COMM. MAIN SERVER ON BACKUP NETWORK\",\n 7: \"NO COMM. BACKUP SERVER ON MAIN NETWORK\",\n 8: \"NO COMM. BACKUP SERVER ON BACKUP NETWORK\",\n 9: \"MAXIMUM DISKSPACE USED. LOGGING STOPPED\",\n 10: \"ALARMLOG: FILE CAN NOT BE WRITTEN\",\n 11: \"MTUS PORT: RD4 COM PORT FAILURE\",\n 12: \"MTUS PORT: RD4 NO COMMUNICATION\",\n 13: \"MTUS PORT: RD4 ERROR IN COMMUNICATION\",\n 14: \"MTUS STBD: RD5 COM PORT FAILURE\",\n 15: \"MTUS STBD: RD5 NO COMMUNICATION\",\n 16: \"MTUS STBD: RD5 ERROR IN COMMUNICATION\",\n 17: \"X101 NOT PRESENT\",\n 18: \"X102 NOT PRESENT\",\n 19: \"X103 NOT PRESENT\",\n 20: \"X104 NOT PRESENT\",\n 21: \"X109 NOT PRESENT\",\n 22: \"X110 NOT PRESENT\",\n 23: \"X111 NOT PRESENT\",\n 24: \"X117 NOT PRESENT\",\n 25: \"X118 NOT PRESENT\",\n 26: \"X119 NOT PRESENT\",\n 27: \"X125 NOT PRESENT\",\n 28: \"X126 NOT PRESENT\",\n 29: \"X127 NOT PRESENT\",\n 30: \"X128 NOT PRESENT\",\n 31: \"XP101 MAIN LINK NOT PRESENT\",\n 32: \"XP109 MAIN LINK NOT PRESENT\",\n 33: \"XP117 MAIN LINK NOT PRESENT\",\n 34: \"XP125 MAIN LINK NOT PRESENT\",\n 35: \"XP101 BACKUP LINK NOT PRESENT\",\n 36: \"XP109 BACKUP LINK NOT PRESENT\",\n 37: \"XP117 BACKUP LINK NOT PRESENT\",\n 38: \"XP125 BACKUP LINK NOT PRESENT\",\n 39: \"X101 INVALID BOARD TYPE\",\n 40: \"X102 INVALID BOARD TYPE\",\n 41: \"X103 INVALID BOARD TYPE\",\n 42: \"X104 INVALID BOARD TYPE\",\n 43: \"X109 INVALID BOARD TYPE\",\n 44: \"X110 INVALID BOARD TYPE\",\n 45: \"X111 INVALID BOARD TYPE\",\n 46: \"X117 INVALID BOARD TYPE\",\n 47: \"X118 INVALID BOARD TYPE\",\n 48: \"X119 INVALID BOARD TYPE\",\n 49: \"X125 INVALID BOARD TYPE\",\n 50: \"X126 INVALID BOARD TYPE\",\n 51: \"X127 INVALID BOARD TYPE\",\n 52: \"X128 INVALID BOARD TYPE\",\n 53: \"MBS_TCP: RD18 TCP/IP Socket Error\",\n 54: \"MBS_TCP: RD18 No Communication\",\n 55: \"MAIN SERVER IO SERVER NOT FOUND\",\n 56: \"BACKUP SERVER IO SERVER NOT FOUND\",\n 57: \"FB1 MAIN LINK NO COMMUNICATION\",\n 58: \"FB1 BACKUP LINK NO COMMUNICATION\",\n 59: \"FB2 MAIN LINK NO COMMUNICATION\",\n 60: \"X201 NOT PRESENT\",\n 61: \"X202 NOT PRESENT\",\n 62: \"X203 NOT PRESENT\",\n 63: \"X204 NOT PRESENT\",\n 64: \"X209 NOT PRESENT\",\n 65: \"X210 NOT PRESENT\",\n 66: \"X211 NOT PRESENT\",\n 67: \"X217 NOT PRESENT\",\n 68: \"X218 NOT PRESENT\",\n 69: \"X219 NOT PRESENT\",\n 70: \"X220 NOT PRESENT\",\n 71: \"FB2 BACKUP LINK NO COMMUNICATION\",\n 72: \"XP201 MAIN LINK NOT PRESENT\",\n 73: \"XP209 MAIN LINK NOT PRESENT\",\n 74: \"XP217 MAIN LINK NOT PRESENT\",\n 75: \"XP201 BACKUP LINK NOT PRESENT\",\n 76: \"XP209 BACKUP LINK NOT PRESENT\",\n 77: \"XP217 BACKUP LINK NOT PRESENT\",\n 78: \"X202 INVALID BOARD TYPE\",\n 79: \"X203 INVALID BOARD TYPE\",\n 80: \"X204 INVALID BOARD TYPE\",\n 81: \"X210 INVALID BOARD TYPE\",\n 82: \"X211 INVALID BOARD TYPE\",\n 83: \"X212 INVALID BOARD TYPE\",\n 84: \"X218 INVALID BOARD TYPE\",\n 85: \"X219 INVALID BOARD TYPE\",\n 86: \"X220 INVALID BOARD TYPE\",\n 87: \"X301 NOT PRESENT\",\n 88: \"X302 NOT PRESENT\",\n 89: \"X303 NOT PRESENT\",\n 90: \"X304 NOT PRESENT\",\n 91: \"X309 NOT PRESENT\",\n 92: \"XP301 MAIN LINK NOT PRESENT\",\n 93: \"XP309 MAIN LINK NOT PRESENT\",\n 94: \"XP301 BACKUP LINK NOT PRESENT\",\n 95: \"FB3 MAIN LINK NO COMMUNICATION\",\n 96: \"FB3 BACKUP LINK NO COMMUNICATION\",\n 97: \"FB3 PROC301 IEC-1131 CONFIG NOT LOADED\",\n 98: \"FB3 PROC301 IEC-1131 PROGRAM NOT RUNNING\",\n 99: \"NMEA_WIND: RD6 COM PORT ERROR\",\n 100: \"NMEA_WIND: RD6 NO COMMUNICATION\",\n 101: \"FB3 PROC309 IEC-1131 CONFIG NOT LOADED\",\n 102: \"FB3 PROC309 IEC-1131 PROGRAM NOT RUNNING\",\n 103: \"X301 INVALID BOARD TYPE\",\n 104: \"X302 INVALID BOARD TYPE\",\n 105: \"X303 INVALID BOARD TYPE\",\n 106: \"X304 INVALID BOARD TYPE\",\n 107: \"X309 INVALID BOARD TYPE\",\n 108: \"FB4 MAIN LINK NO COMMUNICATION\",\n 109: \"FB4 BACKUP LINK NO COMMUNICATION\", \n 110: \"FB4 LOP MESS NOT PRESENT\",\n 111: \"FB4 LOP ENGINEER NOT PRESENT\",\n 112: \"FB4 LOP 1ST MATE NOT PRESENT\",\n 113: \"FB4 LOP ALARMPANEL ENGINEROOM\",\n 114: \"ALARM PANEL E.R. POWER FAIL\",\n 115: \"ALARM PANEL E.R. EARTH FAULT\",\n 116: \"WATERTIGHT DOORS POWER FAILURE\",\n 117: \"WATERTIGHT DOORS BATTERY LOW\",\n 118: \"BILGE FORE PEAK LEVEL HIGH\",\n 119: \"BILGE BOW THRUSTER ROOM LEVEL HIGH\",\n 120: \"BILGE COFFERDAM LEVEL HIGH\"\n}\n\n\n\nvar previous = context.get(\"previous\") || [];\nvar current = [...msg.payload];\nvar table = context.get(\"table\") || [];\nfor (var i = 0; i < msg.payload.length; i++) {\n var channel = (\"\" + (i + 100)).padStart(5,\"0\");\n var sensorNo = (i + 100);\n var sensorName = lookup[sensorNo] || (\"Unknown \" + sensorNo);\n //has value changed?\n if (previous[i] !== current[i]) {\n var row = table.find(e => e.Channel == channel);\n\n if (!row) {\n if (current[i] === 0)\n continue; //dont add this one (its 0)\n \n row = {\n \"Time\":t,\n \"Channel\": channel,\n \"Alarm\": \"\", \n \"Status\": \"\",\n \"Alarmlog\": \"\", \n \"Statuslog\": \"\" \n } \n table.push(row);\n } else {\n //there is a row in the table...\n if (current[i] === 0) {\n ///remove it because its now 0\n table = table.filter(e => e.Channel !== channel);\n continue;\n }\n }\n\n row.Time = t;//update the time\n if (current[i] === 2) {\n row.Status = \"<div style='background-color: red; width:100%; color:white'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM !\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1027) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ; \n } else if (current[i] === 1028) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1029) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"ALARM\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"ALARM\";\n row.Alarmlog = sensorName ;\n } else if (current[i] === 1088) {\n row.Status = \"<div style='background-color: yellow; width:100%; color:red'>\" + \"SENSOR FAIL\" + \"</div>\";\n row.Alarm = \"<div style='background-color: red; width:100%; color:white'>\" + sensorName + \"</div>\";\n row.Statuslog = \"SENSOR FAIL\";\n row.Alarmlog = sensorName ;\n }\n //TODO: \n // You can create the SQL here and send it in the topic OR send an object with \n // the clean alarm and notes info (i.e. no HTML) then build a SQL query in the next node \n node.send( [null, { topic: (\"INSERT INTO alarmlog (Time,Channel,Alarm,Status) \" +\n \"VALUES ('\"+row.Time+\"','\"+row.Channel+\"','\"+row.Alarmlog+\"','\"+row.Statuslog+\"')\")}] ); //Send the SQL query out of output 2\n }\n}\n\ncontext.set(\"previous\", current);\ncontext.set(\"table\", table);\n\nmsg.payload = table;\nreturn [msg, null]; //Return table to function output 1;","outputs":2,"noerr":0,"initialize":"","finalize":"","x":1924,"y":1168,"wires":[["37fac07c.eb383"],["b3b05181.6d535"]]},{"id":"37fac07c.eb383","type":"debug","z":"5e6c8b.7f38b374","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2226,"y":1136,"wires":[]},{"id":"b3b05181.6d535","type":"debug","z":"5e6c8b.7f38b374","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2226,"y":1184,"wires":[]},{"id":"4fb126bd.00d5f8","type":"debug","z":"5e6c8b.7f38b374","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2002,"y":960,"wires":[]},{"id":"ffc09dbd.9bc89","type":"debug","z":"5e6c8b.7f38b374","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2002,"y":1024,"wires":[]},{"id":"58fd7ace.0eb404","type":"debug","z":"5e6c8b.7f38b374","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1698,"y":1216,"wires":[]},{"id":"c18e20a2.23a71","type":"debug","z":"5e6c8b.7f38b374","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":2002,"y":1088,"wires":[]},{"id":"d1841b37.604628","type":"modbus-client","name":"","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"192.168.1.59","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true}]

```

NOTE: Why yours didnt work...

1. You have no guarantee which of those read nodes would fire first (then the join would make the 1st array 2nd and the 2nd array first - completely out of order)
2. There _can be_ problems sending reads to a modbus at the same time. Reading sequentially avoids this potential issue.
3. You were duplicating the function node which was designed to operate on a single array (of any size) - the solution was to join the arrays BEFORE sending to the function (not the other way around)

[Next page](https://discourse.nodered.org/t/how-to-create-an-modbus-tcp-alarm-status-dashboard/43041.md?page=2)
