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

feat: Modbus support multiple slaves (gateway feature) #9279

Merged
merged 21 commits into from
Dec 2, 2021

Conversation

srebhan
Copy link
Member

@srebhan srebhan commented May 19, 2021

  • Updated associated README.md.
  • Wrote appropriate unit tests.

resolves #7523
related to #8013

This is a PR implementing the support for multiple slave devices for the same connection. This is required for devices with limited connectivity (e.g. limiting the concurrent connections to 1 or a small number) but a high number of slave devices. These class of devices become more popular especially with ModbusTCP gateway hardware.

Additionally to supporting multiple slaves this PR implements a second (independent) configuration scheme to configure the reading on a per-request style. This is especially helpful if you need more control over the requests actually sent to the devices e.g. to optimize the query. Smaller features like an omit flag to fill gaps in the requests accompany the code. Most of the features and, to a large degree, the configuration scheme are borrowed from #8013. Thank you @wz2b for the nice work there!

@srebhan srebhan mentioned this pull request May 20, 2021
2 tasks
@srebhan
Copy link
Member Author

srebhan commented Jun 23, 2021

@wz2b and @marfrde if you have some time to test this PR your help will be much appreciated. :-)

@wz2b
Copy link

wz2b commented Jul 11, 2021

I'm testing this now in my configuration and so far I haven't found any problems. The configuration was straight-forward - I figured it out from only the sample config (which means the sample is solid). The only problem I had was not specifying configuration_type but that's just because I didn't read that part of the sample carefully enough. It is appropriately documented, though.

I have two minor comments that you should feel free to ignore

configuration_type = "original"

I'm not certain you really need this. I feel like you could infer it from the presence of an non-empty [[inputs.modbus.request]] array. I also feel like you can pretty easily merge the old and new configurations if you wanted to. If you did so, then requests in the "original" section would just assume the default unit address. This isn't really a super big deal, except that getting rid of configurations you don't really need is always good.

controller = "tcp://192.168.0.179:502"

I think this is controller because that's how it appeared in the original modbus input, but if you're in a gateway configuration the more appropriate term is "gateway." As a compromise, would you be willing to change it to accept either "controller" or "gateway"? or "url" ? (Maybe that's the thing to do - change it to url, then for backward compatibility silently accept "controller". It really think that thinking of it as a URL is sound, and URL is a term that applies whether you're talking directly to a controller or to a controller via a gateway).

No complaints so far, if you have time give me a little while to run it and see what happens.

@wz2b
Copy link

wz2b commented Jul 11, 2021

I'm testing this in as many ways as I can reasonably think of using real-world hardware. One of the devices I'm trying to use is an Eaton (Cutler-Hammer) EasyE4, a very inexpensive nano plc. This particular plc has 32-bit registers that overlap the 16-bit registers in pairs. It's not unusual, but depending on the logic you write it's likely you'll have a mix of 16-bit and 32-bit registers in adjacent addresses. That caused a problem to bubble to the surface.

I ran into a problem with certain byte order specifications. It really occurs if you mix 16 and 32 bit mappings in the same request. I tracked this down, and I know why it's doing it. Here is the configuration:

[[inputs.modbus.request]]
  slave_id = 1
  byte_order = "CDAB"
  register = "holding"
  measurement = "water"

  fields  = [
    { address = 1001, name = "usage", type = "UINT16" },
    { address = 1005, name = "biggish", type = "UINT32" }
  ]

This yields the following error:

2021-07-11T23:02:51Z E! [telegraf] Error running agent: could not initialize input inputs.modbus: cannot process configuraton: initializing field "usage" failed: invalid byte-order: CDAB

The place where it is failing is right here, because CDAB isn't defined:

func endianessConverter16(byteOrder string) (convert16, error) {
	switch byteOrder {
	case "ABCD": // Big endian (Motorola)
		return binary.BigEndian.Uint16, nil
	case "DCBA": // Little endian (Intel)
		return binary.LittleEndian.Uint16, nil
	}
	return nil, fmt.Errorf("invalid byte-order: %s", byteOrder)
}

I know this is confusing, but I can explain it. The problem is that for a 16-bit register, "ABCD" and "CDAB" are the same thing, because either the "AB" part or the "CD" part gets used. This becomes an issue if you're trying to do a mixture of 16 and 32 bit mappings in a single request - which should be allowed, I think, though I admit it's perhaps a bit unusual. I can work around by splitting it into two separate requests.

In my original attempt to support multiple unit addresses I had rewritten all of this code. What I tried to do was to generalize it rather than having a selection of possible byte orders. See here and here.

You can argue that everything I did was unnecessary - that it doesn't need to be generalized ... but according to a comment I made in my unit test I think I thought of this:

{
    format:   "CDAB", /* implies AB, CDABGHEF */
    expected: []interface{}{uint16(0xAABB), uint32(0xCCDDAABB)}
}

so the clue there is that for this to work format CDAB explicitly states a 32-bit conversion but it implies an 16-bit and 64-bit conversion. I think we need to keep that.

I think there are two options to fix this:

  • Reconsider my type converter, but if you do, please help me with some regression tests against existing configurations, because I haven't done that at all. Or,
  • Modify the 16 and 32 bit conversion functions to imply the other formats. Based on how you did it, you don't actually use ABCDEFGH for 64-bit mappings, you assume if the guy said ABCD that he means something. That's less flexible than my approach, but at the same time, I've never seen super wacky ordering on 64-bit numbers (which are very, very rarely used - though you do see them in energy accumulations on power meters. The numbers can get that big if there's high resolution and the meter has been left on for years and years).

At this point, I'm not going to say I trust my generic converter without more eyeballs on it, so I'd lean toward just fixing the immediate problem of allowing the 32-bit order specifiers to imply either AB or BA if it's a 16-bit register. I don't want to let idealism be the enemy of the good enough.

format:   "AB", /* implies ABCD, ABCDEFGH */
format:   "ABCD", /* implies AB, ABCDEFGH */
format:   "BA", /* implies BADC, BADCFEHG */
format:   "CDAB", /* implies AB, CDABGHEF */
format:   "DCBA", /* implies BA, DCBAHGFE */

@srebhan
Copy link
Member Author

srebhan commented Jul 12, 2021

Hey @wz2b, thanks for testing!

Let me first explain one thing regarding field handling and then I try to answer your comments.

The modbus plugin as is, reads the words from the device specified by the request (actually the range from start to end). It stores those words in a byte-array without any modification, i.e. the mentioned byte-array has the raw bytes in the order as delivered by the device.
We then walk the field definitions and grab the bytes from the array corresponding to the field address and then parse the set of bytes to the field values using endianess and type information.
This way, you can have arbitrary field definitions that overlap (partially or completely) and have independent byte-orders. In extreme, you could specify two fields with the same address-range and inverse byte-order. :-)

Coming to the error you get: CDAB really makes no sense for a 16-bit value as it is either AB or BA. Therefore, I allowed only ABCD (aka MSW) and DCBA (aka LSW) for 16-bit registers. We could also add CDAB or BA as a synonym for 16-bit values, but I wanted keep byte-order and datatypes (or their lenght) independent to get rid of ABCDEFGH as it does not add any information.
This being said, if my reasoning causes trouble or confusion to people using this plugin, we could of course add back the synonyms. Do you expect a check of the datatypes length against the byte-order string, i.e. ABCD can only be specified for 32-bit values etc?

@wz2b
Copy link

wz2b commented Jul 12, 2021

Coming to the error you get: CDAB really makes no sense for a 16-bit value as it is either AB or BA.

It makes sense to me. My thought process is that ABCD and CDAB are abbreviated ways of saying these two things:

  • ABCD means "byte order is high-byte first, word order is high-word first"
  • CDAB means "byte order is high-byte first, word order is low-word first"

WIthout that implication it is impossible to fetch both 16 and 32 bit values in the same request if the byte order is "AB" but the word order is CDAB". I think that's part of the problem - it's named "byte order" but really it's byte order and word order.

Now, if you had separate parameters "byte_order" and "word_order"

Do you expect a check of the datatypes length against the byte-order string, i.e. ABCD can only be specified for 32-bit values etc

No, I do not expect that ABCD only means 32-bit ordering. I expect that it means "strictly big endien, regardless of length."

I think you actually think this, too:

func endianessConverter64(byteOrder string) (convert64, error) {
	switch byteOrder {
	case "ABCD": // Big endian (Motorola)
   ...

there, you allow someone to use ABCD to specify a 64-bit value. So ABCD implies ABCDEFGH. You just didn't allow the same implication in the downward direction.

Currently there is no option other than to split the request in two. So the way I see it, the easiest option is to do one of these things:

  • Get rid of all these explicit cases and use my more generic orderer
  • Allow CDAB to mean AB in endianessConverter16()
  • Allow you to override the byte_order within an individual field

I wanted keep byte-order and datatypes (or their lenght) independent to get rid of ABCDEFGH as it does not add any information.

I understand your reasoning here. My choice still would be to deal with the ordering generically rather than with hard-coded cases, because I don't want to have to go back to add cases we didn't think of later.

In extreme, you could specify two fields with the same address-range and inverse byte-order. :-)

I agree, that would be pretty absurd. However what we're talking about here isn't really "byte order" it's "word order" i.e. "how do you assemble modbus registers (words) into bigger representations."

This PLC I'm testing with doesn't have 64-bit numbers so it's a little hard to imagine what they would have done but if I had to guess it would have been CDABGHEF because that would follow the pattern they used for low-part-first.

I suppose my suggestion is Allow CDAB to imply AB in endianessConverter16() ... but if you don't want to use my generic converter then you can't be sure what I am going to find when I test U64 (hopefully today) on my PowerLogic meters. We might have this same conversation all over again but for 64-bit ;-)

@srebhan
Copy link
Member Author

srebhan commented Jul 12, 2021

Hey @wz2b, after having almost finished a two-page reply to your post, I now see your point and see my mistake. :-) Sorry for the noise...
The issue is that byte_order is defined per-request (which is almost equivalent to "per-device" in most cases) and not per field. Therefore, if you have an CDAB device you currently cannot read 16-bit values at least not if you also define some fields with 32- or 64-bit values at the same time... Is this understanding correct?

If so, I'll add CDAB as a synonym for 16-bit AB and BADC for BA respectively.

@wz2b
Copy link

wz2b commented Jul 12, 2021

If so, I'll add CDAB as a synonym for 16-bit AB and BADC for BA respectively.

Yeah. You just said the whole thing I took two pages to type but you said it in one sentence. That's really it. I'm fine with solving it that way, as soon as new artifacts are available I'll resume testing.

@wz2b
Copy link

wz2b commented Jul 13, 2021

Looks like new artifacts were built from this PR. Get them here!

OK, mixing 16-bit and 32-bit requests working now!

@wz2b
Copy link

wz2b commented Jul 22, 2021

I just discovered that if you don't specify register_type it crashes:

anic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x2427f5d]

goroutine 66 [running]:
github.com/influxdata/telegraf/plugins/inputs/modbus.(*Modbus).gatherRequestsHolding(0xc000b42000, 0xc0008d2380, 0x4, 0x4, 0x0, 0x0)
        /go/src/github.com/influxdata/telegraf/plugins/inputs/modbus/modbus.go:355 +0x41d
github.com/influxdata/telegraf/plugins/inputs/modbus.(*Modbus).gatherFields(0xc000b42000, 0x2b36fff4, 0x799b2c0)
        /go/src/github.com/influxdata/telegraf/plugins/inputs/modbus/modbus.go:284 +0x1bb
github.com/influxdata/telegraf/plugins/inputs/modbus.(*Modbus).Gather(0xc000b42000, 0x56dfab8, 0xc0007c8da0, 0x0, 0x0)
        /go/src/github.com/influxdata/telegraf/plugins/inputs/modbus/modbus.go:179 +0x125
github.com/influxdata/telegraf/models.(*RunningInput).Gather(0xc000b3a460, 0x56dfab8, 0xc0007c8da0, 0xc000b3a500, 0x100000000474b61)
        /go/src/github.com/influxdata/telegraf/models/running_input.go:117 +0x6d
github.com/influxdata/telegraf/agent.(*Agent).gatherOnce.func1(0xc0005940c0, 0xc000b3a460, 0x56dfab8, 0xc0007c8da0)
        /go/src/github.com/influxdata/telegraf/agent/agent.go:469 +0x3f
created by github.com/influxdata/telegraf/agent.(*Agent).gatherOnce
        /go/src/github.com/influxdata/telegraf/agent/agent.go:468 +0xb2

The configuration that caused this:

flush_interval = "1s"

[[inputs.modbus]]
name = "fc_babel"
timeout = "1s"
controller = "tcp://localhost:502"
interval = "1s"
configuration_type = "request"

[[inputs.modbus.request]]
  # should have set register_type here, but didn't
  fields = [
    { address=2000, name = "gas1", type = "FLOAT32" },
    { address=2002, name = "gas2", type = "FLOAT32" },
    { address=2004, name = "gas3", type = "FLOAT32" },
    { address=2006, name = "gas4", type = "FLOAT32" },
  ]

My suggestion is that rather than make it required you default it to "holding" since that's what's most common.

@wz2b
Copy link

wz2b commented Jul 22, 2021

This is just food for thought. If you don't specify a slave address, the slave address defaults to 0. From the spec:

On TCP/IP, the MODBUS server is addressed using its IP address; therefore, the MODBUS Unit Identifier is useless. The value 0xFF has to be used. When addressing a MODBUS server connected directly to a TCP/IP network, it’s recommended not using a significant MODBUS slave address in the “Unit Identifier” field. In the event of a re-allocation of the IP addresses within an automated system and if a IP address previously assigned to a MODBUS server is then assigned to a gateway, using a significant slave address may cause trouble because of a bad routing by the gateway. Using a nonsignificant slave address, the gateway will simply discard the MODBUS PDU with no trouble. 0xFF is recommended for the “Unit Identifier" as nonsignificant
value.
Remark : The value 0 is also accepted to communicate directly to a MODBUS/TCP device.

If in your request configuration you don't specify a slave address, then the common interpretation is that you mean to talk to the gateway itself, i.e. it isn't really a gateway it's just a device.

Based on _ The value 0xFF has to be used_ it seems like defaulting to 0xFF is more correct; but then later on it says The value 0 is also accepted to communicate directly to a MODBUS/TCP device which would imply either is OK.

@wz2b
Copy link

wz2b commented Jul 22, 2021

I have a minor complaint about tags.

o2_12,host=gis-tripod,name=fc_babel,slave_id=255,type=holding_register level=21.100000381469727,hl=23.500001907348633,ll=18.000001907348633,flags=0 1626976365000000000
o2_12,host=gis-tripod,name=fc_babel,slave_id=255,type=holding_register level=21.100000381469727,hl=23.500001907348633,ll=18.000001907348633,flags=0 1626976366000000000
  1. I really don't need type=holding_register in there unless you're also going to send in the address. Without the address that's kind of useless information. I would get rid of the 'type' tag, I really don't see a need for it.
  2. You are including "name" in there which is actually the name of the input. Is that a telegraf norm? That's probably okay, but it probably shouldn't be called "name". I don't know what it should be called. Maybe it shouldn't be there?
  3. Along those lines, I'd like a way to specify my own tags in an individual request. Is that possible?

For the last, I have a specific use case. I have a bunch of sensors that measure various gases. I have four oxygen sensors, 11 carbon monoxide sensor, and some other number of hydrogen/propane/methane/etc. For each sensor I want to output

  • The sensor id as the measurement name i.e. 'o2_1' (I can do this now)
  • An additional tag like: type="O2" so I can write filter queries on all the O2 sensors - user-specified, per-request tags

unless there's already a way to have per-request tags and I don't know what it is.

@srebhan
Copy link
Member Author

srebhan commented Jul 23, 2021

My suggestion is that rather than make it required you default it to "holding" since that's what's most common.

I agree and will fix it. Thanks for testing this thoroughly!

Regarding the slave_id, I do not have a good way to initializing it. In the per-request case we even don't know how many sections are there. Unfortunately, zero seems also a valid value (I also had some Modbus TCP device that refused to work if slave-Id was anything other than zero).

@srebhan
Copy link
Member Author

srebhan commented Jul 23, 2021

I have a minor complaint about tags.

o2_12,host=gis-tripod,name=fc_babel,slave_id=255,type=holding_register level=21.100000381469727,hl=23.500001907348633,ll=18.000001907348633,flags=0 1626976365000000000
o2_12,host=gis-tripod,name=fc_babel,slave_id=255,type=holding_register level=21.100000381469727,hl=23.500001907348633,ll=18.000001907348633,flags=0 1626976366000000000
  1. I really don't need type=holding_register in there unless you're also going to send in the address. Without the address that's kind of useless information. I would get rid of the 'type' tag, I really don't see a need for it.

You can still drop the type tag using tag_exclude.
Furthermore, we cannot simply remove the tag due to backward compatibility.

  1. You are including "name" in there which is actually the name of the input. Is that a telegraf norm? That's probably okay, but it probably shouldn't be called "name". I don't know what it should be called. Maybe it shouldn't be there?

I agree that name is ... unfortunate. ;-) I guess device would be better, but again, backward-compatibility.

  1. Along those lines, I'd like a way to specify my own tags in an individual request. Is that possible?

Currently it is not possible. but we should definitively add it on the request level. I also have a use-case (similar to yours), but I don't want to fold it into this PR as it is massive already.

[...]
unless there's already a way to have per-request tags and I don't know what it is.

I'm currently doing it using a processor deciding which tags to add by evaluating the name and slave_id tag. However, I agree that this is not elegant and we should do it using per-request tags.

@wz2b
Copy link

wz2b commented Jul 23, 2021

Along those lines, I'd like a way to specify my own tags in an individual request. Is that possible?

Currently it is not possible. but we should definitively add it on the request level. I also have a use-case (similar to yours), but I don't want to fold it into this PR as it is massive already.

Yup. I can live with that.

@mbezuidenhout
Copy link
Contributor

I'm running this in a production environment. When there are multiple requests with different slave ids there is an i/o timeout. I put a time.Sleep(100 * time.Millisecond) in the gatherFields function between requests which caused the error to go away.

@wz2b
Copy link

wz2b commented Aug 2, 2021

I'm running this in a production environment. When there are multiple requests with different slave ids there is an i/o timeout. I put a time.Sleep(100 * time.Millisecond) in the gatherFields function between requests which caused the error to go away.

We need to get to the bottom of this. Is it possible you have responses arriving out of order? Are your devices slow to respond, or do their response times differ greatly?

@mbezuidenhout
Copy link
Contributor

I'm running this in a production environment. When there are multiple requests with different slave ids there is an i/o timeout. I put a time.Sleep(100 * time.Millisecond) in the gatherFields function between requests which caused the error to go away.

We need to get to the bottom of this. Is it possible you have responses arriving out of order? Are your devices slow to respond, or do their response times differ greatly?

When there are multiple read shortly after each other it seems like the tcp connection gets closed, possibly from the modbus gateway device. I am using a waveshare rs485 to ethernet converter.

Read the comment by gq0 on 7 Jan 2019 here https://github.com/grid-x/modbus/issues/11 where he recommend a >= 64ms delay when reading from a SolarEdge inverter.

@srebhan
Copy link
Member Author

srebhan commented Aug 3, 2021

@mbezuidenhout we also saw this with other (mostly serial) devices. PR #9256 introduces workarounds, so you can set

[[inputs.modbus]]
    ...
    [inputs.modbus.workarounds]
        pause_between_requests = "100ms"

The mentioned PR needs to be merged before this one anyway.

@wz2b
Copy link

wz2b commented Aug 5, 2021

I have another feature request, for this or the next version ... working on a PM800 and the power factor registers has an offset of 1, might be nice to have 'offset' (defaulted to 0.0) in addition to 'scale' in the polling configuration.

@srebhan
Copy link
Member Author

srebhan commented Sep 6, 2021

@wz2b good point. Could you please open an issue for both, the offset feature and the tag-stuff we discussed above in order to not forget about those useful things!?

@srebhan srebhan mentioned this pull request Oct 13, 2021
3 tasks
@srebhan srebhan mentioned this pull request Nov 25, 2021
3 tasks
@srebhan srebhan changed the title Modbus support multiple slaves (gateway feature) feat: Modbus support multiple slaves (gateway feature) Nov 30, 2021
@srebhan srebhan changed the title feat: Modbus support multiple slaves (gateway feature) feat:Modbus support multiple slaves (gateway feature) Nov 30, 2021
@srebhan srebhan changed the title feat:Modbus support multiple slaves (gateway feature) feat: Modbus support multiple slaves (gateway feature) Nov 30, 2021
@telegraf-tiger
Copy link
Contributor

Copy link
Contributor

@powersj powersj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for driving this home!

@sspaink sspaink merged commit 9787f4a into influxdata:master Dec 2, 2021
@bikeymouse
Copy link

bikeymouse commented Dec 5, 2021

Hi, great work!

I would like to use this feature to request 2 modbus-slaves via one TCP/IP gateway, using a Docker image.
So I tried this using the "latest" official Docker image which is updated 2 days ago.

However when I try to use it I get this error message:

[telegraf] Error running agent: Error loading config file /etc/telegraf/telegraf.conf: plugin inputs.modbus: line 154: configuration specified the fields ["request"], but they weren't used

I that because this code is not yet included in the "latest" official Docker image (it says the version is 1.20.4)?
Or have I misconfigured something?

This is the modus-part set-up in my telegraf.conf I'm using to read out 2 SMD630 modbus utility meters that are connected to an TCP/IP gateway:

[[inputs.modbus]]

  name = "ModbusGateway"
  timeout = "2s"
  controller = "tcp://192.168.1.170:520"
  transmission_mode = "RTUoverTCP"

 [[inputs.modbus.request]]
    slave_id = 3
    measurement = "Solar"
    byte_order = "ABCD"
    register = "input"
    fields = [
      { address=[0,1], name="VoltageL1", type="FLOAT32-IEEE"},
      { address=[2,3], name="VoltageL2", type="FLOAT32-IEEE"},
      { address=[4,5], name="VoltageL3", type="FLOAT32-IEEE"},
      { address=[6,7], name="CurrentL1", type="FLOAT32-IEEE"},
      { address=[8,9], name="CurrentL2", type="FLOAT32-IEEE"},
      { address=[10,11], name="CurrentL3", type="FLOAT32-IEEE"},
    ]

  [[inputs.modbus.request]]
    slave_id = 2
    measurement = "Charger"
    byte_order = "ABCD"
    register = "input"
    fields = [
      { address=[0,1], name="VoltageL1", type="FLOAT32-IEEE"},
      { address=[2,3], name="VoltageL2", type="FLOAT32-IEEE"},
      { address=[4,5], name="VoltageL3", type="FLOAT32-IEEE"},
      { address=[6,7], name="CurrentL1", type="FLOAT32-IEEE"},
      { address=[8,9], name="CurrentL2", type="FLOAT32-IEEE"},
      { address=[10,11], name="CurrentL3", type="FLOAT32-IEEE"},
    ]

@srebhan
Copy link
Member Author

srebhan commented Dec 7, 2021

Hey @bikeymouse, this PR is only included in 1.21, so you need at least one of the release-candidates of that version (which is not yet released IIRC). This will solve the error you mention.

Furthermore, your address-specification will not work with this type of specification as you now only need to specify the _start_address, i.e.

[[inputs.modbus]]
  name = "ModbusGateway"
  timeout = "2s"
  controller = "tcp://192.168.1.170:520"
  transmission_mode = "RTUoverTCP"

 [[inputs.modbus.request]]
    slave_id = 3
    measurement = "Solar"
    byte_order = "ABCD"
    register = "input"
    fields = [
      { address=0, name="VoltageL1", type="FLOAT32-IEEE"},
      { address=2, name="VoltageL2", type="FLOAT32-IEEE"},
      { address=4, name="VoltageL3", type="FLOAT32-IEEE"},
      { address=6, name="CurrentL1", type="FLOAT32-IEEE"},
      { address=8, name="CurrentL2", type="FLOAT32-IEEE"},
      { address=10, name="CurrentL3", type="FLOAT32-IEEE"},
    ]

  [[inputs.modbus.request]]
    slave_id = 2
    measurement = "Charger"
    byte_order = "ABCD"
    register = "input"
    fields = [
      { address=0, name="VoltageL1", type="FLOAT32-IEEE"},
      { address=2, name="VoltageL2", type="FLOAT32-IEEE"},
      { address=4, name="VoltageL3", type="FLOAT32-IEEE"},
      { address=6, name="CurrentL1", type="FLOAT32-IEEE"},
      { address=8, name="CurrentL2", type="FLOAT32-IEEE"},
      { address=10, name="CurrentL3", type="FLOAT32-IEEE"},
    ]

@srebhan srebhan mentioned this pull request Dec 7, 2021
3 tasks
@bikeymouse
Copy link

Hi @srebhan thanks so much for you good work and pointing me in the right direction.

I'd like to start using this a.s.a.p. As I don't see any previous release-candidates in Docker hub perhaps that is not done and I have to wait for the 1.21 official release.
Is there a simple way to build the image from the master myself (i.e. is there a Docker file I could adopt)?

@srebhan
Copy link
Member Author

srebhan commented Dec 8, 2021

@bikeymouse just clone this repo, install a recent golang on your machine and type make... :-) If you need help, it's easiest to join the #telegraf channel on Slack.

@srebhan srebhan deleted the modbus_gateway branch December 8, 2021 17:36
@bikeymouse
Copy link

Hi, thanks again!
I used a Golang docker image to build telegraf locally and that was successful with the master-branch I downloaded just after the v1.21.0-rc1 release today.

However when I start Telegraf with the config you posted above, I get this error:

(modbus.requestFieldDefinition.Address) cannot unmarshal TOML array into uint16 (need slice)

This is at the part that starts with:

    fields = [
      { address=0, name="VoltageL1", type="FLOAT32-IEEE"},

Any idea what could cause this?

@srebhan
Copy link
Member Author

srebhan commented Dec 9, 2021

@bikeymouse let's not hijack this PR. Can you please open an issue and attach your inputs.modbus config section so I can reproduce the issue? Please assign or mention me in that new issue!

@bikeymouse
Copy link

You're right, sorry. I did found the reason (not to use FLOAT32-IEEE, but FLOAT32 instead).
So got it almost working now, if needed I will raise an issue.
Thanks for you tips!

powersj pushed a commit to powersj/telegraf that referenced this pull request Jan 21, 2022
phemmer added a commit to phemmer/telegraf that referenced this pull request Feb 18, 2022
* origin/master: (133 commits)
  chore: restart service if it is already running and upgraded via RPM (influxdata#9970)
  feat: update etc/telegraf.conf and etc/telegraf_windows.conf (influxdata#10237)
  fix: Handle duplicate registration of protocol-buffer files gracefully. (influxdata#10188)
  fix(http_listener_v2): fix panic on close (influxdata#10132)
  feat: add Vault input plugin (influxdata#10198)
  feat: support aws managed service for prometheus (influxdata#10202)
  fix: Make telegraf compile on Windows with golang 1.16.2 (influxdata#10246)
  Update changelog
  feat: Modbus add per-request tags (influxdata#10231)
  fix: Implement NaN and inf handling for elasticsearch output (influxdata#10196)
  feat: add nomad input plugin (influxdata#10106)
  fix: Print loaded plugins and deprecations for once and test (influxdata#10205)
  fix: eliminate MIB dependency for ifname processor (influxdata#10214)
  feat: Optimize locking for SNMP MIBs loading. (influxdata#10206)
  feat: Add SMART plugin concurrency configuration option, nvme-cli v1.14+ support and lint fixes. (influxdata#10150)
  feat: update configs (influxdata#10236)
  fix(inputs/kube_inventory): set TLS server name config properly (influxdata#9975)
  fix: Sudden close of Telegraf caused by OPC UA input plugin (influxdata#10230)
  fix: bump github.com/eclipse/paho.mqtt.golang from 1.3.0 to 1.3.5 (influxdata#9913)
  fix: json_v2 parser timestamp setting (influxdata#10221)
  fix: ensure graylog spec fields not prefixed with '_' (influxdata#10209)
  docs: remove duplicate links in CONTRIBUTING.md (influxdata#10218)
  fix: pool detection and metrics gathering for ZFS >= 2.1.x (influxdata#10099)
  fix: parallelism fix for ifname processor (influxdata#10007)
  chore: Forbids "log" package only for aggregators, inputs, outputs, parsers and processors (influxdata#10191)
  docs: address documentation gap when running telegraf in k8s (influxdata#10215)
  feat: update etc/telegraf.conf and etc/telegraf_windows.conf (influxdata#10211)
  fix: mqtt topic extracting no longer requires all three fields (influxdata#10208)
  fix: windows service - graceful shutdown of telegraf (influxdata#9616)
  feat: update etc/telegraf.conf and etc/telegraf_windows.conf (influxdata#10201)
  feat: Modbus support multiple slaves (gateway feature) (influxdata#9279)
  fix: Revert unintented corruption of the Makefile from influxdata#10200. (influxdata#10203)
  chore: remove triggering update-config bot in CI (influxdata#10195)
  Update changelog
  feat: Implement deprecation infrastructure (influxdata#10200)
  fix: extra lock on init for safety (influxdata#10199)
  fix: resolve influxdata#10027 (influxdata#10112)
  fix: register bigquery to output plugins influxdata#10177 (influxdata#10178)
  fix: sysstat use unique temp file vs hard-coded (influxdata#10165)
  refactor: snmp to use gosmi (influxdata#9518)
  ...
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Multiple Modbus terminal Monitoring
6 participants