Firmware for a Waveshare ESP32-S3-Touch-LCD-1.69 board used as a small Nova HA Dashboard client.
The nova-ha-dashboard project that this pairs with can be found at: https://github.com/antidamage/nova-ha-dashboard
The sketch connects to WiFi, subscribes to the Nova dashboard event stream, renders the Nova avatar, polls host-load metrics, and lets the watch toggle the everything lighting zone with a long press.
- Board: Waveshare ESP32-S3-Touch-LCD-1.69
- Arduino FQBN:
esp32:esp32:waveshare_esp32_s3_touch_lcd_169 - Display: ST7789V2, 240 x 280, RGB565
- Touch: CST816 over I2C
- PSRAM: required for the LVGL/avatar canvas
Important pins used by the sketch:
- LCD: SCK
6, MOSI7, CS5, DC4, RST8, BL15 - Touch/I2C: SDA
11, SCL10, RST13, INT14
Do not drive ESP32-S3 strapping pins 0, 3, 45, or 46.
The firmware talks to the Nova dashboard configured in secrets.h:
GET /api/events: SSE stream for dashboard state and shared theme changes.GET /api/nova-load: polled about once per second for host load.POST /api/zone: used to toggle theeverythingzone.
The screen is intentionally just the Nova avatar. There are no WiFi or light-status labels.
- When WiFi is connected, the avatar animates at a 25fps target.
- Higher host load makes the circular arcs longer.
- Shared dashboard theme colors are parsed from pushed state events and applied live.
- If WiFi drops, the screen dims and the avatar settles into a static idle state.
- Touch must be held for at least
500 msbefore it toggles lights.
Create a local secrets.h next to light_toggle.ino.
Start from the example:
Copy-Item .\example-secrets.h .\secrets.hThen edit secrets.h with your real values:
#pragma once
#define WIFI_SSID "your-wifi-ssid"
#define WIFI_PASSWORD "your-wifi-password"
#define NOVA_HOST "nova.local"
#define NOVA_PORT 80secrets.h is ignored by git. Do not commit real credentials.
Use the helper script:
.\flash-watchface.ps1The script:
- Generates
avatar_config.local.hfor local avatar settings. - Auto-detects the connected Waveshare/ESP32-S3 serial port by
VID_303A. - Compiles with
PSRAM=enabled. - Uploads the freshly compiled firmware.
- Checks that the board re-enumerates after flashing.
Useful options:
.\flash-watchface.ps1 -ArcCount 12
.\flash-watchface.ps1 -CompileOnly
.\flash-watchface.ps1 -Port COM3
.\flash-watchface.ps1 -Clean
.\flash-watchface.ps1 -VerifyUpload-ArcCount controls NOVA_AVATAR_ARC_COUNT, valid range 1..60. Lower values are lighter to render; higher values look denser but cost more frame time.
These files are intentionally local-only:
secrets.h: WiFi and dashboard connection details.avatar_config.local.h: generated byflash-watchface.ps1to set the arc count.
Both are ignored by git.
Routine flashing should use normal auto-reset through the serial port. If the board stops enumerating, will not boot, or the screen remains dark after a successful upload, use the watchface recovery workflow rather than changing to a generic ESP32-S3 board profile.