This is a simple bot that allows you to print on your home printer from anywhere from any device that has a telegram client. It also exposes some basic printer diagnostics and print job management. In order to print something, just upload a file without any commands. A lot of formats are supported.
When you send a file, the bot replies with a first-page preview and an interactive print-options panel. Tap the buttons to adjust how it prints, then press Print. After printing, the message keeps you posted on the job's progress and offers a Cancel button.
/start- Starts interaction and prints current state/auth <password>- Authenticates the user with a password against the password stored in theauth_passwordfile/settings- Edit the per-printer default print options (see below)/pending- Lists all pending print jobs/completed- Lists last 10 completed print jobs/cancel <job_id>- Cancels a pending job with a given id
The full command list is also registered with Telegram, so it shows up in the / autocomplete menu.
Both the per-file panel and /settings expose the same controls (translated to CUPS lp options).
Copies use a ➖ / ➕ stepper; the rest are tap-to-expand selectors (marked ▾) — tapping one
shows all of its choices (current marked 🔘), and tapping a choice selects it and returns to the
panel:
- Copies —
➖ / ➕stepper - Sides — single-sided / double-sided (long or short edge)
- Color — color / grayscale
- Paper size — A4 / Letter / Legal / A3
- Pages per sheet — 1 / 2 / 4 / 6 (N-up)
- Page range — type e.g.
2-5or1,3,5, orall - Printer — when more than one CUPS printer is available, pick the target (or "System default")
Saved defaults are kept per printer, not per user — each printer (and "System default") has its
own remembered options, since e.g. a duplex laser and a single-sided photo printer want different
settings. /settings opens the defaults for your system-default printer; pick a different printer
in the panel to edit its defaults instead. When you send a file it's seeded with the default
printer's saved options, and choosing a different printer in the per-file panel loads that printer's
defaults too (keeping the copies and page range you picked for the document).
/settings also has a 🧪 Dry run toggle. When it's on, sending a file (or pressing Print)
logs the exact lp command that would run, to printerbot.log, and reports back that nothing
was printed — useful for testing the bot without wasting paper. Like the other options it's saved
per printer, so it applies to every file printed to that printer until you turn it off.
- Password authentication; authorized users are persisted across restarts (in
state.json) - Per-printer default print settings are persisted in the same
state.json - Uses
libreofficeto convert files to PDF format before printing - Uses
pdftoppm(poppler) to render the first-page preview - Uses
lp(CUPS) to send a file to the printer with the chosen options, andlpstat/cancelfor status and cancellation - Uses the
python-telegram-botpackage to interface with the Telegram API
The code is a small printerbot/ package, split into single-responsibility modules, each
collaborator behind an interface so it can be swapped or tested in isolation:
| Module | Responsibility |
|---|---|
domain.py |
Plain data types — PrintOptions, PrintResult, JobState, enums |
commands.py |
CommandRunner — the single seam for external commands (no shell, captures output) |
storage.py |
StateStore — persistent key/value store with atomic update() (JsonFileStore / InMemoryStateStore) |
interfaces.py |
Abstract PrinterInterface, FileProcessorInterface, AuthManagerInterface, PrinterSettingsStoreInterface |
adapters.py |
SystemPrinter (CUPS), LibreOfficeFileProcessor, auth + settings stores |
service.py |
PrinterBotService — backend-agnostic business logic |
ui.py |
Pure keyboard/option logic (build_options_keyboard, apply_option_action) — unit-tested without Telegram |
bot.py |
TelegramPrinterBot — Telegram I/O; offloads blocking work off the event loop |
app.py |
setup_logging + main wiring |
printerbot/__init__.py re-exports the public API, so from printerbot import … works from anywhere.
- Python 3.11+ and the
python-telegram-botpackage:pip3 install python-telegram-bot - LibreOffice and poppler-utils (
pdftoppm,pdfinfo). Install with your package manager, e.g.apt install libreoffice poppler-utils - CUPS, with at least one configured printer (
lp,lpstat,cancel)
Put your bot token in ./token and the shared password in ./auth_password, then run from the
project directory:
python3 -m printerbot # or: make run
The included Makefile renders printerbot.service.in for this checkout — its directory, your
user, and the active python3 — so nothing is hardcoded. Run it from the directory you want the
bot to live in:
make install # per-user service (systemctl --user), runs as you, no root
This installs the unit to ~/.config/systemd/user/, starts it, and enables lingering so it keeps
running after you log out. Follow logs with journalctl --user -u printerbot.service -f, and
remove it with make uninstall.
Prefer a system-wide service (starts at boot independent of any login)?
make install-system # installs to /etc/systemd/system with User=<you> (uses sudo)
make print-unit shows the rendered unit without installing anything; make help lists all targets.
pip3 install pytest pytest-asyncio
python3 -m pytest tests.py -v
To measure coverage (as CI does):
pip3 install pytest-cov
python3 -m pytest tests.py --cov=printerbot --cov-report=term-missing