Three bugs and two UX defects found on review, plus hardening:
- The control loop fed the task watchdog then slept exactly the watchdog
period (both 10s), tripping the TWDT fractionally late on every single
iteration. Sleep is now sliced 1s with a reset per slice. Also set
CONFIG_ESP_TASK_WDT_PANIC=y - the sdkconfig comment claimed a hung task
panics the chip, but nothing actually made that true.
- The LVGL flush called draw_bitmap (which only queues the framebuffer
switch) and released LVGL immediately, letting it render the next frame
into the buffer still being scanned out - the exact PRD 8.2 race the
double-buffer design exists to prevent. display_present_frame() now
blocks on a vsync handshake until the swap has latched.
- WiFi reconnect slept up to 30s inside the system event handler, stalling
all queued WiFi/IP events. Moved to an esp_timer.
- The setpoint label, arc, and mode/room lines rendered the control loop's
copy of state, which refreshes every 10s - every knob detent looked dead
for up to 10 seconds. The UI now reads settings live; when the fallback
ladder clamps the setpoint it shows both values. Room-select focus now
shows which room is being selected.
- z2m ISO_8601_local timestamps carry a UTC offset the parser ignored,
which would shift apparent reading age by the local offset (5-6h in the
US) and permanently trip the fallback ladder. Offset is now honoured.
- Suppressed the cosmetic "control loop stopped" fault in the window
between relay_init and the control task's first call-in at boot.
- Explicit pullups on the encoder A/B lines.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ESP-IDF v5.3.2 firmware for the CrowPanel 2.1" rotary display. Builds clean;
nothing has been run on hardware yet.
Hardware verified against Elecrow's own source for this board and
cross-checked against their ESPHome config, per PRD 8.1. Three corrections to
the PRD's pinout, all documented in docs/HARDWARE.md:
- touch is CST826 at 0x15, not CST816 (chip ID reads 0x11, not 0xB4)
- the ST7701S needs a 3-wire SPI bus on GPIO 16/2/1 that the PRD omitted;
without it the init sequence cannot be sent and the panel stays black
- the backlight is GPIO6
Two further departures from the PRD, both forced by facts on the ground:
- Transport is MQTT, not HTTP. zigbee2mqtt has no REST endpoint for live
sensor state. Subscribing to the broker also gets retained topics, so
every room's last reading arrives on connect rather than after a poll.
- The furnace is 2-wire R/W with no C, not 3-wire. The board needs its own
5V supply. The thermostat's 5 CPH setting is enforced as a minimum
12-minute period between heat-call starts, which a minimum off-time alone
does not achieve.
All of PRD section 5 is implemented in the relay layer itself: fail-open,
watchdog-gated output, max on-time, min off-time, cycle-rate limit, startup
lockout, and the stale-data fallback ladder down to open-loop freeze
protection. The one gap that cannot be closed in software — the PCF8574 not
resetting when the ESP32 does — is documented rather than papered over.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>