Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

input.modbus Read custom bit lenght in coil #8506

Closed
mirkocomparetti-synesis opened this issue Dec 3, 2020 · 8 comments
Closed

input.modbus Read custom bit lenght in coil #8506

mirkocomparetti-synesis opened this issue Dec 3, 2020 · 8 comments
Labels
area/modbus bug unexpected problem or unintended behavior

Comments

@mirkocomparetti-synesis
Copy link

mirkocomparetti-synesis commented Dec 3, 2020

Relevant telegraf.conf:

This is an example configuration for this case, with a possible proposed solution that will be more clear later.

  coils = [
    { name = "FOut", measurement="alarms", address = [0.0]},
    { name = "ASHigh", measurement="alarms", address = [0.8]},
    { name = "A1High", measurement="alarms", address = [0.9]},
    { name = "A2High", measurement="alarms", address = [0.10]},
    { name = "A3High", measurement="alarms", address = [0.11]},
    { name = "ANHigh", measurement="alarms", address = [0.12]},
    { name = "ASLow", measurement="alarms", address = [0.13]},
    { name = "A1Low", measurement="alarms", address = [0.14]},
    { name = "A2Low", measurement="alarms", address = [0.15]},
    { name = "A3Low", measurement="alarms", address = [0.16]},
    { name = "ANLow", measurement="alarms", address = [0.17]},
    { name = "U12High", measurement="alarms", address = [0.24]},
    { name = "U23High", measurement="alarms", address = [0.25]},
    { name = "U31High", measurement="alarms", address = [0.26]},
    { name = "U12Low", measurement="alarms", address = [0.27]},
    { name = "U23Low", measurement="alarms", address = [0.28]},
    { name = "U31Low", measurement="alarms", address = [0.29]},
    { name = "COM", measurement="alarms", address = [0.31]},
    { name = "USHigh", measurement="alarms", address = [0.32]},
    { name = "U1NHigh", measurement="alarms", address = [0.33]},
    { name = "U2NHigh", measurement="alarms", address = [0.34]},
    { name = "U3NHigh", measurement="alarms", address = [0.35]},
    { name = "USLow", measurement="alarms", address = [0.36]},
    { name = "U1NLow", measurement="alarms", address = [0.37]},
    { name = "U2NLow", measurement="alarms", address = [0.38]},
    { name = "U3NLow", measurement="alarms", address = [0.39]},
  ]

System info:

Telegraf 1.16.3, ubuntu 18.04.4 server

Steps to reproduce:

This is the example configuration

  coils = [
    { name = "FOut", measurement="alarms", address = [0]},
  ]

which retrieves the value

$ telegraf -config testcoil.conf -input-filter modbus -test
2020-12-03T15:47:28Z I! Starting Telegraf 1.16.3
> alarms,host=somehost,name=somedevice,type=coil FOut=0i 1607010449000000000

Expected behavior:

Possibility to read a configurable lenght of bits from a coil address and possibility to map them to single variables; something like the above example configuration. In additional info there is an explaination of why those need to be handled in that way, so that we get

> alarms,host=somehost,name=somedevice,type=coil FrequencyOut=false,ASHigh=false,A1Higg=false,A2High=false,A3High=false,ANHigh=false,ASLow=true,A1Low=true,A2Low=true,A3Low=true,ANlow=true,U12High=false,U23High=true,U31High=false,U12Low=false,U23Low=true,U31Low=false,COM=false,USHigh=false,U1NHigh=false,U2NHigh=false,U3NHigh=true,USLow=false,U1NLow=true,U2NLow=false,U3NLow=true 1607010449000000000

The relevant config above is an example of how this can be achieved using dot notation, but it is not the solution, just an idea.

Actual behavior:

The value 0i for FOut in example above is the first 8bits of the coil 0000, and all the other 32 bits are not retrieved (see additional info)

Additional info:

The device is an energy meter from Seneca; in chapter 7 of the following document you can see how the coils are defined: the first 40bits of address 0000 contain the information that we need to gather and store as separeted bools in the database, because the meaning of each bit is specific and has to be stored separately.

@mirkocomparetti-synesis mirkocomparetti-synesis added the bug unexpected problem or unintended behavior label Dec 3, 2020
@srebhan
Copy link
Member

srebhan commented May 18, 2021

@mirkocomparetti-synesis as far as it concerns the code, the coil address is the BIT address in the coil. So leave out the 0. part of your configuration example and you will get exactly what you want...

@mirkocomparetti-synesis
Copy link
Author

@srebhan I did some more tests with Telegraf unknown (git: pull/9141 8cbbe7f7) and those are the results I found

Using telegraf with this configuration

coils = [
    { name = "FOut", measurement="alarms", address = [32]},
    { name = "ASHigh", measurement="alarms", address = [24]},
    { name = "A1High", measurement="alarms", address = [25]},
    { name = "A2High", measurement="alarms", address = [26]},
    { name = "A3High", measurement="alarms", address = [27]},
    { name = "ANHigh", measurement="alarms", address = [28]},
    { name = "ASLow", measurement="alarms", address = [29]},
    { name = "A1Low", measurement="alarms", address = [30]},
    { name = "A2Low", measurement="alarms", address = [31]},
    { name = "A3Low", measurement="alarms", address = [16]},
    { name = "ANLow", measurement="alarms", address = [17]},
    { name = "U12High", measurement="alarms", address = [8]},
    { name = "U23High", measurement="alarms", address = [9]},
    { name = "U31High", measurement="alarms", address = [10]},
    { name = "U12Low", measurement="alarms", address = [11]},
    { name = "U23Low", measurement="alarms", address = [12]},
    { name = "U31Low", measurement="alarms", address = [13]},
    { name = "COM", measurement="alarms", address = [15]},
    { name = "USHigh", measurement="alarms", address = [0]},
    { name = "U1NHigh", measurement="alarms", address = [1]},
    { name = "U2NHigh", measurement="alarms", address = [2]},
    { name = "U3NHigh", measurement="alarms", address = [3]},
    { name = "USLow", measurement="alarms", address = [4]},
    { name = "U1NLow", measurement="alarms", address = [5]},
    { name = "U2NLow", measurement="alarms", address = [6]},
    { name = "U3NLow", measurement="alarms", address = [7]},
  ]

this is what we got

2021-05-18T09:32:37Z D! [agent] Starting service inputs
2021-05-18T09:32:38Z D! [inputs.modbus] got coil@0[14]: [0 128 1 0 0]
2021-05-18T09:32:38Z D! [inputs.modbus]   field USHigh with bit 0 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U1NHigh with bit 1 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U2NHigh with bit 2 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U3NHigh with bit 3 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field USLow with bit 4 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U1NLow with bit 5 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U2NLow with bit 6 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U3NLow with bit 7 @ byte 0: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U12High with bit 0 @ byte 1: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U23High with bit 1 @ byte 1: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U31High with bit 2 @ byte 1: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U12Low with bit 3 @ byte 1: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U23Low with bit 4 @ byte 1: 0 --> 0
2021-05-18T09:32:38Z D! [inputs.modbus]   field U31Low with bit 5 @ byte 1: 0 --> 0
2021-05-18T09:32:38Z E! [inputs.modbus] Error in plugin: modbus: exception '2' (illegal data address), function '129'
2021-05-18T09:32:40Z D! [inputs.modbus] got coil@0[14]: [0 128 1 0 0]
2021-05-18T09:32:40Z D! [inputs.modbus]   field USHigh with bit 0 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U1NHigh with bit 1 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U2NHigh with bit 2 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U3NHigh with bit 3 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field USLow with bit 4 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U1NLow with bit 5 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U2NLow with bit 6 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U3NLow with bit 7 @ byte 0: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U12High with bit 0 @ byte 1: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U23High with bit 1 @ byte 1: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U31High with bit 2 @ byte 1: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U12Low with bit 3 @ byte 1: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U23Low with bit 4 @ byte 1: 0 --> 0
2021-05-18T09:32:40Z D! [inputs.modbus]   field U31Low with bit 5 @ byte 1: 0 --> 0
2021-05-18T09:32:40Z E! [inputs.modbus] Error in plugin: modbus: exception '2' (illegal data address), function '129'

Looking at those debug you enabled for the PR it makes me think that this is due to the fact that I need to skip some registers (like byte 1, bit 6)... should this be handled by the plugin itself?

Using a modbus client (modbus doctor) this is what we found
image
which works only with the following set of configuration: coil register 0, bit lenght <= 40; so if you use register 0 length 41 or register 1 lenght 1 you will get an "invalid response" (I do not know why for the latter).

@mirkocomparetti-synesis
Copy link
Author

So, using a configuration like

  coils = [
    { name = "FOut", measurement="em_alarms", address = [32]},
    { name = "ASHigh", measurement="em_alarms", address = [24]},
    { name = "A1High", measurement="em_alarms", address = [25]},
    { name = "A2High", measurement="em_alarms", address = [26]},
    { name = "A3High", measurement="em_alarms", address = [27]},
    { name = "ANHigh", measurement="em_alarms", address = [28]},
    { name = "ASLow", measurement="em_alarms", address = [29]},
    { name = "A1Low", measurement="em_alarms", address = [30]},
    { name = "A2Low", measurement="em_alarms", address = [31]},
    { name = "A3Low", measurement="em_alarms", address = [16]},
    { name = "ANLow", measurement="em_alarms", address = [17]},
    { name = "U12High", measurement="em_alarms", address = [8]},
    { name = "U23High", measurement="em_alarms", address = [9]},
    { name = "U31High", measurement="em_alarms", address = [10]},
    { name = "U12Low", measurement="em_alarms", address = [11]},
    { name = "U23Low", measurement="em_alarms", address = [12]},
    { name = "U31Low", measurement="em_alarms", address = [13]},
    { name = "COM", measurement="em_alarms", address = [15]},
    { name = "USHigh", measurement="em_alarms", address = [0]},
    { name = "U1NHigh", measurement="em_alarms", address = [1]},
    { name = "U2NHigh", measurement="em_alarms", address = [2]},
    { name = "U3NHigh", measurement="em_alarms", address = [3]},
    { name = "USLow", measurement="em_alarms", address = [4]},
    { name = "U1NLow", measurement="em_alarms", address = [5]},
    { name = "U2NLow", measurement="em_alarms", address = [6]},
    { name = "U3NLow", measurement="em_alarms", address = [7]},
    { name = "reserved00", measurement="TODROP", address = [14]},
    { name = "reserved01", measurement="TODROP", address = [18]},
    { name = "reserved02", measurement="TODROP", address = [19]},
    { name = "reserved03", measurement="TODROP", address = [20]},
    { name = "reserved04", measurement="TODROP", address = [21]},
    { name = "reserved05", measurement="TODROP", address = [22]},
    { name = "reserved06", measurement="TODROP", address = [23]},
    { name = "reserved07", measurement="TODROP", address = [33]},
    { name = "reserved08", measurement="TODROP", address = [34]},
    { name = "reserved09", measurement="TODROP", address = [35]},
    { name = "reserved10", measurement="TODROP", address = [36]},
    { name = "reserved11", measurement="TODROP", address = [37]},
    { name = "reserved12", measurement="TODROP", address = [38]},
    { name = "reserved13", measurement="TODROP", address = [39]},
  ]
	
  namedrop = [
    "TODROP",
  ]

works fine and the values I want to drop are dropped. But somehow I do not really like it... what do you think @srebhan ?
I think it would be better for the plugin to handle those non sequential registers to be discarded automatically...

@srebhan
Copy link
Member

srebhan commented May 18, 2021

It does (or should at least) discard that registers automatically. What we do is we group all consecutive registers to one request. Seems like there is a bug in your first example when trying to perform the second request. I will add some more debugging capabilities (like outputting the request itself) and we should boil that down to where it goes wrong...

@mirkocomparetti-synesis
Copy link
Author

Thanks a lot for looking into it!

Anyway, even with this workaround it is much better for us so that we do not need nodered to write only the colils directly to the DB!

srebhan pushed a commit to HRI-EU/telegraf that referenced this issue May 18, 2021
@mirkocomparetti-synesis
Copy link
Author

mirkocomparetti-synesis commented May 18, 2021

@srebhan here it is the result with the latest build

2021-05-18T12:20:57Z D! [agent] Starting service inputs
2021-05-18T12:20:58Z D! [inputs.modbus] trying to read coil@0[14]...
2021-05-18T12:20:58Z D! [inputs.modbus] got coil@0[14]: [0 128 1 0 0]
2021-05-18T12:20:58Z D! [inputs.modbus]   field USHigh with bit 0 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U1NHigh with bit 1 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U2NHigh with bit 2 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U3NHigh with bit 3 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field USLow with bit 4 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U1NLow with bit 5 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U2NLow with bit 6 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U3NLow with bit 7 @ byte 0: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U12High with bit 0 @ byte 1: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U23High with bit 1 @ byte 1: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U31High with bit 2 @ byte 1: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U12Low with bit 3 @ byte 1: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U23Low with bit 4 @ byte 1: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus]   field U31Low with bit 5 @ byte 1: 0 --> 0
2021-05-18T12:20:58Z D! [inputs.modbus] trying to read coil@15[3]...
2021-05-18T12:20:58Z E! [inputs.modbus] Error in plugin: modbus: exception '2' (illegal data address), function '129'
2021-05-18T12:21:00Z D! [inputs.modbus] trying to read coil@0[14]...
2021-05-18T12:21:00Z D! [inputs.modbus] got coil@0[14]: [0 128 1 0 0]
2021-05-18T12:21:00Z D! [inputs.modbus]   field USHigh with bit 0 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U1NHigh with bit 1 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U2NHigh with bit 2 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U3NHigh with bit 3 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field USLow with bit 4 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U1NLow with bit 5 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U2NLow with bit 6 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U3NLow with bit 7 @ byte 0: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U12High with bit 0 @ byte 1: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U23High with bit 1 @ byte 1: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U31High with bit 2 @ byte 1: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U12Low with bit 3 @ byte 1: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U23Low with bit 4 @ byte 1: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus]   field U31Low with bit 5 @ byte 1: 0 --> 0
2021-05-18T12:21:00Z D! [inputs.modbus] trying to read coil@15[3]...
2021-05-18T12:21:00Z E! [inputs.modbus] Error in plugin: modbus: exception '2' (illegal data address), function '129'
2021-05-18T12:21:02Z D! [inputs.modbus] trying to read coil@0[14]...
2021-05-18T12:21:02Z D! [inputs.modbus] got coil@0[14]: [0 128 1 0 0]
2021-05-18T12:21:02Z D! [inputs.modbus]   field USHigh with bit 0 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U1NHigh with bit 1 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U2NHigh with bit 2 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U3NHigh with bit 3 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field USLow with bit 4 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U1NLow with bit 5 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U2NLow with bit 6 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U3NLow with bit 7 @ byte 0: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U12High with bit 0 @ byte 1: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U23High with bit 1 @ byte 1: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U31High with bit 2 @ byte 1: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U12Low with bit 3 @ byte 1: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U23Low with bit 4 @ byte 1: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus]   field U31Low with bit 5 @ byte 1: 0 --> 0
2021-05-18T12:21:02Z D! [inputs.modbus] trying to read coil@15[3]...
2021-05-18T12:21:02Z E! [inputs.modbus] Error in plugin: modbus: exception '2' (illegal data address), function '129'
^C2021-05-18T12:21:03Z D! [agent] Stopping service inputs

@mirkocomparetti-synesis
Copy link
Author

mirkocomparetti-synesis commented May 18, 2021

After doing tests with @srebhan, this issue is due to the device which does not allow to read modbus coils with an arbitrary address if you do not start reading all of them from the first one.
Thanks @srebhan!

@srebhan
Copy link
Member

srebhan commented May 18, 2021

For documentation purposes: In case you experience the same issue you can, as a workaround, specify the list of addresses consecutively such that only one request will be issued. Please report here if you also own such a device.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/modbus bug unexpected problem or unintended behavior
Projects
None yet
Development

No branches or pull requests

3 participants