Skip to content

Debugging this device

This is a short methodology note, not an incident log — see docs/troubleshooting.md for already-diagnosed symptoms. Read that one first; only reach for the techniques below if the symptom isn't already documented there.

Where to look

  • Live ESPHome logs (python tools/tab5_logs.py --host <ip> --config-ha <HA config folder> since 3.0, which reads the API key Home Assistant keeps; esphome logs no longer finds a key in the YAML) — the primary source of truth for boot sequence issues, API connection state, and any ESP_LOG* line in the C++ code. Close the session when you're done; a leaked log process holds an API connection open indefinitely (see the "API connections exhausted" entry in troubleshooting.md).
  • The on-screen system console (console_sys.yaml, the System page of the settings popup since 2026-10-08, opened directly by a long press on the gear button btn_control_console, top right — a tap opens the settings on their Screen page; not by swipe since the 14/07/2026 rework) — 4 glass cards: MÉMOIRE (SRAM/PSRAM, max free block, flash), RÉSEAU (SSID/IP/signal + HA connection status), SYSTÈME (uptime, CPU temperature, CPU load of each core, loop time, the tablet's battery, volume) and GESTION (screen re-push = the full push automation run again, automation reload, HA restart and device reboot — the last two behind a confirm overlay, 16/07/2026 redesign). It is not a log viewer — for payload/event logs use tools/tab5_logs.py. Useful when you don't have a laptop connected but can see the screen.

Console overlay on the real device

  • Home Assistant's own logs for anything upstream of the device — automation trigger/condition evaluation, template rendering errors, service call rejections.

Seeing the screen without the tablet

The CI job « Rendu hors tablette » (.github/workflows/rendu-host.yml, ADR-0021) compiles the interface for ESPHome's host platform (tab5-rendu-host.yaml), runs it on the runner, pushes the demo scenes, then opens the ~80 screens of tools/rendu/ecrans.py one by one (popups, sub-windows, Arcade, game menus and games) with a virtual finger, as on the panel. One picture per screen, in the seven languages (one job per language). On a pull request that touches the screen, it says which screens changed compared with main and attaches before/after images (artifact rendu-captures, folder diff/). It does not block the PR. Two tasks do fail on a difference: « clair » and « galerie » (every theme, both modes) compare a live theme switch with a cold start, to the pixel.

  • A change on purpose: nothing to do for the screens, main becomes the reference once the PR is merged. For the gallery scenes of screens.md: python tools/rendu/maj_references.py --run <run id> replaces docs/images/rendu/; review the images, then commit.
  • A new screen: an entry in tools/rendu/ecrans.py (taps at the captures' coordinates, landscape 1280×720). « identique à … » in the run means a tap missed.
  • Tuning one screen: Actions → Rendu hors tablette → Run workflow, fields « seulement » (screen names) and « langues » (e.g. ["de"]).
  • It runs on Linux or macOS only (the host platform): on Windows, use the CI (Actions → Rendu hors tablette → Run workflow).
  • It shows the layout, not the device: no touch, no sound, no voice assistant, no timings or memory.

Marking a spot for later, in code

Use the [AI-DEBUG] tag (see Tab5/README.md) in a comment when you find a good observation point while investigating something, even if you don't fix the underlying issue in the same session — it saves the next debugging pass (human or AI) from re-finding the same vantage point.

After a crash or a Wi-Fi outage: the boot and outage journal

Since 2026-09-26 the device keeps its own journal (Tab5/ecran/tab5_journal.cpp), so a crash or a failure of the Wi-Fi co-processor link (ESP32-C6) can be analysed after the fact, without a USB cable plugged in at the time:

  • What is kept: every error (ESPHome's and ESP-IDF's, including the ESP-Hosted driver of the C6, tag esp-idf), plus the warnings logged while Home Assistant is not connected (boot before HA, Wi-Fi down). A line repeated in a row is counted, not duplicated. ESPHome's own crash report (tag esp32.crash: PC, fault address and backtrace of both cores) is written by the logger before the journal's on_message hook exists, so it never reached the journal on its own; since 2026-10-06 the journal reads it (esp32::crash_handler_has_data()), replays it into its lines when the reset reason is a crash, and clears it once the journal has reached HA (as ESPHome does after a log subscription).
  • ESP-IDF warnings are not in the firmware: ESPHome builds ESP-IDF with its log level at ERROR by default (esp32: framework: log_level, hence CONFIG_LOG_MAXIMUM_LEVEL=1), so the ESP_LOGW and ESP_LOGI lines of ESP-IDF and ESP-Hosted are removed at compile time: they show neither in the journal nor on the serial port. One of them is ESP-Hosted's version check of the C6 (see Hardware). The absence of such a warning therefore proves nothing. Errors stay, including an ESP-Hosted RPC timeout (Response not received for …, or Error reported: Response Timeout for an asynchronous request). Seeing the warnings would take a test build with log_level: WARN under esp32: framework: (not tried). Found while answering discussion #369.
  • Where: 32 lines in .noinit RAM, which survives software resets, crashes, watchdogs and a reset through USB, but not a power cut. Once Wi-Fi has been missing for 90 s, a copy goes to NVS (at most every 15 min, only when something new was logged) and is read back at the next boot if RAM was lost.
  • How it reaches you: at each HA connection, the esphome.tab5_journal event is sent for an abnormal reset or a crash report, Wi-Fi missing for 90 s or more, a boot that never reached HA, an error after HA connected, or HA reached more than 90 s after boot. Lines logged before the first HA connection are context only (the ESP-Hosted link is legitimately "not yet up" once on every boot, 7 to 12 s after it): a normal boot sends nothing. Guard (e) of HomeAssistant_Config/packages/tab5_health.yaml turns it into a persistent notification (and a phone push when grave: abnormal reset, crash, or Wi-Fi missing 90 s). Events stay in the recorder's events table.
  • Reset reason of every boot: the Tab5 Raison du redémarrage entity (Software Reset, Exception, Task Watchdog, Brownout, Power On…), one row per boot in the HA history.
  • Timeline of every boot (next version): the Tab5 Chronologie du démarrage and Tab5 Chronologie du démarrage (suite) entities, the time in ms of each step, from the C++ constructors to the end of setup() (priority bands, on_boot sequence) then after it (backlight, first frame, Wi-Fi, API, battery charger) — how to read them in performance.
  • Reliability beyond the recorder's few days (since 2026-10-09): the HA history keeps states for a few days only, and neither Tab5 Uptime (a timestamp) nor the reset reason (a text) has statistics. packages/tab5_health.yaml adds three sensors with a state_class, whose long-term statistics HA keeps with no time limit: « Tab5 · redémarrages » (every restart the unexpected-reboot guard recognizes, requested or not), « Tab5 · redémarrages inattendus » (the ones that guard notifies) and « Tab5 · fonctionnement continu » (hours since the last boot, every 15 min; a day's maximum is its longest run without a restart). Read them in Developer tools → Statistics, or with a « Statistics graph » card (change over a week or a month for the counters, maximum for the run time). A Wi-Fi drop without a reboot, a HA restart or the tablet's arrival in HA do not count.
  • Watchdog reset with no crash report = the power button (since 2026-10-06): a short press on the power button reboots the tablet with ESP_RST_WDT and no esp32.crash report. The journal calls it « bouton d'alimentation ou chien de garde RTC (rst 0x..) » and sends nothing; the entity shows Power button or RTC watchdog (rst 0x..) instead of ESPHome's text, which for this reason repeats the source of the last requested reboot (Reboot request from esphome.ota: ESPHome never clears it). rst 0x.. is the ROM's own reset code (esp_rom_get_reset_reason(0); on the ESP32-P4, ESP_RST_WDT covers 0x07 and 0x0B, timer-group watchdogs, 0x09, 0x0D and 0x10, RTC watchdog, 0x12, super watchdog). The same reason with a crash report is still a crash and still alerts (Crash, other watchdogs (rst 0x..)). What no longer alerts: a boot stuck for more than 9 s (the bootloader's RTC watchdog) and a timer-group watchdog that resets without reaching the panic handler; both stay visible in the entity's history. Reasoning and sources in the [AI-WARNING] of Tab5/ecran/tab5_journal.cpp.
  • Decoding a backtrace: the addresses belong to the build that crashed. For a local build, keep its ELF (H:/.esphome_data/build/tab5-ha-hmi/build/tab5-ha-hmi.elf, compare config_hash); for a published one, take the elf-<revision> artifact of its « Publication » run (kept 90 days), or rebuild it with Run workflow, tag and elf_seulement (the run checks that the code is the published one). Then riscv32-esp-elf-addr2line -pfiaC -e <elf> <addresses>, or tools/capture_serie.py --relire … --elf …. If the report says captured by a different firmware build, use that build's ELF.
  • Not done on purpose: an ESP-IDF core dump to flash. It needs a coredump partition, the current table (partitions.csv: 2 × 7.75 MB apps + 448 KB NVS) fills the 16 MB, and a partition table change is only written by a USB flash, never by OTA. The journal covers the C6 case, which is not a crash of the P4.

Capturing a crash on the serial port

When the journal says « crash (exception) » with no report (first seen at the end of an update from HA, 3.0.0-rc.1 → rc.2, 2026-09-27), the panic output of ESP-IDF went to the only place it is written: the USB console (CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG), just before the reboot.

  1. Tablet plugged into the PC over USB-C. python tools/capture_serie.py lists the Espressif devices and refuses to guess: pass --mac (the tablet's MAC is its USB serial number) or --port.
  2. python tools/capture_serie.py --mac <MAC>: listens up to 10 min without resetting the tablet (DTR and RTS off before opening), writes capture-serie-<date>.log as it goes, and stops 60 s after a reboot.
  3. Trigger the event (for example Install on the « Firmware » entity in HA).
  4. Read the summary: panic block, reboots, ESPHome's crash report, addresses. Decode with the ELF of the firmware that crashed (the one before the update): python tools/capture_serie.py --relire capture-serie-….log --elf tab5-ha-hmi-st7123.elf.

Never open another Espressif device plugged into the same PC. Closing the ESP Web Tools window (Chrome) restarts the tablet once.

Diagnosing a silent automation failure on the Home Assistant side

If a Home Assistant automation appears to do nothing — no error, no expected result — and you suspect a step is failing validation or a condition is silently false, insert a debug marker directly into the real automation rather than trying to reproduce its logic in a separate, isolated test script.

Concretely: add a input_text.set_value (or similar low-cost, visible side effect) call as an extra step at the point you want to check, using the real automation, the real trigger, the real entity states — then trigger it for real and read the value back.

This matters because a from-scratch reproduction script can differ from the real automation in a way that's exactly the bug — different Jinja context, different entity availability at trigger time, a condition that only fails on a subset of runs. A reproduction that "works" in isolation tells you nothing about why the real one doesn't; it just wastes a debugging cycle. This is exactly how the now()-without-strftime calendar bug (see troubleshooting.md) was found: the isolated repro would have needed to guess the exact template context, while the marker-in-the-real-automation approach surfaced the failing step immediately.

Remove or comment out the marker once the real fix is confirmed — don't leave debug-only automation steps live in production without a reason.