SAFETY-118: read the peak forecast in its own unit
checks / unit (pull_request) Successful in 40m20s
infra-pin / fresh (pull_request) Successful in 1s

peak_forecast_entity is read through pv.watts() by its unit_of_measurement;
the abs(raw) < 50 size rule is gone. No unit or a non-power unit means the
forecast is not used, with one warning per cause. The validator no longer
claims a kW sensor is taken as watts for this entity.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
glenn schrooyen
2026-10-16 16:00:34 +02:00
co-authored by Claude
parent 780c1f67bb
commit f0b4e68e49
11 changed files with 415 additions and 16 deletions
+21
View File
@@ -788,6 +788,25 @@ def row_no_peak_forecast() -> str:
"the peak limit")
def peak_forecast_unit(unit, lang="en") -> str:
"""SAFETY-118. The 15-minute demand forecast has a number but no power
unit, so it is not used. `unit` is "" for none. One sentence, for the log
line, the status row and the settings page. Log lines stay English."""
if lang == "nl":
return ("De kwartierprognose heeft geen eenheid, dus ze wordt niet "
"gebruikt." if not unit else
"De kwartierprognose heeft geen vermogenseenheid, dus ze "
"wordt niet gebruikt.")
return ("The 15-minute demand forecast has no unit, so it is not used."
if not unit else
"The 15-minute demand forecast is not in a power unit, so it is "
"not used.")
def row_peak_forecast_unit(unit) -> str:
return peak_forecast_unit(unit)
def row_peak_guard_waiting() -> str:
return "Peak guard: no decision yet, control has not run"
@@ -1229,6 +1248,8 @@ def status_samples() -> list:
("row_no_estop", AMBER, row_no_estop()),
("row_estop_fitted", GREEN, row_estop_fitted()),
("row_no_peak_forecast", AMBER, row_no_peak_forecast()),
("row_peak_forecast_unit", AMBER, row_peak_forecast_unit("")),
("row_peak_forecast_unit", AMBER, row_peak_forecast_unit("kWh")),
("row_peak_guard_waiting", AMBER, row_peak_guard_waiting()),
("row_pv", GREEN, row_pv(3200, 2)),
("row_pv", GREEN, row_pv(1800, 1, True)),