influxdata / telegraf

Agent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.
https://influxdata.com/telegraf
MIT License
14.6k stars 5.56k forks source link

[inputs.modbus] Wrong readings on INT64 and FLOAT32 registers on a Schneider iEM3255 through a COM'X 510 Gateway. #8111

Closed ImSteph closed 4 years ago

ImSteph commented 4 years ago

Since Schneider devices are very common in the industry, maybe some of you may have encountered this problem and can help me.

Trying to read holding registers of a iEM3255 through a COM'X 510 using modbus but I get completely wrong values for both INT64 and FLOAT32 registers. Registers at page 68: https://download.schneider-electric.com/files?p_enDocType=Catalog&p_File_Name=iEM31003200_UserManual.pdf&p_Doc_Ref=DOCA0005EN-01

FLOAT32 readings

Using modpoll with the following command to read FLOAT32 registers I get the correct values: ./modpoll -f -t 4:float -r 3110 -a 1 -1 192.168.97.11 (In this case I'm reading the frequency)

Value: 50.007988

By looking at the "Usage" section of modpoll (https://www.modbusdriver.com/modpoll.html) I notice that by using -f option your slave operates on big-endian 32-bit floats. Looks like this is what is missing for the telegraf plugin to get the correct readings.

Telegraf reading: -2560641796792856000000000000000

INT64 readings

Same thing happens by reading INT64 registers but the only way I can check if the values are correct, since modpoll doesn't support INT64 registers, is to read them as INT16 and use this formula to get the correct value as INT64: 281474976710656 * Register1 + 4294967296 * Register2 + 65536 * Register3 + 1 * Register4

Example, reading register 3204 with Modpoll as HEX:

Command: ./modpoll -f -t 4:hex -r 3204 -c 4 -a 1 -1 192.168.97.11

Values:

Register                                                                   
    3204: 0000 hex ->     0 dec *  281 474 976 710 656 ->             0  +
    3205: 0001 hex ->     1 dec *        4 294 967 296 -> 4 294 967 296 +
    3206: 341D hex -> 13341 dec *               65 536 ->   87 4315 776 +
    3207: 8443 hex -> 33859 dec * ​                   1 ->        33 859 =
Final value:                                              5 169 316 931 Wh -> 5.17 GWh

Telegraf reading: 338782i

Telegraf modbus plugin configuration:

[[inputs.modbus]]
  name = "Slave Test"
  slave_id = 1
  timeout = "1s"
  controller = "tcp://192.168.97.11:502" # Gateway IP - COM'X 510

  holding_registers = [
     { name = "frequenza", byte_order = "ABCD",  data_type = "FLOAT32-IEEE", scale=0.01, address = [3110,3111]},
     { name = "importazione_energia_attiva_totale", byte_order = "ABCDEFGH",   data_type = "INT64", scale=0.000000001,  address = [3204,3205,3206,3207]},
  ]

Telegraf and modpoll readings

Telegraf

frequenza: -2560641796792856000000000000000 (Register 3110 - FLOAT32) importazione_energia_attiva_totale: 338782i (Register 3204 - INT64)

Modpoll

frequenza: 50.007988 importazione_energia_attiva_totale: 5169316931 (converted with the formula I wrote above) # If you need more information just let me know! Thank you for your time.

srebhan commented 4 years ago

Hey @ImSteph,

I've looked into importazione_energia_attiva_totale and compared it to the modpoll value you get. Converting both values back to hex I get hex(5169316931) --> '0x1341d8443' for you modpoll reference value and hex(int(338782 / 0.000000001)) --> '0x1341ed4c42c00' for the raw register reading of telegraf. As you can see, the telegraf reading strangely has an "additional register" (2-bytes) at the end 2c00. If we leave out these additional bytes we get int(0x1341ed4c4) --> 5169403076 which is approximately the value you are searching...

To me it seems like modpoll starts the registers at one while telegraf is zero-based! So to get the correct readings you should subtract 1 from your registers in the telegraf config. Could you please give it a try!?

Furthermore, did you get the register values from a datasheet? For me I always used the datasheet values for different sensors (no Schneider thou) and got correct values which indicates that those registers specifications follow the telegraf schema...

srebhan commented 4 years ago

Additional comment: The modbus specification clearly states that input register addresses start at zero (section 6.4 in Modbus Specification). It seems that modpoll starts registers at 1 (see comment for -r option) but also specifies the zero-based addressing through the -0 option...

So I'm pretty sure that using

  holding_registers = [
     { name = "frequenza", byte_order = "ABCD",  data_type = "FLOAT32-IEEE", scale=0.01, address = [3109,3110]},
     { name = "importazione_energia_attiva_totale", byte_order = "ABCDEFGH",   data_type = "INT64", scale=0.000000001,  address = [3203,3204,3205,3206]},
  ]

you get exactly the values you are looking for.

ImSteph commented 4 years ago

Thanks @srebhan, that solved my issue!

By the way to check the correct values I used Schneider's web interface and the registers' indexes from the datasheet I linked at the start.

I've actually had a similar problem some time ago and I totally forgot about the starting register. Moving back all register by one worked flawlessly thank you!

Thanks for the fast response!

Stefano

srebhan commented 4 years ago

Can you please close the issue if it is resolved. :-)