node-modbus-serial
node-modbus-serial copied to clipboard
Swapped float point
Hello, I tried to convert the data result to swapped float point but it did not work .
This is the result using modscan32.
My code
const {
SerialPort
} = require('serialport')
const ModbusMaster = require('modbus-serial')
// Function to swap bytes (big-endian to little-endian)
function swapBytes(buffer) {
const len = buffer.length
for (let i = 0; i < len - 3; i += 4) {
const temp = buffer[i]
buffer[i] = buffer[i + 3]
buffer[i + 3] = temp
const temp2 = buffer[i + 1]
buffer[i + 1] = buffer[i + 2]
buffer[i + 2] = temp2
}
}
// Function to convert a 4-byte buffer to a 32-bit floating-point number
function bufferToFloat(buffer) {
swapBytes(buffer); // Swap bytes before converting to float
return buffer.readFloatBE(0) // Interpret the buffer as a big-endian float
}
//read register data from digital meter using modbus-serial package
const readRegistersData = async (id, inputLength) => {
return new Promise(async (resolve, reject) => {
// set ID of slave
await master.setID(id)
// read the 1 registers starting at address 0x00(first register)
await master.readInputRegisters(1, inputLength).then((res) => {
//resolve show result
resolve(res)
}, (e) => {
//reject show error
reject(e)
})
})
}
//run and check if serial port is found on device
SerialPort.list().then(
ports => {
//get all port list
ports.forEach(async port => {
//find device name
if (port.manufacturer.includes("wch.cn")) {
// open connection to a serial port
master = await new ModbusMaster()
await master.connectRTUBuffered(port.path, {
baudRate: 9600,
parity: 'even'
})
readRegistersData(12, 55).then((recvData) => {
const floatValues = []
for (let i = 0; i < 55; i++) {
const buffer = Buffer.from(recvData.buffer.slice(i * 4, (i + 1) * 4)) // Read 4 bytes for each float value
floatValues.push(bufferToFloat(buffer))
console.log(bufferToFloat(buffer))
}
})
}
})
},
error => {
console.log(error)
})
How to get data result in swapped float point. Please advise this
Hi any updates on this I have a similar use case ?
try not to swapBytes yourself, find a buffer to float method, that swap it for you: https://www.geeksforgeeks.org/node-js-buffer-readfloatbe-method/
try not to swapBytes yourself, find a buffer to float method, that swap it for you: https://www.geeksforgeeks.org/node-js-buffer-readfloatbe-method/
Sorry not able to get your point, my usecase is
We get a buffer from readInputRegisters but since smartEnergyMeter specifies only flaot values to be used as also depicted in the screenshot above I need you recommendation on how to proceed to get the desired output like 240.234, by utilising the buffered returned by the readInputRegister API.
here is an example: https://github.com/yaacov/node-modbus-serial/blob/master/examples/buffer.js
you need to remove the swapBytes method and use one of nodejs built in methods to do the swapping for you.
a. test that the raw data you get is the same the one in modscan, e.g. hex in modscan, and see that the hex value are the same for the same address. b. different ways to read the data, did you try use big-endian instead of little? https://nodejs.org/api/buffer.html#bufreadfloatbeoffset
https://github.com/yaacov/node-modbus-serial/blob/master/examples/buffer.js
yes I tried these methods already but all of these return a 32 bit int value whereas I wanted it to be something of sort decimal like 240.324 etc.
For point a ,I tested in modscan the hex values are exactly the same,hence quite confused with this one.
have you tried readFloatBE ?
have you tried
readFloatBE?
yes I tried returns same 32 bit
{ data: { data: [ 43909, 0, 0, 0, 0, 17059, 51118, 17269, 43909, 0 ], buffer: <Buffer ab 85 00 00 00 00 00 00 00 00 42 a3 c7 ae 43 7 5 ab 85 00 00> } }
I'm adding a help wanted because your problem sound very weird
this is how 240.324 looks fp and swapped fp: hex: 4370 52f2 fp: buf.readFloatBE(0) = 240.32400512695312 swapped fp: buf.readFloatLE(0) = -4.168164361781354e+30
in your example I can't find a 2 registrar (32 bit) hex that can represent a 0 to 1000 number using swapped fp (readFloatLE)
assuming this is the same hex input used by modscan, I'm adding a help wanted in case someone knows what the issue is
I pasted a console output of data being received from the meter device from which I want to infer the floating voltage value, would be really helpful if you have any idea on this type of data being thrown by device .
const hexString = 'ab85000000000000000042a3c7ae4375ab850000';
const buf = Buffer.from(hexString, 'hex');
for (let i = 0; i < buf.length - 3; i++) {
const floatValue = buf.readFloatLE(i);
if (floatValue >= 0 && floatValue <= 1000) {
console.log(`Found float value ${floatValue} at position ${i}`);
}
}
hmm, i can actually find some numbers:
Found float value 4.795103215073092e-41 at position 0
Found float value 1.8637269575520067e-43 at position 1
Found float value 0 at position 2
Found float value 0 at position 3
Found float value 0 at position 4
Found float value 0 at position 5
Found float value 0 at position 6
Found float value 32 at position 7
Found float value 349.5596618652344 at position 11
Found float value 1.227562818250744e-38 at position 15
Found float value 4.795103215073092e-41 at position 16
so using your input in position 11 we have somthing that looks like usefull data ...
Historically Modbus RTU was designed only for integer value type using 2-byte 'registers', so there was no definite specification for 4-byte IEEE-754 floating point values. As the result, there are 4 different ways to interpret/convert bytes buffer into IEEE-754 floating point values, see for example settings in the Modbus Poll tool:
Also Modbus RTU uses "Register numbering" starting from 1 while the actual addressing starts from 0, e.g. Register 30001 means that Modbus RTU reading address should be set to 0 (3xxxx means using "Read Input Registers" command) - this also may lead to incorrect data reading/conversion.
There is a very handy conversion tool https://www.h-schmidt.net/FloatConverter/IEEE754.html that can be used to try different combinations of bytes (from your data buffer) and see which one makes sense.
For some reason your example buffer is not multiple of 4x - either there is an additional one byte or missing three bytes.
I am using this library for a while reading floating points values from our instruments, so please consider the following that may be helpful in your case:
- Make sure that your data buffer for floats has an appropriate number of bytes (multiple of 4).
- Make sure that a correct starting address is used.
- Try different 32 Bit Float conversion formats (there are four of them) since it's not stipulated by Modbus RTU standard and companies can implement it as they see fit for their business. You can try these four potential formats by combining swap16() and readFloatLE()/readFloatBE() functions.