diff --git a/meter/config.go b/meter/config.go index 8719c88ee..0810f0127 100644 --- a/meter/config.go +++ b/meter/config.go @@ -2,14 +2,12 @@ package meter import ( "context" - "fmt" - "strings" "github.com/evcc-io/evcc/api" - reg "github.com/evcc-io/evcc/util/registry" + "github.com/evcc-io/evcc/meter/config" ) -var registry = reg.New[api.Meter]("meter") +var registry = config.Registry // Types returns the list of types func Types() []string { @@ -18,15 +16,5 @@ func Types() []string { // NewFromConfig creates meter from configuration func NewFromConfig(ctx context.Context, typ string, other map[string]interface{}) (api.Meter, error) { - factory, err := registry.Get(strings.ToLower(typ)) - if err != nil { - return nil, err - } - - v, err := factory(ctx, other) - if err != nil { - err = fmt.Errorf("cannot create meter type '%s': %w", typ, err) - } - - return v, err + return config.NewFromConfig(ctx, typ, other) } diff --git a/meter/config/config.go b/meter/config/config.go new file mode 100644 index 000000000..c7c93971a --- /dev/null +++ b/meter/config/config.go @@ -0,0 +1,27 @@ +package config + +import ( + "context" + "fmt" + "strings" + + "github.com/evcc-io/evcc/api" + reg "github.com/evcc-io/evcc/util/registry" +) + +var Registry = reg.New[api.Meter]("meter") + +// NewFromConfig creates meter from configuration +func NewFromConfig(ctx context.Context, typ string, other map[string]interface{}) (api.Meter, error) { + factory, err := Registry.Get(strings.ToLower(typ)) + if err != nil { + return nil, err + } + + v, err := factory(ctx, other) + if err != nil { + err = fmt.Errorf("cannot create meter type '%s': %w", typ, err) + } + + return v, err +} diff --git a/plugin/meter.go b/plugin/meter.go new file mode 100644 index 000000000..5d82d8807 --- /dev/null +++ b/plugin/meter.go @@ -0,0 +1,72 @@ +package plugin + +import ( + "context" + "fmt" + + "github.com/evcc-io/evcc/api" + meter "github.com/evcc-io/evcc/meter/config" + "github.com/evcc-io/evcc/util" + "github.com/evcc-io/evcc/util/config" +) + +type meterPlugin struct { + meter api.Meter + method Method +} + +func init() { + registry.AddCtx("meter", NewMeterFromConfig) +} + +// NewMeterFromConfig creates type conversion provider +func NewMeterFromConfig(ctx context.Context, other map[string]interface{}) (Plugin, error) { + var cc struct { + Config config.Typed + Method + } + + if err := util.DecodeOther(other, &cc); err != nil { + return nil, err + } + + meter, err := meter.NewFromConfig(ctx, cc.Config.Type, cc.Config.Other) + if err != nil { + return nil, err + } + + o := &meterPlugin{ + meter: meter, + method: cc.Method, + } + + return o, nil +} + +var _ FloatGetter = (*meterPlugin)(nil) + +func (o *meterPlugin) FloatGetter() (func() (float64, error), error) { + err := fmt.Errorf("unsupported method: %s", o.method.String()) + + switch o.method { + case Energy: + if _, ok := o.meter.(api.MeterEnergy); !ok { + return nil, err + } + case Soc: + if _, ok := o.meter.(api.Battery); !ok { + return nil, err + } + } + + return func() (float64, error) { + switch o.method { + case Energy: + return o.meter.(api.MeterEnergy).TotalEnergy() + case Soc: + return o.meter.(api.Battery).Soc() + default: + return o.meter.CurrentPower() + } + }, nil +} diff --git a/plugin/method.go b/plugin/method.go new file mode 100644 index 000000000..e9ca48d1a --- /dev/null +++ b/plugin/method.go @@ -0,0 +1,11 @@ +package plugin + +//go:generate go tool enumer -type Method +type Method int + +const ( + _ Method = iota + Energy + Power + Soc +) diff --git a/plugin/method_enumer.go b/plugin/method_enumer.go new file mode 100644 index 000000000..ea2238d37 --- /dev/null +++ b/plugin/method_enumer.go @@ -0,0 +1,83 @@ +// Code generated by "enumer -type Method"; DO NOT EDIT. + +package plugin + +import ( + "fmt" + "strings" +) + +const _MethodName = "EnergyPowerSoc" + +var _MethodIndex = [...]uint8{0, 6, 11, 14} + +const _MethodLowerName = "energypowersoc" + +func (i Method) String() string { + i -= 1 + if i < 0 || i >= Method(len(_MethodIndex)-1) { + return fmt.Sprintf("Method(%d)", i+1) + } + return _MethodName[_MethodIndex[i]:_MethodIndex[i+1]] +} + +// An "invalid array index" compiler error signifies that the constant values have changed. +// Re-run the stringer command to generate them again. +func _MethodNoOp() { + var x [1]struct{} + _ = x[Energy-(1)] + _ = x[Power-(2)] + _ = x[Soc-(3)] +} + +var _MethodValues = []Method{Energy, Power, Soc} + +var _MethodNameToValueMap = map[string]Method{ + _MethodName[0:6]: Energy, + _MethodLowerName[0:6]: Energy, + _MethodName[6:11]: Power, + _MethodLowerName[6:11]: Power, + _MethodName[11:14]: Soc, + _MethodLowerName[11:14]: Soc, +} + +var _MethodNames = []string{ + _MethodName[0:6], + _MethodName[6:11], + _MethodName[11:14], +} + +// MethodString retrieves an enum value from the enum constants string name. +// Throws an error if the param is not part of the enum. +func MethodString(s string) (Method, error) { + if val, ok := _MethodNameToValueMap[s]; ok { + return val, nil + } + + if val, ok := _MethodNameToValueMap[strings.ToLower(s)]; ok { + return val, nil + } + return 0, fmt.Errorf("%s does not belong to Method values", s) +} + +// MethodValues returns all values of the enum +func MethodValues() []Method { + return _MethodValues +} + +// MethodStrings returns a slice of all String values of the enum +func MethodStrings() []string { + strs := make([]string, len(_MethodNames)) + copy(strs, _MethodNames) + return strs +} + +// IsAMethod returns "true" if the value is listed in the enum definition. "false" otherwise +func (i Method) IsAMethod() bool { + for _, v := range _MethodValues { + if i == v { + return true + } + } + return false +}