ADR-0028: An Energy popup for a solar installation — sensors picked in the blueprint, live values and production history pushed by HA while the popup is open¶
Status: Accepted (2026-10-04, option B chosen by the author; not yet tried on a tablet nor with a real solar installation) Date: 2026-10-04
Context¶
A user asked for his solar installation on the screen (discussion #278): what the panels produce, what the home uses, what goes to or comes from the grid, the battery, and the production over time. Until now a solar sensor could only sit in a room as a read-only cap tile (ADR-0023): one number, no history.
Three ways were weighed with the author:
- A — more tile types: a « solar » tile showing two or three numbers. No history, and the five-card room layout has no room for a flow.
- B — a popup opened from a tile, with the live values on top and the production as bars below (hours, days, months). Chosen.
- C — a dedicated page in the swipe carousel. Heavier (a page of its own in
tab5-lvgl.yaml, its own idle and wake rules) for a feature most homes do not have.
Constraints that hold: push-only and events-only (ADR-0001, ADR-0025) — the firmware names no entity and calls no HA action; one shared modal chrome (ADR-0009); one registry of modals (ADR-0013); no hardcoded colour (tokens); public HA files without a real entity or placeholder (ADR-0024); the screen in seven languages.
Decision¶
- The sensors are picked in the blueprint « Tab5 — emplacements », in an optional, collapsed section « Énergie · Energy » (split on 2026-10-07 into « Énergie : solaire », « Énergie : réseau et maison » and « Énergie : batterie », same input keys): solar power, solar energy produced (kWh, with statistics), grid power (+ import), grid export power (optional, for meters that give it apart: grid = import − export), home consumption (optional: computed as solar + grid − battery charge, never below 0), battery level, battery power (+ charge), battery temperature, and two « Invert » booleans (grid, battery). Left empty, nothing changes on the screen.
- Entry points. A
captile whose entity is one of these sensors gets the new tile optione: it shows its value withenergie_formater()(W / kW, kWh / MWh) and opens the popup on tap. The solar sensor gets the new palette iconsolaireby default. « Aller à l'écran → Énergie » (HA select) opens it too. An older firmware ignores the unknown lettere(ADR-0023 parsing) and keeps a read-only tile. - Popup (
ui_components/energie_popup.yaml,tab5_energie.cpp, registered as « Énergie »): the shared chrome, then up to four cards (Solar, Home, Grid, Battery; a card whose sensors are all empty is hidden, the others spread over the width), and below, the chart: title « period · total », three view buttons (Hours, Days, Months) and the bars drawn in C++ (gold, the current slot in the accent colour, a reference line at the maximum). Without the produced-energy sensor, the cards alone fill the popup. Instant transitions; MDI glyphs declared inmdi_font_45(rule 9). - Request and answer. The popup sends
esphome.tab5_energiewithvue(heures,jours,mois) when it opens and on each view button. The blueprint answers: - no sensor picked:
tab5_maj_energiewith an empty payload (|||||||) — the popup says « Aucun capteur d'énergie choisi »; - otherwise, if
script.tab5_energieexists (packagepackages/tab5_energie.yaml):script.turn_onwith the tablet's device, the view and the sensors. Without the package, nothing: the popup keeps « En attente de Home Assistant ». - Two new firmware actions.
tab5_maj_energie(payload):solar|home|grid|battery %|battery W|temperature|unit|day(W, kWh; empty field = not picked,nan= picked without a value).tab5_maj_energie_historique(vue, debut, valeurs): the view's production in kWh,;-separated (24 hours, 30 days or 12 months; empty = no data),debut= local date of the first slot. Every caller (blueprint, package, demo, off-device render, docs) is updated with them. - History from the recorder's statistics (
recorder.get_statistics, no new helper, no extra database write): the day = sum of the 5-minutechangesince local midnight + the part since the last 5-minute row (current state − laststate); hours = the same rows by local hour; days = perioddayover 30 days, today replaced by the day; months = periodmonthover 12 months, the current month completed by the 5-minute rows of the current hour and the partial part (just after the hour, the last full hour can miss a few minutes until the recorder compiles it). The energy sensor must have statistics (state_classtotal_increasingortotal, as the HA Energy dashboard requires). - Refresh while open. The script (
mode: restart) pushes the history of the view asked for, then the live values again at each change of a picked sensor (at most every 5 s, at least every minute), the hour bars with them, as long as the tablet's own « Écran courant » sensor says « Énergie » — after a 12 s grace, since that sensor lags by up to 5 s — and for 15 minutes at most. HA pushes nothing while the popup is closed.
Compatibility¶
- New blueprint, older firmware: the
eoption is ignored (read-only tile);esphome.tab5_energieis never sent, so the new branch never runs; the empty-section case sends nothing. - New firmware, older blueprint: no tile gets
e; « Aller à l'écran → Énergie » opens a popup that waits (« En attente de Home Assistant »). - Without the package
tab5_energie.yaml: same waiting popup; the blueprint checksscript.tab5_energieexists before calling it. - Section left empty: no tile changes, no icon changes, nothing pushed except the empty answer when the popup is opened by « Aller à l'écran ».
Consequences¶
- One more popup, package, C++ unit (
tab5_energie.cpp) and two actions; 21 actions in the contract. The demo pushes a solar home (room « Bureau », tile « Solaire ») and the off-device render captures the popup in its three views. - Sign conventions are the user's to set (two « Invert » boxes, or two grid sensors); the project does not guess an integration's convention.
- With two tablets opening the popup at the same time, the last request wins (
mode: restart); the other keeps its last values until its next request. - The popup closes itself after the usual idle time, which ends the script's loop at the next check.
tests/test_energie.pychecks the payloads on both sides, renders the package's templates on simulatedget_statisticsanswers against an independent Python computation, and checks the blueprint (empty section = nothing, filled = optioneand iconsolaire).- Not verified on a real HA:
script.turn_onrestarting amode: restartscript, and the templates against real statistics (only the HA source and simulated answers were read).
Amendment (2026-10-04): solar production in the status strip¶
Axel asked for the solar production, as a share of the panels' maximum, among the status icons (top left). This is the one value the blueprint pushes while the popup is closed; « HA pushes nothing while the popup is closed » above still holds for the popup's live values.
- A key, not an action. The blueprint sends
solaire|<percent>;through the existingtab5_maj_emplacements. An older firmware ignores an unknown key, while an action it lacks stops HA's script (same reason asclimr, ADR-0026, andcrRT/ceRT, ADR-0027). The contract keeps 21 actions. - The peak is a blueprint input (
energie_crete, kWp, number, default 0 = no icon) in the « Énergie · Energy » section (« Énergie : solaire » since 2026-10-07), beside the solar power sensor it divides: a constant of the installation, not an entity, so not a « Tab5 · … » list (ADR-0024 lists pick entities). Percent = power (W, kW or MW read from the sensor's unit) / peak, rounded, clamped 0–100;nanwithout sensor, peak or numeric state, and the icon hides. - Rate. With every full push (connection, reload, « MAJ Écran », HA start), then with the slow measurements every 5 minutes when the sensor changed since the previous pass: at most 12 pushes per sunny hour, none at night (sensor frozen at 0), riding a pass that runs anyway. Not on each change (an inverter publishes every 5 to 30 s) and no filter on the colour tier, which would need the last value sent kept in a helper.
- Screen. Colour of
get_battery_color()(the phone's and the tablet battery's scale); grey at 0 %. Thesolar-panelglyph at every level: the sun over the panel (solar-power, thensolar-power-variant) broke into pieces at 26 px in 1 bpp (captures compared on 2026-10-04), so the colour alone carries the production. Placed before the tablet battery, which stays last.tests/test_solaire.py.
Amendment (2026-10-05): several solar sources¶
The user who asked for the popup has several inverters or panel strings (« pv1 + pv2 + … », discussion #278): one power sensor and one energy meter each.
- Two new list inputs, not
multiple: trueon the old ones.energie_solaire_autres(power) andenergie_production_autres(energy) take the other sources;energie_solaireandenergie_productionstay single. An automation created before holds a string in those two fields, and Home Assistant's editor does not convert a string when a selector becomes a list (ha-selector-entityconverts only when the selector changes under it;ha-entities-pickerthen callsvalue.map, frontend source read on 2026-10-05): the field would no longer show. HA itself does not check blueprint inputs against their selectors (BlueprintInputs.validate), so the templates still accept a string, a list or nothing in all four fields. - Sums. Solar power = the sum of the sources that have a value, each converted to W from its unit; an inverter « unavailable » at night is skipped; none with a value =
nan, as with one source. It feeds the live card, the computed home consumption and the status-strip percentage (energie_creteis then the peak of all the panels). Energy = the sum of the meters' statistics, period by period (5 minutes, day, month; the recorder converts each to kWh); a meter with no row for a period counts as 0 there and does not hide the bar; the part since the last 5-minute row is computed meter by meter. - What the script receives. The blueprint still sends
solaireandproduction(the first source), and adds the listssolairesandproductions. An oldertab5_energiepackage reads the first source only, without error; the new one reads the union of both. The firmware and thetab5_maj_energiecontract do not change: they already carry one solar value and one day total. - Tiles. A
captile of any of these sensors gets optioneand, for a power sensor, thesolaireicon; it still shows its own sensor's value, not the sum. tests/test_energie.pyandtests/test_solaire.py: W + kW added, one or all unavailable, kWh + Wh meters added per hour, day and month with gaps, the old single-string format giving the same values as before (also rendered against the previous templates).