From 9d97ed22e63c7f6e77839c44d24459aba5ffb494 Mon Sep 17 00:00:00 2001 From: Antonio Garcia Date: Mon, 10 Feb 2020 18:54:33 -0600 Subject: [PATCH] Fix float conversion and startup connection issue in modbus input (#7002) --- plugins/inputs/modbus/modbus.go | 87 +++++++++++++++++----------- plugins/inputs/modbus/modbus_test.go | 12 ++-- 2 files changed, 59 insertions(+), 40 deletions(-) diff --git a/plugins/inputs/modbus/modbus.go b/plugins/inputs/modbus/modbus.go index d845ef8fe..d2e913039 100644 --- a/plugins/inputs/modbus/modbus.go +++ b/plugins/inputs/modbus/modbus.go @@ -40,7 +40,6 @@ type Modbus struct { type register struct { Type string RegistersRange []registerRange - ReadValue func(uint16, uint16) ([]byte, error) Fields []fieldContainer } @@ -48,7 +47,7 @@ type fieldContainer struct { Name string `toml:"name"` ByteOrder string `toml:"byte_order"` DataType string `toml:"data_type"` - Scale float32 `toml:"scale"` + Scale float64 `toml:"scale"` Address []uint16 `toml:"address"` value interface{} } @@ -155,13 +154,7 @@ func (m *Modbus) Init() error { return fmt.Errorf("device name is empty") } - err := connect(m) - if err != nil { - m.isConnected = false - return err - } - - err = m.InitRegister(m.DiscreteInputs, cDiscreteInputs) + err := m.InitRegister(m.DiscreteInputs, cDiscreteInputs) if err != nil { return err } @@ -224,21 +217,7 @@ func (m *Modbus) InitRegister(fields []fieldContainer, name string) error { } } - var fn func(uint16, uint16) ([]byte, error) - - if name == cDiscreteInputs { - fn = m.client.ReadDiscreteInputs - } else if name == cCoils { - fn = m.client.ReadCoils - } else if name == cInputRegisters { - fn = m.client.ReadInputRegisters - } else if name == cHoldingRegisters { - fn = m.client.ReadHoldingRegisters - } else { - return fmt.Errorf("not Valid function") - } - - m.registers = append(m.registers, register{name, registersRange, fn, fields}) + m.registers = append(m.registers, register{name, registersRange, fields}) return nil } @@ -306,6 +285,31 @@ func connect(m *Modbus) error { } } +func disconnect(m *Modbus) error { + u, err := url.Parse(m.Controller) + if err != nil { + return err + } + + switch u.Scheme { + case "tcp": + m.tcpHandler.Close() + return nil + case "file": + if m.TransmissionMode == "RTU" { + m.rtuHandler.Close() + return nil + } else if m.TransmissionMode == "ASCII" { + m.asciiHandler.Close() + return nil + } else { + return fmt.Errorf("invalid protocol '%s' - '%s' ", u.Scheme, m.TransmissionMode) + } + default: + return fmt.Errorf("invalid controller") + } +} + func validateFieldContainers(t []fieldContainer, n string) error { nameEncountered := map[string]bool{} for _, item := range t { @@ -379,13 +383,27 @@ func removeDuplicates(elements []uint16) []uint16 { return result } +func readRegisterValues(m *Modbus, rt string, rr registerRange) ([]byte, error) { + if rt == cDiscreteInputs { + return m.client.ReadDiscreteInputs(uint16(rr.address), uint16(rr.length)) + } else if rt == cCoils { + return m.client.ReadCoils(uint16(rr.address), uint16(rr.length)) + } else if rt == cInputRegisters { + return m.client.ReadInputRegisters(uint16(rr.address), uint16(rr.length)) + } else if rt == cHoldingRegisters { + return m.client.ReadHoldingRegisters(uint16(rr.address), uint16(rr.length)) + } else { + return []byte{}, fmt.Errorf("not Valid function") + } +} + 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 := register.ReadValue(uint16(rr.address), uint16(rr.length)) + readValues, err := readRegisterValues(m, register.Type, rr) if err != nil { return err } @@ -530,23 +548,23 @@ func format32(f string, r uint32) interface{} { } } -func scale16toFloat32(s float32, v uint16) float32 { - return float32(v) * s +func scale16toFloat32(s float64, v uint16) float64 { + return float64(v) * s } -func scale32toFloat32(s float32, v uint32) float32 { - return float32(v) * s +func scale32toFloat32(s float64, v uint32) float64 { + return float64(float64(v) * float64(s)) } -func scaleInt16(s float32, v int16) int16 { - return int16(float32(v) * s) +func scaleInt16(s float64, v int16) int16 { + return int16(float64(v) * s) } -func scaleUint16(s float32, v uint16) uint16 { - return uint16(float32(v) * s) +func scaleUint16(s float64, v uint16) uint16 { + return uint16(float64(v) * s) } -func scaleUint32(s float32, v uint32) uint32 { +func scaleUint32(s float64, v uint32) uint32 { return uint32(float64(v) * float64(s)) } @@ -562,6 +580,7 @@ func (m *Modbus) Gather(acc telegraf.Accumulator) error { err := m.getFields() if err != nil { + disconnect(m) m.isConnected = false return err } diff --git a/plugins/inputs/modbus/modbus_test.go b/plugins/inputs/modbus/modbus_test.go index 3d54c68c5..3317067a8 100644 --- a/plugins/inputs/modbus/modbus_test.go +++ b/plugins/inputs/modbus/modbus_test.go @@ -125,7 +125,7 @@ func TestHoldingRegisters(t *testing.T) { quantity uint16 byteOrder string dataType string - scale float32 + scale float64 write []byte read interface{} }{ @@ -137,7 +137,7 @@ func TestHoldingRegisters(t *testing.T) { dataType: "FLOAT32", scale: 0.1, write: []byte{0x08, 0x98}, - read: float32(220), + read: float64(220), }, { name: "register0_register1_ab_float32", @@ -147,7 +147,7 @@ func TestHoldingRegisters(t *testing.T) { dataType: "FLOAT32", scale: 0.001, write: []byte{0x00, 0x00, 0x03, 0xE8}, - read: float32(1), + read: float64(1), }, { name: "register1_register2_abcd_float32", @@ -157,7 +157,7 @@ func TestHoldingRegisters(t *testing.T) { dataType: "FLOAT32", scale: 0.1, write: []byte{0x00, 0x00, 0x08, 0x98}, - read: float32(220), + read: float64(220), }, { name: "register3_register4_abcd_float32", @@ -167,7 +167,7 @@ func TestHoldingRegisters(t *testing.T) { dataType: "FLOAT32", scale: 0.1, write: []byte{0x00, 0x00, 0x08, 0x98}, - read: float32(220), + read: float64(220), }, { name: "register7_ab_float32", @@ -177,7 +177,7 @@ func TestHoldingRegisters(t *testing.T) { dataType: "FLOAT32", scale: 0.1, write: []byte{0x01, 0xF4}, - read: float32(50), + read: float64(50), }, { name: "register10_ab_uint16",