chore: simplify implementing decorators (#28576)
This commit is contained in:
parent
a2ce340210
commit
4b21185219
148 changed files with 1500 additions and 6358 deletions
57
api/implement/caps.go
Normal file
57
api/implement/caps.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package implement
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
// Has registers impl as a capability on c. It panics if impl is nil.
|
||||
func Has[T any](c Caps, impl T) {
|
||||
typ := reflect.TypeFor[T]()
|
||||
if isNil(impl) {
|
||||
panic("implement: nil " + typ.String())
|
||||
}
|
||||
c.add(typ, impl)
|
||||
}
|
||||
|
||||
// May registers impl as a capability on c. If impl is nil, it is silently ignored.
|
||||
func May[T any](c Caps, impl T) {
|
||||
if isNil(impl) {
|
||||
return
|
||||
}
|
||||
c.add(reflect.TypeFor[T](), impl)
|
||||
}
|
||||
|
||||
func isNil(v any) bool {
|
||||
if v == nil {
|
||||
return true
|
||||
}
|
||||
switch rv := reflect.ValueOf(v); rv.Kind() {
|
||||
case reflect.Pointer, reflect.Interface, reflect.Map, reflect.Slice, reflect.Chan, reflect.Func:
|
||||
return rv.IsNil()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
type Caps interface {
|
||||
api.Capable
|
||||
add(typ reflect.Type, impl any)
|
||||
}
|
||||
|
||||
// New creates a capabilities store exposing the api.Capable interface
|
||||
func New() Caps {
|
||||
return make(caps)
|
||||
}
|
||||
|
||||
type caps map[reflect.Type]any
|
||||
|
||||
// Capability implements the api.Capable interface
|
||||
func (caps caps) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := caps[typ]
|
||||
return c, ok
|
||||
}
|
||||
|
||||
func (caps caps) add(typ reflect.Type, impl any) {
|
||||
caps[typ] = impl
|
||||
}
|
||||
81
api/implement/caps_test.go
Normal file
81
api/implement/caps_test.go
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
package implement
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
type isCapable struct {
|
||||
Caps
|
||||
}
|
||||
|
||||
func TestHas(t *testing.T) {
|
||||
s := &isCapable{
|
||||
Caps: New(),
|
||||
}
|
||||
|
||||
Has(s, Meter(func() (float64, error) {
|
||||
return 0, nil
|
||||
}))
|
||||
|
||||
mm, ok := api.Cap[api.Meter](s)
|
||||
assert.True(t, ok)
|
||||
|
||||
v, err := mm.CurrentPower()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 0.0, v)
|
||||
}
|
||||
|
||||
func TestHasPanicsOnNil(t *testing.T) {
|
||||
s := &isCapable{
|
||||
Caps: New(),
|
||||
}
|
||||
|
||||
assert.Panics(t, func() {
|
||||
Has[api.Meter](s, nil)
|
||||
})
|
||||
}
|
||||
|
||||
func TestMayIgnoresNil(t *testing.T) {
|
||||
s := &isCapable{
|
||||
Caps: New(),
|
||||
}
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
May[api.Meter](s, nil)
|
||||
})
|
||||
|
||||
_, ok := api.Cap[api.Meter](s)
|
||||
assert.False(t, ok)
|
||||
}
|
||||
|
||||
func TestMayRegistersNonNil(t *testing.T) {
|
||||
s := &isCapable{
|
||||
Caps: New(),
|
||||
}
|
||||
|
||||
May(s, Meter(func() (float64, error) {
|
||||
return 1.0, nil
|
||||
}))
|
||||
|
||||
mm, ok := api.Cap[api.Meter](s)
|
||||
assert.True(t, ok)
|
||||
|
||||
v, err := mm.CurrentPower()
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, 1.0, v)
|
||||
}
|
||||
|
||||
func TestMayIgnoresNilFuncConstructor(t *testing.T) {
|
||||
s := &isCapable{
|
||||
Caps: New(),
|
||||
}
|
||||
|
||||
var fn func() (float64, error)
|
||||
May(s, Meter(fn))
|
||||
|
||||
_, ok := api.Cap[api.Meter](s)
|
||||
assert.False(t, ok)
|
||||
}
|
||||
449
api/implement/implementations.go
Normal file
449
api/implement/implementations.go
Normal file
|
|
@ -0,0 +1,449 @@
|
|||
package implement
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/api/implement/caps.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func Meter(meter0 func() (float64, error)) api.Meter {
|
||||
if meter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iMeter{meter0}
|
||||
}
|
||||
|
||||
type iMeter struct {
|
||||
meter0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iMeter) CurrentPower() (float64, error) {
|
||||
return i.meter0()
|
||||
}
|
||||
|
||||
func BatteryCapacity(batteryCapacity0 func() float64) api.BatteryCapacity {
|
||||
if batteryCapacity0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iBatteryCapacity{batteryCapacity0}
|
||||
}
|
||||
|
||||
type iBatteryCapacity struct {
|
||||
batteryCapacity0 func() float64
|
||||
}
|
||||
|
||||
func (i *iBatteryCapacity) Capacity() float64 {
|
||||
return i.batteryCapacity0()
|
||||
}
|
||||
|
||||
func SocLimiter(socLimiter0 func() (int64, error)) api.SocLimiter {
|
||||
if socLimiter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iSocLimiter{socLimiter0}
|
||||
}
|
||||
|
||||
type iSocLimiter struct {
|
||||
socLimiter0 func() (int64, error)
|
||||
}
|
||||
|
||||
func (i *iSocLimiter) GetLimitSoc() (int64, error) {
|
||||
return i.socLimiter0()
|
||||
}
|
||||
|
||||
func BatteryController(batteryController0 func(api.BatteryMode) error) api.BatteryController {
|
||||
if batteryController0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iBatteryController{batteryController0}
|
||||
}
|
||||
|
||||
type iBatteryController struct {
|
||||
batteryController0 func(api.BatteryMode) error
|
||||
}
|
||||
|
||||
func (i *iBatteryController) SetBatteryMode(p0 api.BatteryMode) error {
|
||||
return i.batteryController0(p0)
|
||||
}
|
||||
|
||||
func BatterySocLimiter(batterySocLimiter0 func() (float64, float64)) api.BatterySocLimiter {
|
||||
if batterySocLimiter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iBatterySocLimiter{batterySocLimiter0}
|
||||
}
|
||||
|
||||
type iBatterySocLimiter struct {
|
||||
batterySocLimiter0 func() (float64, float64)
|
||||
}
|
||||
|
||||
func (i *iBatterySocLimiter) GetSocLimits() (float64, float64) {
|
||||
return i.batterySocLimiter0()
|
||||
}
|
||||
|
||||
func BatteryPowerLimiter(batteryPowerLimiter0 func() (float64, float64)) api.BatteryPowerLimiter {
|
||||
if batteryPowerLimiter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iBatteryPowerLimiter{batteryPowerLimiter0}
|
||||
}
|
||||
|
||||
type iBatteryPowerLimiter struct {
|
||||
batteryPowerLimiter0 func() (float64, float64)
|
||||
}
|
||||
|
||||
func (i *iBatteryPowerLimiter) GetPowerLimits() (float64, float64) {
|
||||
return i.batteryPowerLimiter0()
|
||||
}
|
||||
|
||||
func PhasePowers(phasePowers0 func() (float64, float64, float64, error)) api.PhasePowers {
|
||||
if phasePowers0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iPhasePowers{phasePowers0}
|
||||
}
|
||||
|
||||
type iPhasePowers struct {
|
||||
phasePowers0 func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (i *iPhasePowers) Powers() (float64, float64, float64, error) {
|
||||
return i.phasePowers0()
|
||||
}
|
||||
|
||||
func PhaseGetter(phaseGetter0 func() (int, error)) api.PhaseGetter {
|
||||
if phaseGetter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iPhaseGetter{phaseGetter0}
|
||||
}
|
||||
|
||||
type iPhaseGetter struct {
|
||||
phaseGetter0 func() (int, error)
|
||||
}
|
||||
|
||||
func (i *iPhaseGetter) GetPhases() (int, error) {
|
||||
return i.phaseGetter0()
|
||||
}
|
||||
|
||||
func ChargeController(chargeController0 func(bool) error) api.ChargeController {
|
||||
if chargeController0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iChargeController{chargeController0}
|
||||
}
|
||||
|
||||
type iChargeController struct {
|
||||
chargeController0 func(bool) error
|
||||
}
|
||||
|
||||
func (i *iChargeController) ChargeEnable(p0 bool) error {
|
||||
return i.chargeController0(p0)
|
||||
}
|
||||
|
||||
func CurrentController(currentController0 func(int64) error) api.CurrentController {
|
||||
if currentController0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iCurrentController{currentController0}
|
||||
}
|
||||
|
||||
type iCurrentController struct {
|
||||
currentController0 func(int64) error
|
||||
}
|
||||
|
||||
func (i *iCurrentController) MaxCurrent(p0 int64) error {
|
||||
return i.currentController0(p0)
|
||||
}
|
||||
|
||||
func PhaseSwitcher(phaseSwitcher0 func(int) error) api.PhaseSwitcher {
|
||||
if phaseSwitcher0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iPhaseSwitcher{phaseSwitcher0}
|
||||
}
|
||||
|
||||
type iPhaseSwitcher struct {
|
||||
phaseSwitcher0 func(int) error
|
||||
}
|
||||
|
||||
func (i *iPhaseSwitcher) Phases1p3p(p0 int) error {
|
||||
return i.phaseSwitcher0(p0)
|
||||
}
|
||||
|
||||
func Battery(battery0 func() (float64, error)) api.Battery {
|
||||
if battery0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iBattery{battery0}
|
||||
}
|
||||
|
||||
type iBattery struct {
|
||||
battery0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iBattery) Soc() (float64, error) {
|
||||
return i.battery0()
|
||||
}
|
||||
|
||||
func ChargeState(chargeState0 func() (api.ChargeStatus, error)) api.ChargeState {
|
||||
if chargeState0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iChargeState{chargeState0}
|
||||
}
|
||||
|
||||
type iChargeState struct {
|
||||
chargeState0 func() (api.ChargeStatus, error)
|
||||
}
|
||||
|
||||
func (i *iChargeState) Status() (api.ChargeStatus, error) {
|
||||
return i.chargeState0()
|
||||
}
|
||||
|
||||
func MeterEnergy(meterEnergy0 func() (float64, error)) api.MeterEnergy {
|
||||
if meterEnergy0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iMeterEnergy{meterEnergy0}
|
||||
}
|
||||
|
||||
type iMeterEnergy struct {
|
||||
meterEnergy0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iMeterEnergy) TotalEnergy() (float64, error) {
|
||||
return i.meterEnergy0()
|
||||
}
|
||||
|
||||
func PhaseCurrents(phaseCurrents0 func() (float64, float64, float64, error)) api.PhaseCurrents {
|
||||
if phaseCurrents0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iPhaseCurrents{phaseCurrents0}
|
||||
}
|
||||
|
||||
type iPhaseCurrents struct {
|
||||
phaseCurrents0 func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (i *iPhaseCurrents) Currents() (float64, float64, float64, error) {
|
||||
return i.phaseCurrents0()
|
||||
}
|
||||
|
||||
func PhaseVoltages(phaseVoltages0 func() (float64, float64, float64, error)) api.PhaseVoltages {
|
||||
if phaseVoltages0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iPhaseVoltages{phaseVoltages0}
|
||||
}
|
||||
|
||||
type iPhaseVoltages struct {
|
||||
phaseVoltages0 func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (i *iPhaseVoltages) Voltages() (float64, float64, float64, error) {
|
||||
return i.phaseVoltages0()
|
||||
}
|
||||
|
||||
func MaxACPowerGetter(maxACPowerGetter0 func() float64) api.MaxACPowerGetter {
|
||||
if maxACPowerGetter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iMaxACPowerGetter{maxACPowerGetter0}
|
||||
}
|
||||
|
||||
type iMaxACPowerGetter struct {
|
||||
maxACPowerGetter0 func() float64
|
||||
}
|
||||
|
||||
func (i *iMaxACPowerGetter) MaxACPower() float64 {
|
||||
return i.maxACPowerGetter0()
|
||||
}
|
||||
|
||||
func CurrentGetter(currentGetter0 func() (float64, error)) api.CurrentGetter {
|
||||
if currentGetter0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iCurrentGetter{currentGetter0}
|
||||
}
|
||||
|
||||
type iCurrentGetter struct {
|
||||
currentGetter0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iCurrentGetter) GetMaxCurrent() (float64, error) {
|
||||
return i.currentGetter0()
|
||||
}
|
||||
|
||||
func Curtailer(curtailer0 func(bool) error, curtailer1 func() (bool, error)) api.Curtailer {
|
||||
if curtailer0 == nil || curtailer1 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iCurtailer{curtailer0, curtailer1}
|
||||
}
|
||||
|
||||
type iCurtailer struct {
|
||||
curtailer0 func(bool) error
|
||||
curtailer1 func() (bool, error)
|
||||
}
|
||||
|
||||
func (i *iCurtailer) Curtail(p0 bool) error {
|
||||
return i.curtailer0(p0)
|
||||
}
|
||||
|
||||
func (i *iCurtailer) Curtailed() (bool, error) {
|
||||
return i.curtailer1()
|
||||
}
|
||||
|
||||
func Resurrector(resurrector0 func() error) api.Resurrector {
|
||||
if resurrector0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iResurrector{resurrector0}
|
||||
}
|
||||
|
||||
type iResurrector struct {
|
||||
resurrector0 func() error
|
||||
}
|
||||
|
||||
func (i *iResurrector) WakeUp() error {
|
||||
return i.resurrector0()
|
||||
}
|
||||
|
||||
func VehicleOdometer(vehicleOdometer0 func() (float64, error)) api.VehicleOdometer {
|
||||
if vehicleOdometer0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iVehicleOdometer{vehicleOdometer0}
|
||||
}
|
||||
|
||||
type iVehicleOdometer struct {
|
||||
vehicleOdometer0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iVehicleOdometer) Odometer() (float64, error) {
|
||||
return i.vehicleOdometer0()
|
||||
}
|
||||
|
||||
func VehicleRange(vehicleRange0 func() (int64, error)) api.VehicleRange {
|
||||
if vehicleRange0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iVehicleRange{vehicleRange0}
|
||||
}
|
||||
|
||||
type iVehicleRange struct {
|
||||
vehicleRange0 func() (int64, error)
|
||||
}
|
||||
|
||||
func (i *iVehicleRange) Range() (int64, error) {
|
||||
return i.vehicleRange0()
|
||||
}
|
||||
|
||||
func VehicleClimater(vehicleClimater0 func() (bool, error)) api.VehicleClimater {
|
||||
if vehicleClimater0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iVehicleClimater{vehicleClimater0}
|
||||
}
|
||||
|
||||
type iVehicleClimater struct {
|
||||
vehicleClimater0 func() (bool, error)
|
||||
}
|
||||
|
||||
func (i *iVehicleClimater) Climater() (bool, error) {
|
||||
return i.vehicleClimater0()
|
||||
}
|
||||
|
||||
func VehicleFinishTimer(vehicleFinishTimer0 func() (time.Time, error)) api.VehicleFinishTimer {
|
||||
if vehicleFinishTimer0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iVehicleFinishTimer{vehicleFinishTimer0}
|
||||
}
|
||||
|
||||
type iVehicleFinishTimer struct {
|
||||
vehicleFinishTimer0 func() (time.Time, error)
|
||||
}
|
||||
|
||||
func (i *iVehicleFinishTimer) FinishTime() (time.Time, error) {
|
||||
return i.vehicleFinishTimer0()
|
||||
}
|
||||
|
||||
func VehiclePosition(vehiclePosition0 func() (float64, float64, error)) api.VehiclePosition {
|
||||
if vehiclePosition0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iVehiclePosition{vehiclePosition0}
|
||||
}
|
||||
|
||||
type iVehiclePosition struct {
|
||||
vehiclePosition0 func() (float64, float64, error)
|
||||
}
|
||||
|
||||
func (i *iVehiclePosition) Position() (float64, float64, error) {
|
||||
return i.vehiclePosition0()
|
||||
}
|
||||
|
||||
func Identifier(identifier0 func() (string, error)) api.Identifier {
|
||||
if identifier0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iIdentifier{identifier0}
|
||||
}
|
||||
|
||||
type iIdentifier struct {
|
||||
identifier0 func() (string, error)
|
||||
}
|
||||
|
||||
func (i *iIdentifier) Identify() (string, error) {
|
||||
return i.identifier0()
|
||||
}
|
||||
|
||||
func ChargerEx(chargerEx0 func(float64) error) api.ChargerEx {
|
||||
if chargerEx0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iChargerEx{chargerEx0}
|
||||
}
|
||||
|
||||
type iChargerEx struct {
|
||||
chargerEx0 func(float64) error
|
||||
}
|
||||
|
||||
func (i *iChargerEx) MaxCurrentMillis(p0 float64) error {
|
||||
return i.chargerEx0(p0)
|
||||
}
|
||||
|
||||
func ChargeRater(chargeRater0 func() (float64, error)) api.ChargeRater {
|
||||
if chargeRater0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iChargeRater{chargeRater0}
|
||||
}
|
||||
|
||||
type iChargeRater struct {
|
||||
chargeRater0 func() (float64, error)
|
||||
}
|
||||
|
||||
func (i *iChargeRater) ChargedEnergy() (float64, error) {
|
||||
return i.chargeRater0()
|
||||
}
|
||||
|
||||
func StatusReasoner(statusReasoner0 func() (api.Reason, error)) api.StatusReasoner {
|
||||
if statusReasoner0 == nil {
|
||||
return nil
|
||||
}
|
||||
return &iStatusReasoner{statusReasoner0}
|
||||
}
|
||||
|
||||
type iStatusReasoner struct {
|
||||
statusReasoner0 func() (api.Reason, error)
|
||||
}
|
||||
|
||||
func (i *iStatusReasoner) StatusReason() (api.Reason, error) {
|
||||
return i.statusReasoner0()
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -31,6 +32,7 @@ import (
|
|||
|
||||
// ABLeMH charger implementation
|
||||
type ABLeMH struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
curr uint16
|
||||
}
|
||||
|
|
@ -96,8 +98,6 @@ func NewABLeMHFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
return NewABLeMH(ctx, cc.URI, cc.Device, cc.Comset, cc.Baudrate, cc.ID, cc.Timeout)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateABLeMH -b *ABLeMH -r api.Charger -t api.Meter,api.PhaseCurrents
|
||||
|
||||
// NewABLeMH creates ABLeMH charger
|
||||
func NewABLeMH(ctx context.Context, uri, device, comset string, baudrate int, slaveID uint8, timeout time.Duration) (api.Charger, error) {
|
||||
conn, err := modbus.NewConnection(ctx, uri, device, comset, baudrate, modbus.Ascii, slaveID)
|
||||
|
|
@ -117,6 +117,7 @@ func NewABLeMH(ctx context.Context, uri, device, comset string, baudrate int, sl
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &ABLeMH{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
curr: uint16(6 / 0.06),
|
||||
}
|
||||
|
|
@ -125,7 +126,8 @@ func NewABLeMH(ctx context.Context, uri, device, comset string, baudrate int, sl
|
|||
|
||||
// check presence of current sensor
|
||||
if err == nil && (b[3]&ablSensorPresent != 0) {
|
||||
return decorateABLeMH(wb, wb.currentPower, wb.currents), nil
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
return wb, nil
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateABLeMH(base *ABLeMH, meter func() (float64, error), phaseCurrents func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateABLeMHMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateABLeMHPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateABLeMHCapable{ABLeMH: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateABLeMHCapable struct {
|
||||
*ABLeMH
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateABLeMHCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateABLeMHMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateABLeMHMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateABLeMHPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateABLeMHPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -35,6 +36,7 @@ import (
|
|||
|
||||
// Alfen charger implementation
|
||||
type Alfen struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
mu sync.Mutex
|
||||
|
|
@ -56,8 +58,6 @@ func init() {
|
|||
registry.AddCtx("alfen", NewAlfenFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateAlfen -b *Alfen -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewAlfenFromConfig creates a Alfen charger from generic config
|
||||
func NewAlfenFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
|
|
@ -86,6 +86,7 @@ func NewAlfen(ctx context.Context, uri string, slaveID uint8) (api.Charger, erro
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Alfen{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
}
|
||||
|
|
@ -97,19 +98,15 @@ func NewAlfen(ctx context.Context, uri string, slaveID uint8) (api.Charger, erro
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
phasesS func(int) error
|
||||
phasesG func() (int, error)
|
||||
)
|
||||
if v2 != 0 && v3 != 0 {
|
||||
wb.log.DEBUG.Println("detected 3p alfen")
|
||||
phasesS = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
} else {
|
||||
wb.log.DEBUG.Println("detected 1p alfen")
|
||||
}
|
||||
|
||||
return decorateAlfen(wb, phasesS, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *Alfen) heartbeat(ctx context.Context) {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateAlfen(base *Alfen, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateAlfenPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateAlfenPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateAlfenCapable{Alfen: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateAlfenCapable struct {
|
||||
*Alfen
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateAlfenCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateAlfenPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateAlfenPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateAlfenPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateAlfenPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -32,6 +33,7 @@ import (
|
|||
|
||||
// Amperfied charger implementation
|
||||
type Amperfied struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
current uint16
|
||||
|
|
@ -59,8 +61,6 @@ func init() {
|
|||
registry.AddCtx("amperfied", NewAmperfiedFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateAmperfied -b *Amperfied -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewAmperfiedFromConfig creates a Amperfied charger from generic config
|
||||
func NewAmperfiedFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -94,6 +94,7 @@ func NewAmperfied(ctx context.Context, uri string, slaveID uint8, phases bool) (
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Amperfied{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
current: 60, // assume min current
|
||||
|
|
@ -108,14 +109,12 @@ func NewAmperfied(ctx context.Context, uri string, slaveID uint8, phases bool) (
|
|||
go wb.heartbeat(ctx, time.Duration(u)*time.Millisecond/2)
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
var phasesG func() (int, error)
|
||||
if phases {
|
||||
phases1p3p = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
return decorateAmperfied(wb, phases1p3p, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *Amperfied) heartbeat(ctx context.Context, timeout time.Duration) {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateAmperfied(base *Amperfied, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateAmperfiedPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateAmperfiedPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateAmperfiedCapable{Amperfied: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateAmperfiedCapable struct {
|
||||
*Amperfied
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateAmperfiedCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateAmperfiedPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateAmperfiedPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateAmperfiedPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateAmperfiedPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/semp"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
|
|
@ -47,6 +48,7 @@ type sempHandler struct {
|
|||
|
||||
// BenderCC charger implementation
|
||||
type BenderCC struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
current uint16
|
||||
regCurr uint16
|
||||
|
|
@ -111,8 +113,6 @@ func NewBenderCCFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
}
|
||||
|
||||
// NewBenderCC creates BenderCC charger
|
||||
//
|
||||
//go:generate go tool decorate -f decorateBenderCC -b *BenderCC -r api.Charger -t api.Meter,api.PhaseCurrents,api.PhaseVoltages,api.MeterEnergy,api.Battery,api.Identifier,api.ChargerEx,api.PhaseSwitcher,api.PhaseGetter
|
||||
func NewBenderCC(ctx context.Context, uri string, id uint8, cache time.Duration) (api.Charger, error) {
|
||||
conn, err := modbus.NewConnection(ctx, uri, "", "", 0, modbus.Tcp, id)
|
||||
if err != nil {
|
||||
|
|
@ -127,6 +127,7 @@ func NewBenderCC(ctx context.Context, uri string, id uint8, cache time.Duration)
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &BenderCC{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
current: 6, // assume min current
|
||||
regCurr: bendRegHemsCurrentLimit,
|
||||
|
|
@ -138,18 +139,6 @@ func NewBenderCC(ctx context.Context, uri string, id uint8, cache time.Duration)
|
|||
wb.legacy = true
|
||||
}
|
||||
|
||||
var (
|
||||
currentPower func() (float64, error)
|
||||
currents func() (float64, float64, float64, error)
|
||||
voltages func() (float64, float64, float64, error)
|
||||
totalEnergy func() (float64, error)
|
||||
soc func() (float64, error)
|
||||
identify func() (string, error)
|
||||
maxCurrentMillis func(float64) error
|
||||
phases1p3p func(int) error
|
||||
getPhases func() (int, error)
|
||||
)
|
||||
|
||||
// check presence of metering
|
||||
reg := uint16(bendRegActivePower)
|
||||
if wb.legacy {
|
||||
|
|
@ -157,41 +146,39 @@ func NewBenderCC(ctx context.Context, uri string, id uint8, cache time.Duration)
|
|||
}
|
||||
|
||||
if b, err := wb.conn.ReadHoldingRegisters(reg, 2); err == nil && binary.BigEndian.Uint32(b) != math.MaxUint32 {
|
||||
currentPower = wb.currentPower
|
||||
currents = wb.currents
|
||||
totalEnergy = wb.totalEnergy
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
|
||||
// check presence of "ocpp meter"
|
||||
if b, err := wb.conn.ReadHoldingRegisters(bendRegVoltages, 2); err == nil && binary.BigEndian.Uint32(b) > 0 {
|
||||
voltages = wb.voltages
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
||||
if !wb.legacy {
|
||||
if _, err := wb.conn.ReadHoldingRegisters(bendRegEVBatteryState, 1); err == nil {
|
||||
soc = wb.soc
|
||||
implement.Has(wb, implement.Battery(wb.soc))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check feature mA
|
||||
if _, err := wb.conn.ReadHoldingRegisters(bendRegHemsCurrentLimit10, 1); err == nil {
|
||||
maxCurrentMillis = wb.maxCurrentMillis
|
||||
implement.Has(wb, implement.ChargerEx(wb.maxCurrentMillis))
|
||||
wb.regCurr = bendRegHemsCurrentLimit10
|
||||
}
|
||||
|
||||
// check feature modbus power control/1p3p fpr Mennekes 4you / 4business chargers
|
||||
// check feature modbus power control/1p3p for Mennekes 4you / 4business chargers
|
||||
if _, err := wb.conn.ReadHoldingRegisters(bendRegHemsPowerLimit, 1); err == nil {
|
||||
phases1p3p = wb.phases1p3pMennekes
|
||||
getPhases = wb.getPhasesMennekes
|
||||
}
|
||||
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3pMennekes))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhasesMennekes))
|
||||
} else {
|
||||
// check feature semp phase switching
|
||||
if phases1p3p == nil {
|
||||
if wb.supportsSEMPPhaseSwitching(uri, cache) {
|
||||
// set initial SEMP power limit to max so modbus control from 6 to 16 A is possible
|
||||
if err := wb.semp.conn.SendDeviceControl(wb.semp.deviceID, 0xffff); err == nil {
|
||||
phases1p3p = wb.phases1p3pSEMP
|
||||
getPhases = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3pSEMP))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
// start heartbeat to keep connection alive
|
||||
go wb.heartbeat(ctx)
|
||||
} else {
|
||||
|
|
@ -202,10 +189,10 @@ func NewBenderCC(ctx context.Context, uri string, id uint8, cache time.Duration)
|
|||
|
||||
// check feature rfid
|
||||
if _, err := wb.identify(); err == nil {
|
||||
identify = wb.identify
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
return decorateBenderCC(wb, currentPower, currents, voltages, totalEnergy, soc, identify, maxCurrentMillis, phases1p3p, getPhases), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// heartbeat ensures that SEMP device control updates are sent about once per minute
|
||||
|
|
|
|||
|
|
@ -1,140 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateBenderCC(base *BenderCC, meter func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), meterEnergy func() (float64, error), battery func() (float64, error), identifier func() (string, error), chargerEx func(float64) error, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateBenderCCMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateBenderCCPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateBenderCCPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateBenderCCMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateBenderCCBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateBenderCCIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decorateBenderCCChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateBenderCCPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateBenderCCPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateBenderCCCapable{BenderCC: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateBenderCCCapable struct {
|
||||
*BenderCC
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateBenderCCCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateBenderCCBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateBenderCCChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
||||
type decorateBenderCCIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateBenderCCMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateBenderCCMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateBenderCCPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateBenderCCPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateBenderCCPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateBenderCCPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateBenderCCPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -31,6 +32,7 @@ const (
|
|||
// 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 {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
}
|
||||
|
||||
|
|
@ -38,8 +40,6 @@ func init() {
|
|||
registry.AddCtx("cfos", NewCfosPowerBrainFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateCfos -b *CfosPowerBrain -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseSwitcher
|
||||
|
||||
// NewCfosPowerBrainFromConfig creates a cFos charger from generic config
|
||||
func NewCfosPowerBrainFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
|
|
@ -70,30 +70,26 @@ func NewCfosPowerBrain(ctx context.Context, uri string, id uint8) (api.Charger,
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &CfosPowerBrain{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
// decorate meter
|
||||
var (
|
||||
power, energy func() (float64, error)
|
||||
currents func() (float64, float64, float64, error)
|
||||
)
|
||||
if b, err := wb.conn.ReadHoldingRegisters(cfosRegMeter, 1); err == nil && binary.BigEndian.Uint16(b) != 0 {
|
||||
power = wb.currentPower
|
||||
energy = wb.totalEnergy
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
|
||||
if b, err := wb.conn.ReadHoldingRegisters(cfosRegMeterFlags, 1); err == nil && binary.BigEndian.Uint16(b) != 0 {
|
||||
currents = wb.currents
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
}
|
||||
|
||||
// decorate phases
|
||||
var phases1p3p func(int) error
|
||||
if b, err := wb.conn.ReadHoldingRegisters(cfosRegSolarEnabled, 1); err == nil && binary.BigEndian.Uint16(b)&(1<<8) != 0 {
|
||||
phases1p3p = wb.phases1p3p
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
}
|
||||
|
||||
return decorateCfos(wb, power, energy, currents, phases1p3p), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateCfos(base *CfosPowerBrain, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseSwitcher func(int) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateCfosMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateCfosMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateCfosPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateCfosPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateCfosCapable{CfosPowerBrain: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateCfosCapable struct {
|
||||
*CfosPowerBrain
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateCfosCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateCfosMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCfosMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateCfosMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCfosMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateCfosPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCfosPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateCfosPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateCfosPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -4,9 +4,9 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/measurement"
|
||||
meter "github.com/evcc-io/evcc/meter/measurement"
|
||||
"github.com/evcc-io/evcc/plugin"
|
||||
|
|
@ -16,6 +16,7 @@ import (
|
|||
// Charger is an api.Charger implementation with configurable getters and setters.
|
||||
type Charger struct {
|
||||
*embed
|
||||
implement.Caps
|
||||
statusG func() (string, error)
|
||||
enabledG func() (bool, error)
|
||||
enableS func(bool) error
|
||||
|
|
@ -26,8 +27,6 @@ func init() {
|
|||
registry.AddCtx(api.Custom, NewConfigurableFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateCustom -b *Charger -r api.Charger -t api.ChargerEx,api.Identifier,api.PhaseSwitcher,api.Resurrector,api.Battery,api.SocLimiter,api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.VehicleFinishTimer
|
||||
|
||||
// NewConfigurableFromConfig creates a new charger from config
|
||||
func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
var cc struct {
|
||||
|
|
@ -75,14 +74,15 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
}
|
||||
|
||||
c.embed = &cc.embed
|
||||
c.Caps = implement.New()
|
||||
|
||||
maxcurrentmillis, err := cc.MaxCurrentMillis.FloatSetter(ctx, "maxcurrentmillis")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("maxcurrentmillis: %w", err)
|
||||
}
|
||||
implement.May(c, implement.ChargerEx(maxcurrentmillis))
|
||||
|
||||
// decorate phases
|
||||
var phases1p3p func(int) error
|
||||
if cc.Phases1p3p != nil {
|
||||
if !cc.Tos {
|
||||
return nil, errors.New("1p3p does no longer handle disable/enable. Use tos: true to confirm you understand the consequences")
|
||||
|
|
@ -93,9 +93,9 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
return nil, fmt.Errorf("phases: %w", err)
|
||||
}
|
||||
|
||||
phases1p3p = func(phases int) error {
|
||||
implement.Has(c, implement.PhaseSwitcher(func(phases int) error {
|
||||
return phases1p3pS(int64(phases))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
// decorate identifier
|
||||
|
|
@ -103,18 +103,18 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("identify: %w", err)
|
||||
}
|
||||
implement.May(c, implement.Identifier(identify))
|
||||
|
||||
// decorate wakeup
|
||||
var wakeup func() error
|
||||
if cc.Wakeup != nil {
|
||||
set, err := cc.Wakeup.BoolSetter(ctx, "wakeup")
|
||||
wakeup, err := cc.Wakeup.BoolSetter(ctx, "wakeup")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("wakeup: %w", err)
|
||||
}
|
||||
|
||||
wakeup = func() error {
|
||||
return set(true)
|
||||
}
|
||||
implement.Has(c, implement.Resurrector(func() error {
|
||||
return wakeup(true)
|
||||
}))
|
||||
}
|
||||
|
||||
// decorate soc; for heating devices (api.Heating feature), the soc slot holds
|
||||
|
|
@ -141,28 +141,32 @@ func NewConfigurableFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
if limitsoc == nil && limitTemp != nil {
|
||||
limitsoc = limitTemp
|
||||
}
|
||||
implement.May(c, implement.Battery(soc))
|
||||
implement.May(c, implement.SocLimiter(limitsoc))
|
||||
|
||||
// decorate measurements
|
||||
powerG, energyG, err := cc.Energy.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(c, implement.Meter(powerG))
|
||||
implement.May(c, implement.MeterEnergy(energyG))
|
||||
|
||||
currentsG, voltagesG, _, err := cc.Phases.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(c, implement.PhaseCurrents(currentsG))
|
||||
implement.May(c, implement.PhaseVoltages(voltagesG))
|
||||
|
||||
// decorate finishtime
|
||||
var finishTime func() (time.Time, error)
|
||||
if cc.FinishTime != nil {
|
||||
finishTime, err = cc.FinishTime.TimeGetter(ctx)
|
||||
finishTime, err := cc.FinishTime.TimeGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("finishTime: %w", err)
|
||||
}
|
||||
}
|
||||
implement.May(c, implement.VehicleFinishTimer(finishTime))
|
||||
|
||||
return decorateCustom(c, maxcurrentmillis, identify, phases1p3p, wakeup, soc, limitsoc, powerG, energyG, currentsG, voltagesG, finishTime), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewConfigurable creates a new charger
|
||||
|
|
|
|||
|
|
@ -1,165 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateCustom(base *Charger, chargerEx func(float64) error, identifier func() (string, error), phaseSwitcher func(int) error, resurrector func() error, battery func() (float64, error), socLimiter func() (int64, error), meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), vehicleFinishTimer func() (time.Time, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decorateCustomChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateCustomIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateCustomPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if resurrector != nil {
|
||||
caps[reflect.TypeFor[api.Resurrector]()] = &decorateCustomResurrectorImpl{resurrector: resurrector}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateCustomBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if socLimiter != nil {
|
||||
caps[reflect.TypeFor[api.SocLimiter]()] = &decorateCustomSocLimiterImpl{socLimiter: socLimiter}
|
||||
}
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateCustomMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateCustomMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateCustomPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateCustomPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if vehicleFinishTimer != nil {
|
||||
caps[reflect.TypeFor[api.VehicleFinishTimer]()] = &decorateCustomVehicleFinishTimerImpl{vehicleFinishTimer: vehicleFinishTimer}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateCustomCapable{Charger: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateCustomCapable struct {
|
||||
*Charger
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateCustomCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateCustomBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateCustomChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decorateCustomChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
||||
type decorateCustomIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateCustomMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateCustomMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateCustomPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateCustomPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateCustomPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateCustomPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
||||
type decorateCustomResurrectorImpl struct {
|
||||
resurrector func() error
|
||||
}
|
||||
|
||||
func (impl *decorateCustomResurrectorImpl) WakeUp() error {
|
||||
return impl.resurrector()
|
||||
}
|
||||
|
||||
type decorateCustomSocLimiterImpl struct {
|
||||
socLimiter func() (int64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomSocLimiterImpl) GetLimitSoc() (int64, error) {
|
||||
return impl.socLimiter()
|
||||
}
|
||||
|
||||
type decorateCustomVehicleFinishTimerImpl struct {
|
||||
vehicleFinishTimer func() (time.Time, error)
|
||||
}
|
||||
|
||||
func (impl *decorateCustomVehicleFinishTimerImpl) FinishTime() (time.Time, error) {
|
||||
return impl.vehicleFinishTimer()
|
||||
}
|
||||
|
|
@ -24,12 +24,14 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
)
|
||||
|
||||
// DaheimLaden charger implementation
|
||||
type DaheimLaden struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
curr uint16
|
||||
|
|
@ -65,8 +67,6 @@ func init() {
|
|||
registry.AddCtx("daheimladen", NewDaheimLadenFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateDaheimLaden -b *DaheimLaden -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewDaheimLadenFromConfig creates a DaheimLaden charger from generic config
|
||||
func NewDaheimLadenFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -96,6 +96,7 @@ func NewDaheimLaden(ctx context.Context, uri string, id uint8, phases bool) (api
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &DaheimLaden{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
curr: 60, // assume min current
|
||||
|
|
@ -120,14 +121,12 @@ func NewDaheimLaden(ctx context.Context, uri string, id uint8, phases bool) (api
|
|||
go wb.heartbeat(ctx, time.Duration(u)*time.Second/2)
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
var phasesG func() (int, error)
|
||||
if phases {
|
||||
phases1p3p = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
return decorateDaheimLaden(wb, phases1p3p, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *DaheimLaden) heartbeat(ctx context.Context, timeout time.Duration) {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateDaheimLaden(base *DaheimLaden, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateDaheimLadenPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateDaheimLadenPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateDaheimLadenCapable{DaheimLaden: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateDaheimLadenCapable struct {
|
||||
*DaheimLaden
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateDaheimLadenCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateDaheimLadenPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateDaheimLadenPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateDaheimLadenPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateDaheimLadenPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"github.com/enbility/eebus-go/usecases/cem/evcem"
|
||||
spineapi "github.com/enbility/spine-go/api"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/server/eebus"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -29,6 +30,7 @@ type minMax struct {
|
|||
}
|
||||
|
||||
type EEBus struct {
|
||||
implement.Caps
|
||||
cem *eebus.CustomerEnergyManagement
|
||||
ev spineapi.EntityRemoteInterface
|
||||
|
||||
|
|
@ -69,8 +71,6 @@ func NewEEBusFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
return NewEEBus(ctx, cc.Ski, cc.Ip, cc.Meter, hasChargedEnergy)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateEEBus -b *EEBus -r api.Charger -t api.Meter,api.PhaseCurrents,api.ChargeRater
|
||||
|
||||
// newEEBus creates and initializes a raw *EEBus charger.
|
||||
// It registers the device with the EEBus instance and waits for the connection.
|
||||
func newEEBus(ctx context.Context, ski, ip string) (*EEBus, error) {
|
||||
|
|
@ -79,6 +79,7 @@ func newEEBus(ctx context.Context, ski, ip string) (*EEBus, error) {
|
|||
}
|
||||
|
||||
c := &EEBus{
|
||||
Caps: implement.New(),
|
||||
log: util.NewLogger("eebus"),
|
||||
current: 6,
|
||||
cem: eebus.Instance.CustomerEnergyManagement(),
|
||||
|
|
@ -113,11 +114,11 @@ func NewEEBus(ctx context.Context, ski, ip string, hasMeter, hasChargedEnergy bo
|
|||
}
|
||||
|
||||
if hasMeter {
|
||||
var energyG func() (float64, error)
|
||||
implement.Has(c, implement.Meter(c.currentPower))
|
||||
implement.Has(c, implement.PhaseCurrents(c.currents))
|
||||
if hasChargedEnergy {
|
||||
energyG = c.chargedEnergy
|
||||
implement.Has(c, implement.ChargeRater(c.chargedEnergy))
|
||||
}
|
||||
return decorateEEBus(c, c.currentPower, c.currents, energyG), nil
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateEEBus(base *EEBus, meter func() (float64, error), phaseCurrents func() (float64, float64, float64, error), chargeRater func() (float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateEEBusMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateEEBusPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if chargeRater != nil {
|
||||
caps[reflect.TypeFor[api.ChargeRater]()] = &decorateEEBusChargeRaterImpl{chargeRater: chargeRater}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateEEBusCapable{EEBus: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateEEBusCapable struct {
|
||||
*EEBus
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateEEBusCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateEEBusChargeRaterImpl struct {
|
||||
chargeRater func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEEBusChargeRaterImpl) ChargedEnergy() (float64, error) {
|
||||
return impl.chargeRater()
|
||||
}
|
||||
|
||||
type decorateEEBusMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEEBusMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateEEBusPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEEBusPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/volkszaehler/mbmd/meters/rs485"
|
||||
|
|
@ -34,6 +35,7 @@ import (
|
|||
|
||||
// Em2Go charger implementation
|
||||
type Em2Go struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
current uint16
|
||||
|
|
@ -70,8 +72,6 @@ func init() {
|
|||
registry.AddCtx("em2go-home", NewEm2GoFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateEm2Go -b *Em2Go -r api.Charger -t api.ChargerEx,api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewEm2GoFromConfig creates a Em2Go charger from generic config
|
||||
func NewEm2GoFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -104,6 +104,7 @@ func NewEm2Go(ctx context.Context, uri string, slaveID uint8) (api.Charger, erro
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Em2Go{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
current: 60,
|
||||
|
|
@ -149,12 +150,6 @@ func (wb *Em2Go) heartbeat(ctx context.Context, interval time.Duration) {
|
|||
|
||||
// initialize performs common initialization for both Em2Go models
|
||||
func (wb *Em2Go) initialize() (api.Charger, error) {
|
||||
var (
|
||||
maxCurrent func(float64) error
|
||||
phases1p3p func(int) error
|
||||
phasesG func() (int, error)
|
||||
)
|
||||
|
||||
// test if workaround is needed (Home fw <1.3)
|
||||
if err := wb.maxCurrentMillis(6.1); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -169,15 +164,15 @@ func (wb *Em2Go) initialize() (api.Charger, error) {
|
|||
if chargerCurrent == 6 {
|
||||
wb.workaround = true
|
||||
} else {
|
||||
maxCurrent = wb.maxCurrentMillis
|
||||
implement.Has(wb, implement.ChargerEx(wb.maxCurrentMillis))
|
||||
}
|
||||
|
||||
if _, err := wb.conn.ReadHoldingRegisters(em2GoRegPhases, 1); err == nil {
|
||||
phases1p3p = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
return decorateEm2Go(wb, maxCurrent, phases1p3p, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateEm2Go(base *Em2Go, chargerEx func(float64) error, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decorateEm2GoChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateEm2GoPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateEm2GoPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateEm2GoCapable{Em2Go: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateEm2GoCapable struct {
|
||||
*Em2Go
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateEm2GoCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateEm2GoChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decorateEm2GoChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
||||
type decorateEm2GoPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEm2GoPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateEm2GoPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateEm2GoPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
)
|
||||
|
|
@ -32,6 +33,7 @@ import (
|
|||
|
||||
// ETEK EKEPC2 charger implementation
|
||||
type Etek struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
}
|
||||
|
|
@ -65,8 +67,6 @@ func init() {
|
|||
registry.AddCtx("etek", NewEtekFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateEtek -b *Etek -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseVoltages
|
||||
|
||||
// NewEtekFromConfig creates an ETEK EKEPC2 charger from generic config
|
||||
func NewEtekFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.Settings{
|
||||
|
|
@ -84,23 +84,18 @@ func NewEtekFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
|
||||
// Check if external meter is configured
|
||||
// If register value is 65535 (0xffff), no external meter is configured
|
||||
var (
|
||||
currentPower func() (float64, error)
|
||||
totalEnergy func() (float64, error)
|
||||
voltages func() (float64, float64, float64, error)
|
||||
)
|
||||
|
||||
// Check power register (94)
|
||||
if b, err := wb.conn.ReadHoldingRegisters(etekRegMeterPowerAddr, 1); err == nil {
|
||||
if binary.BigEndian.Uint16(b) != etekRegInvalidMeterAddr {
|
||||
currentPower = wb.currentPower
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
}
|
||||
}
|
||||
|
||||
// Check energy register (95)
|
||||
if b, err := wb.conn.ReadHoldingRegisters(etekRegMeterEnergyAddr, 1); err == nil {
|
||||
if binary.BigEndian.Uint16(b) != etekRegInvalidMeterAddr {
|
||||
totalEnergy = wb.totalEnergy
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -110,11 +105,11 @@ func NewEtekFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
l2 := binary.BigEndian.Uint16(b[2:4])
|
||||
l3 := binary.BigEndian.Uint16(b[4:6])
|
||||
if l1 != etekRegInvalidMeterAddr && l2 != etekRegInvalidMeterAddr && l3 != etekRegInvalidMeterAddr {
|
||||
voltages = wb.voltages
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
}
|
||||
|
||||
return decorateEtek(wb, currentPower, totalEnergy, voltages), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewEtek creates an ETEK EKEPC2 charger
|
||||
|
|
@ -128,6 +123,7 @@ func NewEtek(ctx context.Context, uri, device, comset string, baudrate int, prot
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Etek{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateEtek(base *Etek, meter func() (float64, error), meterEnergy func() (float64, error), phaseVoltages func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateEtekMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateEtekMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateEtekPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateEtekCapable{Etek: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateEtekCapable struct {
|
||||
*Etek
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateEtekCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateEtekMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEtekMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateEtekMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEtekMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateEtekPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEtekPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -33,6 +34,7 @@ import (
|
|||
|
||||
// EVECUBE charger implementation
|
||||
type EVECUBE struct {
|
||||
implement.Caps
|
||||
*request.Helper
|
||||
uri string
|
||||
connector int
|
||||
|
|
@ -46,8 +48,6 @@ func init() {
|
|||
registry.Add("evecube", NewEVECUBEFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateEVECUBE -b *EVECUBE -r api.Charger -t api.PhaseSwitcher,api.Identifier
|
||||
|
||||
// EVECUBEUnitConfig is the /api/admin/unitconfig response
|
||||
type EVECUBEUnitConfig struct {
|
||||
ForcePhaseCharging int `json:"ForcePhaseCharging"`
|
||||
|
|
@ -135,15 +135,12 @@ func NewEVECUBEFromConfig(other map[string]any) (api.Charger, error) {
|
|||
|
||||
// Phases1p3p and Identify APIs affect the entire charger, not individual connectors
|
||||
// Only enable these APIs if the charger has a single connector
|
||||
var phases1p3p func(int) error
|
||||
var identify func() (string, error)
|
||||
|
||||
if config.NumberOfConnectors == 1 {
|
||||
phases1p3p = wb.phases1p3p
|
||||
identify = wb.identify
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
return decorateEVECUBE(wb, phases1p3p, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewEVECUBE creates EVECUBE charger
|
||||
|
|
@ -151,6 +148,7 @@ func NewEVECUBE(uri, user, password string, connector int, cache time.Duration)
|
|||
log := util.NewLogger("evecube")
|
||||
|
||||
wb := &EVECUBE{
|
||||
Caps: implement.New(),
|
||||
Helper: request.NewHelper(log),
|
||||
uri: strings.TrimRight(uri, "/"),
|
||||
connector: connector,
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateEVECUBE(base *EVECUBE, phaseSwitcher func(int) error, identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateEVECUBEPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateEVECUBEIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateEVECUBECapable{EVECUBE: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateEVECUBECapable struct {
|
||||
*EVECUBE
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateEVECUBECapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateEVECUBEIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEVECUBEIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateEVECUBEPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateEVECUBEPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/volkszaehler/mbmd/encoding"
|
||||
|
|
@ -14,6 +15,7 @@ import (
|
|||
|
||||
// EvseDIN charger implementation
|
||||
type EvseDIN struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
current uint16
|
||||
}
|
||||
|
|
@ -46,8 +48,6 @@ func NewEvseDINFromConfig(ctx context.Context, other map[string]any) (api.Charge
|
|||
return NewEvseDIN(ctx, cc.URI, cc.Device, cc.Comset, cc.Baudrate, cc.Protocol(), cc.ID)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateEvseDIN -b *EvseDIN -r api.Charger -t api.ChargerEx
|
||||
|
||||
// NewEvseDIN creates EVSE DIN charger
|
||||
func NewEvseDIN(ctx context.Context, uri, device, comset string, baudrate int, proto modbus.Protocol, slaveID uint8) (api.Charger, error) {
|
||||
log := util.NewLogger("evse")
|
||||
|
|
@ -61,12 +61,11 @@ func NewEvseDIN(ctx context.Context, uri, device, comset string, baudrate int, p
|
|||
conn.Delay(200 * time.Millisecond)
|
||||
|
||||
evse := &EvseDIN{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
current: 6, // assume min current
|
||||
}
|
||||
|
||||
var maxCurrentMillis func(float64) error
|
||||
|
||||
// check firmware
|
||||
bFirmware, err := evse.conn.ReadHoldingRegisters(evseRegFirmware, 1)
|
||||
if err != nil {
|
||||
|
|
@ -94,7 +93,7 @@ func NewEvseDIN(ctx context.Context, uri, device, comset string, baudrate int, p
|
|||
}
|
||||
|
||||
if config&0x0080 != 0 {
|
||||
maxCurrentMillis = evse.maxCurrentMillis
|
||||
implement.Has(evse, implement.ChargerEx(evse.maxCurrentMillis))
|
||||
evse.current = 600 // assume min current
|
||||
}
|
||||
}
|
||||
|
|
@ -107,7 +106,7 @@ func NewEvseDIN(ctx context.Context, uri, device, comset string, baudrate int, p
|
|||
evse.current = current
|
||||
}
|
||||
|
||||
return decorateEvseDIN(evse, maxCurrentMillis), nil
|
||||
return evse, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateEvseDIN(base *EvseDIN, chargerEx func(float64) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decorateEvseDINChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateEvseDINCapable{EvseDIN: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateEvseDINCapable struct {
|
||||
*EvseDIN
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateEvseDINCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateEvseDINChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decorateEvseDINChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/evse"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -15,6 +16,7 @@ import (
|
|||
// EVSEWifi charger implementation
|
||||
type EVSEWifi struct {
|
||||
*request.Helper
|
||||
implement.Caps
|
||||
uri string
|
||||
alwaysActive bool
|
||||
current int64 // current will always be the physical value sent to the API
|
||||
|
|
@ -27,8 +29,6 @@ func init() {
|
|||
registry.Add("evsewifi", NewEVSEWifiFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateEVSE -b *EVSEWifi -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.ChargerEx,api.Identifier
|
||||
|
||||
// NewEVSEWifiFromConfig creates a EVSEWifi charger from generic config
|
||||
func NewEVSEWifiFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -71,42 +71,32 @@ func NewEVSEWifiFromConfig(other map[string]any) (api.Charger, error) {
|
|||
wb.hires = true
|
||||
}
|
||||
|
||||
// decorate meter
|
||||
var (
|
||||
power, energy func() (float64, error)
|
||||
currents, voltages func() (float64, float64, float64, error)
|
||||
)
|
||||
|
||||
if cc.Meter.Power {
|
||||
power = wb.currentPower
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
}
|
||||
|
||||
if cc.Meter.Energy {
|
||||
energy = wb.totalEnergy
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
}
|
||||
|
||||
if cc.Meter.Currents {
|
||||
currents = wb.currents
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
if cc.Meter.Voltages {
|
||||
voltages = wb.voltages
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
||||
// decorate Charger with MaxCurrentMillis
|
||||
var maxCurrentMillis func(float64) error
|
||||
if wb.hires {
|
||||
maxCurrentMillis = wb.maxCurrentMillis
|
||||
implement.Has(wb, implement.ChargerEx(wb.maxCurrentMillis))
|
||||
wb.current = 100 * wb.current
|
||||
}
|
||||
|
||||
// decorate Charger with Identifier
|
||||
var identify func() (string, error)
|
||||
if params.RFIDUID != nil {
|
||||
identify = wb.identify
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
return decorateEVSE(wb, power, energy, currents, voltages, maxCurrentMillis, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewEVSEWifi creates EVSEWifi charger
|
||||
|
|
@ -115,6 +105,7 @@ func NewEVSEWifi(uri string, cache time.Duration) (*EVSEWifi, error) {
|
|||
|
||||
wb := &EVSEWifi{
|
||||
Helper: request.NewHelper(log),
|
||||
Caps: implement.New(),
|
||||
uri: strings.TrimRight(uri, "/"),
|
||||
current: 6, // 6A defined value
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateEVSE(base *EVSEWifi, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), chargerEx func(float64) error, identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateEVSEMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateEVSEMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateEVSEPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateEVSEPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decorateEVSEChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateEVSEIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateEVSECapable{EVSEWifi: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateEVSECapable struct {
|
||||
*EVSEWifi
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateEVSECapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateEVSEChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decorateEVSEChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
||||
type decorateEVSEIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEVSEIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateEVSEMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEVSEMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateEVSEMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEVSEMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateEVSEPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEVSEPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateEVSEPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateEVSEPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/enbility/spine-go/model"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/ghostone"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -49,8 +50,6 @@ func NewGhostEEBusFromConfig(ctx context.Context, other map[string]any) (api.Cha
|
|||
return NewGhostEEBus(ctx, cc.Ski, cc.Ip, cc.User, cc.Password, cc.Meter, hasChargedEnergy)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateGhostEEBus -b *GhostEEBus -r api.Charger -t api.Meter,api.PhaseCurrents,api.ChargeRater,api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewGhostEEBus creates a GhostEEBus charger combining EEBus with Ghost REST API
|
||||
func NewGhostEEBus(ctx context.Context, ski, ip, user, password string, hasMeter, hasChargedEnergy bool) (api.Charger, error) {
|
||||
eb, err := newEEBus(ctx, ski, ip)
|
||||
|
|
@ -69,9 +68,6 @@ func NewGhostEEBus(ctx context.Context, ski, ip, user, password string, hasMeter
|
|||
}
|
||||
|
||||
// REST API features require IP and credentials
|
||||
var phasesS func(int) error
|
||||
var phasesG func() (int, error)
|
||||
|
||||
if ip != "" && user != "" && password != "" {
|
||||
ts, err := ghostone.TokenSource(ctx, log, wb.uri, user, password)
|
||||
if err != nil {
|
||||
|
|
@ -97,25 +93,21 @@ func NewGhostEEBus(ctx context.Context, ski, ip, user, password string, hasMeter
|
|||
|
||||
// always wire up phase switching and RFID - the wallbox will reject
|
||||
// operations at runtime if the feature is disabled or not possible
|
||||
phasesS = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
wb.hasRFID = true
|
||||
}
|
||||
|
||||
// EEBus meter capabilities
|
||||
var meter func() (float64, error)
|
||||
var phaseCurrents func() (float64, float64, float64, error)
|
||||
var chargeRater func() (float64, error)
|
||||
|
||||
if hasMeter {
|
||||
meter = eb.currentPower
|
||||
phaseCurrents = eb.currents
|
||||
implement.Has(wb, implement.Meter(eb.currentPower))
|
||||
implement.Has(wb, implement.PhaseCurrents(eb.currents))
|
||||
if hasChargedEnergy {
|
||||
chargeRater = eb.chargedEnergy
|
||||
implement.Has(wb, implement.ChargeRater(eb.chargedEnergy))
|
||||
}
|
||||
}
|
||||
|
||||
return decorateGhostEEBus(wb, meter, phaseCurrents, chargeRater, phasesS, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
var _ api.Identifier = (*GhostEEBus)(nil)
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateGhostEEBus(base *GhostEEBus, meter func() (float64, error), phaseCurrents func() (float64, float64, float64, error), chargeRater func() (float64, error), phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateGhostEEBusMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateGhostEEBusPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if chargeRater != nil {
|
||||
caps[reflect.TypeFor[api.ChargeRater]()] = &decorateGhostEEBusChargeRaterImpl{chargeRater: chargeRater}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateGhostEEBusPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateGhostEEBusPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateGhostEEBusCapable{GhostEEBus: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateGhostEEBusCapable struct {
|
||||
*GhostEEBus
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateGhostEEBusCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateGhostEEBusChargeRaterImpl struct {
|
||||
chargeRater func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateGhostEEBusChargeRaterImpl) ChargedEnergy() (float64, error) {
|
||||
return impl.chargeRater()
|
||||
}
|
||||
|
||||
type decorateGhostEEBusMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateGhostEEBusMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateGhostEEBusPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateGhostEEBusPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateGhostEEBusPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateGhostEEBusPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateGhostEEBusPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateGhostEEBusPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ import (
|
|||
spinemocks "github.com/enbility/spine-go/mocks"
|
||||
"github.com/enbility/spine-go/model"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/ghostone"
|
||||
"github.com/evcc-io/evcc/server/eebus"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -26,6 +27,7 @@ func newTestGhostEEBusREST(t *testing.T) *GhostEEBus {
|
|||
t.Helper()
|
||||
return &GhostEEBus{
|
||||
EEBus: &EEBus{
|
||||
Caps: implement.New(),
|
||||
log: util.NewLogger("test"),
|
||||
cem: &eebus.CustomerEnergyManagement{},
|
||||
},
|
||||
|
|
@ -42,6 +44,7 @@ func newTestGhostEEBusWithEEBus(t *testing.T) (*GhostEEBus, *mocks.CemEVCCInterf
|
|||
evEntity := spinemocks.NewEntityRemoteInterface(t)
|
||||
|
||||
eb := &EEBus{
|
||||
Caps: implement.New(),
|
||||
cem: &eebus.CustomerEnergyManagement{
|
||||
EvCC: evccMock,
|
||||
},
|
||||
|
|
@ -285,13 +288,14 @@ func TestGhostEEBus_Decorator(t *testing.T) {
|
|||
wb := newTestGhostEEBusREST(t)
|
||||
|
||||
// with phase switching
|
||||
decorated := decorateGhostEEBus(wb, nil, nil, nil, wb.phases1p3p, wb.getPhases)
|
||||
assert.True(t, api.HasCap[api.PhaseSwitcher](decorated), "expected PhaseSwitcher")
|
||||
assert.True(t, api.HasCap[api.PhaseGetter](decorated), "expected PhaseGetter")
|
||||
implement.May(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.May(wb, implement.PhaseGetter(wb.getPhases))
|
||||
assert.True(t, api.HasCap[api.PhaseSwitcher](wb), "expected PhaseSwitcher")
|
||||
assert.True(t, api.HasCap[api.PhaseGetter](wb), "expected PhaseGetter")
|
||||
|
||||
// without phase switching
|
||||
decorated = decorateGhostEEBus(wb, nil, nil, nil, nil, nil)
|
||||
assert.False(t, api.HasCap[api.PhaseSwitcher](decorated), "unexpected PhaseSwitcher")
|
||||
// without phase switching — capabilities not registered, so expect false
|
||||
wb2 := newTestGhostEEBusREST(t)
|
||||
assert.False(t, api.HasCap[api.PhaseSwitcher](wb2), "unexpected PhaseSwitcher")
|
||||
}
|
||||
|
||||
func TestGhostEEBus_Config(t *testing.T) {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
goe "github.com/evcc-io/evcc/charger/go-e"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -34,6 +35,7 @@ import (
|
|||
|
||||
// GoE charger implementation
|
||||
type GoE struct {
|
||||
implement.Caps
|
||||
api goe.API
|
||||
}
|
||||
|
||||
|
|
@ -46,8 +48,6 @@ func init() {
|
|||
})
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateGoE -b *GoE -r api.Charger -t api.ChargeRater,api.PhaseSwitcher
|
||||
|
||||
// newGoEFromConfig creates a go-e charger from generic config
|
||||
func newGoEFromConfig(v2 bool, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -71,22 +71,22 @@ func newGoEFromConfig(v2 bool, other map[string]any) (api.Charger, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var chargedEnergy func() (float64, error)
|
||||
if v2 {
|
||||
chargedEnergy = c.chargedEnergy
|
||||
implement.Has(c, implement.ChargeRater(c.chargedEnergy))
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
if c.api.IsV2() {
|
||||
phases1p3p = c.phases1p3p
|
||||
implement.Has(c, implement.PhaseSwitcher(c.phases1p3p))
|
||||
}
|
||||
|
||||
return decorateGoE(c, chargedEnergy, phases1p3p), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewGoE creates GoE charger
|
||||
func NewGoE(uri, token string, cache time.Duration) (*GoE, error) {
|
||||
c := &GoE{}
|
||||
c := &GoE{
|
||||
Caps: implement.New(),
|
||||
}
|
||||
|
||||
log := util.NewLogger("go-e").Redact(token)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateGoE(base *GoE, chargeRater func() (float64, error), phaseSwitcher func(int) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if chargeRater != nil {
|
||||
caps[reflect.TypeFor[api.ChargeRater]()] = &decorateGoEChargeRaterImpl{chargeRater: chargeRater}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateGoEPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateGoECapable{GoE: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateGoECapable struct {
|
||||
*GoE
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateGoECapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateGoEChargeRaterImpl struct {
|
||||
chargeRater func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateGoEChargeRaterImpl) ChargedEnergy() (float64, error) {
|
||||
return impl.chargeRater()
|
||||
}
|
||||
|
||||
type decorateGoEPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateGoEPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import (
|
|||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/echarge"
|
||||
"github.com/evcc-io/evcc/charger/echarge/salia"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -42,6 +43,7 @@ import (
|
|||
// Salia charger implementation
|
||||
type Salia struct {
|
||||
*request.Helper
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
uri string
|
||||
current int64
|
||||
|
|
@ -53,8 +55,6 @@ func init() {
|
|||
registry.AddCtx("hardybarth-salia", NewSaliaFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateSalia -b *Salia -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewSaliaFromConfig creates a Salia cPH2 charger from generic config
|
||||
func NewSaliaFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -83,6 +83,7 @@ func NewSalia(ctx context.Context, uri, user, password string, cache time.Durati
|
|||
wb := &Salia{
|
||||
log: log,
|
||||
Helper: request.NewHelper(log),
|
||||
Caps: implement.New(),
|
||||
uri: util.DefaultScheme(uri, "http"),
|
||||
current: 6,
|
||||
}
|
||||
|
|
@ -138,26 +139,18 @@ func NewSalia(ctx context.Context, uri, user, password string, cache time.Durati
|
|||
|
||||
wb.pause(false)
|
||||
|
||||
var (
|
||||
currentPower func() (float64, error)
|
||||
totalEnergy func() (float64, error)
|
||||
currents func() (float64, float64, float64, error)
|
||||
phasesG func() (int, error)
|
||||
phasesS func(int) error
|
||||
)
|
||||
|
||||
if res.Secc.Port0.Metering.Meter.Available > 0 {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
currents = wb.currents
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
if res.Secc.Port0.Salia.PhaseSwitching.Actual > 0 {
|
||||
phasesG = wb.getPhases
|
||||
phasesS = wb.phases1p3p
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
return decorateSalia(wb, currentPower, totalEnergy, currents, phasesS, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *Salia) heartbeat(ctx context.Context) {
|
||||
|
|
|
|||
|
|
@ -1,92 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateSalia(base *Salia, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateSaliaMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateSaliaMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateSaliaPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateSaliaPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateSaliaPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateSaliaCapable{Salia: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateSaliaCapable struct {
|
||||
*Salia
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateSaliaCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateSaliaMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSaliaMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateSaliaMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSaliaMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateSaliaPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSaliaPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateSaliaPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSaliaPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateSaliaPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateSaliaPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/measurement"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/plugin"
|
||||
|
|
@ -30,6 +31,7 @@ import (
|
|||
// Heatpump charger implementation
|
||||
type Heatpump struct {
|
||||
*embed
|
||||
implement.Caps
|
||||
lp loadpoint.API
|
||||
power int64
|
||||
maxPowerG func() (int64, error)
|
||||
|
|
@ -40,8 +42,6 @@ func init() {
|
|||
registry.AddCtx("heatpump", NewHeatpumpFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateHeatpump -b *Heatpump -r api.Charger -t api.Meter,api.MeterEnergy,api.Battery,api.SocLimiter
|
||||
|
||||
// NewHeatpumpFromConfig creates heatpump configurable charger from generic config
|
||||
func NewHeatpumpFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -84,19 +84,24 @@ func NewHeatpumpFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Meter(powerG))
|
||||
implement.May(res, implement.MeterEnergy(energyG))
|
||||
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Battery(tempG))
|
||||
implement.May(res, implement.SocLimiter(limitTempG))
|
||||
|
||||
return decorateHeatpump(res, powerG, energyG, tempG, limitTempG), nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// NewHeatpump creates heatpump charger
|
||||
func NewHeatpump(ctx context.Context, embed *embed, maxPowerS func(int64) error, maxPowerG func() (int64, error)) (*Heatpump, error) {
|
||||
res := &Heatpump{
|
||||
embed: embed,
|
||||
Caps: implement.New(),
|
||||
maxPowerG: maxPowerG,
|
||||
maxPowerS: maxPowerS,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateHeatpump(base *Heatpump, meter func() (float64, error), meterEnergy func() (float64, error), battery func() (float64, error), socLimiter func() (int64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateHeatpumpMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateHeatpumpMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateHeatpumpBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if socLimiter != nil {
|
||||
caps[reflect.TypeFor[api.SocLimiter]()] = &decorateHeatpumpSocLimiterImpl{socLimiter: socLimiter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateHeatpumpCapable{Heatpump: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateHeatpumpCapable struct {
|
||||
*Heatpump
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateHeatpumpCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateHeatpumpBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHeatpumpBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateHeatpumpMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHeatpumpMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateHeatpumpMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHeatpumpMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateHeatpumpSocLimiterImpl struct {
|
||||
socLimiter func() (int64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHeatpumpSocLimiterImpl) GetLimitSoc() (int64, error) {
|
||||
return impl.socLimiter()
|
||||
}
|
||||
|
|
@ -1,20 +1,19 @@
|
|||
package charger
|
||||
|
||||
//go:generate go tool decorate -f decorateHomeAssistant -b *HomeAssistant -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.PhaseSwitcher,api.PhaseGetter
|
||||
// -t api.CurrentGetter
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/homeassistant"
|
||||
)
|
||||
|
||||
// HomeAssistant charger implementation
|
||||
type HomeAssistant struct {
|
||||
implement.Caps
|
||||
conn *homeassistant.Connection
|
||||
status string
|
||||
enabled string
|
||||
|
|
@ -68,6 +67,7 @@ func NewHomeAssistantFromConfig(other map[string]any) (api.Charger, error) {
|
|||
}
|
||||
|
||||
c := &HomeAssistant{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
status: cc.Status,
|
||||
enabled: cc.Enabled,
|
||||
|
|
@ -75,49 +75,43 @@ func NewHomeAssistantFromConfig(other map[string]any) (api.Charger, error) {
|
|||
maxcurrent: cc.MaxCurrent,
|
||||
}
|
||||
|
||||
// decorators for optional interfaces
|
||||
var power, energy func() (float64, error)
|
||||
var currents, voltages func() (float64, float64, float64, error)
|
||||
var phases1p3p func(int) error
|
||||
var phasesG func() (int, error)
|
||||
|
||||
if cc.Power != "" {
|
||||
power = func() (float64, error) { return conn.GetFloatState(cc.Power) }
|
||||
implement.Has(c, implement.Meter(func() (float64, error) { return conn.GetFloatState(cc.Power) }))
|
||||
}
|
||||
if cc.Energy != "" {
|
||||
energy = func() (float64, error) { return conn.GetFloatState(cc.Energy) }
|
||||
implement.Has(c, implement.MeterEnergy(func() (float64, error) { return conn.GetFloatState(cc.Energy) }))
|
||||
}
|
||||
|
||||
// phase currents (optional)
|
||||
if phases, err := homeassistant.ValidatePhaseEntities(cc.Currents); len(phases) > 0 {
|
||||
currents = func() (float64, float64, float64, error) { return conn.GetPhaseFloatStates(phases) }
|
||||
implement.Has(c, implement.PhaseCurrents(func() (float64, float64, float64, error) { return conn.GetPhaseFloatStates(phases) }))
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("currents: %w", err)
|
||||
}
|
||||
|
||||
// phase voltages (optional)
|
||||
if phases, err := homeassistant.ValidatePhaseEntities(cc.Voltages); len(phases) > 0 {
|
||||
voltages = func() (float64, float64, float64, error) { return conn.GetPhaseFloatStates(phases) }
|
||||
implement.Has(c, implement.PhaseVoltages(func() (float64, float64, float64, error) { return conn.GetPhaseFloatStates(phases) }))
|
||||
} else if err != nil {
|
||||
return nil, fmt.Errorf("voltages: %w", err)
|
||||
}
|
||||
|
||||
// phase switching (optional)
|
||||
if cc.Phases != "" {
|
||||
phases1p3p = func(phases int) error {
|
||||
implement.Has(c, implement.PhaseSwitcher(func(phases int) error {
|
||||
return conn.CallSelectService(cc.Phases, strconv.Itoa(phases))
|
||||
}
|
||||
}))
|
||||
|
||||
phasesG = func() (int, error) {
|
||||
implement.Has(c, implement.PhaseGetter(func() (int, error) {
|
||||
val, err := conn.GetIntState(cc.Phases)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int(val), nil
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
return decorateHomeAssistant(c, power, energy, currents, voltages, phases1p3p, phasesG), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
var _ api.Charger = (*HomeAssistant)(nil)
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateHomeAssistant(base *HomeAssistant, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateHomeAssistantMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateHomeAssistantMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateHomeAssistantPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateHomeAssistantPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateHomeAssistantPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateHomeAssistantPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateHomeAssistantCapable{HomeAssistant: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateHomeAssistantCapable struct {
|
||||
*HomeAssistant
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateHomeAssistantCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateHomeAssistantMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateHomeAssistantMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateHomeAssistantPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateHomeAssistantPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"math"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -46,6 +47,7 @@ var igyRegMaxCurrents = []uint16{1012, 1014, 1016} // max current per phase
|
|||
|
||||
// Innogy is an api.Charger implementation for Innogy eBox wallboxes.
|
||||
type Innogy struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
curr float64
|
||||
hasVoltages bool
|
||||
|
|
@ -70,21 +72,16 @@ func NewInnogyFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var totalEnergy func() (float64, error)
|
||||
var voltages func() (float64, float64, float64, error)
|
||||
|
||||
// check presence of energy meter & voltages registers
|
||||
if b, err := wb.conn.ReadInputRegisters(igyRegModbusTableVersion, 1); err == nil && binary.BigEndian.Uint16(b) >= 6 {
|
||||
totalEnergy = wb.totalEnergy
|
||||
voltages = wb.voltages
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
wb.hasVoltages = true
|
||||
}
|
||||
|
||||
return decorateInnogy(wb, totalEnergy, voltages), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateInnogy -b *Innogy -r api.Charger -t api.MeterEnergy,api.PhaseVoltages
|
||||
|
||||
// NewInnogy creates a Innogy charger
|
||||
func NewInnogy(ctx context.Context, uri string, id uint8) (*Innogy, error) {
|
||||
conn, err := modbus.NewConnection(ctx, uri, "", "", 0, modbus.Tcp, id)
|
||||
|
|
@ -100,6 +97,7 @@ func NewInnogy(ctx context.Context, uri string, id uint8) (*Innogy, error) {
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Innogy{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
curr: 6,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateInnogy(base *Innogy, meterEnergy func() (float64, error), phaseVoltages func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateInnogyMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateInnogyPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateInnogyCapable{Innogy: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateInnogyCapable struct {
|
||||
*Innogy
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateInnogyCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateInnogyMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateInnogyMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateInnogyPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateInnogyPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -39,6 +40,7 @@ import (
|
|||
// Keba is an api.Charger implementation
|
||||
type Keba struct {
|
||||
*embed
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
current uint16
|
||||
|
|
@ -72,8 +74,6 @@ func init() {
|
|||
registry.AddCtx("keba-modbus", NewKebaFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateKeba -b *Keba -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.Identifier,api.StatusReasoner,api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewKebaFromConfig creates a new Keba ModbusTCP charger
|
||||
func NewKebaFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -94,16 +94,6 @@ func NewKebaFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
return nil, err
|
||||
}
|
||||
|
||||
// optional features
|
||||
var (
|
||||
currentPower, totalEnergy func() (float64, error)
|
||||
currents func() (float64, float64, float64, error)
|
||||
identify func() (string, error)
|
||||
reason func() (api.Reason, error)
|
||||
phasesS func(int) error
|
||||
phasesG func() (int, error)
|
||||
)
|
||||
|
||||
b, err := wb.conn.ReadHoldingRegisters(kebaRegProduct, 2)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -140,21 +130,21 @@ func NewKebaFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
}
|
||||
|
||||
if hasEnergyMeter {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
currents = wb.currents
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
if hasRFID {
|
||||
identify = wb.identify
|
||||
reason = wb.statusReason
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
implement.Has(wb, implement.StatusReasoner(wb.statusReason))
|
||||
}
|
||||
|
||||
// phases
|
||||
if b, err := wb.conn.ReadHoldingRegisters(kebaRegPhaseSource, 2); err == nil {
|
||||
if source := binary.BigEndian.Uint32(b); source == 3 {
|
||||
phasesS = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +158,7 @@ func NewKebaFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
go wb.heartbeat(ctx, u)
|
||||
}
|
||||
|
||||
return decorateKeba(wb, currentPower, totalEnergy, currents, identify, reason, phasesS, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewKeba creates a new charger
|
||||
|
|
@ -187,6 +177,7 @@ func NewKeba(ctx context.Context, embed embed, uri string, slaveID uint8) (*Keba
|
|||
|
||||
wb := &Keba{
|
||||
embed: &embed,
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
regEnable: kebaRegEnable,
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateKeba(base *Keba, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), identifier func() (string, error), statusReasoner func() (api.Reason, error), phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateKebaMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateKebaMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateKebaPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateKebaIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if statusReasoner != nil {
|
||||
caps[reflect.TypeFor[api.StatusReasoner]()] = &decorateKebaStatusReasonerImpl{statusReasoner: statusReasoner}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateKebaPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateKebaPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateKebaCapable{Keba: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateKebaCapable struct {
|
||||
*Keba
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateKebaCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateKebaIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateKebaMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateKebaMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateKebaPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateKebaPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateKebaPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateKebaPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateKebaStatusReasonerImpl struct {
|
||||
statusReasoner func() (api.Reason, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaStatusReasonerImpl) StatusReason() (api.Reason, error) {
|
||||
return impl.statusReasoner()
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/keba"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
|
@ -20,6 +21,7 @@ const (
|
|||
|
||||
// KebaUdp is an api.Charger implementation
|
||||
type KebaUdp struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn string
|
||||
rfid keba.RFID
|
||||
|
|
@ -32,8 +34,6 @@ func init() {
|
|||
registry.Add("keba-udp", NewKebaUdpFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateKebaUdp -b *KebaUdp -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents
|
||||
|
||||
// NewKebaUdpFromConfig creates a new Keba UDP charger
|
||||
func NewKebaUdpFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -60,7 +60,9 @@ func NewKebaUdpFromConfig(other map[string]any) (api.Charger, error) {
|
|||
}
|
||||
|
||||
if energy > 0 {
|
||||
return decorateKebaUdp(k, k.currentPower, k.totalEnergy, k.currents), nil
|
||||
implement.Has(k, implement.Meter(k.currentPower))
|
||||
implement.Has(k, implement.MeterEnergy(k.totalEnergy))
|
||||
implement.Has(k, implement.PhaseCurrents(k.currents))
|
||||
}
|
||||
|
||||
return k, err
|
||||
|
|
@ -80,6 +82,7 @@ func NewKebaUdp(uri, serial string, rfid keba.RFID, timeout time.Duration) (*Keb
|
|||
sender, err := keba.NewSender(log, conn)
|
||||
|
||||
c := &KebaUdp{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
rfid: rfid,
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateKebaUdp(base *KebaUdp, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateKebaUdpMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateKebaUdpMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateKebaUdpPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateKebaUdpCapable{KebaUdp: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateKebaUdpCapable struct {
|
||||
*KebaUdp
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateKebaUdpCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateKebaUdpMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaUdpMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateKebaUdpMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaUdpMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateKebaUdpPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKebaUdpPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -30,6 +31,7 @@ import (
|
|||
|
||||
// KSE charger implementation
|
||||
type KSE struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
curr uint16
|
||||
|
|
@ -71,8 +73,6 @@ func NewKSEFromConfig(ctx context.Context, other map[string]any) (api.Charger, e
|
|||
return NewKSE(ctx, cc.URI, cc.Device, cc.Comset, cc.Baudrate, cc.ID)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateKSE -b *KSE -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter,api.Identifier
|
||||
|
||||
// NewKSE creates KSE charger
|
||||
func NewKSE(ctx context.Context, uri, device, comset string, baudrate int, slaveID uint8) (api.Charger, error) {
|
||||
conn, err := modbus.NewConnection(ctx, uri, device, comset, baudrate, modbus.Rtu, slaveID)
|
||||
|
|
@ -88,31 +88,26 @@ func NewKSE(ctx context.Context, uri, device, comset string, baudrate int, slave
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &KSE{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
curr: 6, // assume min current
|
||||
}
|
||||
|
||||
var (
|
||||
phases1p3p func(int) error
|
||||
getPhases func() (int, error)
|
||||
identify func() (string, error)
|
||||
)
|
||||
|
||||
// check presence of 1p3p switching
|
||||
if b, err := wb.conn.ReadInputRegisters(kseRegFirmwareVersion, 1); err == nil && b[0] >= 0x52 { // >= HW Rev „R“
|
||||
if b, err := wb.conn.ReadInputRegisters(kseRegFirmwareVersion, 1); err == nil && b[0] >= 0x52 { // >= HW Rev „R”
|
||||
wb.has1p3p = true
|
||||
phases1p3p = wb.phases1p3p
|
||||
getPhases = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
// check presence of rfid
|
||||
if b, err := wb.conn.ReadDiscreteInputs(kseRegRFIDinstalled, 1); err == nil && b[0] != 0 {
|
||||
wb.hasRfid = true
|
||||
identify = wb.identify
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
return decorateKSE(wb, phases1p3p, getPhases, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateKSE(base *KSE, phaseSwitcher func(int) error, phaseGetter func() (int, error), identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateKSEPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateKSEPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateKSEIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateKSECapable{KSE: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateKSECapable struct {
|
||||
*KSE
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateKSECapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateKSEIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKSEIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateKSEPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateKSEPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateKSEPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateKSEPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -33,6 +34,7 @@ import (
|
|||
|
||||
// MennekesCompact is an api.Charger implementation
|
||||
type MennekesCompact struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
}
|
||||
|
|
@ -87,8 +89,6 @@ func NewMennekesCompactFromConfig(ctx context.Context, other map[string]any) (ap
|
|||
return NewMennekesCompact(ctx, cc.URI, cc.Device, cc.Comset, cc.Baudrate, cc.Settings.Protocol(), cc.ID, cc.Timeout)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateMennekesCompact -b *MennekesCompact -r api.Charger -t api.PhaseSwitcher
|
||||
|
||||
// NewMennekesCompact creates Mennekes charger
|
||||
func NewMennekesCompact(ctx context.Context, uri, device, comset string, baudrate int, proto modbus.Protocol, slaveID uint8, timeout time.Duration) (api.Charger, error) {
|
||||
conn, err := modbus.NewConnection(ctx, uri, device, comset, baudrate, proto, slaveID)
|
||||
|
|
@ -108,20 +108,20 @@ func NewMennekesCompact(ctx context.Context, uri, device, comset string, baudrat
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &MennekesCompact{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
// check phase switching support
|
||||
var phasesS func(int) error
|
||||
if b, err := wb.conn.ReadHoldingRegisters(mennekesRegPhaseOptionsHW, 1); err == nil && encoding.Uint16(b) == 2 {
|
||||
phasesS = wb.phases1p3p
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
}
|
||||
|
||||
// failsafe
|
||||
go wb.heartbeat(ctx, mennekesHeartbeatInterval)
|
||||
|
||||
return decorateMennekesCompact(wb, phasesS), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *MennekesCompact) heartbeat(ctx context.Context, timeout time.Duration) {
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateMennekesCompact(base *MennekesCompact, phaseSwitcher func(int) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateMennekesCompactPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateMennekesCompactCapable{MennekesCompact: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateMennekesCompactCapable struct {
|
||||
*MennekesCompact
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateMennekesCompactCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateMennekesCompactPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateMennekesCompactPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -1,35 +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 decorateNexblue(base *Nexblue, phaseSwitcher func(int) error) api.Charger {
|
||||
switch {
|
||||
case phaseSwitcher == nil:
|
||||
return base
|
||||
|
||||
case phaseSwitcher != nil:
|
||||
return &struct {
|
||||
*Nexblue
|
||||
api.PhaseSwitcher
|
||||
}{
|
||||
Nexblue: base,
|
||||
PhaseSwitcher: &decorateNexbluePhaseSwitcherImpl{
|
||||
phaseSwitcher: phaseSwitcher,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type decorateNexbluePhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateNexbluePhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"math"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -18,6 +19,7 @@ import (
|
|||
|
||||
// NRGKickGen2 charger implementation
|
||||
type NRGKickGen2 struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
}
|
||||
|
||||
|
|
@ -49,8 +51,6 @@ func init() {
|
|||
registry.AddCtx("nrggen2", NewNRGKickGen2FromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateNRGKickGen2 -b *NRGKickGen2 -r api.Charger -t api.PhaseSwitcher
|
||||
|
||||
// NewNRGKickGen2FromConfig creates a NRGKickGen2 charger from generic config
|
||||
func NewNRGKickGen2FromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -72,17 +72,16 @@ func NewNRGKickGen2FromConfig(ctx context.Context, other map[string]any) (api.Ch
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var phasesS func(int) error
|
||||
if cc.Phases1p3p {
|
||||
// user could have an adapter plug which doesn't support 3 phases
|
||||
if b, err := nrg.conn.ReadHoldingRegisters(nrgKickGen2MaxPhases, 1); err == nil {
|
||||
if maxPhases := encoding.Uint16(b); maxPhases > 1 {
|
||||
phasesS = nrg.phases1p3p
|
||||
implement.Has(nrg, implement.PhaseSwitcher(nrg.phases1p3p))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return decorateNRGKickGen2(nrg, phasesS), nil
|
||||
return nrg, nil
|
||||
}
|
||||
|
||||
// NewNRGKickGen2 creates NRGKickGen2 charger
|
||||
|
|
@ -100,6 +99,7 @@ func NewNRGKickGen2(ctx context.Context, uri string, slaveID uint8) (*NRGKickGen
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
nrg := &NRGKickGen2{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateNRGKickGen2(base *NRGKickGen2, phaseSwitcher func(int) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateNRGKickGen2PhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateNRGKickGen2Capable{NRGKickGen2: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateNRGKickGen2Capable struct {
|
||||
*NRGKickGen2
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateNRGKickGen2Capable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateNRGKickGen2PhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateNRGKickGen2PhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/ocpp"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -37,6 +38,7 @@ import (
|
|||
|
||||
// OCPP charger implementation
|
||||
type OCPP struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
cp *ocpp.CP
|
||||
conn *ocpp.Connector
|
||||
|
|
@ -102,46 +104,37 @@ func NewOCPPFromConfig(ctx context.Context, other map[string]any) (api.Charger,
|
|||
return nil, api.ErrSponsorRequired
|
||||
}
|
||||
|
||||
var (
|
||||
powerG, totalEnergyG, socG func() (float64, error)
|
||||
currentsG, voltagesG func() (float64, float64, float64, error)
|
||||
)
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandPowerActiveImport) {
|
||||
powerG = c.conn.CurrentPower
|
||||
implement.Has(c, implement.Meter(c.conn.CurrentPower))
|
||||
}
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandEnergyActiveImportRegister) {
|
||||
totalEnergyG = c.conn.TotalEnergy
|
||||
implement.Has(c, implement.MeterEnergy(c.conn.TotalEnergy))
|
||||
}
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandCurrentImport) {
|
||||
currentsG = c.conn.Currents
|
||||
implement.Has(c, implement.PhaseCurrents(c.conn.Currents))
|
||||
}
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandVoltage) {
|
||||
voltagesG = c.conn.Voltages
|
||||
implement.Has(c, implement.PhaseVoltages(c.conn.Voltages))
|
||||
}
|
||||
|
||||
if c.cp.HasMeasurement(types.MeasurandSoC) {
|
||||
socG = c.conn.Soc
|
||||
implement.Has(c, implement.Battery(c.conn.Soc))
|
||||
}
|
||||
|
||||
var phasesS func(int) error
|
||||
if c.cp.PhaseSwitching {
|
||||
phasesS = c.phases1p3p
|
||||
implement.Has(c, implement.PhaseSwitcher(c.phases1p3p))
|
||||
}
|
||||
|
||||
var currentG func() (float64, error)
|
||||
if c.cp.HasMeasurement(types.MeasurandCurrentOffered) {
|
||||
currentG = c.conn.GetMaxCurrent
|
||||
implement.Has(c, implement.CurrentGetter(c.conn.GetMaxCurrent))
|
||||
}
|
||||
|
||||
return decorateOCPP(c, powerG, totalEnergyG, currentsG, voltagesG, currentG, phasesS, socG), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateOCPP -b *OCPP -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.CurrentGetter,api.PhaseSwitcher,api.Battery
|
||||
|
||||
// NewOCPP creates OCPP charger
|
||||
func NewOCPP(ctx context.Context,
|
||||
id string, connector int, idTag string,
|
||||
|
|
@ -187,6 +180,7 @@ func NewOCPP(ctx context.Context,
|
|||
}
|
||||
|
||||
c := &OCPP{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
cp: cp,
|
||||
conn: conn,
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOCPP(base *OCPP, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), currentGetter func() (float64, error), phaseSwitcher func(int) error, battery func() (float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateOCPPMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateOCPPMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateOCPPPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateOCPPPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if currentGetter != nil {
|
||||
caps[reflect.TypeFor[api.CurrentGetter]()] = &decorateOCPPCurrentGetterImpl{currentGetter: currentGetter}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateOCPPPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateOCPPBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateOCPPCapable{OCPP: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateOCPPCapable struct {
|
||||
*OCPP
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateOCPPCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateOCPPBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateOCPPCurrentGetterImpl struct {
|
||||
currentGetter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPCurrentGetterImpl) GetMaxCurrent() (float64, error) {
|
||||
return impl.currentGetter()
|
||||
}
|
||||
|
||||
type decorateOCPPMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateOCPPMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateOCPPPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateOCPPPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateOCPPPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOCPPPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/openevse"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -18,6 +19,7 @@ import (
|
|||
// OpenEVSE charger implementation
|
||||
type OpenEVSE struct {
|
||||
*request.Helper
|
||||
implement.Caps
|
||||
uri string
|
||||
statusG util.Cacheable[openevse.Status]
|
||||
current int
|
||||
|
|
@ -28,8 +30,6 @@ func init() {
|
|||
registry.Add("openevse", NewOpenEVSEFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateOpenEVSE -b *OpenEVSE -r api.Charger -t api.PhaseSwitcher
|
||||
|
||||
// NewOpenEVSEFromConfig creates an OpenEVSE charger from generic config
|
||||
func NewOpenEVSEFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -59,6 +59,7 @@ func NewOpenEVSE(uri, user, password string, cache time.Duration) (api.Charger,
|
|||
|
||||
c := &OpenEVSE{
|
||||
Helper: request.NewHelper(log),
|
||||
Caps: implement.New(),
|
||||
uri: util.DefaultScheme(strings.TrimSuffix(uri, "/"), "http"),
|
||||
}
|
||||
|
||||
|
|
@ -75,9 +76,8 @@ func NewOpenEVSE(uri, user, password string, cache time.Duration) (api.Charger,
|
|||
return res, err
|
||||
}, cache)
|
||||
|
||||
var phases1p3p func(int) error
|
||||
if err := c.hasPhaseSwitchCapabilities(); err == nil {
|
||||
phases1p3p = c.phases1p3p
|
||||
implement.Has(c, implement.PhaseSwitcher(c.phases1p3p))
|
||||
|
||||
// disable EVSE's own 1/3-phase auto-switching
|
||||
if err := c.rapiCommand("$S8 0"); err != nil {
|
||||
|
|
@ -85,7 +85,7 @@ func NewOpenEVSE(uri, user, password string, cache time.Duration) (api.Charger,
|
|||
}
|
||||
}
|
||||
|
||||
return decorateOpenEVSE(c, phases1p3p), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *OpenEVSE) setOverride() error {
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOpenEVSE(base *OpenEVSE, phaseSwitcher func(int) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateOpenEVSEPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateOpenEVSECapable{OpenEVSE: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateOpenEVSECapable struct {
|
||||
*OpenEVSE
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateOpenEVSECapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateOpenEVSEPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenEVSEPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -6,12 +6,14 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
)
|
||||
|
||||
// OpenWB20 charger implementation
|
||||
type OpenWB20 struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
enabled bool
|
||||
curr uint16
|
||||
|
|
@ -41,8 +43,6 @@ func init() {
|
|||
|
||||
// https://openwb.de/main/wp-content/uploads/2023/10/ModbusTCP-openWB-series2-Pro-1.pdf
|
||||
|
||||
//go:generate go tool decorate -f decorateOpenWB20 -b *OpenWB20 -r api.Charger -t api.PhaseSwitcher,api.Identifier
|
||||
|
||||
// NewOpenWB20FromConfig creates a OpenWB20 charger from generic config
|
||||
func NewOpenWB20FromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -66,17 +66,15 @@ func NewOpenWB20FromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
if cc.Phases1p3p {
|
||||
phases1p3p = wb.phases1p3p
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
}
|
||||
|
||||
var identify func() (string, error)
|
||||
if cc.Identify {
|
||||
identify = wb.identify
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
return decorateOpenWB20(wb, phases1p3p, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewOpenWB20 creates OpenWB20 charger
|
||||
|
|
@ -92,6 +90,7 @@ func NewOpenWB20(ctx context.Context, uri string, slaveID uint8, connector uint1
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &OpenWB20{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
curr: 6 * 100,
|
||||
base: (connector - 1) * 100,
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOpenWB20(base *OpenWB20, phaseSwitcher func(int) error, identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateOpenWB20PhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateOpenWB20IdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateOpenWB20Capable{OpenWB20: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateOpenWB20Capable struct {
|
||||
*OpenWB20
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateOpenWB20Capable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateOpenWB20IdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWB20IdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateOpenWB20PhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWB20PhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOpenWbNative(base *OpenWbNative, chargerEx func(float64) error, phaseSwitcher func(int) error, identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decorateOpenWbNativeChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateOpenWbNativePhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateOpenWbNativeIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateOpenWbNativeCapable{OpenWbNative: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateOpenWbNativeCapable struct {
|
||||
*OpenWbNative
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateOpenWbNativeCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateOpenWbNativeChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWbNativeChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
||||
type decorateOpenWbNativeIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWbNativeIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateOpenWbNativePhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWbNativePhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/openwb/native"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
|
|
@ -24,6 +25,7 @@ type openWbGpioLines struct {
|
|||
// OpenWbNative charger implementation
|
||||
type OpenWbNative struct {
|
||||
api.Charger
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
rfId native.RfIdContainer
|
||||
cpWait time.Duration
|
||||
|
|
@ -42,8 +44,6 @@ func init() {
|
|||
registry.AddCtx("openwb-native", NewOpenWbNativeFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -o openwb-native_decorators_linux.go -f decorateOpenWbNative -b *OpenWbNative -r api.Charger -t api.ChargerEx,api.PhaseSwitcher,api.Identifier
|
||||
|
||||
// NewOpenWbNativeFromConfig creates an OpenWbNative charger from generic config
|
||||
func NewOpenWbNativeFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -87,25 +87,20 @@ func NewOpenWbNative(ctx context.Context, uri, device, comset string, baudrate i
|
|||
|
||||
wb := &OpenWbNative{
|
||||
Charger: evse,
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
cpWait: cpWait,
|
||||
connector: connector,
|
||||
chargeState: api.StatusNone,
|
||||
}
|
||||
|
||||
var (
|
||||
phases1p3p func(int) error
|
||||
identify func() (string, error)
|
||||
maxCurrentMillis func(float64) error
|
||||
)
|
||||
|
||||
if ex, ok := api.Cap[api.ChargerEx](evse); ok {
|
||||
maxCurrentMillis = ex.MaxCurrentMillis
|
||||
implement.May(wb, implement.ChargerEx(ex.MaxCurrentMillis))
|
||||
}
|
||||
|
||||
// configure special external hardware features
|
||||
if hasPhases1p3p {
|
||||
phases1p3p = wb.phases1p3p
|
||||
implement.May(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
}
|
||||
|
||||
if rfIdVidPid != "" {
|
||||
|
|
@ -113,8 +108,7 @@ func NewOpenWbNative(ctx context.Context, uri, device, comset string, baudrate i
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
identify = wb.identify
|
||||
implement.May(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
// initialize GPIO lines and set pins to output
|
||||
|
|
@ -141,7 +135,7 @@ func NewOpenWbNative(ctx context.Context, uri, device, comset string, baudrate i
|
|||
wb.gpio.ph3.Close()
|
||||
}()
|
||||
|
||||
return decorateOpenWbNative(wb, maxCurrentMillis, phases1p3p, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/openwb/pro"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -16,12 +17,11 @@ func init() {
|
|||
registry.AddCtx("openwbpro", NewOpenWBProFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateOpenWBPro -b *OpenWBPro -r api.Charger -t api.Resurrector
|
||||
|
||||
// https://openwb.de/main/?page_id=771
|
||||
|
||||
// OpenWBPro charger implementation
|
||||
type OpenWBPro struct {
|
||||
implement.Caps
|
||||
*request.Helper
|
||||
uri string
|
||||
current float64
|
||||
|
|
@ -51,12 +51,11 @@ func NewOpenWBProFromConfig(ctx context.Context, other map[string]any) (api.Char
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var wakeup func() error
|
||||
if status.Version >= 9 {
|
||||
wakeup = wb.wakeup
|
||||
implement.Has(wb, implement.Resurrector(wb.wakeup))
|
||||
}
|
||||
|
||||
return decorateOpenWBPro(wb, wakeup), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewOpenWBPro creates OpenWBPro charger
|
||||
|
|
@ -64,6 +63,7 @@ func NewOpenWBPro(ctx context.Context, uri string, cache time.Duration) (*OpenWB
|
|||
log := util.NewLogger("owbpro")
|
||||
|
||||
wb := &OpenWBPro{
|
||||
Caps: implement.New(),
|
||||
Helper: request.NewHelper(log),
|
||||
uri: strings.TrimRight(uri, "/"),
|
||||
current: 6, // 6A defined value
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOpenWBPro(base *OpenWBPro, resurrector func() error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if resurrector != nil {
|
||||
caps[reflect.TypeFor[api.Resurrector]()] = &decorateOpenWBProResurrectorImpl{resurrector: resurrector}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateOpenWBProCapable{OpenWBPro: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateOpenWBProCapable struct {
|
||||
*OpenWBPro
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateOpenWBProCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateOpenWBProResurrectorImpl struct {
|
||||
resurrector func() error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWBProResurrectorImpl) WakeUp() error {
|
||||
return impl.resurrector()
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/openwb"
|
||||
"github.com/evcc-io/evcc/plugin"
|
||||
"github.com/evcc-io/evcc/plugin/mqtt"
|
||||
|
|
@ -19,6 +20,7 @@ func init() {
|
|||
|
||||
// OpenWB configures generic charger and charge meter for an openWB loadpoint
|
||||
type OpenWB struct {
|
||||
implement.Caps
|
||||
current int64
|
||||
enabled bool
|
||||
statusG func() (string, error)
|
||||
|
|
@ -30,8 +32,6 @@ type OpenWB struct {
|
|||
authS func(string) error
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateOpenWB -b *OpenWB -r api.Charger -t api.PhaseSwitcher,api.Battery
|
||||
|
||||
// NewOpenWBFromConfig creates a new configurable charger
|
||||
func NewOpenWBFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -145,6 +145,7 @@ func NewOpenWB(log *util.Logger, mqttconf mqtt.Config, id int, topic string, p1p
|
|||
}
|
||||
|
||||
c := &OpenWB{
|
||||
Caps: implement.New(),
|
||||
currentS: currentS,
|
||||
statusG: statusG,
|
||||
currentPowerG: currentPowerG,
|
||||
|
|
@ -171,7 +172,6 @@ func NewOpenWB(log *util.Logger, mqttconf mqtt.Config, id int, topic string, p1p
|
|||
|
||||
// optional capabilities
|
||||
|
||||
var phases func(int) error
|
||||
if p1p3 {
|
||||
phasesTopic := openwb.SlavePhasesTopic
|
||||
if id == 2 {
|
||||
|
|
@ -184,20 +184,20 @@ func NewOpenWB(log *util.Logger, mqttconf mqtt.Config, id int, topic string, p1p
|
|||
return nil, err
|
||||
}
|
||||
|
||||
phases = func(phases int) error {
|
||||
implement.Has(c, implement.PhaseSwitcher(func(phases int) error {
|
||||
return phasesS(int64(phases))
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
var soc func() (float64, error)
|
||||
if dc {
|
||||
soc, err = to.FloatGetter(mq(openwb.VehicleSocTopic))
|
||||
soc, err := to.FloatGetter(mq(openwb.VehicleSocTopic))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.Has(c, implement.Battery(soc))
|
||||
}
|
||||
|
||||
return decorateOpenWB(c, phases, soc), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (m *OpenWB) Enable(enable bool) error {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateOpenWB(base *OpenWB, phaseSwitcher func(int) error, battery func() (float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateOpenWBPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateOpenWBBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateOpenWBCapable{OpenWB: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateOpenWBCapable struct {
|
||||
*OpenWB
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateOpenWBCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateOpenWBBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWBBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateOpenWBPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateOpenWBPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/pcelectric"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -14,6 +15,7 @@ import (
|
|||
|
||||
// PCElectric charger implementation
|
||||
type PCElectric struct {
|
||||
implement.Caps
|
||||
*request.Helper
|
||||
log *util.Logger
|
||||
|
||||
|
|
@ -30,8 +32,6 @@ func init() {
|
|||
registry.Add("pcelectric", NewPCElectricFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decoratePCE -b *PCElectric -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents
|
||||
|
||||
// NewPCElectricFromConfig creates a PCElectric charger from generic config
|
||||
func NewPCElectricFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -50,7 +50,10 @@ func NewPCElectricFromConfig(other map[string]any) (api.Charger, error) {
|
|||
if err == nil && wb.slaveIndex == 0 { // Nur Master hat den Zähler...leider
|
||||
var res pcelectric.MeterInfo
|
||||
if err := wb.GetJSON(wb.meter, &res); err == nil && res.MeterSerial != "" {
|
||||
return decoratePCE(wb, wb.currentPower, wb.totalEnergy, wb.currents), nil
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
wb.meter = ""
|
||||
|
|
@ -69,6 +72,7 @@ func NewPCElectric(uri string, slaveIndex int, meter string) (*PCElectric, error
|
|||
}
|
||||
|
||||
wb := &PCElectric{
|
||||
Caps: implement.New(),
|
||||
Helper: request.NewHelper(log),
|
||||
log: log,
|
||||
uri: uri,
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decoratePCE(base *PCElectric, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decoratePCEMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decoratePCEMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decoratePCEPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decoratePCECapable{PCElectric: base, caps: caps}
|
||||
}
|
||||
|
||||
type decoratePCECapable struct {
|
||||
*PCElectric
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decoratePCECapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decoratePCEMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePCEMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decoratePCEMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePCEMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decoratePCEPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePCEPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -33,6 +34,7 @@ import (
|
|||
|
||||
// Peblar charger implementation
|
||||
type Peblar struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
curr uint32
|
||||
enabled bool
|
||||
|
|
@ -70,8 +72,6 @@ func init() {
|
|||
registry.AddCtx("peblar", NewPeblarFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decoratePeblar -b *Peblar -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewPeblarFromConfig creates a Peblar charger from generic config
|
||||
func NewPeblarFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
|
|
@ -103,6 +103,7 @@ func NewPeblar(ctx context.Context, uri string, id uint8) (api.Charger, error) {
|
|||
}
|
||||
|
||||
wb := &Peblar{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
curr: 6000, // assume min current
|
||||
phases: binary.BigEndian.Uint16(b), // required for retrieving the right amount of voltage/current registers
|
||||
|
|
@ -113,15 +114,12 @@ func NewPeblar(ctx context.Context, uri string, id uint8) (api.Charger, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var phasesS func(int) error
|
||||
var phasesG func() (int, error)
|
||||
|
||||
if binary.BigEndian.Uint16(b) == 1 {
|
||||
phasesS = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
return decoratePeblar(wb, phasesS, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decoratePeblar(base *Peblar, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decoratePeblarPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decoratePeblarPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decoratePeblarCapable{Peblar: base, caps: caps}
|
||||
}
|
||||
|
||||
type decoratePeblarCapable struct {
|
||||
*Peblar
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decoratePeblarCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decoratePeblarPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePeblarPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decoratePeblarPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decoratePeblarPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/volkszaehler/mbmd/encoding"
|
||||
|
|
@ -38,6 +39,7 @@ const (
|
|||
|
||||
// PhoenixCharx is an api.Charger implementation for Phoenix CHARX controller
|
||||
type PhoenixCharx struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
connector uint16
|
||||
current uint16
|
||||
|
|
@ -47,8 +49,6 @@ func init() {
|
|||
registry.AddCtx("phoenix-charx", NewPhoenixCharxFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decoratePhoenixCharx -b *PhoenixCharx -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages
|
||||
|
||||
// NewPhoenixCharxFromConfig creates a Phoenix charger from generic config
|
||||
func NewPhoenixCharxFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -76,7 +76,10 @@ func NewPhoenixCharxFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
}
|
||||
|
||||
if meter > 0 && meter != 65535 {
|
||||
return decoratePhoenixCharx(wb, wb.currentPower, wb.totalEnergy, wb.currents, wb.voltages), nil
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
||||
return wb, nil
|
||||
|
|
@ -93,6 +96,7 @@ func NewPhoenixCharx(ctx context.Context, uri string, id uint8, connector uint16
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &PhoenixCharx{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
connector: connector,
|
||||
current: 6, // assume min current
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decoratePhoenixCharx(base *PhoenixCharx, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decoratePhoenixCharxMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decoratePhoenixCharxMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decoratePhoenixCharxPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decoratePhoenixCharxPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decoratePhoenixCharxCapable{PhoenixCharx: base, caps: caps}
|
||||
}
|
||||
|
||||
type decoratePhoenixCharxCapable struct {
|
||||
*PhoenixCharx
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decoratePhoenixCharxCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decoratePhoenixCharxMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixCharxMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decoratePhoenixCharxMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixCharxMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decoratePhoenixCharxPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixCharxPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decoratePhoenixCharxPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixCharxPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/volkszaehler/mbmd/encoding"
|
||||
|
|
@ -27,6 +28,7 @@ const (
|
|||
// PhoenixEMEth is an api.Charger implementation for Phoenix EM-CP-PP-ETH wallboxes.
|
||||
// It uses Modbus TCP to communicate with the wallbox at modbus client id 180.
|
||||
type PhoenixEMEth struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
}
|
||||
|
||||
|
|
@ -34,8 +36,6 @@ func init() {
|
|||
registry.AddCtx("phoenix-em-eth", NewPhoenixEMEthFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decoratePhoenixEMEth -b *PhoenixEMEth -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages
|
||||
|
||||
// NewPhoenixEMEthFromConfig creates a Phoenix charger from generic config
|
||||
func NewPhoenixEMEthFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
|
|
@ -51,22 +51,15 @@ func NewPhoenixEMEthFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var (
|
||||
currentPower func() (float64, error)
|
||||
totalEnergy func() (float64, error)
|
||||
currents func() (float64, float64, float64, error)
|
||||
voltages func() (float64, float64, float64, error)
|
||||
)
|
||||
|
||||
// check presence of meter by voltage on l1
|
||||
if b, err := wb.conn.ReadInputRegisters(phxEMEthRegVoltages, 2); err == nil && encoding.Int32LswFirst(b) > 0 {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
currents = wb.currents
|
||||
voltages = wb.voltages
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.Has(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
||||
return decoratePhoenixEMEth(wb, currentPower, totalEnergy, currents, voltages), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewPhoenixEMEth creates a Phoenix charger
|
||||
|
|
@ -80,6 +73,7 @@ func NewPhoenixEMEth(ctx context.Context, uri string, slaveID uint8) (*PhoenixEM
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &PhoenixEMEth{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decoratePhoenixEMEth(base *PhoenixEMEth, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decoratePhoenixEMEthMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decoratePhoenixEMEthMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decoratePhoenixEMEthPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decoratePhoenixEMEthPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decoratePhoenixEMEthCapable{PhoenixEMEth: base, caps: caps}
|
||||
}
|
||||
|
||||
type decoratePhoenixEMEthCapable struct {
|
||||
*PhoenixEMEth
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decoratePhoenixEMEthCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decoratePhoenixEMEthMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEMEthMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decoratePhoenixEMEthMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEMEthMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decoratePhoenixEMEthPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEMEthPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decoratePhoenixEMEthPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEMEthPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -28,6 +28,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -35,6 +36,7 @@ import (
|
|||
)
|
||||
|
||||
type PhoenixEVEth struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
isWallbe bool
|
||||
}
|
||||
|
|
@ -62,8 +64,6 @@ func init() {
|
|||
registry.AddCtx("phoenix-ev-eth", NewPhoenixEVEthFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decoratePhoenixEVEth -b *PhoenixEVEth -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.ChargerEx,api.Identifier
|
||||
|
||||
// NewPhoenixEVEthFromConfig creates a PhoenixEVEth charger from generic config
|
||||
func NewPhoenixEVEthFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
|
|
@ -92,38 +92,30 @@ func NewPhoenixEVEth(ctx context.Context, uri string, slaveID uint8) (api.Charge
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &PhoenixEVEth{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
var (
|
||||
currentPower func() (float64, error)
|
||||
totalEnergy func() (float64, error)
|
||||
currents func() (float64, float64, float64, error)
|
||||
voltages func() (float64, float64, float64, error)
|
||||
maxCurrentMillis func(float64) error
|
||||
identify func() (string, error)
|
||||
)
|
||||
|
||||
// check presence of meter by voltage on l1
|
||||
if b, err := wb.conn.ReadInputRegisters(phxRegVoltages, 2); err == nil && encoding.Uint32LswFirst(b) > 0 {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
currents = wb.currents
|
||||
voltages = wb.voltages
|
||||
implement.May(wb, implement.Meter(wb.currentPower))
|
||||
implement.May(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.May(wb, implement.PhaseCurrents(wb.currents))
|
||||
implement.May(wb, implement.PhaseVoltages(wb.voltages))
|
||||
}
|
||||
|
||||
// check card reader enabled
|
||||
if b, err := wb.conn.ReadCoils(phxRegCardEnabled, 1); err == nil && b[0] == 1 {
|
||||
identify = wb.identify
|
||||
implement.May(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
|
||||
// check presence of extended Wallbe firmware
|
||||
if b, err := wb.conn.ReadHoldingRegisters(phxRegMaxCurrent, 1); err == nil && encoding.Uint16(b) >= 60 {
|
||||
wb.isWallbe = true
|
||||
maxCurrentMillis = wb.maxCurrentMillis
|
||||
implement.May(wb, implement.ChargerEx(wb.maxCurrentMillis))
|
||||
}
|
||||
|
||||
return decoratePhoenixEVEth(wb, currentPower, totalEnergy, currents, voltages, maxCurrentMillis, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decoratePhoenixEVEth(base *PhoenixEVEth, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), chargerEx func(float64) error, identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decoratePhoenixEVEthMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decoratePhoenixEVEthMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decoratePhoenixEVEthPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decoratePhoenixEVEthPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if chargerEx != nil {
|
||||
caps[reflect.TypeFor[api.ChargerEx]()] = &decoratePhoenixEVEthChargerExImpl{chargerEx: chargerEx}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decoratePhoenixEVEthIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decoratePhoenixEVEthCapable{PhoenixEVEth: base, caps: caps}
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthCapable struct {
|
||||
*PhoenixEVEth
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decoratePhoenixEVEthCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthChargerExImpl struct {
|
||||
chargerEx func(float64) error
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEVEthChargerExImpl) MaxCurrentMillis(p0 float64) error {
|
||||
return impl.chargerEx(p0)
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEVEthIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEVEthMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEVEthMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEVEthPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decoratePhoenixEVEthPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decoratePhoenixEVEthPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -24,12 +24,14 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
)
|
||||
|
||||
// Pulsares charger implementation
|
||||
type Pulsares struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
curr uint16
|
||||
|
|
@ -51,8 +53,6 @@ func init() {
|
|||
registry.AddCtx("pulsares", NewPulsaresFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decoratePulsares -b *Pulsares -r api.Charger -t api.PhaseSwitcher
|
||||
|
||||
// NewPulsaresFromConfig creates a Pulsares charger from generic config
|
||||
func NewPulsaresFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.Settings{
|
||||
|
|
@ -68,12 +68,11 @@ func NewPulsaresFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
if wb.has1p3p() {
|
||||
phases1p3p = wb.phases1p3p
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
}
|
||||
|
||||
return decoratePulsares(wb, phases1p3p), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// NewPulsares creates Pulsares charger
|
||||
|
|
@ -87,6 +86,7 @@ func NewPulsares(ctx context.Context, uri, device, comset string, baudrate int,
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Pulsares{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
curr: 6000,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,44 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decoratePulsares(base *Pulsares, phaseSwitcher func(int) error) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decoratePulsaresPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decoratePulsaresCapable{Pulsares: base, caps: caps}
|
||||
}
|
||||
|
||||
type decoratePulsaresCapable struct {
|
||||
*Pulsares
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decoratePulsaresCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decoratePulsaresPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decoratePulsaresPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -23,6 +23,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/semp"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -30,6 +31,7 @@ import (
|
|||
|
||||
// SEMP charger implementation
|
||||
type SEMP struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *semp.Connection
|
||||
cache time.Duration
|
||||
|
|
@ -44,8 +46,6 @@ type SEMP struct {
|
|||
hasStatusParam bool
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateSEMP -b *SEMP -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter,api.ChargeRater
|
||||
|
||||
func init() {
|
||||
registry.AddCtx("semp", NewSEMPFromConfig)
|
||||
}
|
||||
|
|
@ -76,6 +76,7 @@ func NewSEMP(ctx context.Context, uri, deviceID string, cache time.Duration) (ap
|
|||
log := util.NewLogger("semp")
|
||||
|
||||
wb := &SEMP{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
cache: cache,
|
||||
phases: 3,
|
||||
|
|
@ -113,12 +114,6 @@ func NewSEMP(ctx context.Context, uri, deviceID string, cache time.Duration) (ap
|
|||
log.DEBUG.Printf("auto-detected device ID: %s", wb.deviceID)
|
||||
}
|
||||
|
||||
var (
|
||||
phases1p3p func(int) error
|
||||
getPhases func() (int, error)
|
||||
chargedEnergy func() (float64, error)
|
||||
)
|
||||
|
||||
// Check if device supports phase switching by checking power characteristics
|
||||
info, err := wb.getDeviceInfo()
|
||||
if err != nil {
|
||||
|
|
@ -130,13 +125,13 @@ func NewSEMP(ctx context.Context, uri, deviceID string, cache time.Duration) (ap
|
|||
|
||||
// Assume Phase switching support if MinPowerConsumption < 4140W and MaxPowerConsumption > 4600W
|
||||
if wb.minPower > 0 && wb.minPower < 4140 && wb.maxPower > 4600 {
|
||||
phases1p3p = wb.phases1p3p
|
||||
getPhases = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
// Check if device supports charged energy reporting via Parameters endpoint
|
||||
if _, err := wb.getParameter("Measurement.ChaSess.WhIn"); err == nil {
|
||||
chargedEnergy = wb.chargedEnergy
|
||||
implement.Has(wb, implement.ChargeRater(wb.chargedEnergy))
|
||||
}
|
||||
|
||||
// Check if device supports status reporting via Parameters endpoint
|
||||
|
|
@ -151,7 +146,7 @@ func NewSEMP(ctx context.Context, uri, deviceID string, cache time.Duration) (ap
|
|||
|
||||
go wb.heartbeat(ctx)
|
||||
|
||||
return decorateSEMP(wb, phases1p3p, getPhases, chargedEnergy), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// heartbeat ensures that device control updates are sent at least once per minute
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateSEMP(base *SEMP, phaseSwitcher func(int) error, phaseGetter func() (int, error), chargeRater func() (float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateSEMPPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateSEMPPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if chargeRater != nil {
|
||||
caps[reflect.TypeFor[api.ChargeRater]()] = &decorateSEMPChargeRaterImpl{chargeRater: chargeRater}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateSEMPCapable{SEMP: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateSEMPCapable struct {
|
||||
*SEMP
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateSEMPCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateSEMPChargeRaterImpl struct {
|
||||
chargeRater func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSEMPChargeRaterImpl) ChargedEnergy() (float64, error) {
|
||||
return impl.chargeRater()
|
||||
}
|
||||
|
||||
type decorateSEMPPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSEMPPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateSEMPPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateSEMPPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/measurement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/config"
|
||||
|
|
@ -55,11 +56,6 @@ func NewSgReadyRelayFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
}
|
||||
}
|
||||
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := NewSgReadyRelay(ctx, &cc.embed, boost, dim)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
@ -69,8 +65,17 @@ func NewSgReadyRelayFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Meter(powerG))
|
||||
implement.May(res, implement.MeterEnergy(energyG))
|
||||
|
||||
return decorateSgReady(res, powerG, energyG, tempG, limitTempG), nil
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Battery(tempG))
|
||||
implement.May(res, implement.SocLimiter(limitTempG))
|
||||
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// NewSgReadyRelay creates SG Ready charger with boost relay
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/measurement"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/plugin"
|
||||
|
|
@ -30,6 +31,7 @@ import (
|
|||
// SgReady charger implementation
|
||||
type SgReady struct {
|
||||
*embed
|
||||
implement.Caps
|
||||
mode int64
|
||||
modeS func(int64) error
|
||||
modeG func() (int64, error)
|
||||
|
|
@ -51,8 +53,6 @@ const (
|
|||
Boost // 3
|
||||
)
|
||||
|
||||
//go:generate go tool decorate -f decorateSgReady -b *SgReady -r api.Charger -t api.Meter,api.MeterEnergy,api.Battery,api.SocLimiter
|
||||
|
||||
// NewSgReadyFromConfig creates an SG Ready configurable charger from generic config
|
||||
func NewSgReadyFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -111,19 +111,24 @@ func NewSgReadyFromConfig(ctx context.Context, other map[string]any) (api.Charge
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Meter(powerG))
|
||||
implement.May(res, implement.MeterEnergy(energyG))
|
||||
|
||||
tempG, limitTempG, err := cc.Temperature.Configure(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(res, implement.Battery(tempG))
|
||||
implement.May(res, implement.SocLimiter(limitTempG))
|
||||
|
||||
return decorateSgReady(res, powerG, energyG, tempG, limitTempG), nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// NewSgReady creates SG Ready charger
|
||||
func NewSgReady(ctx context.Context, embed *embed, modeS func(int64) error, modeG func() (int64, error), maxPowerS func(int64) error) (*SgReady, error) {
|
||||
res := &SgReady{
|
||||
embed: embed,
|
||||
Caps: implement.New(),
|
||||
mode: Normal,
|
||||
modeS: modeS,
|
||||
modeG: modeG,
|
||||
|
|
|
|||
|
|
@ -1,80 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateSgReady(base *SgReady, meter func() (float64, error), meterEnergy func() (float64, error), battery func() (float64, error), socLimiter func() (int64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateSgReadyMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateSgReadyMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateSgReadyBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if socLimiter != nil {
|
||||
caps[reflect.TypeFor[api.SocLimiter]()] = &decorateSgReadySocLimiterImpl{socLimiter: socLimiter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateSgReadyCapable{SgReady: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateSgReadyCapable struct {
|
||||
*SgReady
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateSgReadyCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateSgReadyBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSgReadyBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateSgReadyMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSgReadyMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateSgReadyMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSgReadyMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateSgReadySocLimiterImpl struct {
|
||||
socLimiter func() (int64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSgReadySocLimiterImpl) GetLimitSoc() (int64, error) {
|
||||
return impl.socLimiter()
|
||||
}
|
||||
|
|
@ -5,12 +5,14 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/meter/shelly"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
||||
// Shelly charger implementation
|
||||
type Shelly struct {
|
||||
implement.Caps
|
||||
conn *shelly.Connection
|
||||
*switchSocket
|
||||
}
|
||||
|
|
@ -19,8 +21,6 @@ func init() {
|
|||
registry.Add("shelly", NewShellyFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateShelly -b *Shelly -r api.Charger -t api.PhaseVoltages,api.PhaseCurrents,api.PhasePowers
|
||||
|
||||
// NewShellyFromConfig creates a Shelly charger from generic config
|
||||
func NewShellyFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -44,14 +44,13 @@ func NewShellyFromConfig(other map[string]any) (api.Charger, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
var vol, cur, pow func() (float64, float64, float64, error)
|
||||
if phases, ok := c.conn.Generation.(shelly.Phases); ok {
|
||||
vol = phases.Voltages
|
||||
cur = phases.Currents
|
||||
pow = phases.Powers
|
||||
implement.Has(c, implement.PhaseVoltages(phases.Voltages))
|
||||
implement.Has(c, implement.PhaseCurrents(phases.Currents))
|
||||
implement.Has(c, implement.PhasePowers(phases.Powers))
|
||||
}
|
||||
|
||||
return decorateShelly(c, vol, cur, pow), nil
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// NewShelly creates Shelly charger
|
||||
|
|
@ -62,6 +61,7 @@ func NewShelly(embed embed, uri, user, password string, channel int, standbypowe
|
|||
}
|
||||
|
||||
c := &Shelly{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateShelly(base *Shelly, phaseVoltages func() (float64, float64, float64, error), phaseCurrents func() (float64, float64, float64, error), phasePowers func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateShellyPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateShellyPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phasePowers != nil {
|
||||
caps[reflect.TypeFor[api.PhasePowers]()] = &decorateShellyPhasePowersImpl{phasePowers: phasePowers}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateShellyCapable{Shelly: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateShellyCapable struct {
|
||||
*Shelly
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateShellyCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateShellyPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateShellyPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateShellyPhasePowersImpl struct {
|
||||
phasePowers func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateShellyPhasePowersImpl) Powers() (float64, float64, float64, error) {
|
||||
return impl.phasePowers()
|
||||
}
|
||||
|
||||
type decorateShellyPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateShellyPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
)
|
||||
|
|
@ -34,6 +35,7 @@ import (
|
|||
// SmartEVSE3 charger implementation
|
||||
type SmartEVSE3 struct {
|
||||
*request.Helper
|
||||
implement.Caps
|
||||
uri string
|
||||
curr int64
|
||||
mode int
|
||||
|
|
@ -106,8 +108,6 @@ func init() {
|
|||
registry.Add("smart-evse", NewSmartEVSE3FromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateSmartEVSE3 -b *SmartEVSE3 -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseSwitcher,api.PhaseGetter,api.Identifier,api.StatusReasoner
|
||||
|
||||
// NewSmartEVSE3FromConfig creates a SmartEVSE-3.5 REST charger from generic config
|
||||
func NewSmartEVSE3FromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -141,6 +141,7 @@ func NewSmartEVSE3(uri string, cache time.Duration, mode int) (api.Charger, erro
|
|||
|
||||
wb := &SmartEVSE3{
|
||||
Helper: request.NewHelper(log),
|
||||
Caps: implement.New(),
|
||||
uri: strings.TrimRight(util.DefaultScheme(uri, "http"), "/"),
|
||||
curr: 60, // 6 A in 1/10 A
|
||||
mode: mode,
|
||||
|
|
@ -163,31 +164,25 @@ func NewSmartEVSE3(uri string, cache time.Duration, mode int) (api.Charger, erro
|
|||
}
|
||||
|
||||
// decorate optional EV meter if configured in SmartEVSE
|
||||
var currentPower, totalEnergy func() (float64, error)
|
||||
var currents func() (float64, float64, float64, error)
|
||||
if res.EvMeter.Description != "" && res.EvMeter.Description != "Disabled" {
|
||||
currentPower = wb.currentPower
|
||||
totalEnergy = wb.totalEnergy
|
||||
currents = wb.currents
|
||||
implement.Has(wb, implement.Meter(wb.currentPower))
|
||||
implement.Has(wb, implement.MeterEnergy(wb.totalEnergy))
|
||||
implement.Has(wb, implement.PhaseCurrents(wb.currents))
|
||||
}
|
||||
|
||||
// decorate optional 1P/3P phase switching via C2 contactor
|
||||
var phases1p3p func(int) error
|
||||
var getPhases func() (int, error)
|
||||
if res.Settings.EnableC2 != "" && res.Settings.EnableC2 != "Not present" {
|
||||
phases1p3p = wb.phases1p3p
|
||||
getPhases = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
// decorate optional RFID identification and status reason
|
||||
var identify func() (string, error)
|
||||
var statusReason func() (api.Reason, error)
|
||||
if res.Evse.RFIDReader != "" && res.Evse.RFIDReader != "Disabled" {
|
||||
identify = wb.identify
|
||||
statusReason = wb.statusReason
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
implement.Has(wb, implement.StatusReasoner(wb.statusReason))
|
||||
}
|
||||
|
||||
return decorateSmartEVSE3(wb, currentPower, totalEnergy, currents, phases1p3p, getPhases, identify, statusReason), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// post issues a POST request to the SmartEVSE with given query parameters.
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateSmartEVSE3(base *SmartEVSE3, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseSwitcher func(int) error, phaseGetter func() (int, error), identifier func() (string, error), statusReasoner func() (api.Reason, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateSmartEVSE3MeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateSmartEVSE3MeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateSmartEVSE3PhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateSmartEVSE3PhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateSmartEVSE3PhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateSmartEVSE3IdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if statusReasoner != nil {
|
||||
caps[reflect.TypeFor[api.StatusReasoner]()] = &decorateSmartEVSE3StatusReasonerImpl{statusReasoner: statusReasoner}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateSmartEVSE3Capable{SmartEVSE3: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3Capable struct {
|
||||
*SmartEVSE3
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateSmartEVSE3Capable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3IdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3IdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3MeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3MeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3MeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3MeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3PhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3PhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3PhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3PhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3PhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3PhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateSmartEVSE3StatusReasonerImpl struct {
|
||||
statusReasoner func() (api.Reason, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSmartEVSE3StatusReasonerImpl) StatusReason() (api.Reason, error) {
|
||||
return impl.statusReasoner()
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -32,6 +33,7 @@ import (
|
|||
|
||||
// Solax charger implementation
|
||||
type Solax struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
isLegacyHw bool
|
||||
|
|
@ -75,8 +77,6 @@ func init() {
|
|||
registry.AddCtx("solax-g2", NewSolaxG2FromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateSolax -b *Solax -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
func NewSolaxG1FromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
return NewSolaxFromConfig(ctx, other, true)
|
||||
}
|
||||
|
|
@ -113,23 +113,21 @@ func NewSolax(ctx context.Context, uri, device, comset string, baudrate int, pro
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Solax{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
isLegacyHw: isLegacyHw,
|
||||
}
|
||||
|
||||
var phases1p3p func(int) error
|
||||
var phasesG func() (int, error)
|
||||
|
||||
if b, err := wb.conn.ReadInputRegisters(solaxRegFirmwareVersion, 1); err == nil {
|
||||
v := encoding.Uint16(b)
|
||||
if !wb.isLegacyHw && v >= solaxFirmwarePhaseSwitching {
|
||||
phases1p3p = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
}
|
||||
|
||||
return decorateSolax(wb, phases1p3p, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// getPhaseValues returns 3 sequential register values
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateSolax(base *Solax, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateSolaxPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateSolaxPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateSolaxCapable{Solax: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateSolaxCapable struct {
|
||||
*Solax
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateSolaxCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateSolaxPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSolaxPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateSolaxPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateSolaxPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/core/loadpoint"
|
||||
"github.com/evcc-io/evcc/plugin"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -14,13 +15,12 @@ func init() {
|
|||
}
|
||||
|
||||
type SwitchSocket struct {
|
||||
implement.Caps
|
||||
enable func(bool) error
|
||||
enabled func() (bool, error)
|
||||
*switchSocket
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateSwitchSocket -b *SwitchSocket -r api.Charger -t api.MeterEnergy,api.Battery
|
||||
|
||||
func NewSwitchSocketFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
var cc struct {
|
||||
embed `mapstructure:",squash"`
|
||||
|
|
@ -51,23 +51,26 @@ func NewSwitchSocketFromConfig(ctx context.Context, other map[string]any) (api.C
|
|||
return nil, err
|
||||
}
|
||||
|
||||
energy, err := cc.Energy.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
soc, err := cc.Soc.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
c := &SwitchSocket{
|
||||
Caps: implement.New(),
|
||||
enabled: enabled,
|
||||
enable: enable,
|
||||
switchSocket: NewSwitchSocket(&cc.embed, enabled, power, cc.StandbyPower),
|
||||
}
|
||||
|
||||
return decorateSwitchSocket(c, energy, soc), nil
|
||||
energy, err := cc.Energy.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(c, implement.MeterEnergy(energy))
|
||||
|
||||
soc, err := cc.Soc.FloatGetter(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
implement.May(c, implement.Battery(soc))
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func (c *SwitchSocket) Enabled() (bool, error) {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateSwitchSocket(base *SwitchSocket, meterEnergy func() (float64, error), battery func() (float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateSwitchSocketMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateSwitchSocketBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateSwitchSocketCapable{SwitchSocket: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateSwitchSocketCapable struct {
|
||||
*SwitchSocket
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateSwitchSocketCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateSwitchSocketBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSwitchSocketBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateSwitchSocketMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateSwitchSocketMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
|
@ -4,6 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/meter/tasmota"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
)
|
||||
|
|
@ -15,6 +16,7 @@ import (
|
|||
|
||||
// Tasmota charger implementation
|
||||
type Tasmota struct {
|
||||
implement.Caps
|
||||
conn *tasmota.Connection
|
||||
*switchSocket
|
||||
}
|
||||
|
|
@ -23,8 +25,6 @@ func init() {
|
|||
registry.Add("tasmota", NewTasmotaFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateTasmota -b *Tasmota -r api.Charger -t api.PhaseVoltages,api.PhaseCurrents
|
||||
|
||||
// NewTasmotaFromConfig creates a Tasmota charger from generic config
|
||||
func NewTasmotaFromConfig(other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -60,6 +60,7 @@ func NewTasmota(embed embed, uri, user, password, usage string, channels []int,
|
|||
}
|
||||
|
||||
c := &Tasmota{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
}
|
||||
|
||||
|
|
@ -74,7 +75,8 @@ func NewTasmota(embed embed, uri, user, password, usage string, channels []int,
|
|||
}
|
||||
|
||||
if hasPhases || len(channels) == 3 {
|
||||
return decorateTasmota(c, c.voltages, c.currents), nil
|
||||
implement.Has(c, implement.PhaseVoltages(c.voltages))
|
||||
implement.Has(c, implement.PhaseCurrents(c.currents))
|
||||
}
|
||||
|
||||
return c, nil
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateTasmota(base *Tasmota, phaseVoltages func() (float64, float64, float64, error), phaseCurrents func() (float64, float64, float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateTasmotaPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateTasmotaPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateTasmotaCapable{Tasmota: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateTasmotaCapable struct {
|
||||
*Tasmota
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateTasmotaCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateTasmotaPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateTasmotaPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateTasmotaPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateTasmotaPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
|
|
@ -26,6 +26,7 @@ import (
|
|||
|
||||
"github.com/WulfgarW/sensonet"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
"github.com/samber/lo"
|
||||
|
|
@ -43,8 +44,6 @@ type Vaillant struct {
|
|||
systemId string
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateVaillant -b *Vaillant -r api.Charger -t api.Meter,api.Battery
|
||||
|
||||
// NewVaillantFromConfig creates an Vaillant configurable charger from generic config
|
||||
func NewVaillantFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := struct {
|
||||
|
|
@ -155,14 +154,13 @@ func NewVaillantFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
SgReady: sgr,
|
||||
}
|
||||
|
||||
var power func() (float64, error)
|
||||
if devices, _ := conn.GetMpcData(systemId); len(devices) > 0 {
|
||||
power = util.Cached(func() (float64, error) {
|
||||
implement.Has(res, implement.Meter(util.Cached(func() (float64, error) {
|
||||
res, err := conn.GetMpcData(systemId)
|
||||
return lo.SumBy(res, func(d sensonet.MpcDevice) float64 {
|
||||
return d.CurrentPower
|
||||
}), err
|
||||
}, cc.Cache)
|
||||
}, cc.Cache)))
|
||||
}
|
||||
|
||||
heatingTemp := func(zz []sensonet.StateZone) float64 {
|
||||
|
|
@ -181,9 +179,8 @@ func NewVaillantFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
heatingTempSensor = heatingTemp(system.State.Zones) > 0
|
||||
}
|
||||
|
||||
var temp func() (float64, error)
|
||||
if !heating || heatingTempSensor {
|
||||
temp = util.Cached(func() (float64, error) {
|
||||
implement.Has(res, implement.Battery(util.Cached(func() (float64, error) {
|
||||
system, err := conn.GetSystem(systemId)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
|
@ -202,10 +199,10 @@ func NewVaillantFromConfig(ctx context.Context, other map[string]any) (api.Charg
|
|||
default:
|
||||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
}, cc.Cache)
|
||||
}, cc.Cache)))
|
||||
}
|
||||
|
||||
return decorateVaillant(res, power, temp), nil
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (v *Vaillant) print(chapter int, prefix string, zz ...any) {
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateVaillant(base *Vaillant, meter func() (float64, error), battery func() (float64, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateVaillantMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if battery != nil {
|
||||
caps[reflect.TypeFor[api.Battery]()] = &decorateVaillantBatteryImpl{battery: battery}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateVaillantCapable{Vaillant: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateVaillantCapable struct {
|
||||
*Vaillant
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateVaillantCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateVaillantBatteryImpl struct {
|
||||
battery func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateVaillantBatteryImpl) Soc() (float64, error) {
|
||||
return impl.battery()
|
||||
}
|
||||
|
||||
type decorateVaillantMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateVaillantMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
|
@ -25,6 +25,7 @@ import (
|
|||
"time"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/evcc-io/evcc/util/sponsor"
|
||||
|
|
@ -59,6 +60,7 @@ var (
|
|||
// Vestel is an api.Charger implementation for Vestel/Hymes wallboxes with Ethernet (SW modells).
|
||||
// It uses Modbus TCP to communicate with the wallbox at modbus client id 255.
|
||||
type Vestel struct {
|
||||
implement.Caps
|
||||
log *util.Logger
|
||||
conn *modbus.Connection
|
||||
enabled bool
|
||||
|
|
@ -69,8 +71,6 @@ func init() {
|
|||
registry.AddCtx("vestel", NewVestelFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateVestel -b *Vestel -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter,api.Identifier
|
||||
|
||||
// NewVestelFromConfig creates a Vestel charger from generic config
|
||||
func NewVestelFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
cc := modbus.TcpSettings{
|
||||
|
|
@ -99,23 +99,18 @@ func NewVestel(ctx context.Context, uri string, id uint8) (api.Charger, error) {
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Vestel{
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
conn: conn,
|
||||
current: 6,
|
||||
}
|
||||
|
||||
var (
|
||||
phasesS func(int) error
|
||||
phasesG func() (int, error)
|
||||
)
|
||||
if b, err := wb.conn.ReadInputRegisters(vestelRegNumberPhases, 1); err == nil && binary.BigEndian.Uint16(b) == 1 {
|
||||
phasesS = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
|
||||
// compare firmware version to determine if RFID is available
|
||||
var identify func() (string, error)
|
||||
|
||||
b, err := wb.conn.ReadInputRegisters(vestelRegFirmware, 50)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read firmware version: %w", err)
|
||||
|
|
@ -127,7 +122,7 @@ func NewVestel(ctx context.Context, uri string, id uint8) (api.Charger, error) {
|
|||
if v, err := version.NewSemver(fw); err == nil {
|
||||
if v.GreaterThanOrEqual(version.Must(version.NewSemver("3.156.0"))) {
|
||||
// firmware >= v3.156.0 supports RFID according to https://github.com/evcc-io/evcc/issues/21359
|
||||
identify = wb.identify
|
||||
implement.Has(wb, implement.Identifier(wb.identify))
|
||||
}
|
||||
} else {
|
||||
log.WARN.Printf("failed to parse firmware version %q: %v", string(b), err)
|
||||
|
|
@ -150,7 +145,7 @@ func NewVestel(ctx context.Context, uri string, id uint8) (api.Charger, error) {
|
|||
}
|
||||
go wb.heartbeat(ctx, timeout)
|
||||
|
||||
return decorateVestel(wb, phasesS, phasesG, identify), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
func (wb *Vestel) heartbeat(ctx context.Context, timeout time.Duration) {
|
||||
|
|
|
|||
|
|
@ -1,68 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateVestel(base *Vestel, phaseSwitcher func(int) error, phaseGetter func() (int, error), identifier func() (string, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateVestelPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateVestelPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateVestelIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateVestelCapable{Vestel: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateVestelCapable struct {
|
||||
*Vestel
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateVestelCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateVestelIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateVestelIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateVestelPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateVestelPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateVestelPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateVestelPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/modbus"
|
||||
"github.com/spf13/cast"
|
||||
|
|
@ -31,6 +32,7 @@ import (
|
|||
|
||||
// Victron charger implementation
|
||||
type Victron struct {
|
||||
implement.Caps
|
||||
conn *modbus.Connection
|
||||
regs victronRegs
|
||||
}
|
||||
|
|
@ -76,8 +78,6 @@ func init() {
|
|||
registry.AddCtx("victron-evcs", NewVictronEVCSFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateVictron -b *Victron -r api.Charger -t api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
// NewVictronGXFromConfig creates a Victron charger from generic config
|
||||
func NewVictronGXFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
return NewVictronFromConfig(ctx, other, victronGX)
|
||||
|
|
@ -112,6 +112,7 @@ func NewVictron(ctx context.Context, uri string, slaveID uint8, regs victronRegs
|
|||
conn.Logger(log.TRACE)
|
||||
|
||||
wb := &Victron{
|
||||
Caps: implement.New(),
|
||||
conn: conn,
|
||||
regs: regs,
|
||||
}
|
||||
|
|
@ -125,10 +126,6 @@ func NewVictron(ctx context.Context, uri string, slaveID uint8, regs victronRegs
|
|||
return nil, errors.New("charger must be in manual mode")
|
||||
}
|
||||
|
||||
// phase switching (EVCS only, requires hardware modification with second contactor)
|
||||
var phasesS func(int) error
|
||||
var phasesG func() (int, error)
|
||||
|
||||
if !regs.isGX {
|
||||
b, err := wb.conn.ReadHoldingRegisters(wb.regs.ThreePhaseEnabled, 1)
|
||||
if err != nil {
|
||||
|
|
@ -136,12 +133,12 @@ func NewVictron(ctx context.Context, uri string, slaveID uint8, regs victronRegs
|
|||
}
|
||||
|
||||
if binary.BigEndian.Uint16(b) == 1 {
|
||||
phasesS = wb.phases1p3p
|
||||
phasesG = wb.getPhases
|
||||
implement.Has(wb, implement.PhaseSwitcher(wb.phases1p3p))
|
||||
implement.Has(wb, implement.PhaseGetter(wb.getPhases))
|
||||
}
|
||||
}
|
||||
|
||||
return decorateVictron(wb, phasesS, phasesG), nil
|
||||
return wb, nil
|
||||
}
|
||||
|
||||
// Status implements the api.Charger interface
|
||||
|
|
|
|||
|
|
@ -1,56 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateVictron(base *Victron, phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateVictronPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateVictronPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateVictronCapable{Victron: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateVictronCapable struct {
|
||||
*Victron
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateVictronCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateVictronPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateVictronPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateVictronPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateVictronPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/coder/websocket"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/api/implement"
|
||||
"github.com/evcc-io/evcc/charger/warp"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -23,6 +24,7 @@ import (
|
|||
|
||||
type WarpWS struct {
|
||||
*warp.Connection
|
||||
implement.Caps
|
||||
pm *warp.Connection // separate Energy Manager
|
||||
|
||||
// config
|
||||
|
|
@ -54,8 +56,6 @@ func init() {
|
|||
registry.AddCtx("warp-ws", NewWarpWSFromConfig)
|
||||
}
|
||||
|
||||
//go:generate go tool decorate -f decorateWarpWS -b *WarpWS -r api.Charger -t api.Meter,api.MeterEnergy,api.PhaseCurrents,api.PhaseVoltages,api.Identifier,api.PhaseSwitcher,api.PhaseGetter
|
||||
|
||||
func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
|
||||
var cc struct {
|
||||
URI string
|
||||
|
|
@ -79,34 +79,29 @@ func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
}
|
||||
|
||||
// Feature: Meter -> Meter is legacy API, Meters is the new API
|
||||
var currentPower, totalEnergy func() (float64, error)
|
||||
if w.hasFeature(warp.FeatureMeter) || w.hasFeature(warp.FeatureMeters) {
|
||||
currentPower = w.currentPower
|
||||
totalEnergy = w.totalEnergy
|
||||
implement.Has(w, implement.Meter(w.currentPower))
|
||||
implement.Has(w, implement.MeterEnergy(w.totalEnergy))
|
||||
}
|
||||
|
||||
// Feature: Meters | MeterAllValues
|
||||
var currents, voltages func() (float64, float64, float64, error)
|
||||
if w.hasFeature(warp.FeatureMeters) || w.hasFeature(warp.FeatureMeterAllValues) {
|
||||
currents = w.currents
|
||||
voltages = w.voltages
|
||||
implement.Has(w, implement.PhaseCurrents(w.currents))
|
||||
implement.Has(w, implement.PhaseVoltages(w.voltages))
|
||||
}
|
||||
|
||||
// Feature: NFC
|
||||
var identify func() (string, error)
|
||||
if w.hasFeature(warp.FeatureNfc) {
|
||||
identify = w.identify
|
||||
implement.Has(w, implement.Identifier(w.identify))
|
||||
}
|
||||
|
||||
// Feature: Phase Switching
|
||||
// only setup phase switching methods if power manager endpoint is set
|
||||
var phases func(int) error
|
||||
var getPhases func() (int, error)
|
||||
if (w.hasFeature(warp.FeaturePhaseSwitch) || cc.EnergyManagerURI != "") && w.pm != nil {
|
||||
if res, err := w.ensurePmState(); err == nil && res.ExternalControl != warp.ExternalControlDeactivated {
|
||||
w.pmState = &res
|
||||
phases = w.phases1p3p
|
||||
getPhases = w.getPhases
|
||||
implement.Has(w, implement.PhaseSwitcher(w.phases1p3p))
|
||||
implement.Has(w, implement.PhaseGetter(w.getPhases))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +118,7 @@ func NewWarpWSFromConfig(ctx context.Context, other map[string]any) (api.Charger
|
|||
w.log.TRACE.Println("disabled phase auto switching")
|
||||
}
|
||||
|
||||
return decorateWarpWS(w, currentPower, totalEnergy, currents, voltages, identify, phases, getPhases), nil
|
||||
return w, nil
|
||||
}
|
||||
|
||||
func NewWarpWS(ctx context.Context, uri, user, pass, emURI, emUser, emPass string, meterIndex uint) (*WarpWS, error) {
|
||||
|
|
@ -131,6 +126,7 @@ func NewWarpWS(ctx context.Context, uri, user, pass, emURI, emUser, emPass strin
|
|||
|
||||
w := &WarpWS{
|
||||
Connection: warp.NewConnection(log, uri, user, pass),
|
||||
Caps: implement.New(),
|
||||
log: log,
|
||||
meterIndex: meterIndex,
|
||||
meterMap: map[int]int{},
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
package charger
|
||||
|
||||
// Code generated by github.com/evcc-io/evcc/cmd/tools/decorate.go. DO NOT EDIT.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/evcc-io/evcc/api"
|
||||
)
|
||||
|
||||
func decorateWarpWS(base *WarpWS, meter func() (float64, error), meterEnergy func() (float64, error), phaseCurrents func() (float64, float64, float64, error), phaseVoltages func() (float64, float64, float64, error), identifier func() (string, error), phaseSwitcher func(int) error, phaseGetter func() (int, error)) api.Charger {
|
||||
caps := make(map[reflect.Type]any)
|
||||
|
||||
if meter != nil {
|
||||
caps[reflect.TypeFor[api.Meter]()] = &decorateWarpWSMeterImpl{meter: meter}
|
||||
}
|
||||
|
||||
if meterEnergy != nil {
|
||||
caps[reflect.TypeFor[api.MeterEnergy]()] = &decorateWarpWSMeterEnergyImpl{meterEnergy: meterEnergy}
|
||||
}
|
||||
|
||||
if phaseCurrents != nil {
|
||||
caps[reflect.TypeFor[api.PhaseCurrents]()] = &decorateWarpWSPhaseCurrentsImpl{phaseCurrents: phaseCurrents}
|
||||
}
|
||||
|
||||
if phaseVoltages != nil {
|
||||
caps[reflect.TypeFor[api.PhaseVoltages]()] = &decorateWarpWSPhaseVoltagesImpl{phaseVoltages: phaseVoltages}
|
||||
}
|
||||
|
||||
if identifier != nil {
|
||||
caps[reflect.TypeFor[api.Identifier]()] = &decorateWarpWSIdentifierImpl{identifier: identifier}
|
||||
}
|
||||
|
||||
if phaseSwitcher != nil {
|
||||
caps[reflect.TypeFor[api.PhaseSwitcher]()] = &decorateWarpWSPhaseSwitcherImpl{phaseSwitcher: phaseSwitcher}
|
||||
}
|
||||
|
||||
if phaseGetter != nil {
|
||||
caps[reflect.TypeFor[api.PhaseGetter]()] = &decorateWarpWSPhaseGetterImpl{phaseGetter: phaseGetter}
|
||||
}
|
||||
|
||||
if len(caps) == 0 {
|
||||
return base
|
||||
}
|
||||
|
||||
return &decorateWarpWSCapable{WarpWS: base, caps: caps}
|
||||
}
|
||||
|
||||
type decorateWarpWSCapable struct {
|
||||
*WarpWS
|
||||
caps map[reflect.Type]any
|
||||
}
|
||||
|
||||
func (d *decorateWarpWSCapable) Capability(typ reflect.Type) (any, bool) {
|
||||
c, ok := d.caps[typ]
|
||||
if !ok && reflect.TypeOf(d).Implements(typ) {
|
||||
return d, true
|
||||
}
|
||||
return c, ok
|
||||
}
|
||||
|
||||
type decorateWarpWSIdentifierImpl struct {
|
||||
identifier func() (string, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSIdentifierImpl) Identify() (string, error) {
|
||||
return impl.identifier()
|
||||
}
|
||||
|
||||
type decorateWarpWSMeterImpl struct {
|
||||
meter func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSMeterImpl) CurrentPower() (float64, error) {
|
||||
return impl.meter()
|
||||
}
|
||||
|
||||
type decorateWarpWSMeterEnergyImpl struct {
|
||||
meterEnergy func() (float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSMeterEnergyImpl) TotalEnergy() (float64, error) {
|
||||
return impl.meterEnergy()
|
||||
}
|
||||
|
||||
type decorateWarpWSPhaseCurrentsImpl struct {
|
||||
phaseCurrents func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSPhaseCurrentsImpl) Currents() (float64, float64, float64, error) {
|
||||
return impl.phaseCurrents()
|
||||
}
|
||||
|
||||
type decorateWarpWSPhaseGetterImpl struct {
|
||||
phaseGetter func() (int, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSPhaseGetterImpl) GetPhases() (int, error) {
|
||||
return impl.phaseGetter()
|
||||
}
|
||||
|
||||
type decorateWarpWSPhaseSwitcherImpl struct {
|
||||
phaseSwitcher func(int) error
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSPhaseSwitcherImpl) Phases1p3p(p0 int) error {
|
||||
return impl.phaseSwitcher(p0)
|
||||
}
|
||||
|
||||
type decorateWarpWSPhaseVoltagesImpl struct {
|
||||
phaseVoltages func() (float64, float64, float64, error)
|
||||
}
|
||||
|
||||
func (impl *decorateWarpWSPhaseVoltagesImpl) Voltages() (float64, float64, float64, error) {
|
||||
return impl.phaseVoltages()
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue