173 lines
4.4 KiB
Markdown
173 lines
4.4 KiB
Markdown
|
|
# Waveshare 2.9" Touch ePaper Panel
|
|||
|
|
|
|||
|
|
ESPHome project for the [Waveshare 2.9inch Touch e-Paper HAT](https://www.waveshare.com/2.9inch-Touch-e-Paper-HAT.htm) on an ESP32-WROOM-32 (NodeMCU-32S). Drives an LVGL UI with 2-bit grayscale rendering and touchscreen input.
|
|||
|
|
|
|||
|
|
## Hardware
|
|||
|
|
|
|||
|
|
- **MCU:** ESP32-WROOM-32 (NodeMCU-32S)
|
|||
|
|
- **Display:** SSD1680, 296×128, 2-bit grayscale via custom component
|
|||
|
|
- **Touchscreen:** GT1151 / ICNT86X (I2C, polling mode)
|
|||
|
|
|
|||
|
|
### Wiring
|
|||
|
|
|
|||
|
|
| Function | ESP Pin | HAT Pin |
|
|||
|
|
|--- |--- |--- |
|
|||
|
|
| Display SCLK | GPIO18 | Pin23/GPIO11/SPI0_SCLK |
|
|||
|
|
| Display MOSI | GPIO23 | Pin19/GPIO10/SPI0_MOSI |
|
|||
|
|
| Display CS | GPIO19 | Pin24/GPIO8/SPI0_CE0 |
|
|||
|
|
| Display DC | GPIO17 | Pin22/GPIO25 |
|
|||
|
|
| Display BUSY | GPIO4 | Pin24/GPIO24 |
|
|||
|
|
| Display RST | GPIO5 | Pin11/GPIO17/SPI1_CE1 |
|
|||
|
|
| Touch SDA | GPIO21 | Pin3/GPIO2/I2C1_SDA |
|
|||
|
|
| Touch SCL | GPIO22 | Pin5/GPIO3/I2C1_SCL |
|
|||
|
|
| Touch RST | GPIO15 | Pin13/GPIO27 |
|
|||
|
|
| Touch INT | GPIO16 | Pin15/GPIO22 |
|
|||
|
|
|
|||
|
|
## Project Structure
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
waveshare-panel/
|
|||
|
|
├── waveshare-test.yaml # Main ESPHome config (edit LVGL layout here)
|
|||
|
|
├── secrets.yaml # WiFi/API credentials (not committed)
|
|||
|
|
├── FreeSans.ttf # Font used in LVGL
|
|||
|
|
└── custom_components/
|
|||
|
|
├── waveshare_epaper_2bit/ # 2-bit grayscale display driver
|
|||
|
|
└── icnt86x/ # ICNT86X touchscreen driver
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Build Environment Setup
|
|||
|
|
|
|||
|
|
### 1. Install Python 3.11
|
|||
|
|
|
|||
|
|
ESPHome 2026.1.0 requires Python 3.11. Check your version:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python3 --version
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
On Ubuntu/Debian, install it if needed:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
sudo apt update
|
|||
|
|
sudo apt install python3.11 python3.11-venv python3.11-dev
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
On macOS with Homebrew:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
brew install python@3.11
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Create a virtual environment for ESPHome 2026.1.0
|
|||
|
|
|
|||
|
|
Using a dedicated venv keeps this version isolated from other ESPHome installs.
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
python3.11 -m venv ~/esphome-env/esphome-2026.1.0
|
|||
|
|
source ~/esphome-env/esphome-2026.1.0/bin/activate
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. Install ESPHome 2026.1.0
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
pip install esphome==2026.1.0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Verify the install:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome version
|
|||
|
|
# Expected: Version: 2026.1.0
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 4. Activate the environment (each session)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
source ~/esphome-env/esphome-2026.1.0/bin/activate
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
You can add this to your shell profile or run it manually before working on the project.
|
|||
|
|
|
|||
|
|
## Building and Flashing
|
|||
|
|
|
|||
|
|
All commands assume the venv is active and you are in the project directory.
|
|||
|
|
|
|||
|
|
### Compile only
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome compile waveshare-test.yaml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### Flash via USB (first flash or if OTA fails)
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome upload waveshare-test.yaml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Connect the ESP32 via USB before running. You may need to hold the BOOT button during flashing if the device doesn't enter download mode automatically.
|
|||
|
|
|
|||
|
|
### Flash via OTA (subsequent flashes)
|
|||
|
|
|
|||
|
|
Once the device is on WiFi, OTA upload works without USB:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome upload waveshare-test.yaml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
ESPHome will automatically attempt OTA if the device is reachable.
|
|||
|
|
|
|||
|
|
### Monitor serial output
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome logs waveshare-test.yaml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Or via USB:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome logs --device /dev/ttyUSB0 waveshare-test.yaml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Secrets
|
|||
|
|
|
|||
|
|
Copy the secrets template and fill in your credentials:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
cp secrets.yaml.example secrets.yaml # if an example exists, otherwise create it
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`secrets.yaml` format:
|
|||
|
|
|
|||
|
|
```yaml
|
|||
|
|
wifi_ssid: "YourNetworkName"
|
|||
|
|
wappw: "YourWiFiPassword"
|
|||
|
|
enckey: "<32-byte base64 Home Assistant API key>"
|
|||
|
|
apipw: "YourOTAPassword"
|
|||
|
|
hotspotpw: "FallbackPassword"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The `fallbackssid` variable is set in `waveshare-test.yaml` and does not go in secrets.
|
|||
|
|
|
|||
|
|
## Making Layout Changes
|
|||
|
|
|
|||
|
|
The LVGL UI is defined in `waveshare-test.yaml` under the `lvgl:` block. The display renders at **296×128 pixels** in a 4-shade grayscale palette:
|
|||
|
|
|
|||
|
|
| LVGL color | Shade |
|
|||
|
|
|------------|------------|
|
|||
|
|
| `0xFFFFFF` | White |
|
|||
|
|
| `0xAAAAAA` | Light grey |
|
|||
|
|
| `0x555555` | Dark grey |
|
|||
|
|
| `0x000000` | Black |
|
|||
|
|
|
|||
|
|
After editing the YAML, compile and flash:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
esphome upload waveshare-test.yaml
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
The display uses a two-tier refresh:
|
|||
|
|
- **Partial refresh** (fast, 1-bit) — triggers immediately after any draw event for interactive feedback
|
|||
|
|
- **Full refresh** (2-bit grayscale quality) — triggers 10 seconds after the last draw event
|
|||
|
|
|
|||
|
|
Full refresh restores proper 4-shade rendering after the fast partial updates.
|