Skip to content

Commit

Permalink
Use register 1000 for enable/disable and add delay to support older e…
Browse files Browse the repository at this point in the history
…vse's (#380)
  • Loading branch information
andig committed Oct 13, 2020
1 parent 41e29f2 commit 8e61200
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 37 deletions.
45 changes: 24 additions & 21 deletions charger/simpleevse.go
Expand Up @@ -2,6 +2,7 @@ package charger

import (
"errors"
"time"

"github.com/andig/evcc/api"
"github.com/andig/evcc/util"
Expand All @@ -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() {
Expand Down Expand Up @@ -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
Expand All @@ -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
}
Expand All @@ -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
}
Expand All @@ -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
}
43 changes: 27 additions & 16 deletions util/modbus/modbus.go
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"strconv"
"strings"
"time"

"github.com/volkszaehler/mbmd/meters"
"github.com/volkszaehler/mbmd/meters/rs485"
Expand All @@ -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) {
Expand All @@ -33,89 +42,91 @@ 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)
}

// 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
}

Expand Down

0 comments on commit 8e61200

Please sign in to comment.