TagMod: open-sourcing my hacked ereader software
I turned a broken-touchscreen e-reader into a one-button Kindle with an always-on dashboard. Now the code is open source.
I have several Tagus (Onyx e-readers running Android 4.4) with broken touchscreens. Fixing the touch doesn’t make financial sense, but the e-ink panel and hardware work perfectly. So I turned them into something else: an e-reader you drive entirely with a single button, and while it sleeps it shows a dashboard with my agenda, tasks, Umami analytics, server status and weather.
Today I’m releasing it as open source.
The problem
A Tagus without a touchscreen is a paperweight. Android expects you to touch the screen for everything: picking a book, turning pages, going back. Without touch, there’s no way to use it.
The solution was writing a C daemon that hijacks the power button and turns press patterns into keyboard events. The Android system never sees the real button. The daemon interprets:
| Gesture | Library | Reading |
|---|---|---|
| Tap | next item | next page |
| Double tap | previous | previous page |
| Hold 0.8-3s, release | open | back to library |
| Hold 3s | sleep (shows panel) | sleep |
The dashboard
While the e-reader is asleep, the screen doesn’t turn off: it shows a TRMNL-style panel with useful information. The daemon has a kernel timer (CLOCK_REALTIME_ALARM) that wakes the device from deep suspend every hour, updates the panel and puts it back to sleep. The frontlight stays off during the whole cycle, so the room stays dark.
What the panel shows:
- Header: weekday, date, battery level
- Agenda: upcoming calendar events (from a server with iCal)
- Tasks: pending items with due dates (Markdown or Todoist)
- Current book: the last book opened
- Analytics: visitors, sessions, pageviews, average time (self-hosted Umami), 7-day chart, top events
- Server monitor: heartbeat checks every hour, 24h bars, weekly uptime, incident history
- Weather: hourly and weekly forecast (Open-Meteo, no API key needed)
Everything is painted with Canvas in Java onto a 758x1024 bitmap that SurfaceFlinger uses as the sleep image. No Android views, no WebView. The panel is shown in the cover image of this post.
How it works under the hood
The project has four independent pieces:
powerkeyd (C) — the root daemon. Grabs exclusive ownership of /dev/input/event0 (the power button) and emits synthetic keyboard events to other input devices. It runs inside the boot image ramdisk, so it starts before Android. It also listens on an abstract Unix socket (@tagmod) so the launcher can request panel refreshes, kernel wakelocks and scheduled updates.
Launcher APK (Java, API 19) — no Gradle, no external dependencies. One-button library with frontlight control. PanelService collects data with PanelSource (weather, server feed, Umami, battery, services), paints it with PanelRenderer and writes the bitmap. StatusTracker is the uptime monitor. Umami is the analytics client. Http forces TLS 1.2 and bundles current root CAs because the Android 4.4 trust store is expired.
tagmod-server (Python) — optional backend for a VPS. Exposes GET /feed.json with Bearer auth. Combines ICS calendar events (with recurrence expansion) and tasks from a Markdown file or the Todoist API. Each source has its own cache; if one fails, it serves the last good copy.
Boot image and art — Python scripts to pack/unpack Android v0 boot images, inject TagMod files into the ramdisk, patch init.rc and default.prop (ro.secure=0 for adb root), and replace the bootloader logo in the resource partition.
Current status and what’s missing
What works, verified on the device:
- One-button control, library, frontlight 150-255
- Full dashboard with all the blocks described above
- Scheduled refresh from deep suspend
- One-script deployment:
deploy/flash.sh install - Onyx services disabled (status bar, bookstore, OTA)
- WiFi configurable via script
What hasn’t been tested yet:
- Page turning with the button in AlReader (I don’t have FB2/MOBI on the device)
- The server isn’t deployed in production (I use
file:///sdcard/TagMod/feed.jsonlocally with test data)
Why open source
The code works and is tested on real hardware. An e-ink e-reader is a fantastic device for an always-on dashboard without draining battery, and the software to do it shouldn’t stay on my hard drive.
The pieces are independent. The C daemon is generic (any Rockchip with Android 4.4+). The launcher is vanilla Java. The server is standard Python. If you have an old Android e-reader lying around, you can probably adapt it.
The repo documentation includes guides for porting to other devices (Kindle, Kobo, generic), using it as an e-ink dashboard, and firmware modding.
The code is at github.com/IgnacioLD/tagmod under the MIT license.
Drafted with AI, edited by hand. I publish it when it sounds like me.