Node-red-contrib-modbus with negative decimals

Hello
I read in the notes for node-red-contrib-modbus that it can only accept a single decimal between 0:65535 (uint16).

does anyone know the normal method of providing a negative value to a holding register with this plugin, please?

thanks
justin

Hello Justin ..

you can use the node-red-contrib-buffer-parser nodes to first convert the signed INT to a buffer,
then to a UINT and finally construct the msg for the modbus Write node.

Here is an example flow :

[{"id":"33d3ecfcea39961a","type":"inject","z":"937cb040.d8e16","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"-123","payloadType":"num","x":210,"y":920,"wires":[["8a4d45153a2bbd13"]]},{"id":"8a4d45153a2bbd13","type":"buffer-maker","z":"937cb040.d8e16","name":"Convert INT to Buffer","specification":"spec","specificationType":"ui","items":[{"name":"item1","type":"int16be","length":1,"dataType":"msg","data":"payload"}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","x":400,"y":920,"wires":[["d9083768a228b72c","30d6c88b90c5b218"]]},{"id":"d9083768a228b72c","type":"buffer-parser","z":"937cb040.d8e16","name":"Convert Buffer to UINT","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"uint16be","name":"uint16","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"return","multipleResult":false,"fanOutMultipleResult":true,"setTopic":false,"outputs":1,"x":680,"y":920,"wires":[["ad74442fa961ea10","86971d6890ae44e6"]]},{"id":"30d6c88b90c5b218","type":"debug","z":"937cb040.d8e16","name":"debug 1","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":495,"y":860,"wires":[],"l":false},{"id":"ad74442fa961ea10","type":"debug","z":"937cb040.d8e16","name":"debug 2","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":825,"y":860,"wires":[],"l":false},{"id":"86971d6890ae44e6","type":"function","z":"937cb040.d8e16","name":"","func":"\nmsg.payload = {\n    value: msg.payload.uint16,\n    'fc': 6,\n    'unitid': 1,\n    'address': 4,  //your address\n    'quantity': 1\n}\n\nreturn msg","outputs":1,"timeout":"","noerr":0,"initialize":"","finalize":"","libs":[],"x":945,"y":920,"wires":[["c9ea6d2795d44709","671e91517cc5349c"]],"l":false},{"id":"c9ea6d2795d44709","type":"modbus-flex-write","z":"937cb040.d8e16","name":"","showStatusActivities":true,"showErrors":true,"server":"644cb5f29bb9a4f8","emptyMsgOnFail":false,"keepMsgProperties":false,"x":1110,"y":920,"wires":[[],[]]},{"id":"671e91517cc5349c","type":"debug","z":"937cb040.d8e16","name":"debug 3","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1020,"y":860,"wires":[]},{"id":"644cb5f29bb9a4f8","type":"modbus-client","name":"","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"failureLogEnabled":true,"tcpHost":"127.0.0.1","tcpPort":"10502","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":false,"reconnectTimeout":"2000","parallelUnitIdsAllowed":true}]

Thanks

I've had variable success with double conversions using buffer parser. It's a bit counterintuitive for my tastes. For one offs I can easily convert the information manually, I was really wondering whether there was a recommended method. I guess double conversions are the recommended! I might fork the modbus repo and improve that when I have time

All the best

Justin

You could also convert the bits and bytes to whatever type you want in javascript. Should be tons of tutorials on the topic.

@ThingsTinkerer thanks - and yes indeed it's trivial to convert using a function node. My question was whether there was a generally recommended method for use with this package. ModBus is relatively standardised so I was surprised that conversion was not built in or parameterised in the node UI.

when I have time I will add the functionality and send a PR.

for future readers stumbling upon this trying to do the conversion manually, here are a couple of methods

let s_int = -10;
let u_int = s_int & 0xFFFF;
console.log(u_int);

or using typed arrays

let s_int = new Int16Array(1);
s_int[0] = -10;
let u_int = new Uint16Array(s_int);
console.log(u_int[0]);

and to convert back

let u_int = 65526;
let s_int = (u_int << 16) >> 16;
console.log(s_int);

or using typed arrays

let u_int = new Uint16Array(1);
u_int[0] = 65526;
let s_int = new Int16Array(u_int);
console.log(s_int[0]);
1 Like

I would imagine modbus being used for all sorts of values, so there wouldn't be one conversion to fit all? Furthermore, it may be used for many different requests which returns different types of values, so they would need to be handled individually afterwards (downstream).

sure. modbus rtu returns uint16 (I think this is per spec)

it feels like a good enhancement:

  • on input, to test for negative values and autoconvert to uint16.
  • on output to have a format provided in the payload to the getter/flex-getter and for the node to spit out the payload per the requested format.

Are you proposing also that it should provide for float32, float64, byte, bit etc?

converting to/from floats require custom rules. Sure it could be added but that seems more desirable in a function or other node.

standard castings like boolean seem to be similarly useful to negative data.

more importantly than what I think, what do others think?