Writing Modbus Data with node-red

modbus-write-node-red-iconIn the previous tutorial we looked at the modbus nodes and looked at how to read data from a Modbus server using node-red.

In this tutorial we will look at writing data to a modus server using node-red.



Writing Data

To write data we will use the modbus write node and modbus flex write node.

As we saw with the read nodes the write node has all of the configuration done in the node itself whereas the flex write gets the configuration from the preceding node.

modbus-red-write-nodes
The nodes support the function codes 5,6,16,16 which allow you to write to coils,registers,multiple coils and multiple registers.

modbus-write-node-fcs

When writing we have the opposite problem of reading.

Modbus Write Examples

All of the examples use a flow like that shown below:

write-modbus-flow

The function code is used to create the write command and the code shown in the examples is placed in this node. The inject node is used just to trigger the flow but it could also contain the value to write.

Write 16 Bit Integer

Again writing a 16 bit integer is easy as the node expects a 16 bit integer.

Below is the code from a function code that send a value of decimal 16001 to a modbus server using fc =6 (single register ) and start address of 40.

var fc=6;
var sa=40;
var addresses=1;
var value=16001;
msg.slave_ip="192.168.1.76";
msg.payload={"value":value , 'fc': fc, 'unitid': 1, 'address': sa , 'quantity': addresses };
return msg;

You should notice that I didn’t need to manipulate buffers.

Write 32 Bit Integer

However if we need to send a 32 bit integer then it is very different.
The code for the preceding function code is shown below were we write the value 16001 to address 50 using function code 16.The code is shown below:

var fc=16;
var sa=50;
var addresses=2;
var buf=Buffer.alloc(4);//create buffer
buf.writeInt32BE(68001);
var values=[(buf[0]*256+buf[1]),(buf[2]*256)+buf[3]]
msg.slave_ip="192.168.1.76";
msg.payload={"value":values , 'fc': fc, 'unitid': 1, 'address': sa , 'quantity': addresses };
return msg;

This time we use fc=16 for multiple registers and we need to use 2 registers.

32 bits =4*8(bits) which is 4 buffers and so we create our empty buffer.

We then write the integer (68001) into this buffer.

For multiple resisters the node expects 16 bit decimal values for each register and so we need to split our buffer into 2 parts.

We then create an array of the form [value1,value2].

Notice value1 is the low order 2 buffers (0,1), and value 2 is the higher order buffers (2,3). Notice also we need to multiple the buffers 1 and 2 by 256.

Write 32 Bit Float

The code for the preceding function code is shown below were we write the value 16001.5 to address 70 using function code 16.

var fc=16;
var sa=70;
var addresses=2;
var value=16001.5;
buf=Buffer.alloc(4);
buf.writeFloatBE(value);
//buf.writeFloatBE(16001.5);
var values=[(buf[0]*256+buf[1]),(buf[2]*256)+buf[3]]
msg.slave_ip="192.168.1.31";
msg.payload={"value":values , 'fc': fc, 'unitid': 1, 'address': sa , 'quantity': addresses };
return msg;

You should notice it is almost identical to the 32bit integer.

Write 64Bit Float

The code for the preceding function code is shown below were we write the value 16001.5 to address 80 using function code 16. Because it is 64 bits we need 8 buffers.

var fc=16;
var sa=80;
var addresses=4;
var value=16001.5;
buf=Buffer.alloc(8);
buf.writeDoubleBE(value);
//buf.writeFloatBE(16001.5);
var values=[(buf[0]*256+buf[1]),(buf[2]*256)+buf[3],(buf[4]*256+buf[5]),(buf[6]*256)+buf[7]];
msg.slave_ip="192.168.1.76";
msg.payload={"value":values , 'fc': fc, 'unitid': 1, 'address': sa , 'quantity': addresses };
return msg;

Signed and Unsigned

All of the examples given above use signed integers. If you need to write unsigned use writeUInt16BE() and writeUInt32BE().

BE and LE

All of the examples above use BE format. If you need LE format replace BE with LE.

I.e writeUInt16BE() becomes writeUInt16LE() etc

Video Writing data to Modbus

Resources

Flow for video1,video2 and dashboard

download



Using The TCP Node

A reader recently came across a problem resetting a PZEM 017 . The documentation gave the code as:

I have found the code:

Part of Data Package Description Value
01 Slave address 0x01 (1)
42 Function code 0x42 (66)
80 11 Data
00 00 CRC 0x0000 (0)

He was able to reset it using modbus poll but not with the modbus flex write because it doesn’t support function code 66.

We were able to achieve the same result using the TCP node.

tcp-node

Th function node code is:

msg.payload=Buffer.from([0x01,0x42,0x80,0x11]);
return msg;

Notice we needed to create a buffer from the data just using an array doesn’t work.

Related Tutorials

 

Click to rate this post!
[Total: 3 Average: 5]

21 comments

  1. Hi Steve,
    No need to reply to the previous message.
    I have now found what the address field refers to. It is the register address for the selected function code.
    I was really mixing this up with either IP or RTU addressing, however it has nothing to do with that.
    Thanks again.
    Regards,
    Dan

  2. Hi Steve,
    Within the the Modbus read and write nodes properties setting there is an address field. Can you please specify what this represents?
    Currently I am using OpenPLC and Node-Red in a VM and gaining access via my host machine using port forwarding. So therefore I have set OpenPLC’ IP address as the server. I have created a user interface and can switch buttons on/off on the ui, however to do this I must match the address within the Modbus read/write nodes with the I/O addresses of the PLC.
    As I understand it, Node-Red is communicating with the OpenPLC via Modbus TCP/IP. I do not have specific IP addresses for the slave devices, just the addresses that match the I/O numbering of the PLC.
    I am wondering if the address field represents Modbus RTU, as I know they require a specific address which is contained in the PDU. And as I have mentioned none of my external slaves have an IP.
    I have tried to find clarification of this high and low but nothing definitive I have been able to locate.
    My system is working, but if I change the addresses in the Modbus read/write nodes so they do not match the PLC it stops working.
    Can you confirm or deny that perhaps my situation is using Modbus RTU and the address fields represent this?
    Apologies for the story, however I am hoping you can clarify.
    Regards,
    Dan

  3. Hi – Steve
    typo at

    Signed and Unsigned
    All of the examples given above use signed integers. If you need to write signed use writeUInt16BE() and writeUInt32BE().

    If you need to write signed =>> If you need to write Unsigned

  4. Hi
    I’m new for node red I have some doubts mention below kindly any one help
    1. I’m reading distance sensor in my node red now I want to send that sensor data to HMI through TCP/IP protocol how can i do this ( I want to send multiple data )

  5. Hello. I ran into a problem, please help me find a solution.

    There is a two-channel relay with Modbus, I use the package to communicate with it node-red-contrib-modbus
    Read channel 1 and channel 2 state :01 03 00 01 00 02 95 CB — it is not problem
    The problem starts when I initiate the write, namely

    The command to turn on, according to the manual, looks like 01 06 00 01 01 00 D9 9A
    That is, to turn on the channel ‘1’ relay, it is necessary to write the value 0x0001 to the register at address 0x01.

    Now the actual question
    How to write data to a register using LE bit order using node modbus-flex-getter?

    1. Are you using 16bit registers?
      Have you tried the code in the tutorial and the flow
      var fc=6;
      var sa=40;
      var addresses=1;
      var value=16001;
      msg.slave_ip=”192.168.1.76″;
      msg.payload={“value”:value , ‘fc’: fc, ‘unitid’: 1, ‘address’: sa , ‘quantity’: addresses };
      return msg;
      and changing the sa to 1 and the value to 1?
      rgds
      steve
      rgds
      steve

  6. I have successfully been able to read modbus IP/TCP just via the ‘modbus read’ function.
    However I struggle to write to the DO part of the IO-board.

    The modbus IO is a iSMA-b-mix 38, I write to it via the ‘modbus write’ function.
    There’s 12 DO’s and I write to them via 1, for DO1. 2, for DO2. 4, for DO3 and all the way up to 2048 for DO12.

    The relays react but only stays on for 500ms to 1sec.
    Is there an easy way to get them to stay on all the time?

    1. If they react then the write is working maybe there is a setting that determines if they only flip or they stay on?
      rgds
      steve

  7. Hi,
    I wonder how to pass a negative values to my PLC with modbus tcp, I need to send an offset for a regulator that can be both positve and negative value.

    any ide?

    1. The buffer write will write unsigned and signed values so just use the signed values which is what I have used in all my flow examples they look like this
      buf.writeIntBE16
      and not like this
      buf.writeUIntBE16
      Rgds steve

      1. This is just above my competence level to understand.
        I’ve tried to write the value “-5000” to a register (init16) using buffer maker and buffer parser. Without success, hence ending here to see if I could understand this – still cannot.
        Reading via modbus and writing positive values is working fine. I justt cannot send negative value “-5000” equivalent to “-50%) to my inverter
        How would input-, function- node look like if I used FC16(or FC6) and eg. modbus flex writer?
        I’m even willing to pay for the solution – I’ve spent hour and hours to get this to work.
        Thanks in advance,
        Peter

  8. Hi Steve,

    Great guide!!

    Can you help me with my problem?

    I want to reset a counter on a PZEM-017. I have connected it over Modbus TCP. It is already working with Node Red.

    One thing is missing. The reset of the counted energy.

    I know the reset code but I dont know how to put it in the right form.

    # 0x01 Slave address
    # 0x42 Magic code
    # 0x80 CRC for slave address (0x01)
    # 0x11 CRC for magic code (0x42)
    data = [0x01, 0x42, 0x80, 0x11]

    Can you help me please?

    Greatings
    Stefano

  9. Hi Steve,

    thank you for your usefull guide.
    I’m using the node “modbus-flex-write” to write 16 holding register (addr: 40001) but I get this error: “TypeError: Cannot read property ‘getMachineState’ of undefined at Object._inputCallback (/opt/node-red/node_modules/node-red-contrib-modbus/modbus/maps/modbus-flex-write.js:52:5) at Object.Node._emitInput (/opt/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:199:18) at Immediate._onImmediate (/opt/node-red/node_modules/@node-red/runtime/lib/nodes/Node.js:179:33) at processImmediate (internal/timers.js:439:21)”

    I really don’t know to root cause of this error. Didi you ever see this type of error?

    Thanks for your time!

    Best regards,
    Federico

Leave a Reply to steve Cancel reply

Your email address will not be published. Required fields are marked *