Latest Updates done, before integrating
This commit is contained in:
@@ -690,8 +690,12 @@ func (e *Engine) socEmergencyBrake(soc float64, now time.Time) []Action {
|
||||
continue
|
||||
}
|
||||
|
||||
// Proactive wallboxes: only emergency-brake at SOCFloor
|
||||
if cs.ProactiveCharging && (c == ConsumerWallboxA || c == ConsumerWallboxB) {
|
||||
// Intentional wallbox charging (proactive or trip mode): only emergency-brake at SOCFloor.
|
||||
// Trip mode uses ManualOverride=true, proactive charging uses ProactiveCharging=true —
|
||||
// both deserve soc_floor protection instead of the standard block_all gate.
|
||||
isIntentionalCharging := (cs.ProactiveCharging || cs.ManualOverride) &&
|
||||
(c == ConsumerWallboxA || c == ConsumerWallboxB)
|
||||
if isIntentionalCharging {
|
||||
floor := float64(e.cfg.CarCharging.SOCFloor)
|
||||
if floor > 0 && soc >= floor {
|
||||
continue // still above floor, keep charging
|
||||
@@ -967,7 +971,10 @@ func (e *Engine) RecoverState(states map[Consumer]DeviceStatus) {
|
||||
// On match: expired overrides are cleared, resuming normal EMS control.
|
||||
// Power readings (from PM-capable devices) update the low-power cycle counter for
|
||||
// car-not-charging detection.
|
||||
func (e *Engine) SyncHardwareState(states map[Consumer]DeviceStatus, now time.Time, overrideTimeout time.Duration) {
|
||||
// When monitorOnly is true, hardware mismatches silently update engine state without
|
||||
// logging or applying override lockouts — the EMS cannot act anyway, so treating
|
||||
// every missed switch as a "manual override" would produce spurious log spam.
|
||||
func (e *Engine) SyncHardwareState(states map[Consumer]DeviceStatus, now time.Time, overrideTimeout time.Duration, monitorOnly bool) {
|
||||
for c, status := range states {
|
||||
cs, ok := e.consumers[c]
|
||||
if !ok {
|
||||
@@ -975,21 +982,33 @@ func (e *Engine) SyncHardwareState(states map[Consumer]DeviceStatus, now time.Ti
|
||||
}
|
||||
|
||||
if cs.Active != status.On {
|
||||
// External change detected
|
||||
e.logger.Info("manual override detected — external state change",
|
||||
"consumer", c.String(),
|
||||
"engine_state", cs.Active,
|
||||
"hardware_state", status.On,
|
||||
"override_until", now.Add(overrideTimeout).Format("15:04"),
|
||||
)
|
||||
cs.Active = status.On
|
||||
cs.ManualOverride = true
|
||||
cs.OverrideUntil = now.Add(overrideTimeout)
|
||||
cs.LowPowerCycles = 0
|
||||
if !status.On {
|
||||
cs.ActivatedAt = time.Time{}
|
||||
if monitorOnly {
|
||||
// In monitor-only mode the EMS cannot execute switch actions, so a
|
||||
// mismatch just means a pending action couldn't be carried out.
|
||||
// Silently realign engine state to hardware without locking.
|
||||
cs.Active = status.On
|
||||
if !status.On {
|
||||
cs.ActivatedAt = time.Time{}
|
||||
} else {
|
||||
cs.ActivatedAt = now
|
||||
}
|
||||
} else {
|
||||
cs.ActivatedAt = now
|
||||
// External change detected — log and apply override lockout
|
||||
e.logger.Info("manual override detected — external state change",
|
||||
"consumer", c.String(),
|
||||
"engine_state", cs.Active,
|
||||
"hardware_state", status.On,
|
||||
"override_until", now.Add(overrideTimeout).Format("15:04"),
|
||||
)
|
||||
cs.Active = status.On
|
||||
cs.ManualOverride = true
|
||||
cs.OverrideUntil = now.Add(overrideTimeout)
|
||||
cs.LowPowerCycles = 0
|
||||
if !status.On {
|
||||
cs.ActivatedAt = time.Time{}
|
||||
} else {
|
||||
cs.ActivatedAt = now
|
||||
}
|
||||
}
|
||||
} else if cs.ManualOverride && now.After(cs.OverrideUntil) {
|
||||
// Override expired and state matches — resume EMS control
|
||||
|
||||
Reference in New Issue
Block a user