ADR-0054: Tracked sensors — any numeric sensor chosen in Home Assistant, as a curve left of the clock and in a « Suivi » popup, pushed by tab5_maj_suivi¶
Status: Accepted (2026-10-10, asked for by the author; not tried on a tablet when written). Date: 2026-10-10
Context¶
The zone left of the clock shows a content chosen in the blueprint (ADR-0051): the voice controls, a chart of the coming hours or a compact music player. The author asked for a fourth one: the curve of a numeric sensor chosen in Home Assistant (his first use: share prices, but the tablet must not know that), « in the style of the weather chart », with its value and its change; and a full-screen popup listing every sensor he follows, opened by a tap on that card.
Constraints: push-only and events-only (ADR-0001, ADR-0025); no entity ID in the firmware or in the public HA files (ADR-0024); lv_chart and lv_canvas are not compiled; colours from the palette (ADR-0029).
Decision¶
- Generic, not « stocks ». The code and the screen say « Suivi » (tracking), « capteur » (sensor); no word about shares anywhere. Any sensor with
state_class: measurement(a share price, a temperature, a power, a level…). - Chosen in Home Assistant. A multiple-choice list « Tab5 · capteurs suivis · tracked sensors » (
select.tab5_capteurs_suivis,packages/tab5_reglages.yaml), built like « Tab5 · lecteurs de musique » (ADR-0050): « ✓ x » removes a sensor, « ○ x » adds it, six at most, order of choice, memoryinput_text.tab5_choix_suivis. Onlymeasurementsensors are offered: the others have no statistics, so no curve. Never guessed. - One new action, one compact payload.
tab5_maj_suivi(payload): one record per sensor,name|value|unit|change|kind|pointsseparated by;— name =friendly_name(40 characters; empty: the screen writes « Capteur », never an entity ID), value = the state as is when numeric (empty otherwise: « -- »), change + kind =change_pctandpwhen the entity gives it (a share's change of the day, shown with « Aujourd'hui »), otherwise the difference between the value and the first hour of the curve anda(shown in the sensor's unit, with « 24 h »), points = the 24 hourly means of the recorder's statistics then the current value, scaled 0–100 (50 for a flat curve, empty for an hour without a row). Read in pure C++ bysuivis_lire()(Tab5/socle/tab5_parse.*, section 11; cases intools/test_parse.cpp, called by the libFuzzer harness): at most 6 sensors and 32 points, values bounded, a record without at least a name and a value field skipped, more than 3 decimals rounded without trailing zeros, the sign and the arrow decided on the rounded change (never « -0.00 »). - Pushed by a new package, rate-limited.
packages/tab5_suivi.yaml:script.tab5_suivi_pousserreadsrecorder.get_statistics(periodhour, typemean, from the round hour minus 24 h in UTC: no daylight-saving trap) and calls the action. A mirror (« Tab5 · signature du suivi ») changes when a tracked sensor changes; an automation in modesinglepushes at once, waits five minutes (changes meanwhile are dropped silently) and pushes again only if the signature moved: a sensor that changes every second costs one push every five minutes at most. A second automation pushes at once when the list changes, when the tablet connects, on « MAJ Écran », at HA start and every hour (the curve moves on). Both are guarded like the other packages (tab5_origine,tab5_connectee). - The zone content « capteur ».
ZoneGauche::CAPTEUR, codecapteur, at the end of the enum (NVS keeps the index), in the blueprint's options and default cycle. A card with the chart's footprint and glass (zone_suivi,suivi_zone.yaml, 405 × 184 at x 20, y 42): the name top left (cut with « … »), the change top right (trend arrow and text inSUCCESSup,ERRORdown,TEXT_DIMflat), the value in the date's font with its unit, and the 24 h curve over the chart's gradient. The first sensor of the list is the one shown (the simplest rule; no scrolling of sensors in the card). Skipped by the tap and at start while Home Assistant says the list is empty (suivi_zone_disponible(), like the player). A tap opens the popup. - One gradient buffer for two cards. The chart and the sensor card are never shown together: they share the chart's 156 KiB PSRAM buffer through
zone_degrade_peindre()(tab5_zone_gauche.cpp), which hands it over and tells the previous owner (callback) that its picture is gone, so it repaints at its next appearance. No second buffer. - The « Suivi » popup. Full-screen modal with the shared chrome (ADR-0009), one
ModalRegistry::addline (ADR-0013),Ecran::SUIVI(option « Suivi » at the end of « Aller à l'écran », gesture codesuiviat the end ofkCodesGestes, index 26, iconchart-line). One card per sensor (suivi_carte.yaml, six instances), placed bytab5_suivi.cpp: one row up to three sensors, two rows above (two columns for four), the last row centred, inside the modal body (x 24–1226, y 72–670). Each card: name, value and unit, arrow + change + period, and the curve (ui_courbe_lisse(),lv_line, its last point ringed in the background colour). No sensor: « En attente de Home Assistant », or « Aucun capteur suivi » and where to choose them. - Painted only when needed. The popup at its opening and on each push while open; the zone card only while shown (
suivi_zone_montrer(), called byzone_gauche_appliquer()), otherwise marked dirty. Theme change:suivi_rejouer_theme().
Consequences¶
- Contract 1.2.0 (minor: one action added). Update order: firmware first, then
packages/tab5_reglages.yaml,packages/tab5_suivi.yamland the blueprint. New HA files with an older firmware: the push fails without stopping anything else (continue_on_error); new firmware with older HA files: the popup says « En attente de Home Assistant » and the zone card too (it is not skipped before a first push). - A curve is a trend, not a scale: 0 is the lowest of the 24 hours, 100 the highest, so a 0.1 % move looks as large as a 10 % one. The change and the value carry the size.
- A sensor without
state_class(not offered by the list, but a hand-written memory could name it) shows its value without a curve. - Four new screen texts in six languages; MDI glyphs
chart-line(26, 32, 70) andtrending-up/down/neutral(32). - Render: four captures (
suivi-vide,suivi,accueil-zone-capteur,accueil-zone-capteur-gelule).