diff --git a/meter/rct.go b/meter/rct.go index f92336451..9d670d22f 100644 --- a/meter/rct.go +++ b/meter/rct.go @@ -33,7 +33,7 @@ func init() { registry.AddCtx("rct", NewRCTFromConfig) } -//go:generate go tool decorate -f decorateRCT -b *RCT -r api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.Battery,Soc,func() (float64, error)" -t "api.BatterySocLimiter,GetSocLimits,func() (float64, float64)" -t "api.BatteryController,SetBatteryMode,func(api.BatteryMode) error" -t "api.BatteryCapacity,Capacity,func() float64" +//go:generate go tool decorate -f decorateRCT -b *RCT -r api.Meter -t "api.MeterEnergy,TotalEnergy,func() (float64, error)" -t "api.Curtailer,Curtail,func(bool) error,Curtailed,func() (bool, error)" -t "api.Battery,Soc,func() (float64, error)" -t "api.BatterySocLimiter,GetSocLimits,func() (float64, float64)" -t "api.BatteryController,SetBatteryMode,func(api.BatteryMode) error" -t "api.BatteryCapacity,Capacity,func() float64" // NewRCTFromConfig creates an RCT from generic config func NewRCTFromConfig(ctx context.Context, other map[string]any) (api.Meter, error) { @@ -100,6 +100,24 @@ func NewRCT(ctx context.Context, uri, usage string, batterySocLimits batterySocL totalEnergy = m.totalEnergy } + // decorate api.Curtailer + var curtail func(bool) error + var curtailed func() (bool, error) + if usage == "pv" { + curtail = func(b bool) error { + r := float32(1) + if b { + r = 0 + } + return m.conn.Write(rct.BufVControlPowerReduction, m.floatVal(r)) + } + + curtailed = func() (bool, error) { + r, err := m.queryFloat(rct.BufVControlPowerReduction) + return r != 1, err + } + } + // decorate api.Battery var batterySoc func() (float64, error) var batterySocLimiter func() (float64, float64) @@ -191,7 +209,7 @@ func NewRCT(ctx context.Context, uri, usage string, batterySocLimits batterySocL } } - return decorateRCT(m, totalEnergy, batterySoc, batterySocLimiter, batteryMode, batteryCapacity), nil + return decorateRCT(m, totalEnergy, curtail, curtailed, batterySoc, batterySocLimiter, batteryMode, batteryCapacity), nil } func (m *RCT) floatVal(f float32) []byte { diff --git a/meter/rct_decorators.go b/meter/rct_decorators.go index b012360b4..0836d0914 100644 --- a/meter/rct_decorators.go +++ b/meter/rct_decorators.go @@ -6,12 +6,12 @@ import ( "github.com/evcc-io/evcc/api" ) -func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() (float64, error), batterySocLimiter func() (float64, float64), batteryController func(api.BatteryMode) error, batteryCapacity func() float64) api.Meter { +func decorateRCT(base *RCT, meterEnergy func() (float64, error), curtailer0 func(bool) error, curtailer1 func() (bool, error), battery func() (float64, error), batterySocLimiter func() (float64, float64), batteryController func(api.BatteryMode) error, batteryCapacity func() float64) api.Meter { switch { - case battery == nil && meterEnergy == nil: + case battery == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return base - case battery == nil && meterEnergy != nil: + case battery == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.MeterEnergy @@ -22,7 +22,35 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter == nil && meterEnergy == nil: + case battery == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Curtailer + }{ + RCT: base, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -33,7 +61,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter == nil && meterEnergy != nil: + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -48,7 +76,43 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter != nil && meterEnergy == nil: + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -63,7 +127,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter != nil && meterEnergy != nil: + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -82,7 +146,51 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter == nil && meterEnergy == nil: + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatterySocLimiter + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController == nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatterySocLimiter + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -97,7 +205,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter == nil && meterEnergy != nil: + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -116,7 +224,51 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter != nil && meterEnergy == nil: + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatteryController + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatteryController + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -135,7 +287,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter != nil && meterEnergy != nil: + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -158,7 +310,59 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter == nil && meterEnergy == nil: + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatteryController + api.BatterySocLimiter + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity == nil && batteryController != nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatteryController + api.BatterySocLimiter + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -173,7 +377,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter == nil && meterEnergy != nil: + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -192,7 +396,51 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter != nil && meterEnergy == nil: + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -211,7 +459,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter != nil && meterEnergy != nil: + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -234,7 +482,59 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter == nil && meterEnergy == nil: + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.BatterySocLimiter + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController == nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.BatterySocLimiter + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -253,7 +553,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter == nil && meterEnergy != nil: + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter == nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -276,7 +576,59 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter != nil && meterEnergy == nil: + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.BatteryController + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter == nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.BatteryController + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy == nil: return &struct { *RCT api.Battery @@ -299,7 +651,7 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() }, } - case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter != nil && meterEnergy != nil: + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter != nil && curtailer0 == nil && curtailer1 == nil && meterEnergy != nil: return &struct { *RCT api.Battery @@ -325,6 +677,66 @@ func decorateRCT(base *RCT, meterEnergy func() (float64, error), battery func() meterEnergy: meterEnergy, }, } + + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy == nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.BatteryController + api.BatterySocLimiter + api.Curtailer + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + } + + case battery != nil && batteryCapacity != nil && batteryController != nil && batterySocLimiter != nil && curtailer0 != nil && curtailer1 != nil && meterEnergy != nil: + return &struct { + *RCT + api.Battery + api.BatteryCapacity + api.BatteryController + api.BatterySocLimiter + api.Curtailer + api.MeterEnergy + }{ + RCT: base, + Battery: &decorateRCTBatteryImpl{ + battery: battery, + }, + BatteryCapacity: &decorateRCTBatteryCapacityImpl{ + batteryCapacity: batteryCapacity, + }, + BatteryController: &decorateRCTBatteryControllerImpl{ + batteryController: batteryController, + }, + BatterySocLimiter: &decorateRCTBatterySocLimiterImpl{ + batterySocLimiter: batterySocLimiter, + }, + Curtailer: &decorateRCTCurtailerImpl{ + curtailer0: curtailer0, + curtailer1: curtailer1, + }, + MeterEnergy: &decorateRCTMeterEnergyImpl{ + meterEnergy: meterEnergy, + }, + } } return nil @@ -362,6 +774,19 @@ func (impl *decorateRCTBatterySocLimiterImpl) GetSocLimits() (float64, float64) return impl.batterySocLimiter() } +type decorateRCTCurtailerImpl struct { + curtailer0 func(bool) error + curtailer1 func() (bool, error) +} + +func (impl *decorateRCTCurtailerImpl) Curtail(p0 bool) error { + return impl.curtailer0(p0) +} + +func (impl *decorateRCTCurtailerImpl) Curtailed() (bool, error) { + return impl.curtailer1() +} + type decorateRCTMeterEnergyImpl struct { meterEnergy func() (float64, error) }