feat(inputs.modbus): Allow grouping across register types (#16040)
This commit is contained in:
parent
c73559dc6c
commit
f06111499e
|
|
@ -69,6 +69,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
## |---metric -- define fields on a metric base
|
## |---metric -- define fields on a metric base
|
||||||
configuration_type = "register"
|
configuration_type = "register"
|
||||||
|
|
||||||
|
## Exclude the register type tag
|
||||||
|
## Please note, this will also influence the grouping of metrics as you won't
|
||||||
|
## see one metric per register type anymore!
|
||||||
|
# exclude_register_type_tag = false
|
||||||
|
|
||||||
## --- "register" configuration style ---
|
## --- "register" configuration style ---
|
||||||
|
|
||||||
## Measurements
|
## Measurements
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,10 @@ type ConfigurationPerMetric struct {
|
||||||
Optimization string `toml:"optimization"`
|
Optimization string `toml:"optimization"`
|
||||||
MaxExtraRegisters uint16 `toml:"optimization_max_register_fill"`
|
MaxExtraRegisters uint16 `toml:"optimization_max_register_fill"`
|
||||||
Metrics []metricDefinition `toml:"metric"`
|
Metrics []metricDefinition `toml:"metric"`
|
||||||
workarounds ModbusWorkarounds
|
|
||||||
logger telegraf.Logger
|
workarounds ModbusWorkarounds
|
||||||
|
excludeRegisterType bool
|
||||||
|
logger telegraf.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfigurationPerMetric) SampleConfigPart() string {
|
func (c *ConfigurationPerMetric) SampleConfigPart() string {
|
||||||
|
|
@ -343,8 +345,10 @@ func (c *ConfigurationPerMetric) fieldID(seed maphash.Seed, def metricDefinition
|
||||||
|
|
||||||
mh.WriteByte(def.SlaveID)
|
mh.WriteByte(def.SlaveID)
|
||||||
mh.WriteByte(0)
|
mh.WriteByte(0)
|
||||||
mh.WriteString(field.RegisterType)
|
if !c.excludeRegisterType {
|
||||||
mh.WriteByte(0)
|
mh.WriteString(field.RegisterType)
|
||||||
|
mh.WriteByte(0)
|
||||||
|
}
|
||||||
mh.WriteString(def.Measurement)
|
mh.WriteString(def.Measurement)
|
||||||
mh.WriteByte(0)
|
mh.WriteByte(0)
|
||||||
mh.WriteString(field.Name)
|
mh.WriteString(field.Name)
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,11 @@ type requestDefinition struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConfigurationPerRequest struct {
|
type ConfigurationPerRequest struct {
|
||||||
Requests []requestDefinition `toml:"request"`
|
Requests []requestDefinition `toml:"request"`
|
||||||
workarounds ModbusWorkarounds
|
|
||||||
logger telegraf.Logger
|
workarounds ModbusWorkarounds
|
||||||
|
excludeRegisterType bool
|
||||||
|
logger telegraf.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ConfigurationPerRequest) SampleConfigPart() string {
|
func (c *ConfigurationPerRequest) SampleConfigPart() string {
|
||||||
|
|
@ -388,8 +390,10 @@ func (c *ConfigurationPerRequest) fieldID(seed maphash.Seed, def requestDefiniti
|
||||||
|
|
||||||
mh.WriteByte(def.SlaveID)
|
mh.WriteByte(def.SlaveID)
|
||||||
mh.WriteByte(0)
|
mh.WriteByte(0)
|
||||||
mh.WriteString(def.RegisterType)
|
if !c.excludeRegisterType {
|
||||||
mh.WriteByte(0)
|
mh.WriteString(def.RegisterType)
|
||||||
|
mh.WriteByte(0)
|
||||||
|
}
|
||||||
mh.WriteString(field.Measurement)
|
mh.WriteString(field.Measurement)
|
||||||
mh.WriteByte(0)
|
mh.WriteByte(0)
|
||||||
mh.WriteString(field.Name)
|
mh.WriteString(field.Name)
|
||||||
|
|
|
||||||
|
|
@ -47,21 +47,22 @@ type RS485Config struct {
|
||||||
|
|
||||||
// Modbus holds all data relevant to the plugin
|
// Modbus holds all data relevant to the plugin
|
||||||
type Modbus struct {
|
type Modbus struct {
|
||||||
Name string `toml:"name"`
|
Name string `toml:"name"`
|
||||||
Controller string `toml:"controller"`
|
Controller string `toml:"controller"`
|
||||||
TransmissionMode string `toml:"transmission_mode"`
|
TransmissionMode string `toml:"transmission_mode"`
|
||||||
BaudRate int `toml:"baud_rate"`
|
BaudRate int `toml:"baud_rate"`
|
||||||
DataBits int `toml:"data_bits"`
|
DataBits int `toml:"data_bits"`
|
||||||
Parity string `toml:"parity"`
|
Parity string `toml:"parity"`
|
||||||
StopBits int `toml:"stop_bits"`
|
StopBits int `toml:"stop_bits"`
|
||||||
RS485 *RS485Config `toml:"rs485"`
|
RS485 *RS485Config `toml:"rs485"`
|
||||||
Timeout config.Duration `toml:"timeout"`
|
Timeout config.Duration `toml:"timeout"`
|
||||||
Retries int `toml:"busy_retries"`
|
Retries int `toml:"busy_retries"`
|
||||||
RetriesWaitTime config.Duration `toml:"busy_retries_wait"`
|
RetriesWaitTime config.Duration `toml:"busy_retries_wait"`
|
||||||
DebugConnection bool `toml:"debug_connection" deprecated:"1.35.0;use 'log_level' 'trace' instead"`
|
DebugConnection bool `toml:"debug_connection" deprecated:"1.35.0;use 'log_level' 'trace' instead"`
|
||||||
Workarounds ModbusWorkarounds `toml:"workarounds"`
|
Workarounds ModbusWorkarounds `toml:"workarounds"`
|
||||||
ConfigurationType string `toml:"configuration_type"`
|
ConfigurationType string `toml:"configuration_type"`
|
||||||
Log telegraf.Logger `toml:"-"`
|
ExcludeRegisterTypeTag bool `toml:"exclude_register_type_tag"`
|
||||||
|
Log telegraf.Logger `toml:"-"`
|
||||||
|
|
||||||
// Configuration type specific settings
|
// Configuration type specific settings
|
||||||
ConfigurationOriginal
|
ConfigurationOriginal
|
||||||
|
|
@ -147,10 +148,12 @@ func (m *Modbus) Init() error {
|
||||||
cfg = &m.ConfigurationOriginal
|
cfg = &m.ConfigurationOriginal
|
||||||
case "request":
|
case "request":
|
||||||
m.ConfigurationPerRequest.workarounds = m.Workarounds
|
m.ConfigurationPerRequest.workarounds = m.Workarounds
|
||||||
|
m.ConfigurationPerRequest.excludeRegisterType = m.ExcludeRegisterTypeTag
|
||||||
m.ConfigurationPerRequest.logger = m.Log
|
m.ConfigurationPerRequest.logger = m.Log
|
||||||
cfg = &m.ConfigurationPerRequest
|
cfg = &m.ConfigurationPerRequest
|
||||||
case "metric":
|
case "metric":
|
||||||
m.ConfigurationPerMetric.workarounds = m.Workarounds
|
m.ConfigurationPerMetric.workarounds = m.Workarounds
|
||||||
|
m.ConfigurationPerMetric.excludeRegisterType = m.ExcludeRegisterTypeTag
|
||||||
m.ConfigurationPerMetric.logger = m.Log
|
m.ConfigurationPerMetric.logger = m.Log
|
||||||
cfg = &m.ConfigurationPerMetric
|
cfg = &m.ConfigurationPerMetric
|
||||||
default:
|
default:
|
||||||
|
|
@ -242,21 +245,36 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error {
|
||||||
}
|
}
|
||||||
timestamp := time.Now()
|
timestamp := time.Now()
|
||||||
|
|
||||||
|
grouper := metric.NewSeriesGrouper()
|
||||||
tags := map[string]string{
|
tags := map[string]string{
|
||||||
"name": m.Name,
|
"name": m.Name,
|
||||||
"type": cCoils,
|
|
||||||
"slave_id": strconv.Itoa(int(slaveID)),
|
"slave_id": strconv.Itoa(int(slaveID)),
|
||||||
}
|
}
|
||||||
m.collectFields(acc, timestamp, tags, requests.coil)
|
|
||||||
|
|
||||||
tags["type"] = cDiscreteInputs
|
if !m.ExcludeRegisterTypeTag {
|
||||||
m.collectFields(acc, timestamp, tags, requests.discrete)
|
tags["type"] = cCoils
|
||||||
|
}
|
||||||
|
m.collectFields(grouper, timestamp, tags, requests.coil)
|
||||||
|
|
||||||
tags["type"] = cHoldingRegisters
|
if !m.ExcludeRegisterTypeTag {
|
||||||
m.collectFields(acc, timestamp, tags, requests.holding)
|
tags["type"] = cDiscreteInputs
|
||||||
|
}
|
||||||
|
m.collectFields(grouper, timestamp, tags, requests.discrete)
|
||||||
|
|
||||||
tags["type"] = cInputRegisters
|
if !m.ExcludeRegisterTypeTag {
|
||||||
m.collectFields(acc, timestamp, tags, requests.input)
|
tags["type"] = cHoldingRegisters
|
||||||
|
}
|
||||||
|
m.collectFields(grouper, timestamp, tags, requests.holding)
|
||||||
|
|
||||||
|
if !m.ExcludeRegisterTypeTag {
|
||||||
|
tags["type"] = cInputRegisters
|
||||||
|
}
|
||||||
|
m.collectFields(grouper, timestamp, tags, requests.input)
|
||||||
|
|
||||||
|
// Add the metrics grouped by series to the accumulator
|
||||||
|
for _, x := range grouper.Metrics() {
|
||||||
|
acc.AddMetric(x)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disconnect after read if configured
|
// Disconnect after read if configured
|
||||||
|
|
@ -517,8 +535,7 @@ func (m *Modbus) gatherRequestsInput(requests []request) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Modbus) collectFields(acc telegraf.Accumulator, timestamp time.Time, tags map[string]string, requests []request) {
|
func (m *Modbus) collectFields(grouper *metric.SeriesGrouper, timestamp time.Time, tags map[string]string, requests []request) {
|
||||||
grouper := metric.NewSeriesGrouper()
|
|
||||||
for _, request := range requests {
|
for _, request := range requests {
|
||||||
for _, field := range request.fields {
|
for _, field := range request.fields {
|
||||||
// Collect tags from global and per-request
|
// Collect tags from global and per-request
|
||||||
|
|
@ -539,11 +556,6 @@ func (m *Modbus) collectFields(acc telegraf.Accumulator, timestamp time.Time, ta
|
||||||
grouper.Add(measurement, ftags, timestamp, field.name, field.value)
|
grouper.Add(measurement, ftags, timestamp, field.name, field.value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add the metrics grouped by series to the accumulator
|
|
||||||
for _, x := range grouper.Metrics() {
|
|
||||||
acc.AddMetric(x)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the logger interface of the modbus client
|
// Implement the logger interface of the modbus client
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,8 @@
|
||||||
## |---request -- define fields on a requests base
|
## |---request -- define fields on a requests base
|
||||||
## |---metric -- define fields on a metric base
|
## |---metric -- define fields on a metric base
|
||||||
configuration_type = "register"
|
configuration_type = "register"
|
||||||
|
|
||||||
|
## Exclude the register type tag
|
||||||
|
## Please note, this will also influence the grouping of metrics as you won't
|
||||||
|
## see one metric per register type anymore!
|
||||||
|
# exclude_register_type_tag = false
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
duplicated in measurement "modbus"
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
[[inputs.modbus]]
|
||||||
|
name = "Device"
|
||||||
|
controller = "tcp://localhost:502"
|
||||||
|
configuration_type = "request"
|
||||||
|
exclude_register_type_tag = true
|
||||||
|
|
||||||
|
[[inputs.modbus.request]]
|
||||||
|
slave_id = 1
|
||||||
|
register = "holding"
|
||||||
|
fields = [
|
||||||
|
{ name = "humidity", type = "INT16", scale=1.0, address = 1},
|
||||||
|
{ name = "temperature", type = "INT16", scale=1.0, address = 4},
|
||||||
|
{ name = "active", type = "INT16", scale=1.0, address = 7},
|
||||||
|
]
|
||||||
|
|
||||||
|
[[inputs.modbus.request]]
|
||||||
|
slave_id = 1
|
||||||
|
register = "input"
|
||||||
|
fields = [
|
||||||
|
{ name = "humidity", type = "INT16", scale=1.0, address = 2},
|
||||||
|
{ name = "temperature", type = "INT16", scale=1.0, address = 5},
|
||||||
|
{ name = "active", type = "INT16", scale=1.0, address = 8},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
modbus,name=modbus,slave_id=1 3x0135:INT=134i,4x0102:INT=0i,4x0103:INT=101i 1729239973009490185
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
[[inputs.modbus]]
|
||||||
|
name_override = "modbus"
|
||||||
|
name = "modbus"
|
||||||
|
timeout = "1s"
|
||||||
|
controller = "tcp://172.16.2.31:502"
|
||||||
|
configuration_type = "metric"
|
||||||
|
exclude_register_type_tag = true
|
||||||
|
[[inputs.modbus.metric]]
|
||||||
|
slave_id = 1
|
||||||
|
byte_order = "ABCD"
|
||||||
|
fields = [
|
||||||
|
{register = "holding", address = 101, name = '4x0102:INT', type = 'INT16'},
|
||||||
|
{register = "holding", address = 102, name = '4x0103:INT', type = 'INT16'},
|
||||||
|
{register = "input", address = 134, name = '3x0135:INT', type = 'INT16'},
|
||||||
|
]
|
||||||
Loading…
Reference in New Issue