Tickertape is the user-facing web app and CLI for pushing short, time-ordered messages (to-dos, shopping lists, reminders) to a home-network thermal receipt printer.
Built on top of unspooled.
- PWA Support: Install Tickertape to your Android or iOS home screen. On Android, it registers as a "Share Target," so you can instantly share URLs or text directly from other apps straight to your printer queue! See Android Share Setup and iOS Shortcuts Setup.
- Light/Dark Mode: Sleek UI that defaults to your OS setting, with a manual override in the settings menu.
- Idempotent Queueing: Jobs are queued via an SQLite database so they aren't lost if the printer is unplugged.
- Reminders: Send items to the "Inbox" and batch print them later when you're ready.
- Server (
server.py): Serves the mobile-friendly web UI and a simple/api/printendpoint. - Worker (
worker.py): A background process that polls a local SQLite queue and interfaces withunspooledto print. - CLI (
cli.py): A simple Python wrapper around curl/urllib to push jobs to the server from a laptop or cron job.
The easiest way to run the project (both the web UI/API and the print worker) is using Docker Compose.
To run the application locally for development or testing:
- Connect your Rongta RP332 printer via USB. Ensure it appears as
/dev/usb/lp0. - Build and start the services using the development compose file:
docker compose -f docker-compose.dev.yml up --build
- Open
http://localhost:8000in your browser.
If you don't have a printer connected, the worker will safely swallow the PermissionError or FileNotFoundError and you can still test the UI.
If you prefer to run it manually with Python 3.11+:
-
Create a virtual environment and install dependencies (though there are no external dependencies right now!):
python -m venv venv source venv/bin/activate -
Start the API & Web Server (runs on port 8000):
python server.py
-
In a separate terminal, start the Worker process:
python worker.py
You can configure the path to the printer by setting the PRINTER_DEVICE environment variable. It defaults to /dev/rongta-receipt. When running in Docker, ensure you map the printer device (e.g. /dev/usb/lp0) correctly in the compose file under the devices: block.
The test suite is plain pytest and lives in tests/. The tests
import the app's modules directly (e.g. import db), so they must be
run from the repo root with PYTHONPATH=. — exactly as CI does
(.github/workflows/docker-publish.yml).
On Debian / Raspberry Pi OS, pip install pytest fails on the system
Python (PEP 668, externally-managed). Use a project-local venv:
cd ~/github/tickertape
python3 -m venv .venv # one-time; needs `sudo apt install python3-venv` if it errors
.venv/bin/pip install -q pytest # one-time
PYTHONPATH=. .venv/bin/python -m pytest tests/ # run the tests.venv/ is gitignored. If you can't get any test runner working,
say so and stop — do not commit changes claiming "tests pass"
without having run them.
Example .service files for Raspberry Pi deployments are included:
tickertape.servicetickertape-worker.service
sudo cp tickertape*.service /etc/systemd/system/sudo systemctl daemon-reloadsudo systemctl enable --now tickertape.service tickertape-worker.service
For robust deployment, this repository includes an Ansible role at
ansible/roles/tickertape/. It's
designed to be consumed from your own playbook repo via roles_path
(see the role's README for setup); it rsyncs the app to the target,
templates the systemd units, and restarts the services.
# From your playbook repo, once the role is on your roles_path:
ansible-playbook -i inventory.yml your-playbook.yml --tags tickertape --limit your-host -KIf you wish to deploy manually:
- Ensure the remote host has the proper printer setup (udev rules).
- Sync the repository over (
rsync -avz --exclude '.git' ~/github/tickertape user@host:~/github/). - SSH into the host and run the
cp,daemon-reload, andenable --nowsteps for the.servicefiles provided.
Licensed under the Apache License 2.0.

