176 lines
3.6 KiB
Go
176 lines
3.6 KiB
Go
package meter
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/andig/evcc/api"
|
|
"github.com/andig/evcc/provider"
|
|
"github.com/andig/evcc/util"
|
|
)
|
|
|
|
// NewConfigurableFromConfig creates api.Meter from config
|
|
func NewConfigurableFromConfig(other map[string]interface{}) (api.Meter, error) {
|
|
cc := struct {
|
|
Power provider.Config
|
|
Energy *provider.Config // optional
|
|
Currents []provider.Config // optional
|
|
}{}
|
|
|
|
if err := util.DecodeOther(other, &cc); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for k, v := range map[string]string{"power": cc.Power.Type} {
|
|
if v == "" {
|
|
return nil, fmt.Errorf("default meter config: %s required", k)
|
|
}
|
|
}
|
|
|
|
power, err := provider.NewFloatGetterFromConfig(cc.Power)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
m, _ := NewConfigurable(power)
|
|
|
|
// decorate Meter with MeterEnergy
|
|
if cc.Energy != nil {
|
|
energy, err := NewMeterEnergy(*cc.Energy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
type EnergyDecorator struct {
|
|
api.Meter
|
|
api.MeterEnergy
|
|
}
|
|
|
|
m = &EnergyDecorator{
|
|
Meter: m,
|
|
MeterEnergy: energy,
|
|
}
|
|
}
|
|
|
|
// decorate Meter with MeterCurrent
|
|
if len(cc.Currents) > 0 {
|
|
currents, err := NewCurrents(cc.Currents)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
type PowerEnergy interface {
|
|
api.Meter
|
|
api.MeterEnergy
|
|
}
|
|
|
|
if pe, ok := m.(PowerEnergy); ok {
|
|
type CurrentDecorator struct {
|
|
PowerEnergy
|
|
api.MeterCurrent
|
|
}
|
|
|
|
m = &CurrentDecorator{
|
|
PowerEnergy: pe,
|
|
MeterCurrent: currents,
|
|
}
|
|
} else {
|
|
type CurrentDecorator struct {
|
|
api.Meter
|
|
api.MeterCurrent
|
|
}
|
|
|
|
m = &CurrentDecorator{
|
|
Meter: m,
|
|
MeterCurrent: currents,
|
|
}
|
|
}
|
|
}
|
|
|
|
return m, nil
|
|
}
|
|
|
|
// NewConfigurable creates a new charger
|
|
func NewConfigurable(currentPowerG func() (float64, error)) (api.Meter, error) {
|
|
m := &Meter{
|
|
currentPowerG: currentPowerG,
|
|
}
|
|
return m, nil
|
|
}
|
|
|
|
// Meter is an api.Meter implementation with configurable getters and setters.
|
|
type Meter struct {
|
|
currentPowerG func() (float64, error)
|
|
}
|
|
|
|
// CurrentPower implements the Meter.CurrentPower interface
|
|
func (m *Meter) CurrentPower() (float64, error) {
|
|
return m.currentPowerG()
|
|
}
|
|
|
|
// MeterEnergy is an api.MeterEnergy implementation with configurable getters and setters.
|
|
type MeterEnergy struct {
|
|
totalEnergyG func() (float64, error)
|
|
}
|
|
|
|
// NewMeterEnergy creates a new api.MeterEnergy
|
|
func NewMeterEnergy(ccEnergy provider.Config) (api.MeterEnergy, error) {
|
|
totalEnergyG, err := provider.NewFloatGetterFromConfig(ccEnergy)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
e := &MeterEnergy{
|
|
totalEnergyG: totalEnergyG,
|
|
}
|
|
|
|
return e, nil
|
|
}
|
|
|
|
// TotalEnergy implements the Meter.TotalEnergy interface
|
|
func (m *MeterEnergy) TotalEnergy() (float64, error) {
|
|
return m.totalEnergyG()
|
|
}
|
|
|
|
// Currents is an api.MeterCurrent implementation
|
|
type Currents struct {
|
|
currentsG []func() (float64, error)
|
|
}
|
|
|
|
// NewCurrents creates a new api.MeterCurrent
|
|
func NewCurrents(ccCurrents []provider.Config) (api.MeterCurrent, error) {
|
|
if len(ccCurrents) != 3 {
|
|
return nil, errors.New("need 3 currents")
|
|
}
|
|
|
|
var currentsG []func() (float64, error)
|
|
for _, cc := range ccCurrents {
|
|
c, err := provider.NewFloatGetterFromConfig(cc)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
currentsG = append(currentsG, c)
|
|
}
|
|
|
|
c := &Currents{
|
|
currentsG: currentsG,
|
|
}
|
|
|
|
return c, nil
|
|
}
|
|
|
|
// Currents implements the api.Currents interface
|
|
func (c *Currents) Currents() (float64, float64, float64, error) {
|
|
var currents []float64
|
|
for _, currentG := range c.currentsG {
|
|
c, err := currentG()
|
|
if err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
|
|
currents = append(currents, c)
|
|
}
|
|
|
|
return currents[0], currents[1], currents[2], nil
|
|
}
|