Distinguish active export from freeze export in the web header icon - #5131
springfall2008 wants to merge 1 commit into
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Automated comment from the triage bot. — Code review of PR #5131 (diff What was verified:
Findings (all low severity):
Run notes: all finder angles completed (several after the review compiled); every angle was also executed and verified directly. The one candidate claiming the new assertion fails for "Hold exporting" scenarios was checked against the test code and refuted (case-sensitive substring). No flipped config defaults, no setup/teardown asymmetry, no dropped guards in moved code. Test execution was not possible in this session (permissions), so verification is static; run |
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Mixed-inverter precedence is not covered by a regression test.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (1)
What changed in this PR
Updates the web header to distinguish active and freeze exports using status attributes, colour classes, and tooltips.
Changes:
- Publishes
export_statusfrom execution state. - Adds coloured active/freeze export icons with dark-mode styling.
- Adds documentation and tests.
| File | Description |
|---|---|
apps/predbat/const.py |
Defines export status constants. |
apps/predbat/execute.py |
Tracks export mode and publishes precedence. |
apps/predbat/output.py |
Adds the sensor attribute. |
apps/predbat/web.py |
Applies status-specific icon classes and tooltips. |
apps/predbat/web_helper.py |
Adds light/dark CSS rules. |
apps/predbat/tests/test_execute.py |
Tests published statuses. |
apps/predbat/tests/test_web_functions.py |
Tests rendering and CSS. |
docs/output-data.md |
Documents the new attribute. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if exporting_to_target: | ||
| export_status = EXPORT_STATUS_TARGET | ||
| elif exporting_freeze: | ||
| export_status = EXPORT_STATUS_FREEZE |

This is an automated draft PR generated from issue #5125 — a maintainer should review it before merging.
Fixes #5125
Summary
The export icon next to the SoC in the web header was appended whenever
binary_sensor.predbat_exportingwas on, with nothing to say which kind of export was running, so a freeze export (solar surplus only) looked identical to an active export discharging stored capacity.execute_plan()now tracks which of the two export branches actually fired andset_charge_export_status()publishes it as anexport_statusattribute on the exporting binary sensor (target/freeze/none).get_battery_status_icon()reads that attribute and tags the icon with anexport-activeorexport-freezeclass plus an explanatorytitle, andget_header_html()defines those classes green/amber with light- and dark-mode variants. An install that has not published the attribute (or an unrecognised value) keeps the original uncoloured icon.Per the triage note, battery power is not used to tell the two apart — during a freeze export the battery can still discharge to cover house load, which would mislabel freeze as active. The signal is the plan's own branch. Where inverters disagree, active export wins, matching the existing
EXPORT_STATE_PRECEDENCEused for the headline status.Testing
cd coverage && ./run_pre_commit— all 14 hooks pass, and the quick suite it runs passes (All tests passed (4 slow tests skipped)).Red/green on the two affected modules, with only the source changes stashed:
tools/triage_test.sh web_functions— fails without the fix (expected export-active class for active export, got: ...mdi-transmission-tower-export...for both modes, i.e. the reported symptom, plus the four missing CSS rules), passes with it.tools/triage_test.sh execute— fails without the fix (ERROR: export_status should be none for status 'Demand' got None, the attribute not being published at all), passes with it, including all 25Exporting/Freeze exportingscenarios now asserting the right value.The
executered run stops at the first failing scenario, so its red output only shows the "attribute absent" failures rather than a target-vs-freeze mismatch; theweb_functionsred run is the one that demonstrates the two modes rendering identically.Notes
impact, upstream):get_battery_status_iconandget_header_htmlare both CRITICAL — every page header calls them — andexecute_planis HIGH. All three changes are additive: two new locals and one defaulted keyword argument inexecute_plan, an extra class/titleon an existing<span>, and four new CSS rules. No existing output changes when the attribute is absent.set_charge_export_statusreported LOW (0 callers — the indexer misses theexecute.py:802call site; the new argument is defaulted so the old signature stays valid either way).export_status, notexport_mode, deliberately:EXPORT_MODE_TARGET/_FREEZEalready exist as integer window modes (what the planner chose), which is a different thing from what the inverters were actually told to do this cycle. One name is used end to end — constant, argument, attribute, docs.titletooltip naming the mode. The issue's fallback suggestion of an "A"/"F" letter prefix was not added, to keep the header compact — easy to add if you would prefer it.