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
|
||||
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 ---
|
||||
|
||||
## Measurements
|
||||
|
|
|
|||
|
|
@ -36,8 +36,10 @@ type ConfigurationPerMetric struct {
|
|||
Optimization string `toml:"optimization"`
|
||||
MaxExtraRegisters uint16 `toml:"optimization_max_register_fill"`
|
||||
Metrics []metricDefinition `toml:"metric"`
|
||||
workarounds ModbusWorkarounds
|
||||
logger telegraf.Logger
|
||||
|
||||
workarounds ModbusWorkarounds
|
||||
excludeRegisterType bool
|
||||
logger telegraf.Logger
|
||||
}
|
||||
|
||||
func (c *ConfigurationPerMetric) SampleConfigPart() string {
|
||||
|
|
@ -343,8 +345,10 @@ func (c *ConfigurationPerMetric) fieldID(seed maphash.Seed, def metricDefinition
|
|||
|
||||
mh.WriteByte(def.SlaveID)
|
||||
mh.WriteByte(0)
|
||||
mh.WriteString(field.RegisterType)
|
||||
mh.WriteByte(0)
|
||||
if !c.excludeRegisterType {
|
||||
mh.WriteString(field.RegisterType)
|
||||
mh.WriteByte(0)
|
||||
}
|
||||
mh.WriteString(def.Measurement)
|
||||
mh.WriteByte(0)
|
||||
mh.WriteString(field.Name)
|
||||
|
|
|
|||
|
|
@ -38,9 +38,11 @@ type requestDefinition struct {
|
|||
}
|
||||
|
||||
type ConfigurationPerRequest struct {
|
||||
Requests []requestDefinition `toml:"request"`
|
||||
workarounds ModbusWorkarounds
|
||||
logger telegraf.Logger
|
||||
Requests []requestDefinition `toml:"request"`
|
||||
|
||||
workarounds ModbusWorkarounds
|
||||
excludeRegisterType bool
|
||||
logger telegraf.Logger
|
||||
}
|
||||
|
||||
func (c *ConfigurationPerRequest) SampleConfigPart() string {
|
||||
|
|
@ -388,8 +390,10 @@ func (c *ConfigurationPerRequest) fieldID(seed maphash.Seed, def requestDefiniti
|
|||
|
||||
mh.WriteByte(def.SlaveID)
|
||||
mh.WriteByte(0)
|
||||
mh.WriteString(def.RegisterType)
|
||||
mh.WriteByte(0)
|
||||
if !c.excludeRegisterType {
|
||||
mh.WriteString(def.RegisterType)
|
||||
mh.WriteByte(0)
|
||||
}
|
||||
mh.WriteString(field.Measurement)
|
||||
mh.WriteByte(0)
|
||||
mh.WriteString(field.Name)
|
||||
|
|
|
|||
|
|
@ -47,21 +47,22 @@ type RS485Config struct {
|
|||
|
||||
// Modbus holds all data relevant to the plugin
|
||||
type Modbus struct {
|
||||
Name string `toml:"name"`
|
||||
Controller string `toml:"controller"`
|
||||
TransmissionMode string `toml:"transmission_mode"`
|
||||
BaudRate int `toml:"baud_rate"`
|
||||
DataBits int `toml:"data_bits"`
|
||||
Parity string `toml:"parity"`
|
||||
StopBits int `toml:"stop_bits"`
|
||||
RS485 *RS485Config `toml:"rs485"`
|
||||
Timeout config.Duration `toml:"timeout"`
|
||||
Retries int `toml:"busy_retries"`
|
||||
RetriesWaitTime config.Duration `toml:"busy_retries_wait"`
|
||||
DebugConnection bool `toml:"debug_connection" deprecated:"1.35.0;use 'log_level' 'trace' instead"`
|
||||
Workarounds ModbusWorkarounds `toml:"workarounds"`
|
||||
ConfigurationType string `toml:"configuration_type"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
Name string `toml:"name"`
|
||||
Controller string `toml:"controller"`
|
||||
TransmissionMode string `toml:"transmission_mode"`
|
||||
BaudRate int `toml:"baud_rate"`
|
||||
DataBits int `toml:"data_bits"`
|
||||
Parity string `toml:"parity"`
|
||||
StopBits int `toml:"stop_bits"`
|
||||
RS485 *RS485Config `toml:"rs485"`
|
||||
Timeout config.Duration `toml:"timeout"`
|
||||
Retries int `toml:"busy_retries"`
|
||||
RetriesWaitTime config.Duration `toml:"busy_retries_wait"`
|
||||
DebugConnection bool `toml:"debug_connection" deprecated:"1.35.0;use 'log_level' 'trace' instead"`
|
||||
Workarounds ModbusWorkarounds `toml:"workarounds"`
|
||||
ConfigurationType string `toml:"configuration_type"`
|
||||
ExcludeRegisterTypeTag bool `toml:"exclude_register_type_tag"`
|
||||
Log telegraf.Logger `toml:"-"`
|
||||
|
||||
// Configuration type specific settings
|
||||
ConfigurationOriginal
|
||||
|
|
@ -147,10 +148,12 @@ func (m *Modbus) Init() error {
|
|||
cfg = &m.ConfigurationOriginal
|
||||
case "request":
|
||||
m.ConfigurationPerRequest.workarounds = m.Workarounds
|
||||
m.ConfigurationPerRequest.excludeRegisterType = m.ExcludeRegisterTypeTag
|
||||
m.ConfigurationPerRequest.logger = m.Log
|
||||
cfg = &m.ConfigurationPerRequest
|
||||
case "metric":
|
||||
m.ConfigurationPerMetric.workarounds = m.Workarounds
|
||||
m.ConfigurationPerMetric.excludeRegisterType = m.ExcludeRegisterTypeTag
|
||||
m.ConfigurationPerMetric.logger = m.Log
|
||||
cfg = &m.ConfigurationPerMetric
|
||||
default:
|
||||
|
|
@ -242,21 +245,36 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error {
|
|||
}
|
||||
timestamp := time.Now()
|
||||
|
||||
grouper := metric.NewSeriesGrouper()
|
||||
tags := map[string]string{
|
||||
"name": m.Name,
|
||||
"type": cCoils,
|
||||
"slave_id": strconv.Itoa(int(slaveID)),
|
||||
}
|
||||
m.collectFields(acc, timestamp, tags, requests.coil)
|
||||
|
||||
tags["type"] = cDiscreteInputs
|
||||
m.collectFields(acc, timestamp, tags, requests.discrete)
|
||||
if !m.ExcludeRegisterTypeTag {
|
||||
tags["type"] = cCoils
|
||||
}
|
||||
m.collectFields(grouper, timestamp, tags, requests.coil)
|
||||
|
||||
tags["type"] = cHoldingRegisters
|
||||
m.collectFields(acc, timestamp, tags, requests.holding)
|
||||
if !m.ExcludeRegisterTypeTag {
|
||||
tags["type"] = cDiscreteInputs
|
||||
}
|
||||
m.collectFields(grouper, timestamp, tags, requests.discrete)
|
||||
|
||||
tags["type"] = cInputRegisters
|
||||
m.collectFields(acc, timestamp, tags, requests.input)
|
||||
if !m.ExcludeRegisterTypeTag {
|
||||
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
|
||||
|
|
@ -517,8 +535,7 @@ func (m *Modbus) gatherRequestsInput(requests []request) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (m *Modbus) collectFields(acc telegraf.Accumulator, timestamp time.Time, tags map[string]string, requests []request) {
|
||||
grouper := metric.NewSeriesGrouper()
|
||||
func (m *Modbus) collectFields(grouper *metric.SeriesGrouper, timestamp time.Time, tags map[string]string, requests []request) {
|
||||
for _, request := range requests {
|
||||
for _, field := range request.fields {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -50,3 +50,8 @@
|
|||
## |---request -- define fields on a requests base
|
||||
## |---metric -- define fields on a metric base
|
||||
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