EEBus: named scenario constants + fix MGCP scenario indices (#29701)
This commit is contained in:
parent
1b26d77b6c
commit
4b276a4d99
3 changed files with 116 additions and 15 deletions
|
|
@ -316,7 +316,7 @@ func (c *EEBus) Enable(enable bool) error {
|
|||
// send current charging power limits to the EV
|
||||
func (c *EEBus) writeCurrentLimitData(evEntity spineapi.EntityRemoteInterface, current float64) error {
|
||||
// check if the EVSE supports overload protection limits
|
||||
if !c.cem.OpEV.IsScenarioAvailableAtEntity(evEntity, 1) {
|
||||
if !c.cem.OpEV.IsScenarioAvailableAtEntity(evEntity, eebus.OPEVScenarioObligationLimit) {
|
||||
return api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
@ -362,7 +362,7 @@ func (c *EEBus) writeCurrentLimitData(evEntity spineapi.EntityRemoteInterface, c
|
|||
// An active recommendation triggers the EV to charge with surplus energy.
|
||||
// An inactive recommendation is equivalent to no recommendation existing.
|
||||
func (c *EEBus) writeOscevLimits(evEntity spineapi.EntityRemoteInterface, current float64) {
|
||||
if !c.cem.OscEV.IsScenarioAvailableAtEntity(evEntity, 1) {
|
||||
if !c.cem.OscEV.IsScenarioAvailableAtEntity(evEntity, eebus.OSCEVScenarioRecommendationLimit) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -430,7 +430,7 @@ func (c *EEBus) currentPower() (float64, error) {
|
|||
|
||||
// does the EVSE provide power data?
|
||||
var powers []float64
|
||||
if c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, 2) {
|
||||
if c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, eebus.EVCEMScenarioPowerTotal) {
|
||||
// is power data available for real? Elli Gen1 says it supports it, but doesn't provide any data
|
||||
if powerData, err := c.cem.EvCem.PowerPerPhase(evEntity); err == nil {
|
||||
powers = powerData
|
||||
|
|
@ -438,7 +438,7 @@ func (c *EEBus) currentPower() (float64, error) {
|
|||
}
|
||||
|
||||
// if no power data is available, and currents are reported to be supported, use currents
|
||||
if len(powers) == 0 && c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, 1) {
|
||||
if len(powers) == 0 && c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, eebus.EVCEMScenarioPowerPerPhase) {
|
||||
// no power provided, calculate from current
|
||||
if currents, err := c.cem.EvCem.CurrentPerPhase(evEntity); err == nil {
|
||||
for _, current := range currents {
|
||||
|
|
@ -462,7 +462,7 @@ func (c *EEBus) chargedEnergy() (float64, error) {
|
|||
return 0, nil
|
||||
}
|
||||
|
||||
if !c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, 3) {
|
||||
if !c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, eebus.EVCEMScenarioEnergy) {
|
||||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
@ -482,7 +482,7 @@ func (c *EEBus) currents() (float64, float64, float64, error) {
|
|||
}
|
||||
|
||||
// check if the EVSE supports currents
|
||||
if !c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, 1) {
|
||||
if !c.cem.EvCem.IsScenarioAvailableAtEntity(evEntity, eebus.EVCEMScenarioPowerPerPhase) {
|
||||
return 0, 0, 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
@ -538,7 +538,7 @@ func (c *EEBus) Soc() (float64, error) {
|
|||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
if !c.cem.EvSoc.IsScenarioAvailableAtEntity(evEntity, 1) {
|
||||
if !c.cem.EvSoc.IsScenarioAvailableAtEntity(evEntity, eebus.EVSOCScenarioStateOfCharge) {
|
||||
return 0, api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ type EEBus struct {
|
|||
ma *eebus.MonitoringAppliance
|
||||
eg *eebus.EnergyGuard
|
||||
mm measurements
|
||||
scenarios maScenarios
|
||||
|
||||
mu sync.Mutex
|
||||
maEntity spineapi.EntityRemoteInterface
|
||||
|
|
@ -36,6 +37,31 @@ type EEBus struct {
|
|||
egLppEntity spineapi.EntityRemoteInterface
|
||||
}
|
||||
|
||||
// maScenarios holds the spec scenario numbers for the active monitoring use case.
|
||||
// MGCP and MPC use different scenario numbers for the same physical quantity, so
|
||||
// IsScenarioAvailableAtEntity must be called with the per-UC value.
|
||||
type maScenarios struct {
|
||||
power uint
|
||||
energy uint
|
||||
currents uint
|
||||
voltages uint
|
||||
}
|
||||
|
||||
var (
|
||||
mpcScenarios = maScenarios{
|
||||
power: eebus.MPCScenarioPower,
|
||||
energy: eebus.MPCScenarioEnergyConsumed,
|
||||
currents: eebus.MPCScenarioCurrentPerPhase,
|
||||
voltages: eebus.MPCScenarioVoltagePerPhase,
|
||||
}
|
||||
mgcpScenarios = maScenarios{
|
||||
power: eebus.MGCPScenarioPower,
|
||||
energy: eebus.MGCPScenarioEnergyConsumed,
|
||||
currents: eebus.MGCPScenarioCurrentPerPhase,
|
||||
voltages: eebus.MGCPScenarioVoltagePerPhase,
|
||||
}
|
||||
)
|
||||
|
||||
type measurements interface {
|
||||
eebusapi.UseCaseBaseInterface
|
||||
Power(entity spineapi.EntityRemoteInterface) (float64, error)
|
||||
|
|
@ -76,10 +102,12 @@ func NewEEBus(ctx context.Context, ski, ip string, usage *templates.Usage) (api.
|
|||
// Use MGCP only for explicit grid usage, MPC for everything else (default)
|
||||
useCase := "mpc"
|
||||
mm := measurements(ma.MaMPCInterface)
|
||||
scenarios := mpcScenarios
|
||||
|
||||
if usage != nil && *usage == templates.UsageGrid {
|
||||
useCase = "mgcp"
|
||||
mm = ma.MaMGCPInterface
|
||||
scenarios = mgcpScenarios
|
||||
}
|
||||
|
||||
c := &EEBus{
|
||||
|
|
@ -87,6 +115,7 @@ func NewEEBus(ctx context.Context, ski, ip string, usage *templates.Usage) (api.
|
|||
ma: ma,
|
||||
eg: eebus.Instance.EnergyGuard(),
|
||||
mm: mm,
|
||||
scenarios: scenarios,
|
||||
connector: eebus.NewConnector(),
|
||||
}
|
||||
|
||||
|
|
@ -144,13 +173,13 @@ func (c *EEBus) readValue(scenario uint, update func(entity spineapi.EntityRemot
|
|||
var _ api.Meter = (*EEBus)(nil)
|
||||
|
||||
func (c *EEBus) CurrentPower() (float64, error) {
|
||||
return c.readValue(1, c.mm.Power)
|
||||
return c.readValue(c.scenarios.power, c.mm.Power)
|
||||
}
|
||||
|
||||
var _ api.MeterEnergy = (*EEBus)(nil)
|
||||
|
||||
func (c *EEBus) TotalEnergy() (float64, error) {
|
||||
return c.readValue(2, c.mm.EnergyConsumed)
|
||||
return c.readValue(c.scenarios.energy, c.mm.EnergyConsumed)
|
||||
}
|
||||
|
||||
func (c *EEBus) readPhases(scenario uint, update func(entity spineapi.EntityRemoteInterface) ([]float64, error)) (float64, float64, float64, error) {
|
||||
|
|
@ -184,13 +213,13 @@ func (c *EEBus) readPhases(scenario uint, update func(entity spineapi.EntityRemo
|
|||
var _ api.PhaseCurrents = (*EEBus)(nil)
|
||||
|
||||
func (c *EEBus) Currents() (float64, float64, float64, error) {
|
||||
return c.readPhases(3, c.mm.CurrentPerPhase)
|
||||
return c.readPhases(c.scenarios.currents, c.mm.CurrentPerPhase)
|
||||
}
|
||||
|
||||
var _ api.PhaseVoltages = (*EEBus)(nil)
|
||||
|
||||
func (c *EEBus) Voltages() (float64, float64, float64, error) {
|
||||
return c.readPhases(4, c.mm.VoltagePerPhase)
|
||||
return c.readPhases(c.scenarios.voltages, c.mm.VoltagePerPhase)
|
||||
}
|
||||
|
||||
var _ api.Dimmer = (*EEBus)(nil)
|
||||
|
|
@ -200,7 +229,7 @@ func (c *EEBus) Dimmed() (bool, error) {
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
limit, err := eebusReadValue(c.eg.EgLPCInterface, c.egLpcEntity, 1, c.eg.EgLPCInterface.ConsumptionLimit)
|
||||
limit, err := eebusReadValue(c.eg.EgLPCInterface, c.egLpcEntity, eebus.LPCScenarioLimit, c.eg.EgLPCInterface.ConsumptionLimit)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -225,7 +254,7 @@ func (c *EEBus) Dim(dim bool) error {
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.egLpcEntity == nil || !c.eg.EgLPCInterface.IsScenarioAvailableAtEntity(c.egLpcEntity, 1) {
|
||||
if c.egLpcEntity == nil || !c.eg.EgLPCInterface.IsScenarioAvailableAtEntity(c.egLpcEntity, eebus.LPCScenarioLimit) {
|
||||
return api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
@ -244,7 +273,7 @@ func (c *EEBus) Curtailed() (bool, error) {
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
limit, err := eebusReadValue(c.eg.EgLPPInterface, c.egLppEntity, 1, c.eg.EgLPPInterface.ProductionLimit)
|
||||
limit, err := eebusReadValue(c.eg.EgLPPInterface, c.egLppEntity, eebus.LPPScenarioLimit, c.eg.EgLPPInterface.ProductionLimit)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
|
@ -269,7 +298,7 @@ func (c *EEBus) Curtail(curtail bool) error {
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if c.egLppEntity == nil || !c.eg.EgLPPInterface.IsScenarioAvailableAtEntity(c.egLppEntity, 1) {
|
||||
if c.egLppEntity == nil || !c.eg.EgLPPInterface.IsScenarioAvailableAtEntity(c.egLppEntity, eebus.LPPScenarioLimit) {
|
||||
return api.ErrNotAvailable
|
||||
}
|
||||
|
||||
|
|
|
|||
72
server/eebus/scenarios.go
Normal file
72
server/eebus/scenarios.go
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
package eebus
|
||||
|
||||
// EEBUS use case scenario numbers per the respective Use Case Technical Specifications.
|
||||
//
|
||||
// Spec scenario numbers diverge between use cases (e.g. MPC scenario 1 = active power,
|
||||
// MGCP scenario 1 = power factor; MPC scenario 2 = energy, MGCP scenario 2 = active power).
|
||||
// Passing the wrong number to IsScenarioAvailableAtEntity gates reads on the wrong feature.
|
||||
//
|
||||
// Each block mirrors the scenarios registered in the corresponding eebus-go usecase, which
|
||||
// in turn matches the EEBus UC TS document.
|
||||
|
||||
// MGCP — Monitoring of Grid Connection Point (UC TS v1.0.0)
|
||||
const (
|
||||
MGCPScenarioPowerFactor uint = 1 // S1 power factor (cos phi)
|
||||
MGCPScenarioPower uint = 2 // S2 active power per phase + total
|
||||
MGCPScenarioEnergyFeedIn uint = 3 // S3 total feed-in energy
|
||||
MGCPScenarioEnergyConsumed uint = 4 // S4 total consumed energy
|
||||
MGCPScenarioCurrentPerPhase uint = 5 // S5 phase-specific currents
|
||||
MGCPScenarioVoltagePerPhase uint = 6 // S6 phase-specific voltages
|
||||
MGCPScenarioFrequency uint = 7 // S7 frequency
|
||||
)
|
||||
|
||||
// MPC — Monitoring of Power Consumption (UC TS v1.0.0)
|
||||
const (
|
||||
MPCScenarioPower uint = 1 // S1 active power per phase + total
|
||||
MPCScenarioEnergyConsumed uint = 2 // S2 total consumed energy
|
||||
MPCScenarioCurrentPerPhase uint = 3 // S3 phase-specific currents
|
||||
MPCScenarioVoltagePerPhase uint = 4 // S4 phase-specific voltages
|
||||
MPCScenarioFrequency uint = 5 // S5 frequency
|
||||
)
|
||||
|
||||
// LPC — Limitation of Power Consumption (UC TS v1.0.0). Same scenario layout for CS and EG roles.
|
||||
const (
|
||||
LPCScenarioLimit uint = 1 // S1 LoadControl: consumption limit
|
||||
LPCScenarioFailsafe uint = 2 // S2 DeviceConfiguration: failsafe values
|
||||
LPCScenarioHeartbeat uint = 3 // S3 DeviceDiagnosis: heartbeat
|
||||
LPCScenarioElectricalConnection uint = 4 // S4 ElectricalConnection (optional)
|
||||
)
|
||||
|
||||
// LPP — Limitation of Power Production (UC TS v1.0.0). Same scenario layout for CS and EG roles.
|
||||
const (
|
||||
LPPScenarioLimit uint = 1 // S1 LoadControl: production limit
|
||||
LPPScenarioFailsafe uint = 2 // S2 DeviceConfiguration: failsafe values
|
||||
LPPScenarioHeartbeat uint = 3 // S3 DeviceDiagnosis: heartbeat
|
||||
LPPScenarioElectricalConnection uint = 4 // S4 ElectricalConnection (optional)
|
||||
)
|
||||
|
||||
// OPEV — Overload Protection by EV Charging Current Curtailment (UC TS v1.0.1)
|
||||
const (
|
||||
OPEVScenarioObligationLimit uint = 1 // S1 LoadControl + ElectricalConnection
|
||||
OPEVScenarioChargingState uint = 2 // S2 charging state
|
||||
OPEVScenarioChargingPlan uint = 3 // S3 charging plan
|
||||
)
|
||||
|
||||
// OSCEV — Optimization of Self-Consumption during EV Charging (UC TS v1.0.1)
|
||||
const (
|
||||
OSCEVScenarioRecommendationLimit uint = 1 // S1 LoadControl + ElectricalConnection
|
||||
OSCEVScenarioChargingState uint = 2 // S2 charging state
|
||||
OSCEVScenarioChargingPlan uint = 3 // S3 charging plan
|
||||
)
|
||||
|
||||
// EVCEM — Measurement of Electricity during EV Charging (UC TS v1.0.1)
|
||||
const (
|
||||
EVCEMScenarioPowerPerPhase uint = 1 // S1 phase-specific active power + ElectricalConnection (currents)
|
||||
EVCEMScenarioPowerTotal uint = 2 // S2 total active power only
|
||||
EVCEMScenarioEnergy uint = 3 // S3 charging energy summary
|
||||
)
|
||||
|
||||
// EVSOC — EV State of Charge (UC TS v1.0.0 RC1)
|
||||
const (
|
||||
EVSOCScenarioStateOfCharge uint = 1 // S1 state of charge
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue