Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cfos: add attached meter #15192

Merged
merged 2 commits into from
Aug 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 59 additions & 5 deletions charger/cfos.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ const (
cfosRegMaxCurrent = 8093
cfosRegEnable = 8094
cfosRegLastRfid = 8096
cfosRegMeter = 8112
cfosRegSolarEnabled = 8113

cfosRegMeterFlags = 8057
cfosRegEnergy = 8058 // 4 rw Aktiver Import [Wh]
cfosRegPower = 8062 // 2 r Aktive Leistung [W]
cfosRegCurrents = 8064 // 2 r Momentaner Strom L1 [0.1 A]
)

// CfosPowerBrain is an charger implementation for cFos PowerBrain wallboxes.
Expand All @@ -31,7 +37,7 @@ 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"
//go:generate go run ../cmd/tools/decorate.go -f decorateCfos -b *CfosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.PhaseCurrents,Currents,func() (float64, float64, float64, error)" -t "api.PhaseSwitcher,Phases1p3p,func(int) error"

// NewCfosPowerBrainFromConfig creates a cFos charger from generic config
func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) {
Expand Down Expand Up @@ -70,15 +76,28 @@ func NewCfosPowerBrain(uri string, id uint8) (api.Charger, error) {
conn: conn,
}

// decorate meter
var (
power func() (float64, error)
energy func() (float64, error)
currents func() (float64, float64, float64, error)
)
if b, err := wb.conn.ReadHoldingRegisters(cfosRegMeter, 1); err == nil && binary.BigEndian.Uint16(b) != 0 {
power = wb.currentPower
energy = wb.totalEnergy

if b, err := wb.conn.ReadHoldingRegisters(cfosRegMeterFlags, 1); err == nil && binary.BigEndian.Uint16(b) != 0 {
currents = wb.currents
}
}

// decorate phases
var phases1p3p func(int) error

b, err := wb.conn.ReadHoldingRegisters(cfosRegSolarEnabled, 1)
if err == nil && binary.BigEndian.Uint16(b)&(1<<8) != 0 {
if b, err := wb.conn.ReadHoldingRegisters(cfosRegSolarEnabled, 1); err == nil && binary.BigEndian.Uint16(b)&(1<<8) != 0 {
phases1p3p = wb.phases1p3p
}

return decorateCfos(wb, phases1p3p), nil
return decorateCfos(wb, power, energy, currents, phases1p3p), nil
}

// Status implements the api.Charger interface
Expand Down Expand Up @@ -141,6 +160,41 @@ func (wb *CfosPowerBrain) MaxCurrentMillis(current float64) error {
return err
}

// currentPower implements the api.Meter interface
func (wb *CfosPowerBrain) currentPower() (float64, error) {
b, err := wb.conn.ReadHoldingRegisters(cfosRegPower, 2)
if err != nil {
return 0, err
}

return float64(binary.BigEndian.Uint32(b)), nil
}

// totalEnergy implements the api.MeterEnergy interface
func (wb *CfosPowerBrain) totalEnergy() (float64, error) {
b, err := wb.conn.ReadHoldingRegisters(cfosRegEnergy, 4)
if err != nil {
return 0, err
}

return float64(binary.BigEndian.Uint64(b)) / 1e3, nil
}

// currents implements the api.PhaseCurrents interface
func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) {
b, err := wb.conn.ReadHoldingRegisters(cfosRegCurrents, 6)
if err != nil {
return 0, 0, 0, err
}

var res [3]float64
for i := range res {
res[i] = float64(binary.BigEndian.Uint32(b[4*i:])) / 10
}

return res[0], res[1], res[2], nil
}

// phases1p3p implements the api.PhaseSwitcher interface
func (wb *CfosPowerBrain) phases1p3p(phases int) error {
if phases == 3 {
Expand Down
252 changes: 249 additions & 3 deletions charger/cfos_decorators.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions templates/definition/charger/cfos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ capabilities: ["mA", "rfid", "1p3p"]
requirements:
description:
de: |
Der Zähler- falls vorhanden- muss separat als Ladezähler konfiguriert werden.
Ein evtl. vorhandener S0 Zähler 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.
S0 meters 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:
Expand Down