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:
1 parent
393592e327
commit
d2e4c974dd
35 files changed
+4685
No files matched your search
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* app_config.h — site-specific configuration and credentials.
|
||||
*
|
||||
* Copy this file to main/app_config.h and fill it in. app_config.h is
|
||||
* gitignored; this template is tracked.
|
||||
*
|
||||
* cp main/app_config.h.example main/app_config.h
|
||||
*
|
||||
* Everything here is specific to one installation. Behavioural tuning
|
||||
* (hysteresis, timings, safety limits) lives in hvac/control.h and
|
||||
* hvac/relay.h instead, because those are properties of the firmware rather
|
||||
* than of the house.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/* ---------------------------------------------------------------- WiFi -- */
|
||||
|
||||
#define APP_WIFI_SSID "your-ssid"
|
||||
#define APP_WIFI_PASS "your-password"
|
||||
|
||||
/* --------------------------------------------------------------- MQTT --- */
|
||||
/*
|
||||
* The ESP32 talks to the MQTT broker that zigbee2mqtt publishes to, not to
|
||||
* zigbee2mqtt itself. z2m has no REST endpoint for live sensor state — the
|
||||
* frontend streams it over a WebSocket — and subscribing to the broker
|
||||
* directly is both simpler and more robust: the sensor topics are retained,
|
||||
* so the last known reading for every room arrives within milliseconds of
|
||||
* connecting, including after a reboot.
|
||||
*
|
||||
* URI forms: mqtt://host:1883, mqtts://host:8883, ws://host:9001/mqtt
|
||||
*/
|
||||
#define APP_MQTT_URI "mqtt://192.168.1.10:1883"
|
||||
#define APP_MQTT_USER "" /* leave empty for anonymous */
|
||||
#define APP_MQTT_PASS ""
|
||||
|
||||
/* z2m's configured base topic. Sensor topics are <base>/<friendly_name>. */
|
||||
#define APP_MQTT_BASE_TOPIC "zigbee2mqtt"
|
||||
|
||||
/* --------------------------------------------------------------- Rooms -- */
|
||||
/*
|
||||
* One row per room the thermostat knows about.
|
||||
*
|
||||
* X(display_name, zigbee2mqtt_friendly_name)
|
||||
*
|
||||
* display_name — what appears on the round screen. Keep it short; there is
|
||||
* not much horizontal room at 480x480 with a circular mask.
|
||||
* friendly_name — exactly as it appears in zigbee2mqtt, i.e. the last path
|
||||
* element of the MQTT topic. Case and spaces matter. If a
|
||||
* name contains a space the topic will too, which is legal
|
||||
* MQTT and handled correctly here.
|
||||
*
|
||||
* The order is the order the encoder cycles through in manual mode, and the
|
||||
* index is what gets persisted to NVS — so inserting a row in the middle
|
||||
* will shift a previously saved selection. Append rather than insert.
|
||||
*
|
||||
* Room 0 is the power-on default before anything is loaded from NVS.
|
||||
*/
|
||||
#define APP_ROOM_TABLE(X) \
|
||||
X("TV Room", "tv_room_sensor") \
|
||||
X("Bedroom", "bedroom_sensor")
|
||||
|
||||
/* --------------------------------------------------------------- Units -- */
|
||||
/*
|
||||
* Display units. All internal control math is in degrees Celsius regardless;
|
||||
* this only affects what is rendered and how big an encoder detent is.
|
||||
* APP_UNITS_FAHRENHEIT: 1 detent = 1 F. Celsius: 1 detent = 0.5 C.
|
||||
*/
|
||||
#define APP_UNITS_FAHRENHEIT 1
|
||||
|
||||
/* ---------------------------------------------------------------- Time -- */
|
||||
/*
|
||||
* POSIX TZ string, used by schedule mode. SNTP keeps the clock honest; if it
|
||||
* never syncs, schedule mode falls back to the formula rule and says so on
|
||||
* screen rather than acting on a wrong clock.
|
||||
* US Central: "CST6CDT,M3.2.0,M11.1.0" US Eastern: "EST5EDT,M3.2.0,M11.1.0"
|
||||
*/
|
||||
#define APP_TIMEZONE "CST6CDT,M3.2.0,M11.1.0"
|
||||
#define APP_SNTP_SERVER "pool.ntp.org"
|
||||
Reference in new issue
Block a user