diff --git a/charger/openwb.go b/charger/openwb.go index 2a0f0b6f5..1b866e982 100644 --- a/charger/openwb.go +++ b/charger/openwb.go @@ -22,9 +22,10 @@ type OpenWB struct { totalEnergyG func() (float64, error) currentsG []func() (float64, error) phasesS func(int64) error + socG func() (float64, error) } -// go:generate go run ../cmd/tools/decorate.go -f decorateOpenWB -b *OpenWB -r api.Charger -t "api.ChargePhases,Phases1p3p,func(int) (error)" +// go:generate go run ../cmd/tools/decorate.go -f decorateOpenWB -b *OpenWB -r api.Charger -t "api.ChargePhases,Phases1p3p,func(int) (error)" -t "api.Battery,SoC,func() (float64, error)" // NewOpenWBFromConfig creates a new configurable charger func NewOpenWBFromConfig(other map[string]interface{}) (api.Charger, error) { @@ -33,7 +34,7 @@ func NewOpenWBFromConfig(other map[string]interface{}) (api.Charger, error) { Topic string Timeout time.Duration ID int - Phases bool + Phases, DC bool }{ Topic: openwb.RootTopic, Timeout: openwb.Timeout, @@ -46,11 +47,11 @@ func NewOpenWBFromConfig(other map[string]interface{}) (api.Charger, error) { log := util.NewLogger("openwb") - return NewOpenWB(log, cc.Config, cc.ID, cc.Topic, cc.Phases, cc.Timeout) + return NewOpenWB(log, cc.Config, cc.ID, cc.Topic, cc.Phases, cc.DC, cc.Timeout) } // NewOpenWB creates a new configurable charger -func NewOpenWB(log *util.Logger, mqttconf mqtt.Config, id int, topic string, p1p3 bool, timeout time.Duration) (api.Charger, error) { +func NewOpenWB(log *util.Logger, mqttconf mqtt.Config, id int, topic string, p1p3, dc bool, timeout time.Duration) (api.Charger, error) { client, err := mqtt.RegisteredClientOrDefault(log, mqttconf) if err != nil { return nil, err @@ -127,16 +128,24 @@ func NewOpenWB(log *util.Logger, mqttconf mqtt.Config, id int, topic string, p1p } // optional capabilities - c.phasesS = provider.NewMqtt(log, client, - fmt.Sprintf("%s/set/isss/%s", topic, openwb.PhasesTopic), - 1, timeout).IntSetter("phases") var phases func(int) error if p1p3 { + c.phasesS = provider.NewMqtt(log, client, + fmt.Sprintf("%s/set/isss/%s", topic, openwb.PhasesTopic), + 1, timeout).IntSetter("phases") + phases = c.phases } - return decorateOpenWB(c, phases), nil + var soc func() (float64, error) + if dc { + c.socG = floatG(fmt.Sprintf("%s/lp/%d/%s", topic, id, openwb.VehicleSoCTopic)) + + soc = c.socG + } + + return decorateOpenWB(c, phases, soc), nil } var _ api.Meter = (*OpenWB)(nil) @@ -174,3 +183,8 @@ func (m *OpenWB) Currents() (float64, float64, float64, error) { func (c *OpenWB) phases(phases int) error { return c.phasesS(int64(phases)) } + +// soc implements the api.Battery interface +func (c *OpenWB) soc() (float64, error) { + return c.socG() +} diff --git a/charger/openwb/topics.go b/charger/openwb/topics.go index 060d2408a..d3f6f023e 100644 --- a/charger/openwb/topics.go +++ b/charger/openwb/topics.go @@ -26,6 +26,9 @@ const ( ChargePowerTopic = "W" ChargeTotalEnergyTopic = "kWhCounter" + // vehicle + VehicleSoCTopic = "Soc" + // general measurements PowerTopic = "W" SoCTopic = "%Soc" diff --git a/charger/openwb_decorators.go b/charger/openwb_decorators.go index 41120ffb9..64a379788 100644 --- a/charger/openwb_decorators.go +++ b/charger/openwb_decorators.go @@ -6,12 +6,12 @@ import ( "github.com/evcc-io/evcc/api" ) -func decorateOpenWB(base *OpenWB, chargePhases func(int) error) api.Charger { +func decorateOpenWB(base *OpenWB, chargePhases func(int) error, battery func() (float64, error)) api.Charger { switch { - case chargePhases == nil: + case battery == nil && chargePhases == nil: return base - case chargePhases != nil: + case battery == nil && chargePhases != nil: return &struct { *OpenWB api.ChargePhases @@ -21,11 +21,45 @@ func decorateOpenWB(base *OpenWB, chargePhases func(int) error) api.Charger { chargePhases: chargePhases, }, } + + case battery != nil && chargePhases == nil: + return &struct { + *OpenWB + api.Battery + }{ + OpenWB: base, + Battery: &decorateOpenWBBatteryImpl{ + battery: battery, + }, + } + + case battery != nil && chargePhases != nil: + return &struct { + *OpenWB + api.Battery + api.ChargePhases + }{ + OpenWB: base, + Battery: &decorateOpenWBBatteryImpl{ + battery: battery, + }, + ChargePhases: &decorateOpenWBChargePhasesImpl{ + chargePhases: chargePhases, + }, + } } return nil } +type decorateOpenWBBatteryImpl struct { + battery func() (float64, error) +} + +func (impl *decorateOpenWBBatteryImpl) SoC() (float64, error) { + return impl.battery() +} + type decorateOpenWBChargePhasesImpl struct { chargePhases func(int) error }