Implement rotary thermostat firmware from PRD

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>
This commit is contained in:
mattandClaude Opus 5 committed 2026-08-03 19:47:00 -07:00
1 parent 393592e327
commit d2e4c974dd
35 files changed
+4685

No files matched your search

+90
View File
@@ -0,0 +1,90 @@
# Rotary Thermostat — ESP32-S3, 16MB flash, 8MB octal PSRAM
#
# Several entries here are load-bearing for the RGB panel. Read the comments
# before changing any of them; PRD section 8.2 documents what each one costs.
CONFIG_IDF_TARGET="esp32s3"
# --- Flash -------------------------------------------------------------------
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
# --- PSRAM -------------------------------------------------------------------
# Octal (OPI) PSRAM. The vendor's Arduino build uses qio_opi; same thing.
CONFIG_SPIRAM=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_USE_MALLOC=y
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=16384
CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP=y
#
# PRD 8.2: these two contend with the LCD for PSRAM bandwidth and produce a
# black screen plus stalled TLS handshakes. Elecrow's own ESPHome example sets
# both to 'y' — do not copy it. Left explicitly unset:
# CONFIG_SPIRAM_FETCH_INSTRUCTIONS is not set
# CONFIG_SPIRAM_RODATA is not set
#
# 120MHz is the lever if artefacts appear at 480x480, but it drags flash to
# 120MHz with it and needs flash HPM plus a DC-aware bootloader. Not needed at
# this resolution — 480x480 is ~40% of the bandwidth 800x480 required.
# --- Cache -------------------------------------------------------------------
# Bigger data cache and 64-byte lines measurably help RGB panel DMA.
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y
CONFIG_ESP32S3_DATA_CACHE_64KB=y
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
# --- CPU / RTOS --------------------------------------------------------------
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
CONFIG_FREERTOS_HZ=1000
CONFIG_ESP_MAIN_TASK_STACK_SIZE=8192
# --- Console -----------------------------------------------------------------
# PRD 8.2: USB-Serial-JTAG is the ONLY console link on this board (native USB,
# no CH340), so it is made the PRIMARY console rather than the secondary one.
#
# Note the generated sdkconfig ends up with CONFIG_ESP_CONSOLE_SECONDARY_NONE=y,
# which looks like it contradicts PRD 8.2's warning. It does not. "Secondary
# console" only exists when the primary is UART; with USB-JTAG selected as
# primary there is no secondary slot to fill, and
# CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG_ENABLED=y confirms output still goes to
# the USB link. The warning was about the sibling board, where UART was primary
# and the secondary USB-JTAG console silently occupied GPIO19/20.
CONFIG_ESP_CONSOLE_USB_SERIAL_JTAG=y
# --- WiFi --------------------------------------------------------------------
# PRD 8.2: keep WiFi out of NVS. This project writes its own settings to NVS at
# runtime and we do not want WiFi adding uncontrolled flash writes on top.
CONFIG_ESP_WIFI_NVS_ENABLED=n
# --- LCD ---------------------------------------------------------------------
# RGB panel ISRs and callbacks run from IRAM so a flash operation cannot stall
# them. We use no bounce buffers (see drivers/display/display.c) which is what
# actually makes runtime NVS writes safe.
CONFIG_LCD_RGB_ISR_IRAM_SAFE=y
CONFIG_GDMA_CTRL_FUNC_IN_IRAM=y
# --- Watchdogs ---------------------------------------------------------------
# The task watchdog is part of the safety story: a hung control task panics the
# chip, and the reboot path de-asserts the relay within about a second.
CONFIG_ESP_TASK_WDT_INIT=y
CONFIG_ESP_TASK_WDT_TIMEOUT_S=10
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=n
CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=n
CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
# --- Logging -----------------------------------------------------------------
CONFIG_LOG_DEFAULT_LEVEL_INFO=y
# --- LVGL --------------------------------------------------------------------
CONFIG_LV_COLOR_DEPTH_16=y
CONFIG_LV_USE_PERF_MONITOR=n
CONFIG_LV_FONT_MONTSERRAT_16=y
CONFIG_LV_FONT_MONTSERRAT_20=y
CONFIG_LV_FONT_MONTSERRAT_28=y
CONFIG_LV_FONT_MONTSERRAT_48=y
CONFIG_LV_MEM_SIZE_KILOBYTES=64