Input state detection using modbus


I have a board containing 32 digital input and 2 outputs, with an modbus interface. I want to use it as a interface between node red and a bunch of mono-stable buttons to control home lights (and some other stuff, nor really real time application so not relevant)

To test this approach I've prepared a PoC (on my PC) in python that uses modbus to read the status of inputs every 50ms or so (min time is 15ms max was something around 80ms) , and react to given state change, this worked well, even the shortest "clicks" where "discovered" by the app, and a signal to turn light on/off was send successfully.

I want to move this to Node RED running on my raspberry pi zero :slight_smile: I wanted to read the status using normal nodes (just read modbus data every 50ms in a loop) but this task takes >50% of the RPi resources so I assume that this is not good solution :slight_smile:

For now I have a question on HOW I should implement this "properly"?

  1. Write my own service in C/C++ that will talk with the input board and send some data over http (or something else, mayby some IPC...) to node red only when detecting some signal?

  2. Run a python script containing "do while loop" in a "python3 node" and just output the data on state change to node red?

  3. The board contains an ATmega uC I can "hack" this chip quite easily, and write my own implementation that uses the 2 given outputs to signal an interrupt that will signal the RPi and ONLY THEN use node red on RPi to read the state of inputs and decide what to do with this

  4. Do something else?

  • Are you using the modbus contrib nodes in node-red? (which one)?
  • How are you performing the read of these values - all in one go? or individual reads?

I ask that 2nd question as often people do 32 reads for 32 bits - you will never achieve 50ms like this. A better solution it to read all values in one go and parse the bits (potentially using buffer-parser node to nicely split the bits out.

Lastly, you said " want to move this to Node RED running on my raspberry pi zero :slight_smile: I wanted to read the status using normal nodes (just read modbus data every 50ms in a loop) but this task takes >50% of the RPi" - did you ACTUALLY create a loop? This will likely be the reason for high CPU usage (typically we avoid loops in node-red)

If you share your flow (or perhaps a screenshot) we might be able to advice before you go on to other options.


For communication with modbus I use modbus-flex-getter node from node-red-contrib-modbus package.
I read ALL the values at once, I thought that this is obvious, that is why I didn't write this in the first place. Also the modbus uses serial communication not TCP

The flow in node red was super simple loop that waits 50ms and then updates a counter

[{"id":"edb77f82.7b7c8","type":"tab","label":"Flow 2","disabled":false,"info":""},{"id":"86836073.4eaac","type":"delay","z":"edb77f82.7b7c8","name":"","pauseType":"delay","timeout":"50","timeoutUnits":"milliseconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"x":510,"y":180,"wires":[["86cc850c.a3d92"]]},{"id":"86cc850c.a3d92","type":"function","z":"edb77f82.7b7c8","name":"","func":"var counter = flow.get(\"counter\") || 0\n\ncounter += 1\n\nflow.set(\"counter\", counter)\n\nreturn msg","outputs":1,"noerr":0,"initialize":"","finalize":"","x":500,"y":120,"wires":[["86836073.4eaac"]]},{"id":"b2aca1da.9e47d","type":"inject","z":"edb77f82.7b7c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":290,"y":320,"wires":[["bbaabc0a.880298"]]},{"id":"bbaabc0a.880298","type":"change","z":"edb77f82.7b7c8","name":"","rules":[{"t":"set","p":"payload","pt":"msg","to":"counter","tot":"flow"}],"action":"","property":"","from":"","to":"","reg":false,"x":480,"y":320,"wires":[["251e34b.cd88bcc"]]},{"id":"251e34b.cd88bcc","type":"debug","z":"edb77f82.7b7c8","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":690,"y":320,"wires":[]},{"id":"f99a84e.b56f8f8","type":"inject","z":"edb77f82.7b7c8","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":320,"y":100,"wires":[["86cc850c.a3d92"]]}]

And THAT consumes a loot of (>50% of CPU) resources, so adding input state change detection and actual modbus reading is out of the question already... I need a different approach, that is why I'm asking, how the community handles such problems :slight_smile:

I run this test again, and I can see now that the CPU is used a lot at the beginning but after a couple of minutes it stabilizes at ~15%CPU which is kind of OK... but still, this is a "nobrainer" task, and should consume little to nothing of CPU, and thous I want to cover some other methods of achieving the same result

Search modbus on the forum - you would be surprised :slight_smile:

so re-reading your post, I neglected to read the "zero" part of "Node RED running on my raspberry pi zero"

I would suggest, due to your requirements, you would be better off running a C++ or python app that publishes the values to MQTT. Even then 50ms might be a bit adventurous for continuous values (and ultimately superfluous) - in your C/python code I would suggest you send all values on initial read, then only publish changes thereafter.

Lastly, as it seems this is the only task, you might be better off with an ESP32 for this this task. (pretty sure an ESP32 could achieve this)

PS, the loop is not really the node-red way. An inject set to repeat every 0.05sec is a better solution.

there will be some load of node-red process.

try changing that loop to a single inject set to interval 0.05s

also, remove connections to debug nodes as they (under the hood) have to do a bunch of work preparing debug msgs and sending them to your the browser over websockets.

After some tests.

Python script (read state, detect change, send message) takes < 10% CPU, still a bit higher value than I want, but acceptable.
The same thing in Node-RED takes < 30% CPU Which... To be honest, Is not so bad, I am quite surprised of the performance of Node RED, and also I did a pretty shitty job during the first test...

My RPi has already couple of things to do, so the 20% CPU is a lot, considering this, the solution for me is a python "deamon" running the background and sending MQTT messages to Node RED.

Thank you for help

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