Skip to content

fix(alerts): replace corte_red heuristic with differential clamp + battery confirmation - #15

Merged
gnacho merged 2 commits into
mainfrom
fix/helios-corte-red
Aug 9, 2026
Merged

gnacho merged 2 commits into
mainfrom
fix/helios-corte-red

Conversation

@gnacho

@gnacho gnacho commented Aug 9, 2026

Copy link
Copy Markdown
Owner

What

corte_red was firing on perfectly normal self-consumption: the old heuristic treated currentGridPower ≈ 0 as a proxy for "no grid", but that is just "not importing right now" — and a well-regulated Solis in self-consumption / peak-shaving holds grid flow at zero for minutes with the grid perfectly up. The audit log showed repeated false criticals every few minutes (8:37, 9:01, 9:07, 9:12, 9:32, 9:36, 9:42 on the day of the fix).

New signature

Replaces the "zero grid flow" guess with a differential signature based on the Tongou clamps on the main house board (already wired as ENTITIES.consRespaldo and ENTITIES.consNoRespaldada):

sinRed = fresco
  && gridMag < 0.05
  && noRespaldadaKw < 0.05         // circuito NO respaldado cae (sin red)
  && respaldoKw     > 0.03         // circuito RESPALDADO sigue (Solis+batería vía EPS)
  && live.batteryPower < -0.05     // batería DESCARGANDO (sin red, no se podría cargar)

In a real outage with the Solis EPS alive, the non-backed-up circuit drops to ~0 W while the backed-up circuit keeps running off the battery, and the battery must be discharging to sustain it. In a full blackout without EPS, both clamps go to 0 and this alert does not fire — inversor_offline covers that via anti-islanding.

Why the Fox is NOT used

The first version of this PR tried to use sensor.foxess_running_state (on-grid / off-grid) as the primary signal. Investigation against 8 months of recorder statistics showed it is unsafe: the 2025-07-12 incident had foxess_r_volt ≈ 0 V for ~20 hours while vivienda_medidor_power kept reading 200–1800 W the whole time. That was a foxess_modbus communication dropout, not a grid outage. Any signal based on the Fox can fire on Modbus/WiFi loss.

Battery-discharging clause (second commit)

The pure differential signature was still fragile: when the non-backed-up clamp itself drops to 0 W due to a Zigbee dropout, the signature looks identical to a real outage. Caught this on the first production run after deploying commit b2c177f — the clamp was stuck at 0 W with grid perfectly up (Fox on-grid, calentador_voltage 232 V, inverterOnline=1) and the battery charging from PV. Requiring the battery to be discharging filters this case: in a real outage with Solis EPS, the backed-up circuit is powered by the battery, so the battery cannot be charging.

Tests

server/test/push.test.js covers the new behavior matrix:

  • self-consumption with gridPower=0 and both clamps > 0 → does not fire
  • peak-shaving (battery discharging, gridPower=0, red present) → does not fire
  • Fox Modbus dropout (2025-07-12 incident shape) → does not fire
  • non-backed-up clamp Zigbee dropout + battery charging → does not fire
  • full blackout without EPS → does not fire (covered by inversor_offline)
  • real outage + EPS alive → fires after 3 ticks, recovers after 2

solar.computeLive now also exposes respaldoKw and noRespaldadaKw on the live snapshot.

Verified in production: 0 false criticals in the observed window after deploy, while the clamp was still in dropout. Closing #13.

gnacho added 2 commits August 9, 2026 09:46
…ature

The previous corte_red heuristic fired whenever currentGridPower was
near zero (gridMag < 0.02 kW) and the house was consuming. That
condition is normal in self-consumption, peak-shaving and cloud
transients — gridPower=0 with the grid perfectly up. It produced
false positives.

New signature uses the backed-up vs non-backed-up Tongou clamps on
the main house board (already wired as ENTITIES.consRespaldo and
consNoRespaldada): in a real outage with Solis EPS alive, the
non-backed-up circuit drops to ~0 W while the backed-up circuit
keeps running off the battery.

  sinRed = fresco && gridMag < 0.05
        && noRespaldadaKw < 0.05
        && respaldoKw     > 0.03

Fox signals (foxess_r_volt, running_state) are intentionally not used:
a Modbus/WiFi dropout of the Fox is indistinguishable from a real
outage (2025-07-12 incident: r_volt=0 for 20 h with the house
consuming 1.5 kW the whole time = comms dropout, not grid outage).

solar.computeLive now exposes respaldoKw and noRespaldadaKw on the
live snapshot. Tests cover the new behavior matrix: autoconsumption,
peak-shaving, Fox Modbus dropout, real outage + EPS, and full
blackout (covered by inversor_offline instead).

Refs #13
First production run surfaced a hole in the differential heuristic:
when the non-backed-up Tongou clamp (vivienda_medidor_power) drops to
0 W due to a Zigbee dropout (HA holding the last value), the signature
looks identical to a real outage and the engine fires a false
critical. Observed 9-Aug-2026: clamp stuck at 0 W with grid perfectly
up (Fox on-grid, calentador_voltage 232 V, inverterOnline=1) and the
battery charging from PV at +0.29 kW.

Add a hard confirmation: the battery must be DISCHARGING (<-0.05 kW).
In a real outage with Solis EPS alive, the backed-up circuit is
powered by the battery, so the battery cannot be charging. This drops
the dropout case (and any other pinza-anomaly scenario where the
backed-up circuit keeps running off the grid while the non-backed-up
reading goes weird).

Adds regression test for the exact scenario above.

Refs #13
@gnacho
gnacho merged commit f36405c into main Aug 9, 2026
4 checks passed
@gnacho
gnacho deleted the fix/helios-corte-red branch August 9, 2026 08:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant