ADR-0006: All non-trivial LVGL logic centralized in C++, never inline in sensor lambdas¶
Page en anglais
Cette page n'existe qu'en anglais.
Status: Accepted
Context¶
ESPHome lets you write arbitrary C++ lambdas directly inline in sensor:/text_sensor:/binary_sensor: YAML blocks. It's tempting to just call lv_obj_set_style_*/lv_label_set_text right there when a sensor updates — it's fewer files to jump between for a one-off change.
Decision¶
Sensors and services only read Home Assistant state and call a named function declared in tab5_custom.h / defined in tab5_custom.cpp. They never manipulate lv_obj_* directly, except for genuinely trivial 2-3 line cases (e.g. picking an icon color inline) that were judged not worth extracting.
Consequences¶
- All non-trivial LVGL state logic is greppable and testable in one place (
tab5_custom.cpp, ~520 lines when this ADR was written — 2 900+ by 2026-09, which is why the 2026-09-06 audit recommends splitting it into several compilation units, the way the games already are) instead of scattered acrosstab5-sensors.yaml,tab5-api-logic.yaml, and 16ui_components/*.yamlfiles. - Every new "sensor reacts to X" feature requires touching two files (the YAML trigger + the C++ handler) instead of one — a small ongoing tax, accepted for the searchability/testability gain.
- This is enforced as code rule 2 in
Tab5/README.mdand checked by theesphome compile+ manual review gate in the PR template, not by an automated lint — a lambda that violates this will still compile. - Update 2026-09-08 (audit lot (e)):
tab5_custom.cppis split into nine units (tab5_text/forecast/central/services/assist/cards/console/anim/calendar.cpp, 164 to 741 lines each);tab5_custom.hstays the single public header, so the rule reads exactly as before — call a function declared there.tab5_internal.hholds the six helpers shared between units. - Update 2026-09-08: for the HA contract it is now linted.
tools/check_tab5_code_rules.py(run bypytest, so by CI) fails on anylv_*call intab5-api-logic.yamlother than the read-onlylv_obj_has_flag, on any rawsprintfanywhere inTab5/, and on anyglobals:entry nobody references. The last inline LVGL blocks of the contract (shutter, Météo-France vigilance, 1 h rain bars, snow icon, climate target, assistant image hint) moved totab5_custom.cppthat day.