From 6ee4b7e43654dc4af1e67c7fdd3899fdecca8810 Mon Sep 17 00:00:00 2001 From: andig Date: Mon, 9 May 2022 08:25:01 +0200 Subject: [PATCH] EM24: fix decoding (#3348) --- charger/amtron.go | 3 +- charger/wallbe.go | 2 +- go.mod | 2 +- go.sum | 4 +-- templates/definition/meter/cg-em24.yaml | 4 +-- templates/docs/meter/cg-em24_0.yaml | 46 +++++------------------- util/modbus/modbus.go | 48 ++++++++++++------------- 7 files changed, 41 insertions(+), 68 deletions(-) diff --git a/charger/amtron.go b/charger/amtron.go index ba1416d24..1ed588076 100644 --- a/charger/amtron.go +++ b/charger/amtron.go @@ -26,6 +26,7 @@ import ( "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/modbus" "github.com/evcc-io/evcc/util/sponsor" + "github.com/volkszaehler/mbmd/encoding" "github.com/volkszaehler/mbmd/meters/rs485" ) @@ -177,7 +178,7 @@ var _ api.Diagnosis = (*Amtron)(nil) // Diagnose implements the api.Diagnosis interface func (wb *Amtron) Diagnose() { if b, err := wb.conn.ReadInputRegisters(amtronRegName, 11); err == nil { - fmt.Printf("Name: %s\n", modbus.RTUStringSwapped(b)) + fmt.Printf("Name: %s\n", encoding.StringLsbFirst(b)) } if b, err := wb.conn.ReadInputRegisters(amtronRegPhases, 1); err == nil { diff --git a/charger/wallbe.go b/charger/wallbe.go index 64d9a3f79..041c5629e 100644 --- a/charger/wallbe.go +++ b/charger/wallbe.go @@ -228,6 +228,6 @@ var _ api.Diagnosis = (*Wallbe)(nil) // Diagnose implements the Diagnosis interface func (wb *Wallbe) Diagnose() { if b, err := wb.conn.ReadInputRegisters(wbRegFirmware, 6); err == nil { - fmt.Printf("Firmware:\t%s\n", encoding.StringSwapped(b)) + fmt.Printf("Firmware:\t%s\n", encoding.StringLsbFirst(b)) } } diff --git a/go.mod b/go.mod index 0b9bc902b..d1a8a0090 100644 --- a/go.mod +++ b/go.mod @@ -73,7 +73,7 @@ require ( github.com/spf13/viper v1.11.0 github.com/stretchr/testify v1.7.1 github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c - github.com/volkszaehler/mbmd v0.0.0-20220429083530-4218d966b2dc + github.com/volkszaehler/mbmd v0.0.0-20220509062004-21ece8c27e5e github.com/writeas/go-strip-markdown v2.0.1+incompatible gitlab.com/bboehmke/sunny v0.15.1-0.20211022160056-2fba1c86ade6 golang.org/x/exp v0.0.0-20220428152302-39d4317da171 diff --git a/go.sum b/go.sum index f0cb36c15..a701113ef 100644 --- a/go.sum +++ b/go.sum @@ -902,8 +902,8 @@ github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9 github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc= github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g= github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds= -github.com/volkszaehler/mbmd v0.0.0-20220429083530-4218d966b2dc h1:ErvZcShn2BDQoeU/RQw9z/Y33yqu1ECe1ko6zza/MF0= -github.com/volkszaehler/mbmd v0.0.0-20220429083530-4218d966b2dc/go.mod h1:JP4R5rxFO4QlDo/DoNp8YrPD2YV0+imTfRTL5xBCUjs= +github.com/volkszaehler/mbmd v0.0.0-20220509062004-21ece8c27e5e h1:2dGaYpWS+pW4L6cvBQndHvkvhpUt5ZEHErWUADbd0ug= +github.com/volkszaehler/mbmd v0.0.0-20220509062004-21ece8c27e5e/go.mod h1:JP4R5rxFO4QlDo/DoNp8YrPD2YV0+imTfRTL5xBCUjs= github.com/writeas/go-strip-markdown v2.0.1+incompatible h1:IIqxTM5Jr7RzhigcL6FkrCNfXkvbR+Nbu1ls48pXYcw= github.com/writeas/go-strip-markdown v2.0.1+incompatible/go.mod h1:Rsyu10ZhbEK9pXdk8V6MVnZmTzRG0alMNLMwa0J01fE= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= diff --git a/templates/definition/meter/cg-em24.yaml b/templates/definition/meter/cg-em24.yaml index cce09e8be..824f612b2 100644 --- a/templates/definition/meter/cg-em24.yaml +++ b/templates/definition/meter/cg-em24.yaml @@ -2,12 +2,12 @@ template: cg-em24 products: - brand: Carlo Gavazzi description: - generic: EM 24 + generic: EM24 E1 params: - name: usage choice: ["grid", "pv", "battery", "charge"] - name: modbus - choice: ["rs485"] + choice: ["tcpip"] render: | type: modbus model: cgem24 diff --git a/templates/docs/meter/cg-em24_0.yaml b/templates/docs/meter/cg-em24_0.yaml index 5af65f500..3bacf69cd 100644 --- a/templates/docs/meter/cg-em24_0.yaml +++ b/templates/docs/meter/cg-em24_0.yaml @@ -1,6 +1,6 @@ product: brand: Carlo Gavazzi - description: EM 24 + description: EM24 E1 render: - usage: grid default: | @@ -8,15 +8,8 @@ render: template: cg-em24 usage: grid - # RS485 via adapter (Modbus RTU) - modbus: rs485serial - id: 1 - device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse - baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200 - comset: "8N1" # Kommunikationsparameter für den Adapter - - # RS485 via TCP/IP (Modbus RTU) - modbus: rs485tcpip + # Modbus TCP + modbus: tcpip id: 1 host: 192.0.2.2 # Hostname port: 502 # Port @@ -26,15 +19,8 @@ render: template: cg-em24 usage: pv - # RS485 via adapter (Modbus RTU) - modbus: rs485serial - id: 1 - device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse - baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200 - comset: "8N1" # Kommunikationsparameter für den Adapter - - # RS485 via TCP/IP (Modbus RTU) - modbus: rs485tcpip + # Modbus TCP + modbus: tcpip id: 1 host: 192.0.2.2 # Hostname port: 502 # Port @@ -44,15 +30,8 @@ render: template: cg-em24 usage: battery - # RS485 via adapter (Modbus RTU) - modbus: rs485serial - id: 1 - device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse - baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200 - comset: "8N1" # Kommunikationsparameter für den Adapter - - # RS485 via TCP/IP (Modbus RTU) - modbus: rs485tcpip + # Modbus TCP + modbus: tcpip id: 1 host: 192.0.2.2 # Hostname port: 502 # Port @@ -62,15 +41,8 @@ render: template: cg-em24 usage: charge - # RS485 via adapter (Modbus RTU) - modbus: rs485serial - id: 1 - device: /dev/ttyUSB0 # USB-RS485 Adapter Adresse - baudrate: 9600 # Prüfe die Geräteeinstellungen, typische Werte sind 9600, 19200, 38400, 57600, 115200 - comset: "8N1" # Kommunikationsparameter für den Adapter - - # RS485 via TCP/IP (Modbus RTU) - modbus: rs485tcpip + # Modbus TCP + modbus: tcpip id: 1 host: 192.0.2.2 # Hostname port: 502 # Port diff --git a/util/modbus/modbus.go b/util/modbus/modbus.go index a861fc452..c7130a5fd 100644 --- a/util/modbus/modbus.go +++ b/util/modbus/modbus.go @@ -10,9 +10,11 @@ import ( "github.com/evcc-io/evcc/util" "github.com/grid-x/modbus" + "github.com/volkszaehler/mbmd/encoding" "github.com/volkszaehler/mbmd/meters" "github.com/volkszaehler/mbmd/meters/rs485" "github.com/volkszaehler/mbmd/meters/sunspec" + "golang.org/x/exp/constraints" ) type Protocol int @@ -272,6 +274,13 @@ type Register struct { BitMask string } +// asFloat64 creates a function that returns numerics vales as float64 +func asFloat64[T constraints.Signed | constraints.Unsigned | constraints.Float](f func([]byte) T) func([]byte) float64 { + return func(v []byte) float64 { + return float64(f(v)) + } +} + // RegisterOperation creates a read operation from a register definition func RegisterOperation(r Register) (rs485.Operation, error) { op := rs485.Operation{ @@ -294,16 +303,16 @@ func RegisterOperation(r Register) (rs485.Operation, error) { // 16 bit case "int16": - op.Transform = rs485.RTUInt16ToFloat64 + op.Transform = asFloat64(encoding.Int16) op.ReadLen = 1 case "int16nan": - op.Transform = decodeNaN16(1<<15, rs485.RTUInt16ToFloat64) + op.Transform = decodeNaN16(1<<15, asFloat64(encoding.Int16)) op.ReadLen = 1 case "uint16": - op.Transform = rs485.RTUUint16ToFloat64 + op.Transform = asFloat64(encoding.Uint16) op.ReadLen = 1 case "uint16nan": - op.Transform = decodeNaN16(0xFFFF, rs485.RTUUint16ToFloat64) + op.Transform = decodeNaN16(0xFFFF, asFloat64(encoding.Uint16)) op.ReadLen = 1 case "bool16": mask, err := decodeMask(r.BitMask) @@ -315,31 +324,31 @@ func RegisterOperation(r Register) (rs485.Operation, error) { // 32 bit case "int32": - op.Transform = rs485.RTUInt32ToFloat64 + op.Transform = asFloat64(encoding.Int32) case "int32nan": - op.Transform = decodeNaN32(1<<31, rs485.RTUInt32ToFloat64) + op.Transform = decodeNaN32(1<<31, asFloat64(encoding.Int32)) case "int32s": - op.Transform = rs485.RTUInt32ToFloat64Swapped + op.Transform = asFloat64(encoding.Int32LswFirst) case "uint32": - op.Transform = rs485.RTUUint32ToFloat64 + op.Transform = asFloat64(encoding.Uint32) case "uint32s": - op.Transform = rs485.RTUUint32ToFloat64Swapped + op.Transform = asFloat64(encoding.Uint32LswFirst) case "uint32nan": - op.Transform = decodeNaN32(0xFFFFFFFF, rs485.RTUUint32ToFloat64) + op.Transform = decodeNaN32(0xFFFFFFFF, asFloat64(encoding.Uint32)) case "float32", "ieee754": - op.Transform = rs485.RTUIeee754ToFloat64 + op.Transform = asFloat64(encoding.Float32) case "float32s", "ieee754s": - op.Transform = rs485.RTUIeee754ToFloat64Swapped + op.Transform = asFloat64(encoding.Float32LswFirst) // 64 bit case "uint64": - op.Transform = rs485.RTUUint64ToFloat64 + op.Transform = asFloat64(encoding.Uint64) op.ReadLen = 4 case "uint64nan": - op.Transform = decodeNaN64(0xFFFFFFFFFFFFFFFF, rs485.RTUUint64ToFloat64) + op.Transform = decodeNaN64(0xFFFFFFFFFFFFFFFF, asFloat64(encoding.Uint64)) op.ReadLen = 4 case "float64": - op.Transform = rs485.RTUFloat64ToFloat64 + op.Transform = encoding.Float64 op.ReadLen = 4 default: @@ -349,15 +358,6 @@ func RegisterOperation(r Register) (rs485.Operation, error) { return op, nil } -func RTUStringSwapped(b []byte) string { - s := new(strings.Builder) - for i := 0; i < len(b); i += 2 { - s.WriteByte(b[i+1]) - s.WriteByte(b[i]) - } - return s.String() -} - // SunSpecOperation is a sunspec modbus operation type SunSpecOperation struct { Model, Block int