From 4a87610a3faa159179799b055606a804201e16ed Mon Sep 17 00:00:00 2001 From: premultiply Date: Fri, 12 Mar 2021 12:23:48 +0100 Subject: [PATCH 1/9] wip --- charger/cfos.go | 181 +++++++++++++++++++++++++++++++++++++ charger/cfos_decorators.go | 137 ++++++++++++++++++++++++++++ 2 files changed, 318 insertions(+) create mode 100644 charger/cfos.go create mode 100644 charger/cfos_decorators.go diff --git a/charger/cfos.go b/charger/cfos.go new file mode 100644 index 0000000000..454c77abd8 --- /dev/null +++ b/charger/cfos.go @@ -0,0 +1,181 @@ +package charger + +import ( + "encoding/binary" + "errors" + "fmt" + + "github.com/andig/evcc/api" + "github.com/andig/evcc/util" + "github.com/andig/evcc/util/modbus" +) + +const ( + cfosRegStatus = 8092 // Input + cfosRegMaxCurrent = 8093 // Holding + cfosRegEnable = 8094 // Coil + + cfosRegPower = 8062 // power reading + cfosRegEnergy = 8058 // energy reading +) + +var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings + +// cFosPowerBrain is an api.ChargeController implementation for cFosPowerBrain wallboxes. +// It uses Modbus TCP to communicate with the wallbox at modbus client id 1 and power meters at id 2 and 3. +type cFosPowerBrain struct { + conn *modbus.Connection +} + +func init() { + registry.Add("cfos", NewcFosPowerBrainFromConfig) +} + +//go:generate go run ../cmd/tools/decorate.go -p charger -f decoratecFosPowerBrain -o cfos_decorators -b *cFosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.MeterCurrent,Currents,func() (float64, float64, float64, error)" + +// NewcFosPowerBrainFromConfig creates a cFos charger from generic config +func NewcFosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) { + cc := struct { + URI string + ID uint8 + Meter struct { + Power, Energy, Currents bool + } + }{ + URI: "192.168.2.2:4701", // default + ID: 1, // default + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + wb, err := NewcFosPowerBrain(cc.URI, cc.ID) + + var currentPower func() (float64, error) + if cc.Meter.Power { + currentPower = wb.currentPower + } + + var totalEnergy func() (float64, error) + if cc.Meter.Energy { + totalEnergy = wb.totalEnergy + } + + var currents func() (float64, float64, float64, error) + if cc.Meter.Currents { + currents = wb.currents + } + + return decoratecFosPowerBrain(wb, currentPower, totalEnergy, currents), err +} + +// NewcFosPowerBrain creates a cFos charger +func NewcFosPowerBrain(uri string, id uint8) (*cFosPowerBrain, error) { + conn, err := modbus.NewConnection(uri, "", "", 0, false, id) + if err != nil { + return nil, err + } + + log := util.NewLogger("cfos") + conn.Logger(log.TRACE) + + wb := &cFosPowerBrain{ + conn: conn, + } + + return wb, nil +} + +// Status implements the Charger.Status interface +func (wb *cFosPowerBrain) Status() (api.ChargeStatus, error) { + b, err := wb.conn.ReadHoldingRegisters(cfosRegStatus, 1) + if err != nil { + return api.StatusNone, err + } + + switch b[0] { + case 0: // warten + return api.StatusA, nil + case 1: // Fahrzeug erkannt + return api.StatusB, nil + case 2: // laden + return api.StatusC, nil + case 3: // laden mit Kühlung + return api.StatusD, nil + case 4: // kein Strom + return api.StatusE, nil + case 5: // Fehler + return api.StatusF, nil + default: + return api.StatusNone, errors.New("invalid response") + } +} + +// Enabled implements the Charger.Enabled interface +func (wb *cFosPowerBrain) Enabled() (bool, error) { + b, err := wb.conn.ReadHoldingRegisters(cfosRegEnable, 1) + if err != nil { + return false, err + } + + return b[0] == 1, nil +} + +// Enable implements the Charger.Enable interface +func (wb *cFosPowerBrain) Enable(enable bool) error { + var u uint16 + if enable { + u = 1 + } + + _, err := wb.conn.WriteSingleCoil(cfosRegEnable, u) + + return err +} + +// MaxCurrent implements the Charger.MaxCurrent interface +func (wb *cFosPowerBrain) MaxCurrent(current int64) error { + if current < 6 { + return fmt.Errorf("invalid current %d", current) + } + + _, err := wb.conn.WriteSingleRegister(cfosRegMaxCurrent, uint16(current*10)) + + return err +} + +// CurrentPower implements the Meter.CurrentPower 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)) / 10, err +} + +// totalEnergy implements the Meter.TotalEnergy 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)), err +} + +// currents implements the Meter.Currents interface +func (wb *cFosPowerBrain) currents() (float64, float64, float64, error) { + var currents []float64 + for _, regCurrent := range cfosRegCurrents { + b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) + if err != nil { + return 0, 0, 0, err + } + + currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) + } + + return currents[0], currents[1], currents[2], nil +} diff --git a/charger/cfos_decorators.go b/charger/cfos_decorators.go new file mode 100644 index 0000000000..ca4e79cbb0 --- /dev/null +++ b/charger/cfos_decorators.go @@ -0,0 +1,137 @@ +package charger + +// Code generated by github.com/andig/cmd/tools/decorate.go. DO NOT EDIT. + +import ( + "github.com/andig/evcc/api" +) + +func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error), meterCurrent func() (float64, float64, float64, error)) api.Charger { + switch { + case meter == nil && meterCurrent == nil && meterEnergy == nil: + return base + + case meter != nil && meterCurrent == nil && meterEnergy == nil: + return &struct { + *cFosPowerBrain + api.Meter + }{ + cFosPowerBrain: base, + Meter: &decoratecFosPowerBrainMeterImpl{ + meter: meter, + }, + } + + case meter == nil && meterCurrent == nil && meterEnergy != nil: + return &struct { + *cFosPowerBrain + api.MeterEnergy + }{ + cFosPowerBrain: base, + MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case meter != nil && meterCurrent == nil && meterEnergy != nil: + return &struct { + *cFosPowerBrain + api.Meter + api.MeterEnergy + }{ + cFosPowerBrain: base, + Meter: &decoratecFosPowerBrainMeterImpl{ + meter: meter, + }, + MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case meter == nil && meterCurrent != nil && meterEnergy == nil: + return &struct { + *cFosPowerBrain + api.MeterCurrent + }{ + cFosPowerBrain: base, + MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ + meterCurrent: meterCurrent, + }, + } + + case meter != nil && meterCurrent != nil && meterEnergy == nil: + return &struct { + *cFosPowerBrain + api.Meter + api.MeterCurrent + }{ + cFosPowerBrain: base, + Meter: &decoratecFosPowerBrainMeterImpl{ + meter: meter, + }, + MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ + meterCurrent: meterCurrent, + }, + } + + case meter == nil && meterCurrent != nil && meterEnergy != nil: + return &struct { + *cFosPowerBrain + api.MeterCurrent + api.MeterEnergy + }{ + cFosPowerBrain: base, + MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ + meterCurrent: meterCurrent, + }, + MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case meter != nil && meterCurrent != nil && meterEnergy != nil: + return &struct { + *cFosPowerBrain + api.Meter + api.MeterCurrent + api.MeterEnergy + }{ + cFosPowerBrain: base, + Meter: &decoratecFosPowerBrainMeterImpl{ + meter: meter, + }, + MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ + meterCurrent: meterCurrent, + }, + MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + } + + return nil +} + +type decoratecFosPowerBrainMeterImpl struct { + meter func() (float64, error) +} + +func (impl *decoratecFosPowerBrainMeterImpl) CurrentPower() (float64, error) { + return impl.meter() +} + +type decoratecFosPowerBrainMeterCurrentImpl struct { + meterCurrent func() (float64, float64, float64, error) +} + +func (impl *decoratecFosPowerBrainMeterCurrentImpl) Currents() (float64, float64, float64, error) { + return impl.meterCurrent() +} + +type decoratecFosPowerBrainMeterEnergyImpl struct { + meterEnergy func() (float64, error) +} + +func (impl *decoratecFosPowerBrainMeterEnergyImpl) TotalEnergy() (float64, error) { + return impl.meterEnergy() +} From 145e5a23eb13b111837c6bfd83f904c8ac48f02f Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 11:07:56 +0200 Subject: [PATCH 2/9] wip --- charger/cfos.go | 60 ++++++++++++++++++++------------------ charger/cfos_decorators.go | 34 ++++++++++----------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/charger/cfos.go b/charger/cfos.go index 454c77abd8..8da4402a98 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -3,11 +3,10 @@ package charger import ( "encoding/binary" "errors" - "fmt" - "github.com/andig/evcc/api" - "github.com/andig/evcc/util" - "github.com/andig/evcc/util/modbus" + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/modbus" ) const ( @@ -21,20 +20,20 @@ const ( var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings -// cFosPowerBrain is an api.ChargeController implementation for cFosPowerBrain wallboxes. +// CfosPowerBrain is an api.ChargeController implementation for CfosPowerBrain wallboxes. // It uses Modbus TCP to communicate with the wallbox at modbus client id 1 and power meters at id 2 and 3. -type cFosPowerBrain struct { +type CfosPowerBrain struct { conn *modbus.Connection } func init() { - registry.Add("cfos", NewcFosPowerBrainFromConfig) + registry.Add("cfos", NewCfosPowerBrainFromConfig) } -//go:generate go run ../cmd/tools/decorate.go -p charger -f decoratecFosPowerBrain -o cfos_decorators -b *cFosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.MeterCurrent,Currents,func() (float64, float64, float64, error)" +//go:generate go run ../cmd/tools/decorate.go -f decoratecFosPowerBrain -o cfos_decorators -b *CfosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.MeterCurrent,Currents,func() (float64, float64, float64, error)" -// NewcFosPowerBrainFromConfig creates a cFos charger from generic config -func NewcFosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) { +// NewCfosPowerBrainFromConfig creates a cFos charger from generic config +func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) { cc := struct { URI string ID uint8 @@ -42,8 +41,7 @@ func NewcFosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, err Power, Energy, Currents bool } }{ - URI: "192.168.2.2:4701", // default - ID: 1, // default + ID: 1, } if err := util.DecodeOther(other, &cc); err != nil { @@ -71,8 +69,10 @@ func NewcFosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, err } // NewcFosPowerBrain creates a cFos charger -func NewcFosPowerBrain(uri string, id uint8) (*cFosPowerBrain, error) { - conn, err := modbus.NewConnection(uri, "", "", 0, false, id) +func NewcFosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { + uri = util.DefaultPort(uri, 4701) + + conn, err := modbus.NewConnection(uri, "", "", 0, modbus.RtuFormat, id) if err != nil { return nil, err } @@ -80,7 +80,7 @@ func NewcFosPowerBrain(uri string, id uint8) (*cFosPowerBrain, error) { log := util.NewLogger("cfos") conn.Logger(log.TRACE) - wb := &cFosPowerBrain{ + wb := &CfosPowerBrain{ conn: conn, } @@ -88,7 +88,7 @@ func NewcFosPowerBrain(uri string, id uint8) (*cFosPowerBrain, error) { } // Status implements the Charger.Status interface -func (wb *cFosPowerBrain) Status() (api.ChargeStatus, error) { +func (wb *CfosPowerBrain) Status() (api.ChargeStatus, error) { b, err := wb.conn.ReadHoldingRegisters(cfosRegStatus, 1) if err != nil { return api.StatusNone, err @@ -113,7 +113,7 @@ func (wb *cFosPowerBrain) Status() (api.ChargeStatus, error) { } // Enabled implements the Charger.Enabled interface -func (wb *cFosPowerBrain) Enabled() (bool, error) { +func (wb *CfosPowerBrain) Enabled() (bool, error) { b, err := wb.conn.ReadHoldingRegisters(cfosRegEnable, 1) if err != nil { return false, err @@ -123,7 +123,7 @@ func (wb *cFosPowerBrain) Enabled() (bool, error) { } // Enable implements the Charger.Enable interface -func (wb *cFosPowerBrain) Enable(enable bool) error { +func (wb *CfosPowerBrain) Enable(enable bool) error { var u uint16 if enable { u = 1 @@ -135,18 +135,20 @@ func (wb *cFosPowerBrain) Enable(enable bool) error { } // MaxCurrent implements the Charger.MaxCurrent interface -func (wb *cFosPowerBrain) MaxCurrent(current int64) error { - if current < 6 { - return fmt.Errorf("invalid current %d", current) - } +func (wb *CfosPowerBrain) MaxCurrent(current int64) error { + return wb.MaxCurrentMillis(float64(current)) +} - _, err := wb.conn.WriteSingleRegister(cfosRegMaxCurrent, uint16(current*10)) +var _ api.ChargerEx = (*CfosPowerBrain)(nil) +// MaxCurrentMillis implements the api.ChargerEx interface +func (wb *CfosPowerBrain) MaxCurrentMillis(current float64) error { + _, err := wb.conn.WriteSingleRegister(cfosRegMaxCurrent, uint16(current*10)) return err } -// CurrentPower implements the Meter.CurrentPower interface -func (wb *cFosPowerBrain) currentPower() (float64, error) { +// 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 @@ -155,8 +157,8 @@ func (wb *cFosPowerBrain) currentPower() (float64, error) { return float64(binary.BigEndian.Uint32(b)) / 10, err } -// totalEnergy implements the Meter.TotalEnergy interface -func (wb *cFosPowerBrain) totalEnergy() (float64, error) { +// 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 @@ -165,8 +167,8 @@ func (wb *cFosPowerBrain) totalEnergy() (float64, error) { return float64(binary.BigEndian.Uint64(b)), err } -// currents implements the Meter.Currents interface -func (wb *cFosPowerBrain) currents() (float64, float64, float64, error) { +// currents implements the api.MeterCurrent interface +func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) { var currents []float64 for _, regCurrent := range cfosRegCurrents { b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) diff --git a/charger/cfos_decorators.go b/charger/cfos_decorators.go index ca4e79cbb0..30ecc9e5c2 100644 --- a/charger/cfos_decorators.go +++ b/charger/cfos_decorators.go @@ -1,22 +1,22 @@ package charger -// Code generated by github.com/andig/cmd/tools/decorate.go. DO NOT EDIT. +// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT. import ( - "github.com/andig/evcc/api" + "github.com/evcc-io/evcc/api" ) -func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error), meterCurrent func() (float64, float64, float64, error)) api.Charger { +func decoratecFosPowerBrain(base *CfosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error), meterCurrent func() (float64, float64, float64, error)) api.Charger { switch { case meter == nil && meterCurrent == nil && meterEnergy == nil: return base case meter != nil && meterCurrent == nil && meterEnergy == nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.Meter }{ - cFosPowerBrain: base, + CfosPowerBrain: base, Meter: &decoratecFosPowerBrainMeterImpl{ meter: meter, }, @@ -24,10 +24,10 @@ func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), case meter == nil && meterCurrent == nil && meterEnergy != nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.MeterEnergy }{ - cFosPowerBrain: base, + CfosPowerBrain: base, MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ meterEnergy: meterEnergy, }, @@ -35,11 +35,11 @@ func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), case meter != nil && meterCurrent == nil && meterEnergy != nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.Meter api.MeterEnergy }{ - cFosPowerBrain: base, + CfosPowerBrain: base, Meter: &decoratecFosPowerBrainMeterImpl{ meter: meter, }, @@ -50,10 +50,10 @@ func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), case meter == nil && meterCurrent != nil && meterEnergy == nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.MeterCurrent }{ - cFosPowerBrain: base, + CfosPowerBrain: base, MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ meterCurrent: meterCurrent, }, @@ -61,11 +61,11 @@ func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), case meter != nil && meterCurrent != nil && meterEnergy == nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.Meter api.MeterCurrent }{ - cFosPowerBrain: base, + CfosPowerBrain: base, Meter: &decoratecFosPowerBrainMeterImpl{ meter: meter, }, @@ -76,11 +76,11 @@ func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), case meter == nil && meterCurrent != nil && meterEnergy != nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.MeterCurrent api.MeterEnergy }{ - cFosPowerBrain: base, + CfosPowerBrain: base, MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ meterCurrent: meterCurrent, }, @@ -91,12 +91,12 @@ func decoratecFosPowerBrain(base *cFosPowerBrain, meter func() (float64, error), case meter != nil && meterCurrent != nil && meterEnergy != nil: return &struct { - *cFosPowerBrain + *CfosPowerBrain api.Meter api.MeterCurrent api.MeterEnergy }{ - cFosPowerBrain: base, + CfosPowerBrain: base, Meter: &decoratecFosPowerBrainMeterImpl{ meter: meter, }, From 08ed6a2370196da43da77fb65eac68a17cbb0d5d Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 11:09:48 +0200 Subject: [PATCH 3/9] tcp instead of rtu --- charger/cfos.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charger/cfos.go b/charger/cfos.go index 8da4402a98..091c58fae8 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -72,7 +72,7 @@ func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, err func NewcFosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { uri = util.DefaultPort(uri, 4701) - conn, err := modbus.NewConnection(uri, "", "", 0, modbus.RtuFormat, id) + conn, err := modbus.NewConnection(uri, "", "", 0, modbus.TcpFormat, id) if err != nil { return nil, err } From e8a33e2205241d98dac7d194a983e8b503bc9df1 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 14:17:06 +0200 Subject: [PATCH 4/9] wip --- charger/cfos.go | 89 ++++++++++++++++++++++-------------- charger/cfos_decorators.go | 94 ++++++-------------------------------- 2 files changed, 67 insertions(+), 116 deletions(-) diff --git a/charger/cfos.go b/charger/cfos.go index 091c58fae8..c3aef0ed8c 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -13,15 +13,16 @@ const ( cfosRegStatus = 8092 // Input cfosRegMaxCurrent = 8093 // Holding cfosRegEnable = 8094 // Coil - - cfosRegPower = 8062 // power reading - cfosRegEnergy = 8058 // energy reading + cfosRegEnergy = 8058 // energy reading + cfosRegPower = 8062 // power reading + cfosRegMeter = 8096 // has meter ) var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings -// CfosPowerBrain is an api.ChargeController implementation for CfosPowerBrain wallboxes. -// It uses Modbus TCP to communicate with the wallbox at modbus client id 1 and power meters at id 2 and 3. +// CfosPowerBrain is an api.ChargeController implementation for cFos PowerBrain wallboxes. +// It uses Modbus TCP to communicate at modbus client id 1 and power meters at id 2 and 3. +// https://www.cfos-emobility.de/en-gb/cfos-power-brain/modbus-registers.htm type CfosPowerBrain struct { conn *modbus.Connection } @@ -30,7 +31,7 @@ func init() { registry.Add("cfos", NewCfosPowerBrainFromConfig) } -//go:generate go run ../cmd/tools/decorate.go -f decoratecFosPowerBrain -o cfos_decorators -b *CfosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.MeterCurrent,Currents,func() (float64, float64, float64, error)" +//go:generate go run ../cmd/tools/decorate.go -f decorateCfosPowerBrain -o cfos_decorators -b *CfosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" // NewCfosPowerBrainFromConfig creates a cFos charger from generic config func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) { @@ -48,28 +49,37 @@ func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, err return nil, err } - wb, err := NewcFosPowerBrain(cc.URI, cc.ID) - - var currentPower func() (float64, error) - if cc.Meter.Power { - currentPower = wb.currentPower - } - - var totalEnergy func() (float64, error) - if cc.Meter.Energy { - totalEnergy = wb.totalEnergy + wb, err := NewCfosPowerBrain(cc.URI, cc.ID) + if err != nil { + return wb, err } - var currents func() (float64, float64, float64, error) - if cc.Meter.Currents { - currents = wb.currents + ok, err := wb.hasMeter() + if ok && err == nil { + // var currentPower func() (float64, error) + // if cc.Meter.Power { + // currentPower = wb.currentPower + // } + + // var totalEnergy func() (float64, error) + // if cc.Meter.Energy { + // totalEnergy = wb.totalEnergy + // } + + // var currents func() (float64, float64, float64, error) + // if cc.Meter.Currents { + // currents = wb.currents + // } + + // return decorateCfosPowerBrain(wb, wb.currentPower, wb.totalEnergy, wb.currents), err + return decorateCfosPowerBrain(wb, wb.currentPower, wb.totalEnergy), err } - return decoratecFosPowerBrain(wb, currentPower, totalEnergy, currents), err + return wb, err } -// NewcFosPowerBrain creates a cFos charger -func NewcFosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { +// NewCfosPowerBrain creates a cFos charger +func NewCfosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { uri = util.DefaultPort(uri, 4701) conn, err := modbus.NewConnection(uri, "", "", 0, modbus.TcpFormat, id) @@ -87,6 +97,14 @@ func NewcFosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { return wb, nil } +func (wb *CfosPowerBrain) hasMeter() (bool, error) { + b, err := wb.conn.ReadHoldingRegisters(cfosRegMeter, 1) + if err != nil { + return false, err + } + return b[0] == 1, nil +} + // Status implements the Charger.Status interface func (wb *CfosPowerBrain) Status() (api.ChargeStatus, error) { b, err := wb.conn.ReadHoldingRegisters(cfosRegStatus, 1) @@ -168,16 +186,17 @@ func (wb *CfosPowerBrain) totalEnergy() (float64, error) { } // currents implements the api.MeterCurrent interface -func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) { - var currents []float64 - for _, regCurrent := range cfosRegCurrents { - b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) - if err != nil { - return 0, 0, 0, err - } - - currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) - } - - return currents[0], currents[1], currents[2], nil -} +// not used as currents are only calculated from S0 meter +// func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) { +// var currents []float64 +// for _, regCurrent := range cfosRegCurrents { +// b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) +// if err != nil { +// return 0, 0, 0, err +// } + +// currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) +// } + +// return currents[0], currents[1], currents[2], nil +// } diff --git a/charger/cfos_decorators.go b/charger/cfos_decorators.go index 30ecc9e5c2..e3e7c5fb3c 100644 --- a/charger/cfos_decorators.go +++ b/charger/cfos_decorators.go @@ -6,104 +6,44 @@ import ( "github.com/evcc-io/evcc/api" ) -func decoratecFosPowerBrain(base *CfosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error), meterCurrent func() (float64, float64, float64, error)) api.Charger { +func decorateCfosPowerBrain(base *CfosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error)) api.Charger { switch { - case meter == nil && meterCurrent == nil && meterEnergy == nil: + case meter == nil && meterEnergy == nil: return base - case meter != nil && meterCurrent == nil && meterEnergy == nil: + case meter != nil && meterEnergy == nil: return &struct { *CfosPowerBrain api.Meter }{ CfosPowerBrain: base, - Meter: &decoratecFosPowerBrainMeterImpl{ + Meter: &decorateCfosPowerBrainMeterImpl{ meter: meter, }, } - case meter == nil && meterCurrent == nil && meterEnergy != nil: + case meter == nil && meterEnergy != nil: return &struct { *CfosPowerBrain api.MeterEnergy }{ CfosPowerBrain: base, - MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ + MeterEnergy: &decorateCfosPowerBrainMeterEnergyImpl{ meterEnergy: meterEnergy, }, } - case meter != nil && meterCurrent == nil && meterEnergy != nil: + case meter != nil && meterEnergy != nil: return &struct { *CfosPowerBrain api.Meter api.MeterEnergy }{ CfosPowerBrain: base, - Meter: &decoratecFosPowerBrainMeterImpl{ + Meter: &decorateCfosPowerBrainMeterImpl{ meter: meter, }, - MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ - meterEnergy: meterEnergy, - }, - } - - case meter == nil && meterCurrent != nil && meterEnergy == nil: - return &struct { - *CfosPowerBrain - api.MeterCurrent - }{ - CfosPowerBrain: base, - MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ - meterCurrent: meterCurrent, - }, - } - - case meter != nil && meterCurrent != nil && meterEnergy == nil: - return &struct { - *CfosPowerBrain - api.Meter - api.MeterCurrent - }{ - CfosPowerBrain: base, - Meter: &decoratecFosPowerBrainMeterImpl{ - meter: meter, - }, - MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ - meterCurrent: meterCurrent, - }, - } - - case meter == nil && meterCurrent != nil && meterEnergy != nil: - return &struct { - *CfosPowerBrain - api.MeterCurrent - api.MeterEnergy - }{ - CfosPowerBrain: base, - MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ - meterCurrent: meterCurrent, - }, - MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ - meterEnergy: meterEnergy, - }, - } - - case meter != nil && meterCurrent != nil && meterEnergy != nil: - return &struct { - *CfosPowerBrain - api.Meter - api.MeterCurrent - api.MeterEnergy - }{ - CfosPowerBrain: base, - Meter: &decoratecFosPowerBrainMeterImpl{ - meter: meter, - }, - MeterCurrent: &decoratecFosPowerBrainMeterCurrentImpl{ - meterCurrent: meterCurrent, - }, - MeterEnergy: &decoratecFosPowerBrainMeterEnergyImpl{ + MeterEnergy: &decorateCfosPowerBrainMeterEnergyImpl{ meterEnergy: meterEnergy, }, } @@ -112,26 +52,18 @@ func decoratecFosPowerBrain(base *CfosPowerBrain, meter func() (float64, error), return nil } -type decoratecFosPowerBrainMeterImpl struct { +type decorateCfosPowerBrainMeterImpl struct { meter func() (float64, error) } -func (impl *decoratecFosPowerBrainMeterImpl) CurrentPower() (float64, error) { +func (impl *decorateCfosPowerBrainMeterImpl) CurrentPower() (float64, error) { return impl.meter() } -type decoratecFosPowerBrainMeterCurrentImpl struct { - meterCurrent func() (float64, float64, float64, error) -} - -func (impl *decoratecFosPowerBrainMeterCurrentImpl) Currents() (float64, float64, float64, error) { - return impl.meterCurrent() -} - -type decoratecFosPowerBrainMeterEnergyImpl struct { +type decorateCfosPowerBrainMeterEnergyImpl struct { meterEnergy func() (float64, error) } -func (impl *decoratecFosPowerBrainMeterEnergyImpl) TotalEnergy() (float64, error) { +func (impl *decorateCfosPowerBrainMeterEnergyImpl) TotalEnergy() (float64, error) { return impl.meterEnergy() } From 9b261f3186098c93645e12166f2e70281c75cca5 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 14:41:57 +0200 Subject: [PATCH 5/9] Split meter and charger --- charger/cfos.go | 76 ++-------------------------- charger/cfos_decorators.go | 69 ------------------------- meter/cfos.go | 100 +++++++++++++++++++++++++++++++++++++ 3 files changed, 105 insertions(+), 140 deletions(-) delete mode 100644 charger/cfos_decorators.go create mode 100644 meter/cfos.go diff --git a/charger/cfos.go b/charger/cfos.go index c3aef0ed8c..4869fa9892 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -1,8 +1,8 @@ package charger import ( - "encoding/binary" "errors" + "fmt" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" @@ -31,16 +31,11 @@ func init() { registry.Add("cfos", NewCfosPowerBrainFromConfig) } -//go:generate go run ../cmd/tools/decorate.go -f decorateCfosPowerBrain -o cfos_decorators -b *CfosPowerBrain -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" - // NewCfosPowerBrainFromConfig creates a cFos charger from generic config func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, error) { cc := struct { - URI string - ID uint8 - Meter struct { - Power, Energy, Currents bool - } + URI string + ID uint8 }{ ID: 1, } @@ -49,33 +44,7 @@ func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Charger, err return nil, err } - wb, err := NewCfosPowerBrain(cc.URI, cc.ID) - if err != nil { - return wb, err - } - - ok, err := wb.hasMeter() - if ok && err == nil { - // var currentPower func() (float64, error) - // if cc.Meter.Power { - // currentPower = wb.currentPower - // } - - // var totalEnergy func() (float64, error) - // if cc.Meter.Energy { - // totalEnergy = wb.totalEnergy - // } - - // var currents func() (float64, float64, float64, error) - // if cc.Meter.Currents { - // currents = wb.currents - // } - - // return decorateCfosPowerBrain(wb, wb.currentPower, wb.totalEnergy, wb.currents), err - return decorateCfosPowerBrain(wb, wb.currentPower, wb.totalEnergy), err - } - - return wb, err + return NewCfosPowerBrain(cc.URI, cc.ID) } // NewCfosPowerBrain creates a cFos charger @@ -102,6 +71,7 @@ func (wb *CfosPowerBrain) hasMeter() (bool, error) { if err != nil { return false, err } + fmt.Printf("hasMeter % x\n", b) return b[0] == 1, nil } @@ -164,39 +134,3 @@ func (wb *CfosPowerBrain) MaxCurrentMillis(current float64) error { _, err := wb.conn.WriteSingleRegister(cfosRegMaxCurrent, uint16(current*10)) 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)) / 10, err -} - -// 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)), err -} - -// currents implements the api.MeterCurrent interface -// not used as currents are only calculated from S0 meter -// func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) { -// var currents []float64 -// for _, regCurrent := range cfosRegCurrents { -// b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) -// if err != nil { -// return 0, 0, 0, err -// } - -// currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) -// } - -// return currents[0], currents[1], currents[2], nil -// } diff --git a/charger/cfos_decorators.go b/charger/cfos_decorators.go deleted file mode 100644 index e3e7c5fb3c..0000000000 --- a/charger/cfos_decorators.go +++ /dev/null @@ -1,69 +0,0 @@ -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 decorateCfosPowerBrain(base *CfosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error)) api.Charger { - switch { - case meter == nil && meterEnergy == nil: - return base - - case meter != nil && meterEnergy == nil: - return &struct { - *CfosPowerBrain - api.Meter - }{ - CfosPowerBrain: base, - Meter: &decorateCfosPowerBrainMeterImpl{ - meter: meter, - }, - } - - case meter == nil && meterEnergy != nil: - return &struct { - *CfosPowerBrain - api.MeterEnergy - }{ - CfosPowerBrain: base, - MeterEnergy: &decorateCfosPowerBrainMeterEnergyImpl{ - meterEnergy: meterEnergy, - }, - } - - case meter != nil && meterEnergy != nil: - return &struct { - *CfosPowerBrain - api.Meter - api.MeterEnergy - }{ - CfosPowerBrain: base, - Meter: &decorateCfosPowerBrainMeterImpl{ - meter: meter, - }, - MeterEnergy: &decorateCfosPowerBrainMeterEnergyImpl{ - meterEnergy: meterEnergy, - }, - } - } - - return nil -} - -type decorateCfosPowerBrainMeterImpl struct { - meter func() (float64, error) -} - -func (impl *decorateCfosPowerBrainMeterImpl) CurrentPower() (float64, error) { - return impl.meter() -} - -type decorateCfosPowerBrainMeterEnergyImpl struct { - meterEnergy func() (float64, error) -} - -func (impl *decorateCfosPowerBrainMeterEnergyImpl) TotalEnergy() (float64, error) { - return impl.meterEnergy() -} diff --git a/meter/cfos.go b/meter/cfos.go new file mode 100644 index 0000000000..86362bc243 --- /dev/null +++ b/meter/cfos.go @@ -0,0 +1,100 @@ +package meter + +import ( + "encoding/binary" + + "github.com/evcc-io/evcc/api" + "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/modbus" +) + +const ( + cfosRegStatus = 8092 // Input + cfosRegMaxCurrent = 8093 // Holding + cfosRegEnable = 8094 // Coil + cfosRegEnergy = 8058 // energy reading + cfosRegPower = 8062 // power reading + cfosRegMeter = 8096 // has meter +) + +var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings + +// CfosPowerBrain is an api.ChargeController implementation for cFos PowerBrain wallboxes. +// It uses Modbus TCP to communicate at modbus client id 1 and power meters at id 2 and 3. +// https://www.cfos-emobility.de/en-gb/cfos-power-brain/modbus-registers.htm +type CfosPowerBrain struct { + conn *modbus.Connection +} + +func init() { + registry.Add("cfos", NewCfosPowerBrainFromConfig) +} + +// NewCfosPowerBrainFromConfig creates a cFos meter from generic config +func NewCfosPowerBrainFromConfig(other map[string]interface{}) (api.Meter, error) { + cc := struct { + URI string + ID uint8 + }{} + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + return NewCfosPowerBrain(cc.URI, cc.ID) +} + +// NewCfosPowerBrain creates a cFos meter +func NewCfosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { + conn, err := modbus.NewConnection(uri, "", "", 0, modbus.TcpFormat, id) + if err != nil { + return nil, err + } + + log := util.NewLogger("cfos") + conn.Logger(log.TRACE) + + wb := &CfosPowerBrain{ + conn: conn, + } + + return wb, nil +} + +// 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)) / 10, err +} + +var _ api.MeterEnergy = (*CfosPowerBrain)(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)), err +} + +// currents implements the api.MeterCurrent interface +// not used as currents are only calculated from S0 meter +// func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) { +// var currents []float64 +// for _, regCurrent := range cfosRegCurrents { +// b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) +// if err != nil { +// return 0, 0, 0, err +// } + +// currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) +// } + +// return currents[0], currents[1], currents[2], nil +// } From 56af6d77766ab47c67e7f97e3996b688239ae3e3 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 14:43:35 +0200 Subject: [PATCH 6/9] wip --- charger/cfos.go | 2 +- meter/cfos.go | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/charger/cfos.go b/charger/cfos.go index 4869fa9892..6f6ccee509 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -20,7 +20,7 @@ const ( var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings -// CfosPowerBrain is an api.ChargeController implementation for cFos PowerBrain wallboxes. +// CfosPowerBrain is an charger implementation for cFos PowerBrain wallboxes. // It uses Modbus TCP to communicate at modbus client id 1 and power meters at id 2 and 3. // https://www.cfos-emobility.de/en-gb/cfos-power-brain/modbus-registers.htm type CfosPowerBrain struct { diff --git a/meter/cfos.go b/meter/cfos.go index 86362bc243..3ed885369f 100644 --- a/meter/cfos.go +++ b/meter/cfos.go @@ -19,7 +19,7 @@ const ( var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings -// CfosPowerBrain is an api.ChargeController implementation for cFos PowerBrain wallboxes. +// CfosPowerBrain is a meter implementation for cFos PowerBrain wallboxes. // It uses Modbus TCP to communicate at modbus client id 1 and power meters at id 2 and 3. // https://www.cfos-emobility.de/en-gb/cfos-power-brain/modbus-registers.htm type CfosPowerBrain struct { @@ -83,18 +83,19 @@ func (wb *CfosPowerBrain) TotalEnergy() (float64, error) { return float64(binary.BigEndian.Uint64(b)), err } -// currents implements the api.MeterCurrent interface -// not used as currents are only calculated from S0 meter -// func (wb *CfosPowerBrain) currents() (float64, float64, float64, error) { -// var currents []float64 -// for _, regCurrent := range cfosRegCurrents { -// b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) -// if err != nil { -// return 0, 0, 0, err -// } - -// currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) -// } - -// return currents[0], currents[1], currents[2], nil -// } +var _ api.MeterCurrent = (*CfosPowerBrain)(nil) + +// Currents implements the api.MeterCurrent interface +func (wb *CfosPowerBrain) Currents() (float64, float64, float64, error) { + var currents []float64 + for _, regCurrent := range cfosRegCurrents { + b, err := wb.conn.ReadHoldingRegisters(regCurrent, 2) + if err != nil { + return 0, 0, 0, err + } + + currents = append(currents, float64(binary.BigEndian.Uint32(b))/10) + } + + return currents[0], currents[1], currents[2], nil +} From 9502402162a39f20f2a53c82bbd5a3abd7353d9b Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 14:48:47 +0200 Subject: [PATCH 7/9] Add to readme --- README.md | 2 +- charger/cfos.go | 5 +++++ meter/cfos.go | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 14984ffc9f..26ff5b816b 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ EVCC is an extensible EV Charge Controller with PV integration implemented in [G - simple and clean user interface - multiple [chargers](#charger): - Open source: [openWB](https://openwb.de/), [EVSEWifi](https://www.evse-wifi.de) (includes smartWB) - - Other commercial: ABL eMH1, go-eCharger, Heidelberg Energy Control, KEBA/BMW, NRGkick, Wallbe, Mobile Charger Connect, EEBUS (experimental) + - Closed source: ABL eMH1, cFos PowerBrain, go-eCharger, Heidelberg Energy Control, KEBA/BMW, NRGkick, Wallbe, Mobile Charger Connect, EEBUS (experimental) - Build-your-own: Phoenix (includes ESL Walli), [SimpleEVSE](https://www.evse-wifi.de/produkt-schlagwort/simple-evse-wb/) - Smart-Home outlets: FritzDECT, Shelly, Tasmota, TP-Link - multiple [meters](#meter): ModBus (Eastron SDM, MPM3PM, SBC ALE3 and many more), Discovergy (using HTTP plugin), SMA Sunny Home Manager and Energy Meter, KOSTAL Smart Energy Meter (KSEM, EMxx), any Sunspec-compatible inverter or home battery devices (Fronius, SMA, SolarEdge, KOSTAL, STECA, E3DC, ...), Tesla PowerWall, LG ESS HOME diff --git a/charger/cfos.go b/charger/cfos.go index 6f6ccee509..e65824496a 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -7,6 +7,7 @@ import ( "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" "github.com/evcc-io/evcc/util/modbus" + "github.com/evcc-io/evcc/util/sponsor" ) const ( @@ -59,6 +60,10 @@ func NewCfosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { log := util.NewLogger("cfos") conn.Logger(log.TRACE) + if !sponsor.IsAuthorized() { + return nil, api.ErrSponsorRequired + } + wb := &CfosPowerBrain{ conn: conn, } diff --git a/meter/cfos.go b/meter/cfos.go index 3ed885369f..bfc52a379a 100644 --- a/meter/cfos.go +++ b/meter/cfos.go @@ -80,7 +80,7 @@ func (wb *CfosPowerBrain) TotalEnergy() (float64, error) { return 0, err } - return float64(binary.BigEndian.Uint64(b)), err + return float64(binary.BigEndian.Uint64(b)) / 1e3, err } var _ api.MeterCurrent = (*CfosPowerBrain)(nil) From 7f35e31bd7dfe55cab4ba198b6f3914a30022237 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 14:53:59 +0200 Subject: [PATCH 8/9] Lint --- charger/cfos.go | 15 --------------- meter/cfos.go | 8 ++------ 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/charger/cfos.go b/charger/cfos.go index e65824496a..28a2f0eb2a 100644 --- a/charger/cfos.go +++ b/charger/cfos.go @@ -2,7 +2,6 @@ package charger import ( "errors" - "fmt" "github.com/evcc-io/evcc/api" "github.com/evcc-io/evcc/util" @@ -14,13 +13,8 @@ const ( cfosRegStatus = 8092 // Input cfosRegMaxCurrent = 8093 // Holding cfosRegEnable = 8094 // Coil - cfosRegEnergy = 8058 // energy reading - cfosRegPower = 8062 // power reading - cfosRegMeter = 8096 // has meter ) -var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings - // CfosPowerBrain is an charger implementation for cFos PowerBrain wallboxes. // It uses Modbus TCP to communicate at modbus client id 1 and power meters at id 2 and 3. // https://www.cfos-emobility.de/en-gb/cfos-power-brain/modbus-registers.htm @@ -71,15 +65,6 @@ func NewCfosPowerBrain(uri string, id uint8) (*CfosPowerBrain, error) { return wb, nil } -func (wb *CfosPowerBrain) hasMeter() (bool, error) { - b, err := wb.conn.ReadHoldingRegisters(cfosRegMeter, 1) - if err != nil { - return false, err - } - fmt.Printf("hasMeter % x\n", b) - return b[0] == 1, nil -} - // Status implements the Charger.Status interface func (wb *CfosPowerBrain) Status() (api.ChargeStatus, error) { b, err := wb.conn.ReadHoldingRegisters(cfosRegStatus, 1) diff --git a/meter/cfos.go b/meter/cfos.go index bfc52a379a..300c88ab12 100644 --- a/meter/cfos.go +++ b/meter/cfos.go @@ -9,12 +9,8 @@ import ( ) const ( - cfosRegStatus = 8092 // Input - cfosRegMaxCurrent = 8093 // Holding - cfosRegEnable = 8094 // Coil - cfosRegEnergy = 8058 // energy reading - cfosRegPower = 8062 // power reading - cfosRegMeter = 8096 // has meter + cfosRegEnergy = 8058 // energy reading + cfosRegPower = 8062 // power reading ) var cfosRegCurrents = []uint16{8064, 8066, 8068} // current readings From fd44b53eba83c979f1d5ddd3c4ab2311f54734bf Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 30 Oct 2021 14:56:38 +0200 Subject: [PATCH 9/9] wip --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 26ff5b816b..22bc2aa6bb 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,7 @@ Charger is responsible for handling EV state and adjusting charge current. Available charger implementations are: - `abl`: ABL eMH1 (requires Modbus adapter; [sponsors only](#sponsorship)) +- `cfos`: cFos PowerBrain charger (meters must configured separately, [sponsors only](#sponsorship)) - `easee`: Easee Home charger ([sponsors only](#sponsorship)) - `eebus`: EEBUS compatible chargers (experimental) - `evsewifi`: chargers with SimpleEVSE controllers using [EVSE-WiFi](https://www.evse-wifi.de/) (includes smartWB)