A repo for the TRMNL e-paper display.
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Adam Outler 89af046a7d feat: migrate download speed sensor to sensor.fast_com_download
- Update ingested entity_id and component id to sensor.fast_com_download
- Update display lambda column 2 rendering to read from fast_com_download
- Update README.md and GEMINI.md dependency declarations
2026-10-15 10:17:15 -04:00
docs docs(qa): add screenshot verification of ESPHome web editor matching repository 2026-10-15 08:55:06 -04:00
.gitignore feat: initial commit for TRMNL ESPHome e-paper display 2026-10-15 08:31:02 -04:00
GEMINI.md feat: migrate download speed sensor to sensor.fast_com_download 2026-10-15 10:17:15 -04:00
LICENSE feat: initial commit for TRMNL ESPHome e-paper display 2026-10-15 08:31:02 -04:00
README.md feat: migrate download speed sensor to sensor.fast_com_download 2026-10-15 10:17:15 -04:00
secrets.yaml.example feat: initial commit for TRMNL ESPHome e-paper display 2026-10-15 08:31:02 -04:00
trmnl.yaml feat: migrate download speed sensor to sensor.fast_com_download 2026-10-15 10:17:15 -04:00

TRMNL e-Paper Display on ESPHome

ESPHome Version Hardware Target Display License

An open-source, fully sovereign ESPHome firmware configuration for the TRMNL 7.5-inch e-Paper Display. This implementation bypasses TRMNL's proprietary cloud and subscription framework, integrating the hardware directly with Home Assistant over local Wi-Fi.


Highlights

  • 100% Local & Sovereign: Zero external cloud dependencies. Connects directly to Home Assistant using encrypted native API.
  • Unified 3-Column Dashboard:
    • Column 1 (Time & Date): Large digital clock with dynamic weekday and month/day rendering.
    • Column 2 (Network Performance): Live download speed and firewall WAN gateway packet loss percentage.
    • Column 3 (Weather Forecast): Dynamic weather glyphs, condition text, temperature (°F), humidity (%), and wind speed (mph).
    • Header Status: Battery capacity percentage and dynamic Material Design icon glyphs.
  • Hardware Button Support: Physical pushbuttons (GPIO2, GPIO3, and GPIO5) fully mapped as ESPHome binary sensors, capable of triggering instant display refreshes or custom Home Assistant automations.
  • Accurate Battery Gauge: LiPo discharge curve linearization via a 12-point piece-wise calibration table and power rail switching (GPIO6 gate).

Hardware Architecture & Pinout

The TRMNL hardware uses an Espressif ESP32-S3 microcontroller driving a 7.5" Waveshare V2 e-paper display (800x480 resolution).

+-------------------------------------------------------------+
|                          TRMNL                              |
|                                                             |
|  +-------------------------------------------------------+  |
|  |             Waveshare 7.5" e-Paper Display            |  |
|  |                     (800 x 480)                       |  |
|  +-------------------------------------------------------+  |
|                                                             |
|  +------------------------+     +------------------------+  |
|  |   ESP32-S3 (WROOM-1)   |     |  LiPo Battery Circuit  |  |
|  |  SPI2_HOST: GPIO7/9/44 |<--->|  Gate: GPIO6           |  |
|  |  DC: GPIO10, RST: 38   |     |  ADC:  GPIO1 (12dB)    |  |
|  |  Busy: GPIO4 (inv)     |     +------------------------+  |
|  +-----------+------------+                                 |
|              |                                              |
|              v                                              |
|      [ Physical Buttons ]                                   |
|      Key 1: GPIO2 | Key 2: GPIO3 | Wake: GPIO5              |
+-------------------------------------------------------------+

Complete Pinout Summary

ESP32-S3 Pin Function Mode Description
GPIO1 BATT_ADC Analog In Battery voltage divider reading
GPIO2 KEY_1 Input (INPUT_PULLUP) User button 1 (active low)
GPIO3 KEY_2 Input (INPUT_PULLUP) User button 2 (ignore_strapping_warning: true)
GPIO4 EPD_BUSY Input (inverted: true) Display busy state line
GPIO5 INTERRUPT Input (INPUT_PULLUP) Wake / action button interrupt
GPIO6 BATT_EN Output High-side power gate for battery ADC
GPIO7 EPD_SCK SPI Clock Display SPI Clock (SPI2_HOST)
GPIO9 EPD_MOSI SPI MOSI Display SPI Master-Out-Slave-In
GPIO10 EPD_DC Output Display Data / Command selection
GPIO38 EPD_RST Output Display hardware reset line
GPIO44 EPD_CS Output Display SPI Chip Select

For in-depth hardware documentation, see docs/hardware-pinout.md.


Getting Started

1. Prerequisites

  • ESPHome (via Home Assistant Add-on or CLI pip install esphome).
  • Home Assistant instance with the following sensors available (or adjusted to your entity IDs in trmnl.yaml):
    • sensor.fast_com_download (Download speed in Mbps)
    • sensor.office_fluffysnet_gateway_star_gateway_loss (or WAN packet loss sensor)
    • weather.nws_34_635074_78_63374230025875_keyf (National Weather Service or local weather entity)

2. Configure Secrets

Clone this repository and create your local secrets.yaml:

cp secrets.yaml.example secrets.yaml

Edit secrets.yaml and set your credentials:

wifi_ssid: "Your_WiFi_SSID"
wifi_password: "Your_WiFi_Password"
fallback_ssid: "TRMNL-Fallback"
fallback_password: "SecurePassword123"
api_encryption_key: "YOUR_32_BYTE_BASE64_KEY="
ota_password: "YourOtaPassword"

3. Compile & Flash

First-Time Flash (USB-C)

  1. Connect the TRMNL device to your computer via USB-C.
  2. Put the ESP32-S3 into bootloader mode if required (hold the boot button while plugging in).
  3. Compile and flash via ESPHome CLI:
    esphome run trmnl.yaml --device /dev/ttyACM0
    
    (Or claim and install via the Home Assistant ESPHome Dashboard using Web Serial in Chrome/Edge).

Subsequent Updates (OTA over Wi-Fi)

Once the device is on your local network, all future updates flash wirelessly:

esphome run trmnl.yaml

Power & Battery Linearization

Single-cell Lithium batteries have non-linear discharge profiles. This configuration uses a 12-point piecewise calibration mapping terminal voltage (halved by the divider and read via ADC1 Channel 0 with 12dB attenuation) to true battery capacity percentage:

 4.15V -> 100%   3.80V -> 60%   3.49V -> 20%
 3.96V ->  90%   3.75V -> 50%   3.41V -> 10%
 3.91V ->  80%   3.68V -> 40%   3.30V ->  5%
 3.85V ->  70%   3.58V -> 30%   3.27V ->  0%

To prevent continuous parasitic drain through the resistor divider, bsp_battery_enable (GPIO6) is switched on selectively during boot and measurement cycles.

For complete details, see docs/battery-management.md.


Physical Buttons

The device features physical buttons configured as active-low inputs with internal pull-ups:

  • Key 1 (GPIO2): Triggers immediate display refresh. Exposed to Home Assistant as binary_sensor.obdy_key_1.
  • Key 2 (GPIO3): Triggers immediate display refresh. Handled with ignore_strapping_warning: true to avoid bootloader strapping conflicts. Exposed as binary_sensor.obdy_key_2.
  • Wake / User Button (GPIO5): Exposed as binary_sensor.obdy_user_wake_button.

For historical context on the buttons and the Gemini conversation analysis, see docs/conversation-analysis.md.


Repository Structure

├── README.md                           # Master documentation
├── GEMINI.md                           # Module architecture manifest
├── trmnl.yaml                          # Production ESPHome configuration
├── secrets.yaml.example                # Template for Wi-Fi and API keys
├── .gitignore                          # Git exclusions for secrets and builds
└── docs/
    ├── hardware-pinout.md              # Detailed pinout & electrical specs
    ├── battery-management.md           # Power topology, ADC divider & calibration curve
    └── conversation-analysis.md        # Gemini design conversation breakdown & lessons learned

License

This project is open-source software licensed under the MIT License.