Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 

Repository files navigation

weclawbot-kindle

A poll-based BYOA display client that turns a jailbroken Kindle into a WeClawBot screen — the same product that ships official firmware for the Waveshare ESP32-S3-RLCD-4.2 board (openbrt/weclawbot), extended here to a device the main project deliberately does not ship firmware for.

Status as of 2026-07-10: proven end to end on a real jailbroken Kindle Basic 2, running continuously in a landscape desk stand, against a poll server implementing the contract documented below. Not yet wired into WeClawBot's production gateway — see "What production needs to add" below.

This repo ships the device-side client only. The server half (the /kindle/* endpoints below) is not published here — point WECLAWBOT_POLL_BASE_URL at any server that implements the contract, whether that's WeClawBot's production gateway once it's wired up, or your own.

Why polling, not the ESP32's MQTT push protocol

Every established jailbroken-Kindle dashboard project — TRMNL (usetrmnl/trmnl-kindle), KOReader, kindle-dash-client, weather_kindle, kindledashboard — uses a plain HTTP polling loop (curl an endpoint, fbink the result, sleep), not a long-lived push connection. That's what a Kindle jailbreak player already recognizes and can copy without reading WeClawBot's BYOA/MQTT protocol docs at all, so this client follows that convention instead of the ESP32 firmware's MQTT/WSS path.

Layout

client/                  the KUAL extension, drop-in installable
  config.xml
  menu.json
  bin/
    weclawbot-poll.sh    main loop: pair, then poll + fbink
    start.sh / stop.sh / status.sh
    power-tune.sh        one-shot: preventScreenSaver=1, wl PM 0
    keepalive.sh         same, silent, meant for cron
    toggle-autostart.sh  sets a marker file only, see caveat below
    reset-pairing.sh     forgets local device_id, does not revoke server-side

Install (jailbroken Kindle + KUAL already set up)

  1. Copy client/ to /mnt/us/extensions/weclawbot/ on the device.
  2. chmod +x /mnt/us/extensions/weclawbot/bin/*.sh
  3. Point the client at a server implementing the contract below, in /mnt/us/extensions/weclawbot/config:
    WECLAWBOT_POLL_BASE_URL=http://<your-server-ip>:8799
    
  4. From KUAL, run WeClawBot → Start WeClawBot (or sh /mnt/us/extensions/weclawbot/bin/start.sh over SSH). The screen shows a 6-digit pairing code.
  5. From your Agent (or, until this is wired into the real gateway, by hand against your server):
    curl -X POST http://<server>:8799/kindle/bind/confirm \
      -H 'content-type: application/json' \
      -d '{"code":"<the 6-digit code>","name":"my-kindle"}'
  6. Push content:
    curl -X POST http://<server>:8799/kindle/screen \
      -H 'content-type: application/json' \
      -d '{"device_id":"<from bind response>","title":"提醒","body":"..."}'
    The Kindle picks it up on its next poll (refresh_rate seconds, default 45s idle / 4s while unpaired) and calls fbink -c -f -g file=... -W GC16 -w.

Protocol (proven working)

POST /kindle/bind/request  { device_id? }              -> { device_id, code, expires_in }
POST /kindle/bind/confirm  { code, name? }              -> { ok, device_id, name }
GET  /kindle/status?device_id=...                       -> { bound, name }
POST /kindle/screen        { device_id, title, body }   -> { ok, revision }
GET  /kindle/poll?device_id=...                         -> { status, image_url, revision, refresh_rate }
GET  /kindle/image/<device_id>.png                      -> image/png
GET  /kindle/pairing-image.png?code=...&name=...        -> image/png (rendered on the fly)

weclawbot-poll.sh on the device: generates/caches a device_id, calls bind/request, shows the returned 6-digit code (as a rendered image — see below for why not fbink text mode), polls /kindle/status every 5s until bound, then switches to the steady-state loop: GET /kindle/poll → if revision changed, download image_urlfbink -c -f -g file=... -W GC16 -wsleep refresh_rate.

This mirrors WeClawBot's existing ESP32 BYOA flow on purpose: an Agent would run the exact same

weclawbotctl bind <code> --name my-kindle
weclawbotctl doctor --online
weclawbotctl screen /path/to/screen-document.json

with no Kindle-specific knowledge required on the Agent side — the translation from screen_document to {image_url, refresh_rate} is meant to happen entirely on the gateway (not yet implemented — see below).

Real-hardware findings baked into this implementation

  • fbink's default bitmap font (IBM 8x8) has no CJK glyph coverage. The pairing-code screen is therefore rendered server-side as an image (same rsvg-convert → cairo/pango pipeline as regular content) instead of fbink text mode, which can't render Chinese at all.
  • The panel's framebuffer is natively portrait (600x800, rotation: 3), but a landscape desk stand holds the unit sideways, and fbink -g has no per-call rotation flag. Content must be pre-rotated server-side. Determined empirically: pulled a known-good image from an unrelated, already-working landscape dashboard on the same physical unit, rotated it both directions locally, and visually confirmed which rotation produces upright text. Answer: author content landscape (LOGICAL_W=800 x LOGICAL_H=600), then translate(600,0) rotate(90) (90° clockwise) into the PANEL_W=600 x PANEL_H=800 physical buffer. If your stand holds the panel portrait instead, delete that transform and swap LOGICAL_W/LOGICAL_H back to match PANEL_W/PANEL_H.
  • -W GC16 alone does not force a full flashing refresh — it's a higher-quality non-flashing waveform by default. Without -f, --flash, ghosting from whatever was on screen before (another app's dashboard, a previous WeClawBot page) stays visible. Both fbink -g calls in weclawbot-poll.sh use -c -f -g ... -W GC16 -w; confirmed on real hardware that this actually clears prior-content ghosting where -W GC16 -w alone did not.
  • WiFi chip is Broadcom (bcmdhd), not Atheros. Use wl PM 0 to disable power-save, not wmiconfig (an Atheros-only tool that may not even be installed).
  • preventScreenSaver and WiFi PM do not survive reboots, and preventScreenSaver was observed getting cleared over time even without an obvious trigger. power-tune.sh is therefore not a one-shot: it's also installed as keepalive.sh in /etc/crontab/root, firing every minute. Live-tested: forcing both settings off and waiting confirmed cron puts them back within 60s.
  • This firmware uses Upstart, but initctl and mntroot are not on the default non-interactive SSH PATH — call them as /sbin/initctl and /usr/sbin/mntroot.
  • USB OTG host mode is not worth pursuing on this hardware. /sys/.../ci_hdrc.0 only exposes a fixed UDC (device-controller) node, no role-switch file. The common usbnet KUAL extension gives working USB gadget networking, but only as an SSH/recovery fallback — it requires tethering to another always-on host, which defeats the point of a freestanding plugged-in kiosk.
  • Editing /etc/crontab/root needs mntroot rw / mntroot ro bracketing since / is normally mounted read-only. weclawbot-poll.sh backs the file up before appending.
  • If a pgrep -f <pattern> kill command is embedded directly in an SSH command string, it can match and kill the SSH session's own remote shell (its argv literally contains the pattern text you're searching for). Write the kill logic to a file on the device and execute the file instead.
  • Killing a competing display process doesn't fully clear its visual ghosting — E Ink retains a faint trace of prior content across a non-flashing update. A -f flash refresh (see above) after taking over the screen from another app is necessary, not optional.

Known gaps / honestly not done

  • toggle-autostart.sh does not actually wire an Upstart job. It only writes a marker file. Making WeClawBot survive an unattended reboot needs a real /etc/upstart/weclawbot.conf job (mntroot rw, needs a reboot to verify) — deliberately left undone rather than silently bundled into a "toggle" button, since it's a persistent root-filesystem change.
  • No reference server is published in this repo — see "What WeClawBot's production gateway needs to add" below for the endpoints a server needs to implement. The client was validated against a minimal, dependency-free Node.js implementation of the contract, but it is not shipped here.
  • No TLS. A real deployment must serve /kindle/* over HTTPS, and shouldn't trust this device's outdated CA bundle blindly (embed a pinned CA instead of trusting the system store).
  • "Online" status is not implemented beyond bound. For parity with ESP32 devices (which report live MQTT connection state), a real deployment needs a poll-recency check (e.g. "online" iff last successful poll < 2× refresh_rate ago), since there's no persistent connection to check.
  • Text contrast is whatever this specific Pearl-generation E Ink panel can do. Verified the rendered PNG's actual pixel data is pure black text (not washed-out gray) — if it still looks light in person, that's panel/waveform physics, not a rendering bug; increasing body-text font weight is the next thing to try, not yet done.

What WeClawBot's production gateway needs to add to use this for real

  1. Implement the /kindle/* endpoints above in the real gateway, reusing its existing screen_document → PNG rendering pipeline. Remember the client expects the response to already be rotated/sized for the target device's physical mount (see "Real-hardware findings" above) — that's a per-device-profile concern the gateway needs to track.
  2. Add a transport field to the BYOA device table (mqtt vs poll), so weclawbotctl bind/screen/doctor route correctly without the Agent needing to know or care which kind of device it's talking to.
  3. Real auth: bind/request/bind/confirm here are unauthenticated in-memory demo state. Production needs the same scoped-credential model the ESP32 BYOA path already uses.
  4. Decide the thinking-state UX: MQTT devices get near-instant overlays; poll devices are bounded by refresh_rate. Either accept the latency difference in product copy, or shorten refresh_rate while thinking is active.
  5. Package client/ as a distributable zip following KUAL convention (a folder with config.xml + menu.json + bin/, dropped into /mnt/us/extensions/) for one-step install.

See openbrt/weclawbot for the main WeClawBot project (ESP32 firmware, official/BYOA protocol, weclawbotctl). The design discussion this client grew out of will be published there as docs/kindle-display-client-discussion.md.

License

MIT, see LICENSE.

About

Poll-based WeClawBot BYOA display client for jailbroken Kindles

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages