diff --git a/charger/daheimladen-mb.go b/charger/daheimladen-mb.go index edb8a70e88..88aec65504 100644 --- a/charger/daheimladen-mb.go +++ b/charger/daheimladen-mb.go @@ -52,27 +52,38 @@ const ( dlRegChargeControl = 93 // Uint16 WR ENUM dlRegChargeCmd = 95 // Uint16 WR ENUM dlRegVoltages = 108 // 3xUint32 RO 0.1V + + // PRO only + dlRegPhaseSwitchState = 184 + dlRegPhaseSwitchControl = 186 ) func init() { registry.AddCtx("daheimladen-mb", NewDaheimLadenMBFromConfig) } +//go:generate go tool decorate -f decorateDaheimLaden -b *DaheimLadenMB -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) error" -t "api.PhaseGetter,GetPhases,func() (int, error)" + // NewDaheimLadenMBFromConfig creates a DaheimLadenMB charger from generic config func NewDaheimLadenMBFromConfig(ctx context.Context, other map[string]interface{}) (api.Charger, error) { - cc := modbus.TcpSettings{ - ID: 255, + cc := struct { + modbus.TcpSettings `mapstructure:",squash"` + Phases1p3p bool + }{ + TcpSettings: modbus.TcpSettings{ + ID: 255, + }, } if err := util.DecodeOther(other, &cc); err != nil { return nil, err } - return NewDaheimLadenMB(ctx, cc.URI, cc.ID) + return NewDaheimLadenMB(ctx, cc.URI, cc.ID, cc.Phases1p3p) } // NewDaheimLadenMB creates DaheimLadenMB charger -func NewDaheimLadenMB(ctx context.Context, uri string, id uint8) (api.Charger, error) { +func NewDaheimLadenMB(ctx context.Context, uri string, id uint8, phases bool) (api.Charger, error) { conn, err := modbus.NewConnection(ctx, uri, "", "", 0, modbus.Tcp, id) if err != nil { return nil, err @@ -105,7 +116,14 @@ func NewDaheimLadenMB(ctx context.Context, uri string, id uint8) (api.Charger, e go wb.heartbeat(ctx, time.Duration(u)*time.Second/2) } - return wb, err + var phases1p3p func(int) error + var phasesG func() (int, error) + if phases { + phases1p3p = wb.phases1p3p + phasesG = wb.getPhases + } + + return decorateDaheimLaden(wb, phases1p3p, phasesG), nil } func (wb *DaheimLadenMB) heartbeat(ctx context.Context, timeout time.Duration) { @@ -256,6 +274,25 @@ func (wb *DaheimLadenMB) Voltages() (float64, float64, float64, error) { return wb.getPhaseValues(dlRegVoltages) } +// phases1p3p implements the api.PhaseSwitcher interface +func (wb *DaheimLadenMB) phases1p3p(phases int) error { + b := make([]byte, 2) + binary.BigEndian.PutUint16(b, uint16(phases)) + + _, err := wb.conn.WriteMultipleRegisters(dlRegPhaseSwitchControl, 1, b) + return err +} + +// getPhases implements the api.PhaseGetter interface +func (wb *DaheimLadenMB) getPhases() (int, error) { + b, err := wb.conn.ReadHoldingRegisters(dlRegPhaseSwitchState, 1) + if err != nil { + return 0, err + } + + return int(binary.BigEndian.Uint16(b)), nil +} + var _ api.Diagnosis = (*DaheimLadenMB)(nil) // Diagnose implements the api.Diagnosis interface diff --git a/charger/daheimladen-mb_decorators.go b/charger/daheimladen-mb_decorators.go new file mode 100644 index 0000000000..616c08a143 --- /dev/null +++ b/charger/daheimladen-mb_decorators.go @@ -0,0 +1,58 @@ +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 decorateDaheimLaden(base *DaheimLadenMB, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger { + switch { + case phaseSwitcher == nil: + return base + + case phaseGetter == nil && phaseSwitcher != nil: + return &struct { + *DaheimLadenMB + api.PhaseSwitcher + }{ + DaheimLadenMB: base, + PhaseSwitcher: &decorateDaheimLadenPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + + case phaseGetter != nil && phaseSwitcher != nil: + return &struct { + *DaheimLadenMB + api.PhaseGetter + api.PhaseSwitcher + }{ + DaheimLadenMB: base, + PhaseGetter: &decorateDaheimLadenPhaseGetterImpl{ + phaseGetter: phaseGetter, + }, + PhaseSwitcher: &decorateDaheimLadenPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + } + + return nil +} + +type decorateDaheimLadenPhaseGetterImpl struct { + phaseGetter func() (int, error) +} + +func (impl *decorateDaheimLadenPhaseGetterImpl) GetPhases() (int, error) { + return impl.phaseGetter() +} + +type decorateDaheimLadenPhaseSwitcherImpl struct { + phaseSwitcher func(int) error +} + +func (impl *decorateDaheimLadenPhaseSwitcherImpl) Phases1p3p(p0 int) error { + return impl.phaseSwitcher(p0) +} diff --git a/templates/definition/charger/daheimladen-mb.yaml b/templates/definition/charger/daheimladen-mb.yaml index 85d32cb85a..a29a85aa64 100644 --- a/templates/definition/charger/daheimladen-mb.yaml +++ b/templates/definition/charger/daheimladen-mb.yaml @@ -2,7 +2,7 @@ template: daheimladen-mb products: - brand: DaheimLaden description: - generic: Wallbox + generic: Smart/Touch requirements: description: de: Die Wallbox muss über eine aktuelle Firmware mit Modbus-Unterstützung verfügen. In den Einstellungen muss "Nachladen" (Smart) bzw. "RSDA" (Touch) aktiviert sein diff --git a/templates/definition/charger/daheimladen-pro.yaml b/templates/definition/charger/daheimladen-pro.yaml new file mode 100644 index 0000000000..415855df28 --- /dev/null +++ b/templates/definition/charger/daheimladen-pro.yaml @@ -0,0 +1,14 @@ +template: daheimladen-pro +products: + - brand: DaheimLaden + description: + generic: Pro +capabilities: ["1p3p"] +params: + - name: host + - name: port + default: 502 +render: | + type: daheimladen-mb + uri: {{ .host }}:{{ .port }} + phases1p3p: true