DBDelve
Dive deep into your data. A fast, native, multi-engine database client written in Rust. Free and open source, no telemetry.
翻訳待ち
TRMNL ePaper device firmware
翻訳待ち
開発ツールC · C++GitHub @usetrmnl自分でインストール所有者未確認
Paste into Claude or ChatGPT for installation instructions suited to your environment.
Have you tried it? One tap is enough. No sign-in needed.
The maker's introduction consists of the line above. Read the repository README for more details. Repository README ↗
Loading the full README.
Read the full README ↗created for the TRMNL e-ink display.
[!IMPORTANT] the
mainbranch is under constant development and may contain breaking changes. flash at your own risk.to access production-ready firmware, check out the tagged releases or use the Flash Assistant.
Each wake the device connects to Wi-Fi, fetches its screen from /api/display, draws it, checks for a reset or firmware update and goes back to deep sleep.
flowchart TD
Wake(["Wake: power-on, button or timer"]) --> Init("Init board, pins, preferences")
Init --> IsButton{"Woken by<br/>the button?"}
%% Button wake (the TRMNL X reads its touch bar instead)
IsButton -->|"Yes"| Press{"How was it<br/>pressed?"}
Press -->|"Hold ≥ 15 s"| Wipe1(["Wipe credentials, reboot"])
Press -->|"Hold 5–15 s"| ForgetWifi("Forget Wi-Fi")
Press -->|"Double-click"| SpecialFn("Run special function")
Press -->|"Short press"| Hardware
ForgetWifi --> Hardware
SpecialFn --> Hardware
IsButton -->|"No"| Hardware("Read battery, init display<br/>and filesystem<br/>(wake logo unless timer wake)")
%% Wi-Fi
Hardware --> IsWifiSaved{"Wi-Fi<br/>saved?"}
IsWifiSaved -->|"No"| Portal{"Captive portal"}
Portal -->|"Reset device"| Wipe2(["Wipe credentials, reboot"])
Portal -->|"Timed out"| WifiError(["Show Wi-Fi error, sleep"])
Portal -->|"Connected"| Clock
IsWifiSaved -->|"Yes"| Connect{"Connected?<br/>(3 attempts)"}
Connect -->|"No"| WifiRetry(["Sleep with backoff<br/>(error shown on button wake<br/>or 12th failed wake)"])
Connect -->|"Yes"| Clock("Sync clock (NTP)")
%% Setup
Clock --> HasKeys{"API key and<br/>friendly ID saved?"}
HasKeys -->|"No"| Setup{"GET /api/setup"}
Setup -->|"404 MAC unknown"| NotRegistered(["Show not-registered<br/>screen, sleep"])
Setup -->|"200"| SetupOk("Save credentials, show<br/>friendly ID screen")
Setup -->|"Other error"| SetupError("Show setup error")
SetupOk --> Fetch
SetupError --> Fetch
HasKeys -->|"Yes"| Fetch
%% Display
Fetch("Send stored logs, GET /api/display,<br/>download and draw the image") --> StayQuiet{"Failed on a timer<br/>wake, < 12 tries?"}
StayQuiet -->|"Yes"| QuietSleep(["Sleep with backoff"])
StayQuiet -->|"No"| ResetAsked{"Server asked<br/>for a reset?"}
ResetAsked -->|"Yes"| Wipe3(["Wipe credentials, reboot"])
ResetAsked -->|"No"| UpdateDue{"Firmware<br/>update due?"}
UpdateDue -->|"Yes"| Update{"Download and<br/>flash, success?"}
Update -->|"Yes"| Reboot(["Reboot"])
Update -->|"No"| ShowResult
UpdateDue -->|"No"| ShowResult("Show error screen, if any")
ShowResult --> MoreTaps{"TRMNL X:<br/>touch bar tapped?"}
MoreTaps -->|"Yes"| Fetch
MoreTaps -->|"No"| Sleep(["Sleep until the refresh<br/>interval or a button press"])
The device talks to its server through three endpoints: GET /api/setup, GET /api/display and POST /api/log. The BYOS guide documents the request headers, every field the firmware reads, the filename rules and the image size + format for each model.
A bit of background first. The ESP32-C3 inside the TRMNL OG is one of Espressif's newer, more efficient microcontrollers. For battery powered applications, it's designed to be put to sleep to conserve power when your project doesn't need it to be active. There are two sleep modes - light and deep. Deep sleep conserves the most power, but at the cost of losing the contents of the main memory. The lowest possible power consumption is about 4uA @ 3V with a timed wakeup, but TRMNL needs to be able to wake up with a button press. Keeping the GPIO active during deep sleep (to detect the button press) uses about 100uA on average (see power profile below). This means that a 2500mAh battery could theoretically keep the TRMNL powered in this state for approximately 25,000 hours.
Of course its not very useful to have a device that's permanently sleeping, so shown below is the power profile of TRMNL doing a normal display update (timed wake up, send device status, fetch new image, show it on the e-paper display):
The peaks and valleys you see above represent the variation in electrical current (power) drawn by the ESP32-C3 at different points during the ~10.5 second update cycle. The majority of energy is used while WiFi is active (between the 3 and 9 second marks). The last portion of the graph with higher frequency peaks is from the e-paper display cycling through its update (average power is quite low). The total electrical charge needed for the update is shown in the lower right corner (0.67c). This value is in Coulombs and represents the number of electrons that have moved through the circuit.
0.67 C = 0.186111 mAh
If we ignore the ESP32 sleep periods, the energy used in each display update would allow 2500/0.186111 = 13433 updates. If we configure our TRMNL account to update the information every 15 minutes, we'll be requesting 96 updates per day and the battery charge could last for 140 days (13433 / 96). This isn't too far off from real world results. The battery voltage will drop below a safe threshold before it has released its full energy and in the equation above, we haven't counted the energy used during the sleep periods nor the energy lost in the TRMNL's power supply (between the battery and the ESP32). The real world result will be closer to 120 days on a full charge.
We can extend the battery life further by disabling updates during our sleeping hours. In the TRMNL web portal there is a setting for “Sleep Mode” (see screenshot below):
This is the beginning of the README. Read the rest at the original. Read the full README ↗