# Installing and running the server The server is a Python package, `todays_paper_web`, managed with [uv](https://docs.astral.sh/uv/). ## Local development ```bash 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=&format=png ``` `uuid` is the config name (see {doc}`screen-design/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 ```bash 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 {doc}`screen-design/config-format`): | Variable | Default | Purpose | | --- | --- | --- | | `CONFIG_DIR` | `configs` | Directory (or S3 prefix) the server loads device configs and screen templates from. | | `CACHE_DIR` | `cache` | Where rendered screens (`.png` / `.epdiy`) and per-device request logs are written. | | `TP_STORAGE` | `local` | Storage backend: `local` (reads `CONFIG_DIR`/`CACHE_DIR` from disk) or `s3`. | | `TP_S3_BUCKET` | — | Bucket name, required when `TP_STORAGE=s3`. | | `PORT` | `8000` | 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//` 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: ```bash # from web/ uv run todays_paper -o output.png ``` `` is the config name *without* the `.yml` extension (`dev`, not `dev.yml`). Useful flags: - `-s ` — 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.