From 3d583ccce6a5f369ebcf5275f879d10b170124e0 Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Tue, 4 Aug 2020 11:01:52 +0200 Subject: [PATCH 1/7] Added config option to omit tag 'type' --- plugins/inputs/modbus/modbus.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index ec68890c5eb91..f6e968e27b4cf 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -29,6 +29,7 @@ type Modbus struct { SlaveID int `toml:"slave_id"` Timeout internal.Duration `toml:"timeout"` Retries int `toml:"busy_retries"` + OmitRegisterType bool `toml:"omit_register_type"` RetriesWaitTime internal.Duration `toml:"busy_retries_wait"` DiscreteInputs []fieldContainer `toml:"discrete_inputs"` Coils []fieldContainer `toml:"coils"` @@ -87,6 +88,9 @@ const sampleConfig = ` ## Timeout for each request timeout = "1s" + ## Do not add Register Type as Tag + omit_register_type = false + ## Maximum number of retries and the time to wait between retries ## when a slave-device is busy. # busy_retries = 0 @@ -701,9 +705,9 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error { grouper := metric.NewSeriesGrouper() for _, reg := range m.registers { - tags := map[string]string{ - "name": m.Name, - "type": reg.Type, + tags := map[string]string{"name": m.Name} + if !m.OmitRegisterType { + tags["type"] = reg.Type } for _, field := range reg.Fields { From c616d4c0455699d6fead9fea00df7768de1eb365 Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Tue, 4 Aug 2020 11:38:18 +0200 Subject: [PATCH 2/7] Renamed 'name' to 'device_name' and added option to omit tag --- plugins/inputs/modbus/modbus.go | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index f6e968e27b4cf..dd7fd9c898ae1 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -19,7 +19,7 @@ import ( // Modbus holds all data relevant to the plugin type Modbus struct { - Name string `toml:"name"` + Name string `toml:"device_name"` Controller string `toml:"controller"` TransmissionMode string `toml:"transmission_mode"` BaudRate int `toml:"baud_rate"` @@ -29,6 +29,7 @@ type Modbus struct { SlaveID int `toml:"slave_id"` Timeout internal.Duration `toml:"timeout"` Retries int `toml:"busy_retries"` + OmitDeviceName bool `toml:"omit_device_name"` OmitRegisterType bool `toml:"omit_register_type"` RetriesWaitTime internal.Duration `toml:"busy_retries_wait"` DiscreteInputs []fieldContainer `toml:"discrete_inputs"` @@ -78,8 +79,8 @@ const sampleConfig = ` ## The plugin supports connections to PLCs via MODBUS/TCP or ## via serial line communication in binary (RTU) or readable (ASCII) encoding ## - ## Device name - name = "Device" + ## Name of the MODBUS device to read from + device_name = "Device" ## Slave ID - addresses a MODBUS device on the bus ## Range: 0 - 255 [0 = broadcast; 248 - 255 = reserved] @@ -88,6 +89,9 @@ const sampleConfig = ` ## Timeout for each request timeout = "1s" + ## Do not add Device Name as Tag + omit_device_name = false + ## Do not add Register Type as Tag omit_register_type = false @@ -705,7 +709,10 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error { grouper := metric.NewSeriesGrouper() for _, reg := range m.registers { - tags := map[string]string{"name": m.Name} + tags := map[string]string{} + if !m.OmitDeviceName { + tags["device_name"] = m.Name + } if !m.OmitRegisterType { tags["type"] = reg.Type } From 93e1f34b1d46f1bbdb63054f493ef42f98405985 Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Tue, 4 Aug 2020 12:00:14 +0200 Subject: [PATCH 3/7] Updated README.md --- plugins/inputs/modbus/README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/inputs/modbus/README.md b/plugins/inputs/modbus/README.md index 2476f3d368eb5..22629a78223d3 100644 --- a/plugins/inputs/modbus/README.md +++ b/plugins/inputs/modbus/README.md @@ -12,8 +12,8 @@ Registers via Modbus TCP or Modbus RTU/ASCII. ## The plugin supports connections to PLCs via MODBUS/TCP or ## via serial line communication in binary (RTU) or readable (ASCII) encoding ## - ## Device name - name = "Device" + ## Name of the MODBUS device to read from + device_name = "Device" ## Slave ID - addresses a MODBUS device on the bus ## Range: 0 - 255 [0 = broadcast; 248 - 255 = reserved] @@ -22,6 +22,12 @@ Registers via Modbus TCP or Modbus RTU/ASCII. ## Timeout for each request timeout = "1s" + ## Do not add Device Name as Tag + omit_device_name = false + + ## Do not add Register Type as Tag + omit_register_type = false + ## Maximum number of retries and the time to wait between retries ## when a slave-device is busy. # busy_retries = 0 @@ -131,5 +137,5 @@ from unsigned values). ``` $ ./telegraf -config telegraf.conf -input-filter modbus -test -modbus.InputRegisters,host=orangepizero Current=0,Energy=0,Frecuency=60,Power=0,PowerFactor=0,Voltage=123.9000015258789 1554079521000000000 +modbus,device_name=OpenPLC,host=orangepizero,type=holding_register current=0,energy=0,frecuency=60,power=0,power_factor=0,voltage=123.9000015258789 1554079521000000000 ``` From 56458db43691e0d18d53e3c1e561edfad4dfc72b Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Tue, 4 Aug 2020 18:41:20 +0200 Subject: [PATCH 4/7] modbus: changed config format * each measurement gets a separate section in config * different measurements can have the same name * each measurement can have custom tags --- plugins/inputs/modbus/README.md | 94 +++++---- plugins/inputs/modbus/modbus.go | 302 +++++++++++++++------------ plugins/inputs/modbus/modbus_test.go | 73 ++++--- 3 files changed, 271 insertions(+), 198 deletions(-) diff --git a/plugins/inputs/modbus/README.md b/plugins/inputs/modbus/README.md index 22629a78223d3..7d30f16f2ed00 100644 --- a/plugins/inputs/modbus/README.md +++ b/plugins/inputs/modbus/README.md @@ -12,6 +12,7 @@ Registers via Modbus TCP or Modbus RTU/ASCII. ## The plugin supports connections to PLCs via MODBUS/TCP or ## via serial line communication in binary (RTU) or readable (ASCII) encoding ## + ## Name of the MODBUS device to read from device_name = "Device" @@ -48,49 +49,54 @@ Registers via Modbus TCP or Modbus RTU/ASCII. ## Measurements ## - ## Digital Variables, Discrete Inputs and Coils - ## measurement - the (optional) measurement name, defaults to "modbus" - ## name - the variable name - ## address - variable address - - discrete_inputs = [ - { name = "start", address = [0]}, - { name = "stop", address = [1]}, - { name = "reset", address = [2]}, - { name = "emergency_stop", address = [3]}, - ] - coils = [ - { name = "motor1_run", address = [0]}, - { name = "motor1_jog", address = [1]}, - { name = "motor1_stop", address = [2]}, - ] - - ## Analog Variables, Input Registers and Holding Registers - ## measurement - the (optional) measurement name, defaults to "modbus" - ## name - the variable name - ## byte_order - the ordering of bytes - ## |---AB, ABCD - Big Endian - ## |---BA, DCBA - Little Endian - ## |---BADC - Mid-Big Endian - ## |---CDAB - Mid-Little Endian - ## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32-IEEE (the IEEE 754 binary representation) - ## FLOAT32 (deprecated), FIXED, UFIXED (fixed-point representation on input) - ## scale - the final numeric variable representation - ## address - variable address - - holding_registers = [ - { name = "power_factor", byte_order = "AB", data_type = "FIXED", scale=0.01, address = [8]}, - { name = "voltage", byte_order = "AB", data_type = "FIXED", scale=0.1, address = [0]}, - { name = "energy", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [5,6]}, - { name = "current", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [1,2]}, - { name = "frequency", byte_order = "AB", data_type = "UFIXED", scale=0.1, address = [7]}, - { name = "power", byte_order = "ABCD", data_type = "UFIXED", scale=0.1, address = [3,4]}, - ] - input_registers = [ - { name = "tank_level", byte_order = "AB", data_type = "INT16", scale=1.0, address = [0]}, - { name = "tank_ph", byte_order = "AB", data_type = "INT16", scale=1.0, address = [1]}, - { name = "pump1_speed", byte_order = "ABCD", data_type = "INT32", scale=1.0, address = [3,4]}, - ] + [[inputs.modbus.measurement]] + name = "power" + tags = [ + {key = "system", value = "solar"}, + {key = "location", value = "roof"}, + ] + + ## Digital Variables, Discrete Inputs and Coils + ## name - the variable name + ## address - variable address + + discrete_inputs = [ + { name = "start", address = [0]}, + { name = "stop", address = [1]}, + { name = "reset", address = [2]}, + { name = "emergency_stop", address = [3]}, + ] + coils = [ + { name = "motor1_run", address = [0]}, + { name = "motor1_jog", address = [1]}, + { name = "motor1_stop", address = [2]}, + ] + + ## Analog Variables, Input Registers and Holding Registers + ## name - the variable name + ## byte_order - the ordering of bytes + ## |---AB, ABCD - Big Endian + ## |---BA, DCBA - Little Endian + ## |---BADC - Mid-Big Endian + ## |---CDAB - Mid-Little Endian + ## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32-IEEE (the IEEE 754 binary representation) + ## FLOAT32, FIXED, UFIXED (fixed-point representation on input) + ## scale - the final numeric variable representation + ## address - variable address + + holding_registers = [ + { name = "power_factor", byte_order = "AB", data_type = "FIXED", scale=0.01, address = [8]}, + { name = "voltage", byte_order = "AB", data_type = "FIXED", scale=0.1, address = [0]}, + { name = "energy", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [5,6]}, + { name = "current", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [1,2]}, + { name = "frequency", byte_order = "AB", data_type = "UFIXED", scale=0.1, address = [7]}, + { name = "power", byte_order = "ABCD", data_type = "UFIXED", scale=0.1, address = [3,4]}, + ] + input_registers = [ + { name = "tank_level", byte_order = "AB", data_type = "INT16", scale=1.0, address = [0]}, + { name = "tank_ph", byte_order = "AB", data_type = "INT16", scale=1.0, address = [1]}, + { name = "pump1_speed", byte_order = "ABCD", data_type = "INT32", scale=1.0, address = [3,4]}, + ] ``` ### Metrics @@ -137,5 +143,5 @@ from unsigned values). ``` $ ./telegraf -config telegraf.conf -input-filter modbus -test -modbus,device_name=OpenPLC,host=orangepizero,type=holding_register current=0,energy=0,frecuency=60,power=0,power_factor=0,voltage=123.9000015258789 1554079521000000000 +power,device_name=Device,host=orangepizero,type=holding_register,system=solar,location=roof current=0,energy=0,frecuency=60,power=0,power_factor=0,voltage=123.9000015258789 1554079521000000000 ``` diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index dd7fd9c898ae1..5257dddbbb579 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -29,14 +29,10 @@ type Modbus struct { SlaveID int `toml:"slave_id"` Timeout internal.Duration `toml:"timeout"` Retries int `toml:"busy_retries"` + RetriesWaitTime internal.Duration `toml:"busy_retries_wait"` OmitDeviceName bool `toml:"omit_device_name"` OmitRegisterType bool `toml:"omit_register_type"` - RetriesWaitTime internal.Duration `toml:"busy_retries_wait"` - DiscreteInputs []fieldContainer `toml:"discrete_inputs"` - Coils []fieldContainer `toml:"coils"` - HoldingRegisters []fieldContainer `toml:"holding_registers"` - InputRegisters []fieldContainer `toml:"input_registers"` - registers []register + Measurements []measurement `toml:"measurement"` isConnected bool tcpHandler *mb.TCPClientHandler rtuHandler *mb.RTUClientHandler @@ -51,13 +47,12 @@ type register struct { } type fieldContainer struct { - Measurement string `toml:"measurement"` - Name string `toml:"name"` - ByteOrder string `toml:"byte_order"` - DataType string `toml:"data_type"` - Scale float64 `toml:"scale"` - Address []uint16 `toml:"address"` - value interface{} + Name string `toml:"name"` + ByteOrder string `toml:"byte_order"` + DataType string `toml:"data_type"` + Scale float64 `toml:"scale"` + Address []uint16 `toml:"address"` + value interface{} } type registerRange struct { @@ -72,6 +67,21 @@ const ( cInputRegisters = "input_register" ) +type tag struct { + Key string `toml:"key"` + Value string `toml:"value"` +} + +type measurement struct { + Name string `toml:"name"` + Tags []tag `toml:"tags"` + DiscreteInputs []fieldContainer `toml:"discrete_inputs"` + Coils []fieldContainer `toml:"coils"` + HoldingRegisters []fieldContainer `toml:"holding_registers"` + InputRegisters []fieldContainer `toml:"input_registers"` + registers []register +} + const description = `Retrieve data from MODBUS slave devices` const sampleConfig = ` ## Connection Configuration @@ -115,49 +125,54 @@ const sampleConfig = ` ## Measurements ## - ## Digital Variables, Discrete Inputs and Coils - ## measurement - the (optional) measurement name, defaults to "modbus" - ## name - the variable name - ## address - variable address - - discrete_inputs = [ - { name = "start", address = [0]}, - { name = "stop", address = [1]}, - { name = "reset", address = [2]}, - { name = "emergency_stop", address = [3]}, - ] - coils = [ - { name = "motor1_run", address = [0]}, - { name = "motor1_jog", address = [1]}, - { name = "motor1_stop", address = [2]}, - ] - - ## Analog Variables, Input Registers and Holding Registers - ## measurement - the (optional) measurement name, defaults to "modbus" - ## name - the variable name - ## byte_order - the ordering of bytes - ## |---AB, ABCD - Big Endian - ## |---BA, DCBA - Little Endian - ## |---BADC - Mid-Big Endian - ## |---CDAB - Mid-Little Endian - ## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32-IEEE (the IEEE 754 binary representation) - ## FLOAT32, FIXED, UFIXED (fixed-point representation on input) - ## scale - the final numeric variable representation - ## address - variable address - - holding_registers = [ - { name = "power_factor", byte_order = "AB", data_type = "FIXED", scale=0.01, address = [8]}, - { name = "voltage", byte_order = "AB", data_type = "FIXED", scale=0.1, address = [0]}, - { name = "energy", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [5,6]}, - { name = "current", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [1,2]}, - { name = "frequency", byte_order = "AB", data_type = "UFIXED", scale=0.1, address = [7]}, - { name = "power", byte_order = "ABCD", data_type = "UFIXED", scale=0.1, address = [3,4]}, - ] - input_registers = [ - { name = "tank_level", byte_order = "AB", data_type = "INT16", scale=1.0, address = [0]}, - { name = "tank_ph", byte_order = "AB", data_type = "INT16", scale=1.0, address = [1]}, - { name = "pump1_speed", byte_order = "ABCD", data_type = "INT32", scale=1.0, address = [3,4]}, - ] + [[inputs.modbus.measurement]] + name = "power" + tags = [ + {key = "system", value = "solar"}, + {key = "location", value = "roof"}, + ] + + ## Digital Variables, Discrete Inputs and Coils + ## name - the variable name + ## address - variable address + + discrete_inputs = [ + { name = "start", address = [0]}, + { name = "stop", address = [1]}, + { name = "reset", address = [2]}, + { name = "emergency_stop", address = [3]}, + ] + coils = [ + { name = "motor1_run", address = [0]}, + { name = "motor1_jog", address = [1]}, + { name = "motor1_stop", address = [2]}, + ] + + ## Analog Variables, Input Registers and Holding Registers + ## name - the variable name + ## byte_order - the ordering of bytes + ## |---AB, ABCD - Big Endian + ## |---BA, DCBA - Little Endian + ## |---BADC - Mid-Big Endian + ## |---CDAB - Mid-Little Endian + ## data_type - INT16, UINT16, INT32, UINT32, INT64, UINT64, FLOAT32-IEEE (the IEEE 754 binary representation) + ## FLOAT32, FIXED, UFIXED (fixed-point representation on input) + ## scale - the final numeric variable representation + ## address - variable address + + holding_registers = [ + { name = "power_factor", byte_order = "AB", data_type = "FIXED", scale=0.01, address = [8]}, + { name = "voltage", byte_order = "AB", data_type = "FIXED", scale=0.1, address = [0]}, + { name = "energy", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [5,6]}, + { name = "current", byte_order = "ABCD", data_type = "FIXED", scale=0.001, address = [1,2]}, + { name = "frequency", byte_order = "AB", data_type = "UFIXED", scale=0.1, address = [7]}, + { name = "power", byte_order = "ABCD", data_type = "UFIXED", scale=0.1, address = [3,4]}, + ] + input_registers = [ + { name = "tank_level", byte_order = "AB", data_type = "INT16", scale=1.0, address = [0]}, + { name = "tank_ph", byte_order = "AB", data_type = "INT16", scale=1.0, address = [1]}, + { name = "pump1_speed", byte_order = "ABCD", data_type = "INT32", scale=1.0, address = [3,4]}, + ] ` // SampleConfig returns a basic configuration for the plugin @@ -180,30 +195,46 @@ func (m *Modbus) Init() error { return fmt.Errorf("retries cannot be negative") } - err := m.InitRegister(m.DiscreteInputs, cDiscreteInputs) + err := validateMeasurements(m.Measurements) if err != nil { return err } - err = m.InitRegister(m.Coils, cCoils) + for idx, _ := range m.Measurements { + err := m.Measurements[idx].InitMeasurement() + if err != nil { + return err + } + } + + return nil +} + +func (meas *measurement) InitMeasurement() error { + err := meas.InitRegister(meas.DiscreteInputs, cDiscreteInputs) if err != nil { - return err + return fmt.Errorf("%s: %s", meas.Name, err) } - err = m.InitRegister(m.HoldingRegisters, cHoldingRegisters) + err = meas.InitRegister(meas.Coils, cCoils) if err != nil { - return err + return fmt.Errorf("%s: %s", meas.Name, err) } - err = m.InitRegister(m.InputRegisters, cInputRegisters) + err = meas.InitRegister(meas.HoldingRegisters, cHoldingRegisters) if err != nil { - return err + return fmt.Errorf("%s: %s", meas.Name, err) + } + + err = meas.InitRegister(meas.InputRegisters, cInputRegisters) + if err != nil { + return fmt.Errorf("%s: %s", meas.Name, err) } return nil } -func (m *Modbus) InitRegister(fields []fieldContainer, name string) error { +func (meas *measurement) InitRegister(fields []fieldContainer, name string) error { if len(fields) == 0 { return nil } @@ -243,7 +274,7 @@ func (m *Modbus) InitRegister(fields []fieldContainer, name string) error { } } - m.registers = append(m.registers, register{name, registersRange, fields}) + meas.registers = append(meas.registers, register{name, registersRange, fields}) return nil } @@ -336,6 +367,17 @@ func disconnect(m *Modbus) error { } } +func validateMeasurements(m []measurement) error { + for _, item := range m { + //check empty name + if item.Name == "" { + return fmt.Errorf("unnamed measurement found") + } + } + + return nil +} + func validateFieldContainers(t []fieldContainer, n string) error { nameEncountered := map[string]bool{} for _, item := range t { @@ -345,11 +387,10 @@ func validateFieldContainers(t []fieldContainer, n string) error { } //search name duplicate - canonical_name := item.Measurement + "." + item.Name - if nameEncountered[canonical_name] { - return fmt.Errorf("name '%s' is duplicated in measurement '%s' '%s' - '%s'", item.Name, item.Measurement, n, item.Name) + if nameEncountered[item.Name] { + return fmt.Errorf("name '%s' is duplicated '%s' - '%s'", item.Name, n, item.Name) } else { - nameEncountered[canonical_name] = true + nameEncountered[item.Name] = true } if n == cInputRegisters || n == cHoldingRegisters { @@ -426,62 +467,64 @@ func readRegisterValues(m *Modbus, rt string, rr registerRange) ([]byte, error) } func (m *Modbus) getFields() error { - for _, register := range m.registers { - rawValues := make(map[uint16][]byte) - bitRawValues := make(map[uint16]uint16) - for _, rr := range register.RegistersRange { - address := rr.address - readValues, err := readRegisterValues(m, register.Type, rr) - if err != nil { - return err - } + for _, meas := range m.Measurements { + for _, register := range meas.registers { + rawValues := make(map[uint16][]byte) + bitRawValues := make(map[uint16]uint16) + for _, rr := range register.RegistersRange { + address := rr.address + readValues, err := readRegisterValues(m, register.Type, rr) + if err != nil { + return err + } - // Raw Values - if register.Type == cDiscreteInputs || register.Type == cCoils { - for _, readValue := range readValues { - for bitPosition := 0; bitPosition < 8; bitPosition++ { - bitRawValues[address] = getBitValue(readValue, bitPosition) - address = address + 1 - if address+1 > rr.length { - break + // Raw Values + if register.Type == cDiscreteInputs || register.Type == cCoils { + for _, readValue := range readValues { + for bitPosition := 0; bitPosition < 8; bitPosition++ { + bitRawValues[address] = getBitValue(readValue, bitPosition) + address = address + 1 + if address+1 > rr.length { + break + } } } } - } - // Raw Values - if register.Type == cInputRegisters || register.Type == cHoldingRegisters { - batchSize := 2 - for batchSize < len(readValues) { + // Raw Values + if register.Type == cInputRegisters || register.Type == cHoldingRegisters { + batchSize := 2 + for batchSize < len(readValues) { + rawValues[address] = readValues[0:batchSize:batchSize] + address = address + 1 + readValues = readValues[batchSize:] + } + rawValues[address] = readValues[0:batchSize:batchSize] - address = address + 1 - readValues = readValues[batchSize:] } - - rawValues[address] = readValues[0:batchSize:batchSize] } - } - if register.Type == cDiscreteInputs || register.Type == cCoils { - for i := 0; i < len(register.Fields); i++ { - register.Fields[i].value = bitRawValues[register.Fields[i].Address[0]] + if register.Type == cDiscreteInputs || register.Type == cCoils { + for i := 0; i < len(register.Fields); i++ { + register.Fields[i].value = bitRawValues[register.Fields[i].Address[0]] + } } - } - if register.Type == cInputRegisters || register.Type == cHoldingRegisters { - for i := 0; i < len(register.Fields); i++ { - var values_t []byte + if register.Type == cInputRegisters || register.Type == cHoldingRegisters { + for i := 0; i < len(register.Fields); i++ { + var values_t []byte - for j := 0; j < len(register.Fields[i].Address); j++ { - tempArray := rawValues[register.Fields[i].Address[j]] - for x := 0; x < len(tempArray); x++ { - values_t = append(values_t, tempArray[x]) + for j := 0; j < len(register.Fields[i].Address); j++ { + tempArray := rawValues[register.Fields[i].Address[j]] + for x := 0; x < len(tempArray); x++ { + values_t = append(values_t, tempArray[x]) + } } + + register.Fields[i].value = convertDataType(register.Fields[i], values_t) } - register.Fields[i].value = convertDataType(register.Fields[i], values_t) } - } } @@ -707,30 +750,29 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error { break } - grouper := metric.NewSeriesGrouper() - for _, reg := range m.registers { - tags := map[string]string{} - if !m.OmitDeviceName { - tags["device_name"] = m.Name - } - if !m.OmitRegisterType { - tags["type"] = reg.Type - } - - for _, field := range reg.Fields { - // In case no measurement was specified we use "modbus" as default - measurement := "modbus" - if field.Measurement != "" { - measurement = field.Measurement + for _, meas := range m.Measurements { + grouper := metric.NewSeriesGrouper() + for _, reg := range meas.registers { + tags := map[string]string{} + for _, tag := range meas.Tags { + tags[tag.Key] = tag.Value + } + if !m.OmitDeviceName { + tags["device_name"] = m.Name + } + if !m.OmitRegisterType { + tags["type"] = reg.Type } - // Group the data by series - grouper.Add(measurement, tags, timestamp, field.Name, field.value) - } + for _, field := range reg.Fields { + // Group the data by series + grouper.Add(meas.Name, tags, timestamp, field.Name, field.value) + } - // Add the metrics grouped by series to the accumulator - for _, metric := range grouper.Metrics() { - acc.AddMetric(metric) + // Add the metrics grouped by series to the accumulator + for _, metric := range grouper.Metrics() { + acc.AddMetric(metric) + } } } diff --git a/plugins/inputs/modbus/modbus_test.go b/plugins/inputs/modbus/modbus_test.go index 8c5241dc2aaee..8c732b97f4251 100644 --- a/plugins/inputs/modbus/modbus_test.go +++ b/plugins/inputs/modbus/modbus_test.go @@ -96,10 +96,15 @@ func TestCoils(t *testing.T) { Name: "TestCoils", Controller: "tcp://localhost:1502", SlaveID: 1, - Coils: []fieldContainer{ + Measurements: []measurement{ { - Name: ct.name, - Address: []uint16{ct.address}, + Name: "TestCoils", + Coils: []fieldContainer{ + { + Name: ct.name, + Address: []uint16{ct.address}, + }, + }, }, }, } @@ -109,9 +114,9 @@ func TestCoils(t *testing.T) { var acc testutil.Accumulator err = modbus.Gather(&acc) assert.NoError(t, err) - assert.NotEmpty(t, modbus.registers) + assert.NotEmpty(t, modbus.Measurements[0].registers) - for _, coil := range modbus.registers { + for _, coil := range modbus.Measurements[0].registers { assert.Equal(t, ct.read, coil.Fields[0].value) } }) @@ -571,13 +576,18 @@ func TestHoldingRegisters(t *testing.T) { Name: "TestHoldingRegisters", Controller: "tcp://localhost:1502", SlaveID: 1, - HoldingRegisters: []fieldContainer{ + Measurements: []measurement{ { - Name: hrt.name, - ByteOrder: hrt.byteOrder, - DataType: hrt.dataType, - Scale: hrt.scale, - Address: hrt.address, + Name: "TestHoldingRegisters", + HoldingRegisters: []fieldContainer{ + { + Name: hrt.name, + ByteOrder: hrt.byteOrder, + DataType: hrt.dataType, + Scale: hrt.scale, + Address: hrt.address, + }, + }, }, }, } @@ -586,9 +596,9 @@ func TestHoldingRegisters(t *testing.T) { assert.NoError(t, err) var acc testutil.Accumulator modbus.Gather(&acc) - assert.NotEmpty(t, modbus.registers) + assert.NotEmpty(t, modbus.Measurements[0].registers) - for _, coil := range modbus.registers { + for _, coil := range modbus.Measurements[0].registers { assert.Equal(t, hrt.read, coil.Fields[0].value) } }) @@ -628,10 +638,15 @@ func TestRetrySuccessful(t *testing.T) { Controller: "tcp://localhost:1502", SlaveID: 1, Retries: maxretries, - Coils: []fieldContainer{ + Measurements: []measurement{ { - Name: "retry_success", - Address: []uint16{0}, + Name: "TestRetry", + Coils: []fieldContainer{ + { + Name: "retry_success", + Address: []uint16{0}, + }, + }, }, }, } @@ -641,9 +656,9 @@ func TestRetrySuccessful(t *testing.T) { var acc testutil.Accumulator err = modbus.Gather(&acc) assert.NoError(t, err) - assert.NotEmpty(t, modbus.registers) + assert.NotEmpty(t, modbus.Measurements[0].registers) - for _, coil := range modbus.registers { + for _, coil := range modbus.Measurements[0].registers { assert.Equal(t, uint16(value), coil.Fields[0].value) } }) @@ -673,10 +688,15 @@ func TestRetryFail(t *testing.T) { Controller: "tcp://localhost:1502", SlaveID: 1, Retries: maxretries, - Coils: []fieldContainer{ + Measurements: []measurement{ { - Name: "retry_fail", - Address: []uint16{0}, + Name: "TestRetryFail", + Coils: []fieldContainer{ + { + Name: "retry_fail", + Address: []uint16{0}, + }, + }, }, }, } @@ -706,10 +726,15 @@ func TestRetryFail(t *testing.T) { Controller: "tcp://localhost:1502", SlaveID: 1, Retries: maxretries, - Coils: []fieldContainer{ + Measurements: []measurement{ { - Name: "retry_fail", - Address: []uint16{0}, + Name: "TestRetryFail", + Coils: []fieldContainer{ + { + Name: "retry_fail", + Address: []uint16{0}, + }, + }, }, }, } From d8f564ba13483e9b478dc677150b61dfb424b843 Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Wed, 5 Aug 2020 10:27:51 +0200 Subject: [PATCH 5/7] ran 'make fmt' --- plugins/inputs/modbus/modbus.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index 5257dddbbb579..bb87890ca5b11 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -200,7 +200,7 @@ func (m *Modbus) Init() error { return err } - for idx, _ := range m.Measurements { + for idx := range m.Measurements { err := m.Measurements[idx].InitMeasurement() if err != nil { return err From 23ed210e10036768a209e529db22dca3d5c82d51 Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Wed, 25 Nov 2020 11:37:54 +0100 Subject: [PATCH 6/7] Removed 'omit_...' options * Use 'tagexclude = ["type", ..] instead --- plugins/inputs/modbus/README.md | 6 ------ plugins/inputs/modbus/modbus.go | 19 ++++--------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/plugins/inputs/modbus/README.md b/plugins/inputs/modbus/README.md index 7d30f16f2ed00..7405931e9b5b3 100644 --- a/plugins/inputs/modbus/README.md +++ b/plugins/inputs/modbus/README.md @@ -23,12 +23,6 @@ Registers via Modbus TCP or Modbus RTU/ASCII. ## Timeout for each request timeout = "1s" - ## Do not add Device Name as Tag - omit_device_name = false - - ## Do not add Register Type as Tag - omit_register_type = false - ## Maximum number of retries and the time to wait between retries ## when a slave-device is busy. # busy_retries = 0 diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index bb87890ca5b11..aa3d909a15371 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -30,8 +30,6 @@ type Modbus struct { Timeout internal.Duration `toml:"timeout"` Retries int `toml:"busy_retries"` RetriesWaitTime internal.Duration `toml:"busy_retries_wait"` - OmitDeviceName bool `toml:"omit_device_name"` - OmitRegisterType bool `toml:"omit_register_type"` Measurements []measurement `toml:"measurement"` isConnected bool tcpHandler *mb.TCPClientHandler @@ -99,12 +97,6 @@ const sampleConfig = ` ## Timeout for each request timeout = "1s" - ## Do not add Device Name as Tag - omit_device_name = false - - ## Do not add Register Type as Tag - omit_register_type = false - ## Maximum number of retries and the time to wait between retries ## when a slave-device is busy. # busy_retries = 0 @@ -753,16 +745,13 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error { for _, meas := range m.Measurements { grouper := metric.NewSeriesGrouper() for _, reg := range meas.registers { - tags := map[string]string{} + tags := map[string]string{ + "device_name": m.Name, + "type": reg.Type, + } for _, tag := range meas.Tags { tags[tag.Key] = tag.Value } - if !m.OmitDeviceName { - tags["device_name"] = m.Name - } - if !m.OmitRegisterType { - tags["type"] = reg.Type - } for _, field := range reg.Fields { // Group the data by series From 35c3085928a42874381c1850dffb887e21308e8d Mon Sep 17 00:00:00 2001 From: Henry Schwanbeck Date: Wed, 25 Nov 2020 11:41:27 +0100 Subject: [PATCH 7/7] ran 'make fmt' --- plugins/inputs/modbus/modbus.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index aa3d909a15371..e0a32a4abf46d 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -747,7 +747,7 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error { for _, reg := range meas.registers { tags := map[string]string{ "device_name": m.Name, - "type": reg.Type, + "type": reg.Type, } for _, tag := range meas.Tags { tags[tag.Key] = tag.Value