diff --git a/charger/cfos.go b/charger/cfos.go index 12f6a5fc0..0337d2d47 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -1,6 +1,7 @@ package charger import ( + "encoding/binary" "errors" "github.com/evcc-io/evcc/api" @@ -10,10 +11,12 @@ import ( ) const ( - cfosRegStatus = 8092 // Holding - cfosRegMaxCurrent = 8093 // Holding - cfosRegEnable = 8094 // Holding - cfosRegLastRfid = 8096 // Holding + cfosRegRelaySelect = 8087 // Holding + cfosRegStatus = 8092 // Holding + cfosRegMaxCurrent = 8093 // Holding + cfosRegEnable = 8094 // Holding + cfosRegLastRfid = 8096 // Holding + cfosRegSolarEnabled = 8113 // Holding ) // CfosPowerBrain is an charger implementation for cFos PowerBrain wallboxes. @@ -27,6 +30,8 @@ func init() { registry.Add("cfos", NewCfosPowerBrainFromConfig) } +// go:generate go run ../cmd/tools/decorate.go -f decorateCfos -b "*CfosPowerBrain" -r api.Charger -t "api.PhaseSwitcher,Phases1p3p,func(int) error" + // NewCfosPowerBrainFromConfig creates a cFos charger from generic config func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) { cc := modbus.TcpSettings{ @@ -41,7 +46,7 @@ func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, err } // NewCfosPowerBrain creates a cFos charger -func NewCfosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { +func NewCfosPowerBrain(uri string, id uint8) (api.Charger, error) { uri = util.DefaultPort(uri, 4701) conn, err := modbus.NewConnection(uri, "", "", 0, modbus.Tcp, id) @@ -64,7 +69,15 @@ func NewCfosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { conn: conn, } - return wb, nil + // decorate phases + var phases1p3p func(int) error + + b, err := wb.conn.ReadHoldingRegisters(cfosRegSolarEnabled, 1) + if err == nil && binary.BigEndian.Uint16(b) == 256 { + phases1p3p = wb.phases1p3p + } + + return decorateCfos(wb, phases1p3p), nil } // Status implements the api.Charger interface @@ -127,6 +140,15 @@ func (wb *CfosPowerBrain) MaxCurrentMillis(current float64) error { return err } +// phases1p3p implements the api.PhaseSwitcher interface +func (wb *CfosPowerBrain) phases1p3p(phases int) error { + if phases == 3 { + phases = 0 + } + _, err := wb.conn.WriteSingleRegister(cfosRegRelaySelect, uint16(phases)) + return err +} + var _ api.Identifier = (*CfosPowerBrain)(nil) // Identify implements the api.Identifier interface diff --git a/charger/cfos_decorators.go b/charger/cfos_decorators.go new file mode 100644 index 000000000..84b9cadcf --- /dev/null +++ b/charger/cfos_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 decorateCfos(base *CfosPowerBrain, phaseSwitcher func(int) error) api.Charger { + switch { + case phaseSwitcher == nil: + return base + + case phaseSwitcher != nil: + return &struct { + *CfosPowerBrain + api.PhaseSwitcher + }{ + CfosPowerBrain: base, + PhaseSwitcher: &decorateCfosPhaseSwitcherImpl{ + phaseSwitcher: phaseSwitcher, + }, + } + } + + return nil +} + +type decorateCfosPhaseSwitcherImpl struct { + phaseSwitcher func(int) error +} + +func (impl *decorateCfosPhaseSwitcherImpl) Phases1p3p(phases int) error { + return impl.phaseSwitcher(phases) +} diff --git a/templates/definition/charger/cfos.yaml b/templates/definition/charger/cfos.yaml index 341402104..6fa06090b 100644 --- a/templates/definition/charger/cfos.yaml +++ b/templates/definition/charger/cfos.yaml @@ -2,12 +2,16 @@ template: cfos products: - brand: cFos description: - generic: PowerBrain -capabilities: ["mA", "rfid"] + generic: Power Brain, Power Brain Solar +capabilities: ["mA", "rfid", "1p3p"] requirements: description: - de: Der Zähler- falls vorhanden- muss separat als Ladezähler konfiguriert werden. - en: The meter- if present- must be configured separately as charge meter. + de: | + Der Zähler- falls vorhanden- muss separat als Ladezähler konfiguriert werden. + Phasenumschaltung bietet nur die Solar-Variante und muss vom Anwender freigeschaltet werden. + en: | + The meter- if present- must be configured separately as charge meter. + Phase switching is only available with the Solar variant and must be enabled by the user. evcc: ["sponsorship"] params: - name: host