EM24: fix decoding (#3348)

This commit is contained in:
andig 2022-05-09 08:25:01 +02:00 • committed by GitHub
parent 6832b5f364
commit 6ee4b7e436
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 41 additions and 68 deletions

View file

@ -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 {

View file

@ -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))
}
}

2
go.mod
View file

@ -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

4
go.sum
View file

@ -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=

View file

@ -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

View file

@ -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

View file

@ -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