Skip to content

ADR-0055: Fridges and freezers — levels decided by Home Assistant against food-safety norms, a « Froid » popup, central-card alerts and a blinking icon on the clock, pushed by tab5_maj_froid

Status: Accepted (2026-10-10, asked for by the author; not tried on a tablet when written). Date: 2026-10-10

Context

The author wants to watch his fridge and freezer from the tablet: declare them in the settings, check their temperature against the norms, catch a rise (a door left ajar), see the last 24 hours, get the usual alerts of the central card, and — for a serious problem only — an icon that blinks in the clock's top-right corner. A full-screen popup gathers the curves and the incidents.

Constraints: push-only and events-only (ADR-0001, ADR-0025); no entity ID in the firmware or in the public HA files (ADR-0024); colours from the palette (ADR-0029); lv_chart is not compiled; instant transitions, no fade (author's taste).

Decision

  • Declared in Home Assistant, never guessed. Two multiple-choice lists built like « Tab5 · capteurs suivis » (ADR-0054): « Tab5 · réfrigérateurs · fridges » (select.tab5_refrigerateurs) and « Tab5 · congélateurs · freezers » (select.tab5_congelateurs), memories input_text.tab5_choix_frigos / tab5_choix_congelateurs. Only temperature sensors with statistics are offered (device_class: temperature, state_class: measurement); a sensor chosen in one list is not offered in the other; four appliances at most in all (the popup's four cards). Empty lists work: the popup says where to declare them.
  • Home Assistant decides, the tablet shows. packages/tab5_froid.yaml computes, for each appliance, a level (0 within norm, 1 attention, 2 serious), a cause (ok, chaud, froid, porte, indispo) and since when, from the current value and recorder.get_statistics (5-minute statistics for the last 30 minutes, hourly ones for the curve and the 24-hour extremes). The thresholds are in one place, the seuils variable of script.tab5_froid_calculer, commented:
  • fridge: norm 0 to 5 °C; attention when the 15-minute mean is above 5 or below 0; serious above 8 for 30 minutes, or at 10 or more;
  • freezer: norm -18 °C at most; attention when the 15-minute mean is above -15; serious above -12 for 30 minutes, or at -10 or more;
  • door: a rise of 2 °C (fridge) / 4 °C (freezer) between the lowest of the last 30 minutes and now is « porte ouverte ? » (attention); still there after 20 minutes and not going down (no more than 0.5 °C under the episode's highest) it is « porte mal fermée » (serious). The « not going down » guard is ours: a door closed after a long opening cools down slowly and must not end as « mal fermée »;
  • no reading for 30 minutes: « capteur muet » (attention); shorter gaps keep the previous state. A Fahrenheit sensor is converted. The rules are applied in that order (first true wins) and mirrored by an independent Python calculation in tests/test_froid.py.
  • State kept in Home Assistant, not in the tablet. A trigger-based template sensor sensor.tab5_froid (state = the most serious level, attribute appareils, restored at restart) is updated only by the tab5_froid_bilan event that the script fires; the script reads its previous attributes (when a cause started, the running incident, the last finished one). An incident runs from the first non-zero level to the return to 0; the last finished one (most serious cause, start, duration, extreme) stays with the appliance.
  • When. A mirror (« Tab5 · signature du froid ») changes when a sensor changes: an automation in mode single computes at once, waits one minute (changes meanwhile are dropped) and computes again if the signature moved. A second automation computes every five minutes (durations move on without a change), when a list changes, when the tablet connects, on « MAJ Écran » and at HA start (tab5_origine guard). The state is kept even when the tablet is away; the push needs tab5_connectee.
  • One new action, one compact payload. tab5_maj_froid(payload): one record per appliance, fifteen | fields — name|type|value|level|cause|since|min|max|low|high|points|icause|istart|iduration|imax — temperatures in °C with one decimal (empty: unknown; empty low: no lower limit), the norm pushed by HA (the tablet hard-codes none), 24 hourly means then the current value. Read in pure C++ by froid_lire() (Tab5/socle/tab5_parse.*, section 12; cases in tools/test_parse.cpp, called by the libFuzzer harness and fuzzed with the other services): four appliances, 32 points, temperatures bounded to ±80 °C, an unknown type skips the record, a level above 2 is 2.
  • Alerts of the central card. A source « froid » in custom_templates/tab5_alertes.jinja: one stable id per appliance (froid:<entity_id>), revision key = cause and level (a value that changes only updates the text), Orange at level 1, Red at level 2, coded text @froid:<cause>:<level>:<value>:<name> composed by the tablet in its language (ha_alerte_texte(): « Frigo cuisine : porte mal fermée, 9.1 °C »). Subscription: « Tab5 · alertes : réfrigérateurs et congélateurs » (Oui / Non). Doubt (sensor.tab5_froid unavailable) is never an end.
  • The blinking icon. fridge-alert (F11B1, mdi_font_26, role ERROR) in the clock tile's top-right corner (btn_froid_alerte, the 27 px left of the minutes' frame), shown only while an appliance is at level 2. It blinks without fade: one lv_timer of 500 ms created once, paused while the icon is hidden; it stays lit while the Froid popup is open. No acknowledgement: it stays as long as the serious level lasts. A tap opens the popup through tab5_ecran_ouvrir. It follows the theme (role style).
  • The « Froid » popup. Full-screen modal with the shared chrome (ADR-0009), one ModalRegistry::add line (ADR-0013, 26 of 32), Ecran::FROID (option « Froid » at the end of « Aller à l'écran », gesture code froid at the end of kCodesGestes, index 27, offered by the blueprint), and in the navigation wheel (ADR-0042) at the end of Agenda — Devices (8 of 8) and the first ring (6 of 6) are full; offered unless Home Assistant said no appliance is declared. Its title is « Frigos et congélateurs » and its wheel word « Frigos »: the key « Froid » already translates as « Cool » (a climate mode, a lamp's white). One card per appliance (froid_carte.yaml, four instances), one row for one or two, two rows of two above: icon (fridge or snowflake), name, temperature coloured by level (SUCCESS / WARNING / ERROR), status (« Conforme », « Trop chaud depuis 14 h 32 », « Porte mal fermée »…), 24-hour extremes and the norm, the 24-hour curve (ui_courbe_lisse()) between the dashed lines of the norm, and the last incident.

Consequences

  • Contract stays 1.2.0: one action added since the last release (v3.8.0-rc.4, contract 1.1.0), already a minor step. Update order: firmware first, then packages/tab5_reglages.yaml, packages/tab5_froid.yaml, packages/tab5_alerts.yaml, custom_templates/tab5_alertes.jinja and the blueprint. New HA files with an older firmware: the push fails without stopping anything else (continue_on_error), and the alert text shows raw (@froid:…) until the firmware is updated; new firmware with older HA files: the popup says « En attente de Home Assistant ».
  • The 5-minute statistics are compiled after their period ends: the current value always joins the 15-minute mean and the 30-minute minimum, so a rise is seen at once.
  • A door opened for shopping can raise « porte ouverte ? » (attention, Orange) for a few minutes: that is the requested threshold. It becomes serious only if the rise lasts 20 minutes without cooling down.
  • 37 new screen texts in six languages; MDI glyphs fridge (F0290: 26, 32, 36, 45, 70) and fridge-alert (F11B1: 26).
  • Render: three captures (froid-vide, froid, and accueil-froid, not compared: the icon blinks).