Installing and running the server
The server is a Python package, todays_paper_web, managed with uv.
Local development
uv sync
uv run uvicorn todays_paper_web.paper:app --reload --host 0.0.0.0
This starts the FastAPI app from todays_paper_web/paper.py on port 8000 by default, reloading on
code changes. A device (or curl) fetches its current screen with:
GET /paper?uuid=<config-name>&format=png
uuid is the config name (see Config format) — for a real device this is the
UUID it generated and persisted in its own NVS storage; for local testing it’s just the filename (minus
.yml) of one of the files under configs/. Omit format=png to get the raw e-paper epdiy image the
device itself consumes. POST /paper is what the firmware calls in practice, additionally reporting
battery voltage, temperature and firmware version.
Docker
docker build -t todays-paper-web .
docker run -p 8000:8000 -v "$(pwd):/app" todays-paper-web
The container runs the same uvicorn command, listening on $PORT (default 8000).
Configuration
The server has no config file of its own — behavior is controlled by environment variables and by the per-device YAML configs it loads (see Config format):
Variable |
Default |
Purpose |
|---|---|---|
|
|
Directory (or S3 prefix) the server loads device configs and screen templates from. |
|
|
Where rendered screens ( |
|
|
Storage backend: |
|
— |
Bucket name, required when |
|
|
Listen port (Docker only). |
With TP_STORAGE=local, every config’s files — templates, fonts, images — are resolved directly under
CONFIG_DIR, shared across all configs. With TP_STORAGE=s3, each config is namespaced under
configs/<config-name>/ in the bucket instead. Keep this in mind when deciding whether an asset (a
font, a shared partial template) belongs at the top of CONFIG_DIR or inside a specific config’s own
folder.
Rendering a screen without the server
Useful while designing a screen, since it doesn’t require running the FastAPI app or waiting for the scheduler:
# from web/
uv run todays_paper <config> -o output.png
<config> is the config name without the .yml extension (dev, not dev.yml). Useful flags:
-s <screen>— render a specific screen by name instead of whatever the scheduler would currently pick.-t "2024-12-25 08:00"— render as if it were this date/time, instead of now. Handy for testing time-of-day or day-of-week logic in a template without waiting for it to actually happen.-d— dump the intermediate rendered XML (after Jinja, before the widget tree walks it) to the log, which is the fastest way to debug a template that isn’t producing the layout you expect.-f {png,waveshare,epdiy}— output format; inferred from-o’s extension if omitted.
See also tpconvert (cli/convert.py) for converting a rendered image between png/waveshare/epdiy
after the fact.