Payload's number to two 16 bit register to be send via modbus

#1

Hi!

I need help width, how to split/create two 16 bit from payload to be send via modbus leater.

We get payload value trough kplex and tcp in node, leater use switch node to take those rows we need.
in GPRMC function node we split it to messages, json node convert lat to number...
now after that we need to get rid of dot in number 59.3234917 to 593234917 then get it to 2 modbus registers (16bit) 4 byte array which we can feed modbus. Reason to get rid of dot is if we use like float latitude not going to be so exact coz float will round numbers.

19/10/2018, 10:59:09node: e8e2ab9e.6a8748
msg.payload : Object
object
lat: 59.3234917
lon: "18.1840927"

Feed from tcp in looks like

19/10/2018, 10:58:44node: cd9ba9b2.09dd28
msg.payload : string[66]
"$GPRMC,085844.00,A,5932.80963,N,018.60482,E,0.026,,191018,,,A*7A"

in attached flow is function to 2 UInt16 witch contain code I found both to read and create float registers

[{"id":"9b787397.f9a65","type":"tcp in","z":"df4f10d2.533e3","name":"","server":"client","host":"192.168.10.144","port":"10110","datamode":"stream","datatype":"utf8","newline":"\r\n","topic":"","base64":false,"x":157,"y":157,"wires":[["becb5746.5aea38"]]},{"id":"f8588990.06deb8","type":"debug","z":"df4f10d2.533e3","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1157,"y":156,"wires":[]},{"id":"becb5746.5aea38","type":"switch","z":"df4f10d2.533e3","name":"","property":"payload","propertyType":"msg","rules":[{"t":"cont","v":"$GPRMC","vt":"str"},{"t":"cont","v":"$GPGGA","vt":"str"},{"t":"cont","v":"$SDDBT","vt":"str"},{"t":"cont","v":"$SDMTW","vt":"str"}],"checkall":"true","repair":false,"outputs":4,"x":395,"y":155,"wires":[["9e22f267.aca55","f8588990.06deb8"],["f8588990.06deb8"],["f8588990.06deb8"],["f8588990.06deb8"]]},{"id":"71b6fba0.c710b4","type":"function","z":"df4f10d2.533e3","name":"to 2 Uint16 ","func":"var rawData = new ArrayBuffer(4);\nvar intView = new Uint16Array(rawData);\nvar fltView = new Float32Array(rawData);\n\nintView[0] = msg.payload[1]; //low\nintView[1] = msg.payload[0]; //high\n\nmsg.payload = parseFloat(fltView[0].toFixed(1));\nmsg.topic = "to 2 Uint16";\n\nnode.status({fill:"blue",shape:"ring",text:msg.topic + ":" + msg.payload}); \n\nreturn msg;\n//The above code expects a 4 byte array \n//which is 2 Modbus registers\n//from https://stackoverflow.com/questions/6887003/convert-32bit-unsigned-real-data-type-splitted-into-two-16-bit-signed-words\n/\nfunction uint16ToFloat32(low, high) {\n var buffer = new ArrayBuffer(4);\n var intView = new Uint16Array(buffer);\n var floatView = new Float32Array(buffer);\n\n intView[0] = low;\n intView[1] = high;\n return floatView[0];\n}\n\nfunction float32ToUint16(value) {\n var buffer = new ArrayBuffer(4);\n var intView = new Uint16Array(buffer);\n var floatView = new Float32Array(buffer);\n\n floatView[0] = value;\n return [intView[0], intView[1]];\n}\n\nconsole.log("Converted ints to", uint16ToFloat32(18584, 18081));\nconsole.log("Converted float to", float32ToUint16(20644.297));\n/","outputs":1,"noerr":0,"x":936,"y":261,"wires":[["fc550a63.065c68"]]},{"id":"9e22f267.aca55","type":"function","z":"df4f10d2.533e3","name":"GPRMC","func":"//Example of data received:\n//"$GPRMC,071723.00,A,5914.81006,N,01816.64371,E,0.006,,191018,,,A*7D"\n\n\nmessage0 = {};\nmessage1 = {};\nmessage2 = {};\nmessage3 = {};\nmessage4 = {};\nmessage5 = {};\nmessage6 = {};\nmessage7 = {};\nmessage8 = {};\nmessage9 = {};\nmessage10 = {};\nmessage11 = {};\nvar symblat = "";\nvar symblong = "";\n\n//Split the 12 NMEA data into 12 messages\nmsg.string = msg.payload.split(",");\n\n//Find if the data gps fix is valid \nif (msg.string[2] == "A") {\n \n//Find if latitude is south and add minus\nif (msg.string[4] == "S") {\nsymblat = "-";\n} else {\n\n}\n\n//Find if longitude is west and add minus\nif (msg.string[6] == "W") {\nsymblong = "-";\n} else {\n\n}\n\nvar nvals = msg.payload.match(/,(\d+)(\d\d\.\d+),(N|S)/);\nvar evals = msg.payload.match(/,(\d+)(\d\d\.\d+),(E|W)/);\nmsg.payload = {\nlat: symblat + (+nvals[1] + nvals[2]/60).toFixed(7),\nlon: symblong + (+evals[1] + evals[2]/60).toFixed(7)\n\n}}\n\nreturn [msg];","outputs":1,"noerr":0,"x":644,"y":92,"wires":[["f8588990.06deb8","eaa9f38e.e839c"]]},{"id":"eaa9f38e.e839c","type":"json","z":"df4f10d2.533e3","name":"","property":"payload.lat","action":"","pretty":true,"x":923.5,"y":85,"wires":[["fc550a63.065c68","71b6fba0.c710b4"]]},{"id":"fc550a63.065c68","type":"debug","z":"df4f10d2.533e3","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":1273,"y":84,"wires":[]}]

/IQAPPS

0 Likes

#2

Suppose the number was 59.320 would you convert that to 59320? If so how do you know where the point is supposed to be?

0 Likes

#3

Be careful here... GPRMC format is DDMM.MMMMM for latitude and DDDMM.MMMMM for longitude... ie it's not just decimal - so yes you can remove the decimal point - BUT are you sure that's what you want ???

0 Likes

#4

Yeah good question maybe is easier to use it like float even if it's roundet location gooing to be enough accurate...

0 Likes

#5

Yes I know.... U are right guys.
My troughs was to doit easy in flow but its complete wrong...
We take like float....

0 Likes

#6

you must absolutely NOT use it like a float... you will be a long way out. You need to parse GPRMC properly to split off the DD and DDD parts from the MM.MMMMM and then do the maths to then create a proper float.

0 Likes

#7

In GPRMC function node we do allready that math to get like "Google maps format of latitude"
How we split that....split node? Or?
I do not understand how to take out eg lat from payload for next step!

19/10/2018, 10:59:09node: e8e2ab9e.6a8748
msg.payload : Object
object
lat: 59.3234917
lon: "18.1840927"
0 Likes

#8

msg.payload.lat

0 Likes

#9

It seems odd that you have converted the lat to a number but the lon is a string. I suspect that is not intentional.

0 Likes

#10

I think it probably will be accurate enough. Floats in javascript (actually all numbers in js) are 64 bit floating point which I estimate should give you a maximum error of about 10^-14 degrees which is about .00001 mm. I doubt if your GPS is that accurate.

0 Likes

#11

Yes agree gps is not that acurrate

That was only test to test conversions....

0 Likes

#12

Of course if you just add a msg.name to the object you then feed it direct to a worldmap node to see/check its in the right place

0 Likes

#13

May be you can use this method convert float to int16 value.

let base = new ArrayBuffer(4); //4 bytes
let int16_view = new Int16Array(base);
let float32_view = new Float32Array(base);

float32_view[0] = msg.payload;

let rValue = [];
rValue.push(int16_view[0]);
rValue.push(int16_view[1]);

msg.payload = rValue;

this is example for node-red

[{"id":"2a79d0f3.318d3","type":"function","z":"6dd3fb7d.264d44","name":"float32 -> int16","func":"let base = new ArrayBuffer(4); //4 bytes\nlet int16_view = new Int16Array(base);\nlet float32_view = new Float32Array(base);\n\nfloat32_view[0] = msg.payload;\n\nlet rValue = [];\nrValue.push(int16_view[0]);\nrValue.push(int16_view[1]);\n\nmsg.payload = rValue;\n\nreturn msg;","outputs":1,"noerr":0,"x":530,"y":380,"wires":[["46d2875c.9da9e8","4874a5f0.1de0dc"]]},{"id":"8f55454e.8ce888","type":"inject","z":"6dd3fb7d.264d44","name":"","topic":"","payload":"0.5","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":400,"wires":[["64b0d21e.d3996c"]]},{"id":"33a7dcdd.dff8f4","type":"inject","z":"6dd3fb7d.264d44","name":"","topic":"","payload":"1.0","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":340,"wires":[["64b0d21e.d3996c"]]},{"id":"53bca83.01fdb58","type":"inject","z":"6dd3fb7d.264d44","name":"","topic":"","payload":"0.25","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":170,"y":460,"wires":[["64b0d21e.d3996c"]]},{"id":"6b0b8b9.0e44774","type":"inject","z":"6dd3fb7d.264d44","name":"","topic":"","payload":"12345.67891234567","payloadType":"num","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":200,"y":520,"wires":[["64b0d21e.d3996c"]]},{"id":"46d2875c.9da9e8","type":"debug","z":"6dd3fb7d.264d44","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","x":760,"y":380,"wires":[]},{"id":"64b0d21e.d3996c","type":"function","z":"6dd3fb7d.264d44","name":"link","func":"\nreturn msg;","outputs":1,"noerr":0,"x":330,"y":380,"wires":[["2a79d0f3.318d3"]]},{"id":"acabf386.47cdf","type":"debug","z":"6dd3fb7d.264d44","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":760,"y":440,"wires":[]},{"id":"4874a5f0.1de0dc","type":"function","z":"6dd3fb7d.264d44","name":"int16 -> float32","func":"let base = new ArrayBuffer(4); //4 bytes\nlet int16_view = new Int16Array(base);\nlet float32_view = new Float32Array(base);\n\nint16_view[0] = msg.payload[0];\nint16_view[1] = msg.payload[1];\n\nmsg.payload = float32_view[0];\n\nreturn msg;","outputs":1,"noerr":0,"x":530,"y":440,"wires":[["acabf386.47cdf"]]}]
0 Likes

#14

Thanks
I used already similar code.... Gooing to post flow here soon...

0 Likes