From 8e61200216c95a2bbb7fee27705b60e651a2be0b Mon Sep 17 00:00:00 2001 From: andig Date: Tue, 13 Oct 2020 07:59:21 +0200 Subject: [PATCH] Use register 1000 for enable/disable and add delay to support older evse's (#380) --- charger/simpleevse.go | 45 +++++++++++++++++++++++-------------------- util/modbus/modbus.go | 43 ++++++++++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/charger/simpleevse.go b/charger/simpleevse.go index cd22457ca..ba043be55 100644 --- a/charger/simpleevse.go +++ b/charger/simpleevse.go @@ -2,6 +2,7 @@ package charger import ( "errors" + "time" "github.com/andig/evcc/api" "github.com/andig/evcc/util" @@ -10,14 +11,14 @@ import ( // SimpleEVSE charger implementation type SimpleEVSE struct { - log *util.Logger - conn *modbus.Connection + log *util.Logger + conn *modbus.Connection + current int64 } const ( evseRegAmpsConfig = 1000 evseRegVehicleStatus = 1002 - evseRegTurnOff = 1004 ) func init() { @@ -49,9 +50,13 @@ func NewSimpleEVSE(uri, device, comset string, baudrate int, rtu bool, slaveID u return nil, err } + conn.Logger(log.TRACE) + conn.Delay(200 * time.Millisecond) + evse := &SimpleEVSE{ - log: log, - conn: conn, + log: log, + conn: conn, + current: 6, // assume min current } return evse, nil @@ -60,7 +65,6 @@ func NewSimpleEVSE(uri, device, comset string, baudrate int, rtu bool, slaveID u // Status implements the Charger.Status interface func (evse *SimpleEVSE) Status() (api.ChargeStatus, error) { b, err := evse.conn.ReadHoldingRegisters(evseRegVehicleStatus, 1) - evse.log.TRACE.Printf("read status (%d): %0 X", evseRegVehicleStatus, b) if err != nil { return api.StatusNone, err } @@ -83,31 +87,28 @@ func (evse *SimpleEVSE) Status() (api.ChargeStatus, error) { // Enabled implements the Charger.Enabled interface func (evse *SimpleEVSE) Enabled() (bool, error) { - b, err := evse.conn.ReadHoldingRegisters(evseRegTurnOff, 1) - evse.log.TRACE.Printf("read charge enable (%d): %0 X", evseRegTurnOff, b) + b, err := evse.conn.ReadHoldingRegisters(evseRegAmpsConfig, 1) if err != nil { return false, err } - return b[1] == 1, nil + enabled := b[1] != 0 + if enabled { + evse.current = int64(b[1]) + } + + return enabled, nil } // Enable implements the Charger.Enable interface func (evse *SimpleEVSE) Enable(enable bool) error { - b, err := evse.conn.ReadHoldingRegisters(evseRegTurnOff, 1) - evse.log.TRACE.Printf("read charge enable (%d): %0 X", evseRegTurnOff, b) - if err != nil { - return err - } + b := []byte{0, 0} if enable { - b[1] |= 1 - } else { - b[1] &= ^byte(1) + b[1] = byte(evse.current) } - bb, err := evse.conn.WriteMultipleRegisters(evseRegTurnOff, 1, b) - evse.log.TRACE.Printf("write charge enable (%d) %0X: %0 X", evseRegTurnOff, b, bb) + _, err := evse.conn.WriteMultipleRegisters(evseRegAmpsConfig, 1, b) return err } @@ -116,8 +117,10 @@ func (evse *SimpleEVSE) Enable(enable bool) error { func (evse *SimpleEVSE) MaxCurrent(current int64) error { b := []byte{0, byte(current)} - b, err := evse.conn.WriteMultipleRegisters(evseRegAmpsConfig, 1, b) - evse.log.TRACE.Printf("write max current (%d) %0X: %0 X", evseRegAmpsConfig, current, b) + _, err := evse.conn.WriteMultipleRegisters(evseRegAmpsConfig, 1, b) + if err == nil { + evse.current = current + } return err } diff --git a/util/modbus/modbus.go b/util/modbus/modbus.go index 75a1b2ef4..0dd44536d 100644 --- a/util/modbus/modbus.go +++ b/util/modbus/modbus.go @@ -5,6 +5,7 @@ import ( "fmt" "strconv" "strings" + "time" "github.com/volkszaehler/mbmd/meters" "github.com/volkszaehler/mbmd/meters/rs485" @@ -24,6 +25,14 @@ type Settings struct { type Connection struct { slaveID uint8 conn meters.Connection + delay time.Duration +} + +func (mb *Connection) prepare() { + mb.conn.Slave(mb.slaveID) + if mb.delay > 0 { + time.Sleep(mb.delay) + } } func (mb *Connection) handle(res []byte, err error) ([]byte, error) { @@ -33,6 +42,11 @@ func (mb *Connection) handle(res []byte, err error) ([]byte, error) { return res, err } +// Delay sets delay so use between subsequent modbus operations +func (mb *Connection) Delay(delay time.Duration) { + mb.delay = delay +} + // Logger sets logger implementation func (mb *Connection) Logger(logger meters.Logger) { mb.conn.Logger(logger) @@ -40,82 +54,79 @@ func (mb *Connection) Logger(logger meters.Logger) { // ReadCoils wraps the underlying implementation func (mb *Connection) ReadCoils(address, quantity uint16) ([]byte, error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().ReadCoils(address, quantity)) } // WriteSingleCoil wraps the underlying implementation func (mb *Connection) WriteSingleCoil(address, quantity uint16) ([]byte, error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().WriteSingleCoil(address, quantity)) } // ReadInputRegisters wraps the underlying implementation func (mb *Connection) ReadInputRegisters(address, quantity uint16) ([]byte, error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().ReadInputRegisters(address, quantity)) } // ReadHoldingRegisters wraps the underlying implementation func (mb *Connection) ReadHoldingRegisters(address, quantity uint16) ([]byte, error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().ReadHoldingRegisters(address, quantity)) } // WriteSingleRegister wraps the underlying implementation func (mb *Connection) WriteSingleRegister(address, value uint16) ([]byte, error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().WriteSingleRegister(address, value)) } // WriteMultipleRegisters wraps the underlying implementation func (mb *Connection) WriteMultipleRegisters(address, quantity uint16, value []byte) ([]byte, error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().WriteMultipleRegisters(address, quantity, value)) } // ReadDiscreteInputs wraps the underlying implementation func (mb *Connection) ReadDiscreteInputs(address, quantity uint16) (results []byte, err error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().ReadDiscreteInputs(address, quantity)) } // WriteMultipleCoils wraps the underlying implementation func (mb *Connection) WriteMultipleCoils(address, quantity uint16, value []byte) (results []byte, err error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().WriteMultipleCoils(address, quantity, value)) } // ReadWriteMultipleRegisters wraps the underlying implementation func (mb *Connection) ReadWriteMultipleRegisters(readAddress, readQuantity, writeAddress, writeQuantity uint16, value []byte) (results []byte, err error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().ReadWriteMultipleRegisters(readAddress, readQuantity, writeAddress, writeQuantity, value)) } // MaskWriteRegister wraps the underlying implementation func (mb *Connection) MaskWriteRegister(address, andMask, orMask uint16) (results []byte, err error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().MaskWriteRegister(address, andMask, orMask)) } // ReadFIFOQueue wraps the underlying implementation func (mb *Connection) ReadFIFOQueue(address uint16) (results []byte, err error) { - mb.conn.Slave(mb.slaveID) + mb.prepare() return mb.handle(mb.conn.ModbusClient().ReadFIFOQueue(address)) } -var connections map[string]meters.Connection +var connections = make(map[string]meters.Connection) func registeredConnection(key string, newConn meters.Connection) meters.Connection { - if connections == nil { - connections = make(map[string]meters.Connection) - } - if conn, ok := connections[key]; ok { return conn } connections[key] = newConn + return newConn }