Modbustcp-read Function Script

Hi at all,
I would like to connect my pool meter to Homematic via node-red.

The connection to the device works. I need 3 registers that I read with modbustcp-read and then want to split into 3 channels with function.

I need help creating the script

Register1 : 100 (Chlor)
Register2 : 115 (PH)
Register3 : 130 (Redox)

I hope someone can help me.

Best Regards

What is triggering the MODBUS query for your register reads? Or is that part of what you need help developing?

With modbustcp-read I can query 1 register. But I need to query 3 registers and I can't use modustcp-read 3 times on one device. The data format of the register is 32bit sw. float.

Ok. Fair enough. Are you using node-red-contrib-modbus as your MODBUS node package or something else?

Preferably node-red-contrib-modbus if it supports 32bit sw. float. But I don't know how to do that.

The node itself doesn't support it directly. But that doesn't matter because it's how you pull the data that matters. Here's how you would setup your flow.

[{"id":"5aa8e938caef0145","type":"tab","label":"Pool","disabled":false,"info":"","env":[]},{"id":"bfe67d7edd06ac3e","type":"inject","z":"5aa8e938caef0145","name":"1m Trigger","props":[{"p":"payload"}],"repeat":"60","crontab":"","once":true,"onceDelay":"0.5","topic":"","payload":"","payloadType":"date","x":170,"y":100,"wires":[["73732dbb88492cd4"]]},{"id":"73732dbb88492cd4","type":"modbus-flex-sequencer","z":"5aa8e938caef0145","name":"Pool Control","sequences":[{"name":"chlor","unitid":"1","fc":"FC3","address":"100","quantity":"2"},{"name":"ph","unitid":"1","fc":"FC3","address":"115","quantity":"2"},{"name":"redox","unitid":"1","fc":"FC3","address":"130","quantity":"2"}],"server":"dfe14343b607d506","showStatusActivities":false,"showErrors":false,"logIOActivities":false,"useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":false,"keepMsgProperties":false,"x":330,"y":100,"wires":[[],["cdf20a5b85d365eb"]]},{"id":"cdf20a5b85d365eb","type":"function","z":"5aa8e938caef0145","name":"","func":"var temp = Buffer.from(msg.payload.buffer);\nmsg.payload = temp.readFloatBE();\nif( == \"chlor\"){\n    return([msg,null,null]);\n}\nif( == \"ph\"){\n    return([null,msg,null]);\n}\nif( == \"redox\"){\n    return([null,null,msg]);\n}","outputs":3,"noerr":0,"initialize":"","finalize":"","libs":[],"x":480,"y":100,"wires":[[],[],[]]},{"id":"dfe14343b607d506","type":"modbus-client","name":"Test Server","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"failureLogEnabled":true,"tcpHost":"","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","serialAsciiResponseStartDelimiter":"0x3A","unit_id":"1","commandDelay":"1","clientTimeout":"1000","reconnectOnTimeout":true,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true}]

Now obviously, you'll need to correct your MODBUS server information in the Pool Control node to make it work as I don't have that info. But that should be the minimum to start getting data out.

How it works is you have an inject node working as a timer. You can adjust it to whatever update frequency you want. I just set it for one minute. That timer feeds a sequencer that's part of the node-red-contrib-modbus package. The sequencer's job is to go through a sequence (hence the name) of MODBUS registers and spit out the data as it goes. I'm assuming each register is a 32 bit float, which is why you're pulling a quantity of two (first and second halves of the float in MODBUS speak). The data from these pulls will be output on the bottom channel as a buffer, which is one of the easiest forms to work with when reconstructing your float.

Once you have your data from a pull, it's spit out to the function which will convert the data from the buffer into a float. There's something to pay attention to here. There's no specific order MODBUS specifies for the float to come back as. Your controller may pass it back big Endian or little Endian. If you look at the data and it doesn't look right, change the readFloatBE to readFloatLE in the function to make it convert the float as little Endian and see if that works. Once the float is converted, it's assigned to the payload. The requesting component in the sequencer is then checked to figure out what data was being requested. Based on that data, it's rerouted to one of the function outputs to be used as the data for what I assume would be a dashboard display.

Anyways, that's the minimum to get you started. It will take some tuning to match your setup, but it shouldn't be too difficult to accomplish.

Since I have node-red running on my Redmatic (Homematic CCU3), I can only install node-red-contrib-modbus v5.13.3. but this does not contain a sequencer node.

I've been looking on the Redmatic GitHub and wiki, but I can't find anywhere that has those limits setup. Can you show where it has the limit of v5.13.3? Everything I'm finding says you should be able to install the most recent version.

Just as a curiosity, have you gone into your palette manager recently and seen if there is an update to the MODBUS node set?

I'm just having a hard time finding out why this would be limited.

In Redmatic I can only install the package v5.13.3. In node-red I can install package v5.23.3 but it always fails

fail log here

It says you need to install python.

I'm with Colin on this one. The computer I'm on right now can't get to Dropbox (company computer), so I can't look at the log. But if your error claims you're missing python, just NPM it.

npm install -g node-gyp

That should get you what you need. Once you install node-gyp, it will have the ability to compile the new MODBUS nodes and make them work.

node-gyp is there ok, it is python that is missing.

Ok. Thanks Colin. Like I said, I can't open the logs so that's helpful to know.

@Cupra85, I did some further digging on this, like you may already have tried to do. Unless you can install python as a package, you may not be able to upgrade to the most recent MODBUS node set. But that's not an issue. You should still be able to get the same result with three inject nodes pointing into a flex-getter. Each inject node will hold the fc, address and quantity variables for the data you want. fc will always be 3, the address will be the MODBUS address and the quantity will be 2 so it can pull the full 32 bits for the float (same setups as the sequencer, just split out). Also, your inject node can use msg.topic for the label (i.e. chlor, ph, redox) as that will carry through the flex-getter to the function on the other side where you can use it instead of msg.request properties to direct your data. The flex-getter should have a built-in queue function that will queue the messages from the three inject nodes and give you the same result on the other side as what I originally posted.

Let me know if you're stuck on any of that and I'll help you get out.

can you build me such a flow? I don't quite follow you. :frowning:

It would look like this:

Same type of setup as before. But where before I only used one inject node to trigger the sequencer, I'm using three inject nodes to actually inject the queries. You can see the node arrangement on the left with an example of the inject node on the right.

Then in the function I originally gave, just change to msg.topic. Should produce the same results.

I have that, but what has to be in the function?
Change topic doesn't work

Your if statements will change from what I originally posted to look like this:

if(msg.topic == "chlor"){
if(msg.topic == "ph"){
if(msg.topic == "redox"){

The rest should work the same.

No it doesn't work as advertised.

What are you getting from Node-Red? Is there anything in your debug window? Do you have debug nodes attached to the outputs of the function? That should tell you what you're getting, if anything.

I have ccu sysvar node at the output and they don't show the current value.