Some hardware links on this page are affiliate links. As an Amazon Associate I earn from qualifying purchases. We may earn a commission if you buy through them, at no extra cost to you. See the affiliate disclosure.
A to-do list on a phone is easy to ignore on the way out the door. This pack puts the current part of the day on a 1.54″ e-paper panel that holds the image with the power off. Morning, midday, and evening each have their own Home Assistant to-do list, up to five items. The CoreInk wakes at that start time, shows the list, and goes back to sleep. Checking an item on the device updates the list. Editing the list in Home Assistant shows up the next time the device wakes.
A chore stored as a single date, reset with an NFC tag, is NFC chore tracker. This one is a short checklist that changes with the time of day.
Wi-Fi credentials, the API key, and the MQTT password stay in secrets.yaml. Do not publish the lists’ real task names.
What problem it solves
You want a desk checklist that follows three Home Assistant to-do lists through the day and does not need the panel powered between those times.
How it works
The board is an M5Stack CoreInk (ESP32-PICO-D4, 200×200 e-paper). ESPHome draws the list. Home Assistant owns the tasks. MQTT carries the config and the checkmarks. The onboard RTC (read with the PCF8563 platform) decides when to wake. SNTP sets that RTC when the network is up.
- Three lists — Local To-do, one list per daypart. The package expects the entity ids
todo.todo_3310_morning,todo.todo_3310_midday, andtodo.todo_3310_evening. Rename in the entity settings if Home Assistant appended a suffix. More than five items stay in Home Assistant and are not drawn. The first five are the ones on the panel. - Start times — helpers, pack defaults 06:00, 12:00, and 18:00. The device wakes shortly after the start (a few seconds of margin so a slow RTC still lands in the new daypart). The first daypart of a new day resets all three lists. Later dayparts do not clear what you already checked.
- On the device — up and down move a selection bar. The center press toggles that item and publishes the slot. When every item is done, the finish card stays and up, down, and press do nothing. The top button undoes only the latest toggle of this wake, including a slip on the last item. The side button wakes the device early. Each press restarts a short awake window (pack default 15 seconds) so the panel is not held on.
- Sleep image — before deep sleep the panel does a full refresh, drops the selection bar, and shows the next wake time. Partial refreshes while you are tapping would otherwise ghost for the hours the image has to stay put. A change you make in Home Assistant while it sleeps applies on the next wake. Press the side button if you want that now.
- Language and titles — a helper switches the on-device language between English and German without a reflash. Daypart titles and the finish-card lines are helpers too. They survive a restart. The package does not write
initial:on those helpers, so a restart does not put the defaults back over your text.
Battery voltage and percent, availability, last seen, and the seconds until the next wake are MQTT sensors. The always-on clock YAML in the same project is a different firmware. It does not deep sleep, and it is not this checklist.
The project’s own notes call the firmware experimental. Validate in ESPHome before you flash. A bad flash needs a recovery path you still have.
Hardware notes
- Board. M5Stack CoreInk, 1.54″ 200×200 panel, USB-C, about a 390 mAh battery. ESPHome board
m5stack-coreink. The panel is1.54inv2. Chip select GPIO9, DC GPIO15, reset GPIO0, busy GPIO4. SPI clock GPIO18, MOSI GPIO23. Buttons, all active low: up GPIO37, center GPIO38, down GPIO39, top GPIO5, side GPIO27. The side button is also the deep-sleep wake pin. Buzzer GPIO2, status LED GPIO10, battery ADC GPIO35, power-hold GPIO12. I²C GPIO21 and GPIO22, RTC at 0x51. Leave those pins. - Refresh. E-paper does not like a refresh every second. This pack refreshes on a button and once more, fully, before sleep. That matches how this panel wants to be used.
- Power. The battery is the point of the deep sleep. USB-C is for the first flash and for a desk that can spare the cable. Charge-only is fine after the firmware is on, because later updates can be OTA while it is awake.
- MQTT. The broker Home Assistant already uses. Authenticate it. Do not point the device at a public broker. The topic prefix in the pack is
todo_3310/. - Optional sticker. The CoreInk does not read NFC. A passive NTAG215 on the case can open a Companion deep link to the dashboard view. That link is not a
tag_scannedevent. Writing the tag from Home Assistant’s Tags screen does the opposite: it fires the event and does not open the view. Pick one.
Snippet
The daypart times and the awake window are substitutions and helpers. The drawing and the MQTT sync are in the pack.
substitutions:
device_name: desk_checklist
awake_timeout: 15s
wake_margin_s: "20"
timezone: UTC
esp32:
board: m5stack-coreink
deep_sleep:
id: checklist_sleep
wakeup_pin:
number: GPIO27
inverted: true
wakeup_pin_mode: KEEP_AWAKE
Home Assistant side, the three lists are ordinary to-do entities. The package publishes retained config on todo_3310/config and list state on todo_3310/command/slot/0 through slot/2. The device answers on todo_3310/state/slot/<n> and sets todo_3310/state/config_applied after it has taken a config.
Setup outline
- Add the Local To-do integration three times and set the entity ids above. Add at most five items to each for the first test.
- Copy the package into
config/packages/and include that folder from the existinghomeassistant:block. Do not add a secondhomeassistant:key. Validate, then restart. - Copy the ESPHome YAML. Put a font next to it (the layout was tuned on a bold UI face; a Google font works if you accept the spacing). Fill secrets. Run Validate. Fix every error before flashing.
- Flash over USB-C. After the first wake,
todo_3310/state/config_appliedshould publish and the morning list should match Home Assistant. - Toggle an item on the device. The to-do item should check. Toggle it in Home Assistant, press the side button, and the panel should match. Wait out the awake window and confirm the sleep image shows the next start time.
Troubleshooting
- The panel shows example tasks. Config never arrived. Check the broker for
todo_3310/configand the automation trace that publishes it. A wrong MQTT password fails quietly if you only look at the panel. - Home Assistant edits do nothing until later. The ESP32 is asleep and cannot take a push. That is the design. The side button wakes it.
seconds_to_wakeupis a snapshot from the last sleep, not a live countdown. - Only five items appear. The rest are still on the to-do entity. This firmware draws five per daypart.
- The last item will not uncheck. The list is locked when it is complete. The top button undoes the latest toggle of this wake only. After the next sleep, that undo is gone. Uncheck it in Home Assistant and wake the device.
- A restart put the titles back. An older copy of the package set
initial:on the helpers. This pack does not. If a restart clobbers them, the helpers in use are not these ones. - Validate fails. Do not flash. The firmware targets ESPHome 2026.10. A font path that does not exist fails config, which is the error you want before a flash.
- You wanted one NFC tag per chore and a due date. That is NFC chore tracker. This panel is three lists and a clock, not an interval timer.
Credits
Based on 3310-eink. That project draws a monochrome checklist on a CoreInk from three Home Assistant to-do lists, with deep sleep between dayparts and MQTT in both directions. This write-up is an original overview of the checklist firmware: the five-item cap, the lock when the list is finished, the top-button undo, and the sleep image. The separate always-on clock YAML is named so it is not flashed by mistake. Sample tasks from that repository are not part of this pack.