diff --git a/charger/pulsares.go b/charger/pulsares.go index b40261aa4..be66ed378 100644 --- a/charger/pulsares.go +++ b/charger/pulsares.go @@ -35,35 +35,48 @@ type Pulsares struct { } const ( + pulsaresRegSwVersion = 0x07 pulsaresRegConnectionStatus = 0x1b pulsaresRegChargeStatus = 0x1f pulsaresRegCurrent = 0x5d pulsaresRegBackup = 0x61 + pulsaresRegPhaseWake = 0x75 + pulsaresRegPhaseModule = 0x77 + pulsaresRegHwVersion = 0x7b + pulsaresRegPhases = 0x8b ) func init() { registry.Add("pulsares", NewPulsaresFromConfig) } +//go:generate go run ../cmd/tools/decorate.go -f decoratePulsares -b *Pulsares -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) error" + // NewPulsaresFromConfig creates a Pulsares charger from generic config func NewPulsaresFromConfig(other map[string]interface{}) (api.Charger, error) { - cc := struct { - modbus.Settings `mapstructure:",squash"` - }{ - Settings: modbus.Settings{ - ID: 1, - }, + cc := modbus.Settings{ + ID: 1, } if err := util.DecodeOther(other, &cc); err != nil { return nil, err } - return NewPulsares(cc.URI, cc.Device, cc.Comset, cc.Baudrate, modbus.ProtocolFromRTU(cc.RTU), cc.ID) + wb, err := NewPulsares(cc.URI, cc.Device, cc.Comset, cc.Baudrate, modbus.ProtocolFromRTU(cc.RTU), cc.ID) + if err != nil { + return nil, err + } + + var phases1p3p func(int) error + if wb.has1p3p() { + phases1p3p = wb.phases1p3p + } + + return decoratePulsares(wb, phases1p3p), nil } // NewPulsares creates Pulsares charger -func NewPulsares(uri, device, comset string, baudrate int, proto modbus.Protocol, slaveID uint8) (api.Charger, error) { +func NewPulsares(uri, device, comset string, baudrate int, proto modbus.Protocol, slaveID uint8) (*Pulsares, error) { conn, err := modbus.NewConnection(uri, device, comset, baudrate, proto, slaveID) if err != nil { return nil, err @@ -121,6 +134,22 @@ func (wb *Pulsares) heartbeat(timeout time.Duration) { } } +func (wb *Pulsares) has1p3p() bool { + if b, err := wb.conn.ReadHoldingRegisters(pulsaresRegSwVersion, 1); err != nil || binary.BigEndian.Uint16(b) < 4 { + return false + } + if b, err := wb.conn.ReadHoldingRegisters(pulsaresRegHwVersion, 1); err != nil || binary.BigEndian.Uint16(b) < 1 { + return false + } + if b, err := wb.conn.ReadHoldingRegisters(pulsaresRegPhaseModule, 1); err != nil || binary.BigEndian.Uint16(b) != 1 { + return false + } + if b, err := wb.conn.ReadHoldingRegisters(pulsaresRegPhaseWake, 1); err != nil || binary.BigEndian.Uint16(b) < 1 { + return false + } + return true +} + func (wb *Pulsares) setCurrent(current uint16) error { b := make([]byte, 2) binary.BigEndian.PutUint16(b, current) @@ -201,3 +230,15 @@ func (wb *Pulsares) MaxCurrentMillis(current float64) error { return err } + +// phases1p3p implements the api.PhaseSwitcher interface +func (wb *Pulsares) phases1p3p(phases int) error { + b := make([]byte, 2) + if phases == 3 { + binary.BigEndian.PutUint16(b, 2) + } + + _, err := wb.conn.WriteMultipleRegisters(pulsaresRegPhases, 1, b) + + return err +} diff --git a/charger/pulsares_decorators.go b/charger/pulsares_decorators.go new file mode 100644 index 000000000..9528fcc34 --- /dev/null +++ b/charger/pulsares_decorators.go @@ -0,0 +1,35 @@ +package charger + +// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT. + +import ( + "github.com/evcc-io/evcc/api" +) + +func decoratePulsares(base *Pulsares, phaseSwitcher func(int) error) api.Charger { + switch { + case phaseSwitcher == nil: + return base + + case phaseSwitcher != nil: + return &struct { + *Pulsares + api.PhaseSwitcher + }{ + Pulsares: base, + PhaseSwitcher: &decoratePulsaresPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + } + + return nil +} + +type decoratePulsaresPhaseSwitcherImpl struct { + phaseSwitcher func(int) error +} + +func (impl *decoratePulsaresPhaseSwitcherImpl) Phases1p3p(p0 int) error { + return impl.phaseSwitcher(p0) +}