Curtailment: distribute limits to all devices by percent (#31390)
This commit is contained in:
parent
949daf4670
commit
eea55d282d
22 changed files with 147 additions and 131 deletions
|
|
@ -278,18 +278,9 @@ func (c *EEBus) Curtailed() (bool, error) {
|
|||
return limit.IsActive && limit.Value <= 0, nil
|
||||
}
|
||||
|
||||
// Curtail implements the api.Curtailer interface
|
||||
func (c *EEBus) Curtail(curtail bool) error {
|
||||
// Sets or removes the production power limit
|
||||
|
||||
// TODO: change api.Curtailer to make limit configurable
|
||||
// For now, we use a fixed safe limit of 0W
|
||||
limit := 0.0
|
||||
|
||||
var value float64
|
||||
if curtail {
|
||||
value = limit
|
||||
}
|
||||
// SetCurtailPercent implements the api.Curtailer interface
|
||||
func (c *EEBus) SetCurtailPercent(percent int) error {
|
||||
curtail := percent < 100
|
||||
|
||||
c.mu.Lock()
|
||||
entity := c.egLppEntity
|
||||
|
|
@ -299,6 +290,15 @@ func (c *EEBus) Curtail(curtail bool) error {
|
|||
return api.ErrNotAvailable
|
||||
}
|
||||
|
||||
// derive a proportional feed-in limit from the producer's nominal power
|
||||
// (limits are negative watts); fall back to a safe 0W limit if unavailable
|
||||
var value float64
|
||||
if curtail {
|
||||
if nominal, err := c.eg.EgLPPInterface.ProductionNominalMax(entity); err == nil && nominal > 0 {
|
||||
value = -float64(percent) / 100 * nominal
|
||||
}
|
||||
}
|
||||
|
||||
return eebus.Await(func(cb func(model.ResultDataType)) (*model.MsgCounterType, error) {
|
||||
return c.eg.EgLPPInterface.WriteProductionLimit(entity, ucapi.LoadLimit{Value: value, IsActive: curtail}, cb)
|
||||
})
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ func (c *EEBus) maUseCaseSupportUpdate(entity spineapi.EntityRemoteInterface) {
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// use most specific selector
|
||||
// prefer the shallowest (device-level) entity
|
||||
if c.maEntity == nil || len(entity.Address().Entity) < len(c.maEntity.Address().Entity) {
|
||||
c.maEntity = entity
|
||||
}
|
||||
|
|
@ -76,7 +76,7 @@ func (c *EEBus) egLpcUseCaseSupportUpdate(entity spineapi.EntityRemoteInterface)
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// use most specific selector
|
||||
// prefer the shallowest (device-level) entity
|
||||
if c.egLpcEntity == nil || len(entity.Address().Entity) < len(c.egLpcEntity.Address().Entity) {
|
||||
c.egLpcEntity = entity
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ func (c *EEBus) egLppUseCaseSupportUpdate(entity spineapi.EntityRemoteInterface)
|
|||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
// use most specific selector
|
||||
// prefer the shallowest (device-level) entity
|
||||
if c.egLppEntity == nil || len(entity.Address().Entity) < len(c.egLppEntity.Address().Entity) {
|
||||
c.egLppEntity = entity
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,11 +53,11 @@ type Curtailer struct {
|
|||
}
|
||||
|
||||
func (cc *Curtailer) Configure(ctx context.Context) (
|
||||
func(bool) error,
|
||||
func(int64) error,
|
||||
func() (bool, error),
|
||||
error,
|
||||
) {
|
||||
curtailS, err := cc.Curtail.BoolSetter(ctx, "curtail")
|
||||
curtailS, err := cc.Curtail.IntSetter(ctx, "curtail")
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("curtail: %w", err)
|
||||
}
|
||||
|
|
@ -80,7 +80,10 @@ func (cc *Curtailer) Implement(ctx context.Context, i implement.Caps) error {
|
|||
return err
|
||||
}
|
||||
|
||||
implement.May(i, implement.Curtailer(curtailS, curtailedG))
|
||||
if curtailS != nil {
|
||||
setPercent := func(percent int) error { return curtailS(int64(percent)) }
|
||||
implement.May(i, implement.Curtailer(curtailedG, setPercent))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
10
meter/rct.go
10
meter/rct.go
|
|
@ -107,12 +107,8 @@ func NewRCT(ctx context.Context, uri, usage string, batterySocLimits batterySocL
|
|||
}
|
||||
|
||||
if usage == "pv" {
|
||||
curtail := func(b bool) error {
|
||||
var r float64
|
||||
if !b {
|
||||
r = 1.0
|
||||
}
|
||||
return m.conn.Write(rct.BufVControlPowerReduction, floatVal(r))
|
||||
curtail := func(percent int) error {
|
||||
return m.conn.Write(rct.BufVControlPowerReduction, floatVal(float64(percent)/100))
|
||||
}
|
||||
|
||||
curtailed := func() (bool, error) {
|
||||
|
|
@ -120,7 +116,7 @@ func NewRCT(ctx context.Context, uri, usage string, batterySocLimits batterySocL
|
|||
return r != 1, err
|
||||
}
|
||||
|
||||
implement.Has(m, implement.Curtailer(curtail, curtailed))
|
||||
implement.Has(m, implement.Curtailer(curtailed, curtail))
|
||||
implement.May(m, implement.MaxACPowerGetter(maxACPower))
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue