Keba: auto-detect optional meter (#1541)

This commit is contained in:
andig 2021-09-17 22:57:47 +02:00 • committed by GitHub
parent 9c32874c88
commit ac98b8a543
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 308 additions and 45 deletions

View file

@ -37,6 +37,8 @@ func init() {
registry.Add("keba", NewKebaFromConfig)
}
//go:generate go run ../cmd/tools/decorate.go -f decorateKeba -b *Keba -r api.Charger -t "api.Meter,CurrentPower,func() (float64, error)" -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.ChargeRater,ChargedEnergy,func() (float64, error)" -t "api.MeterCurrent,Currents,func() (float64, float64, float64, error)"
// NewKebaFromConfig creates a new configurable charger
func NewKebaFromConfig(other map[string]interface{}) (api.Charger, error) {
cc := struct {
@ -47,15 +49,30 @@ func NewKebaFromConfig(other map[string]interface{}) (api.Charger, error) {
}{
Timeout: udpTimeout,
}
if err := util.DecodeOther(other, &cc); err != nil {
return nil, err
}
return NewKeba(cc.URI, cc.Serial, cc.RFID, cc.Timeout)
k, err := NewKeba(cc.URI, cc.Serial, cc.RFID, cc.Timeout)
if err != nil {
return nil, err
}
energy, err := k.totalEnergy()
if err != nil {
return nil, err
}
if energy > 0 {
return decorateKeba(k, k.currentPower, k.totalEnergy, k.chargedEnergy, k.currents), nil
}
return k, err
}
// NewKeba creates a new charger
func NewKeba(uri, serial string, rfid RFID, timeout time.Duration) (api.Charger, error) {
func NewKeba(uri, serial string, rfid RFID, timeout time.Duration) (*Keba, error) {
log := util.NewLogger("keba")
if keba.Instance == nil {
@ -264,10 +281,8 @@ func (c *Keba) MaxCurrentMillis(current float64) error {
return nil
}
var _ api.Meter = (*Keba)(nil)
// CurrentPower implements the api.Meter interface
func (c *Keba) CurrentPower() (float64, error) {
// currentPower implements the api.Meter interface
func (c *Keba) currentPower() (float64, error) {
var kr keba.Report3
err := c.roundtrip("report", 3, &kr)
@ -275,10 +290,8 @@ func (c *Keba) CurrentPower() (float64, error) {
return float64(kr.P) / 1e3, err
}
var _ api.MeterEnergy = (*Keba)(nil)
// TotalEnergy implements the api.MeterEnergy interface
func (c *Keba) TotalEnergy() (float64, error) {
// totalEnergy implements the api.MeterEnergy interface
func (c *Keba) totalEnergy() (float64, error) {
var kr keba.Report3
err := c.roundtrip("report", 3, &kr)
@ -286,10 +299,8 @@ func (c *Keba) TotalEnergy() (float64, error) {
return float64(kr.ETotal) / 1e4, err
}
var _ api.ChargeRater = (*Keba)(nil)
// ChargedEnergy implements the ChargeRater interface
func (c *Keba) ChargedEnergy() (float64, error) {
// chargedEnergy implements the ChargeRater interface
func (c *Keba) chargedEnergy() (float64, error) {
var kr keba.Report3
err := c.roundtrip("report", 3, &kr)
@ -297,10 +308,8 @@ func (c *Keba) ChargedEnergy() (float64, error) {
return float64(kr.EPres) / 1e4, err
}
var _ api.MeterCurrent = (*Keba)(nil)
// Currents implements the api.MeterCurrent interface
func (c *Keba) Currents() (float64, float64, float64, error) {
// currents implements the api.MeterCurrent interface
func (c *Keba) currents() (float64, float64, float64, error) {
var kr keba.Report3
err := c.roundtrip("report", 3, &kr)

281
charger/keba_decorators.go Normal file
View file

@ -0,0 +1,281 @@
package charger
// Code generated by github.com/andig/cmd/tools/decorate.go. DO NOT EDIT.
import (
"github.com/evcc-io/evcc/api"
)
func decorateKeba(base *Keba, meter func() (float64, error), meterEnergy func() (float64, error), chargeRater func() (float64, error), meterCurrent func() (float64, float64, float64, error)) api.Charger {
switch {
case chargeRater == nil && meter == nil && meterCurrent == nil && meterEnergy == nil:
return base
case chargeRater == nil && meter != nil && meterCurrent == nil && meterEnergy == nil:
return &struct {
*Keba
api.Meter
}{
Keba: base,
Meter: &decorateKebaMeterImpl{
meter: meter,
},
}
case chargeRater == nil && meter == nil && meterCurrent == nil && meterEnergy != nil:
return &struct {
*Keba
api.MeterEnergy
}{
Keba: base,
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater == nil && meter != nil && meterCurrent == nil && meterEnergy != nil:
return &struct {
*Keba
api.Meter
api.MeterEnergy
}{
Keba: base,
Meter: &decorateKebaMeterImpl{
meter: meter,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater != nil && meter == nil && meterCurrent == nil && meterEnergy == nil:
return &struct {
*Keba
api.ChargeRater
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
}
case chargeRater != nil && meter != nil && meterCurrent == nil && meterEnergy == nil:
return &struct {
*Keba
api.ChargeRater
api.Meter
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
Meter: &decorateKebaMeterImpl{
meter: meter,
},
}
case chargeRater != nil && meter == nil && meterCurrent == nil && meterEnergy != nil:
return &struct {
*Keba
api.ChargeRater
api.MeterEnergy
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater != nil && meter != nil && meterCurrent == nil && meterEnergy != nil:
return &struct {
*Keba
api.ChargeRater
api.Meter
api.MeterEnergy
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
Meter: &decorateKebaMeterImpl{
meter: meter,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater == nil && meter == nil && meterCurrent != nil && meterEnergy == nil:
return &struct {
*Keba
api.MeterCurrent
}{
Keba: base,
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
}
case chargeRater == nil && meter != nil && meterCurrent != nil && meterEnergy == nil:
return &struct {
*Keba
api.Meter
api.MeterCurrent
}{
Keba: base,
Meter: &decorateKebaMeterImpl{
meter: meter,
},
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
}
case chargeRater == nil && meter == nil && meterCurrent != nil && meterEnergy != nil:
return &struct {
*Keba
api.MeterCurrent
api.MeterEnergy
}{
Keba: base,
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater == nil && meter != nil && meterCurrent != nil && meterEnergy != nil:
return &struct {
*Keba
api.Meter
api.MeterCurrent
api.MeterEnergy
}{
Keba: base,
Meter: &decorateKebaMeterImpl{
meter: meter,
},
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater != nil && meter == nil && meterCurrent != nil && meterEnergy == nil:
return &struct {
*Keba
api.ChargeRater
api.MeterCurrent
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
}
case chargeRater != nil && meter != nil && meterCurrent != nil && meterEnergy == nil:
return &struct {
*Keba
api.ChargeRater
api.Meter
api.MeterCurrent
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
Meter: &decorateKebaMeterImpl{
meter: meter,
},
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
}
case chargeRater != nil && meter == nil && meterCurrent != nil && meterEnergy != nil:
return &struct {
*Keba
api.ChargeRater
api.MeterCurrent
api.MeterEnergy
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
case chargeRater != nil && meter != nil && meterCurrent != nil && meterEnergy != nil:
return &struct {
*Keba
api.ChargeRater
api.Meter
api.MeterCurrent
api.MeterEnergy
}{
Keba: base,
ChargeRater: &decorateKebaChargeRaterImpl{
chargeRater: chargeRater,
},
Meter: &decorateKebaMeterImpl{
meter: meter,
},
MeterCurrent: &decorateKebaMeterCurrentImpl{
meterCurrent: meterCurrent,
},
MeterEnergy: &decorateKebaMeterEnergyImpl{
meterEnergy: meterEnergy,
},
}
}
return nil
}
type decorateKebaChargeRaterImpl struct {
chargeRater func() (float64, error)
}
func (impl *decorateKebaChargeRaterImpl) ChargedEnergy() (float64, error) {
return impl.chargeRater()
}
type decorateKebaMeterImpl struct {
meter func() (float64, error)
}
func (impl *decorateKebaMeterImpl) CurrentPower() (float64, error) {
return impl.meter()
}
type decorateKebaMeterCurrentImpl struct {
meterCurrent func() (float64, float64, float64, error)
}
func (impl *decorateKebaMeterCurrentImpl) Currents() (float64, float64, float64, error) {
return impl.meterCurrent()
}
type decorateKebaMeterEnergyImpl struct {
meterEnergy func() (float64, error)
}
func (impl *decorateKebaMeterEnergyImpl) TotalEnergy() (float64, error) {
return impl.meterEnergy()
}

View file

@ -1,27 +0,0 @@
package charger
import (
"testing"
"github.com/evcc-io/evcc/api"
)
func TestKeba(t *testing.T) {
var wb api.Charger
wb, err := NewKeba("localhost", "bar", RFID{}, 0)
if err != nil {
t.Error(err)
}
if _, ok := wb.(api.MeterEnergy); !ok {
t.Error("missing MeterEnergy interface")
}
if _, ok := wb.(api.MeterCurrent); !ok {
t.Error("missing MeterCurrent interface")
}
if _, ok := wb.(api.ChargeRater); !ok {
t.Error("missing ChargeRater interface")
}
}