ESPHomeHome Assistant

E-ink daypart checklist on a CoreInk

An M5Stack CoreInk wakes for morning, midday, and evening, shows up to five to-do items for that part of the day, and sleeps. Checking an item on the device updates the Home Assistant list.

Difficulty · IntermediateSetup · 60–90 minutesHA · 2024.10 or newerESPHome · 2026.10
Get the pack · from $19Have us set it up

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.

  1. Three lists — Local To-do, one list per daypart. The package expects the entity ids todo.todo_3310_morning, todo.todo_3310_midday, and todo.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.
  2. 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.
  3. 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.
  4. 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.
  5. 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 is 1.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_scanned event. 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

  1. 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.
  2. Copy the package into config/packages/ and include that folder from the existing homeassistant: block. Do not add a second homeassistant: key. Validate, then restart.
  3. 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.
  4. Flash over USB-C. After the first wake, todo_3310/state/config_applied should publish and the morning list should match Home Assistant.
  5. 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/config and 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_wakeup is 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.

Changelog

v1.0 · Oct 29, 2026: First publish.