Config format

Each device has one YAML file, e.g. configs/dev.yml. The filename without .yml is the config name — it’s what a device sends as its uuid when it requests /paper, and what you pass to the todays_paper CLI. A config has four top-level sections.

settings

settings:
  timezone: Europe/Stockholm

Key

Description

timezone

An IANA timezone name. Used for scheduling (see below) and for the timestamp/tomorrow values templates receive.

sources

Named data sources a template can pull from with source("name"). Each entry picks a registered DataSource by name and passes it a params dict, which becomes that source’s attributes (e.g. self.url, self.lat — see Data sources for what each source type expects):

sources:
  weather:
    source: weather.yr
    params:
      lat: 55.64277
      lon: 13.20638
      altitude: 17
  school_work:
    source: calendar.ical
    params:
      url: https://cal.vklass.se/....ics

A source is instantiated once per config load and reused across every screen render — .fetch() is called fresh each time a template calls source(...), so a source that hits a network API does so on every render, not once at startup.

screens

screens:
  width: 1448
  height: 1072
  rotate: 0
  family_calendar:
    template: home/family_calendar.xml.jinja
  weather:
    template: weather.xml.jinja

Key

Description

width, height

The panel’s resolution in pixels. Required — rendering fails without them. These are handed to every template as the width/height variables, and this is also what the root <screen> element’s size is always taken from (see Layout: box, column, row, screen); a width/height written directly on <screen> in the template is ignored. Use 1024×758 for an ED060XC3 panel, 1448×1072 for an ED060KC1 panel (see the firmware’s screen.h).

rotate

Degrees to rotate the final composited image (e.g. 90/180/270), applied after the template has rendered at width×height. Use this rather than swapping width/height if a panel is mounted rotated relative to how the template is authored.

Any other key

A screen name → {template: <path>}. The path is resolved relative to CONFIG_DIR (see Installing and running the server’s note on the storage backends) — home/family_calendar.xml.jinja means configs/home/family_calendar.xml.jinja under local storage.

scheduler

A weekly timetable of which screen name is “current” at any given moment:

scheduler:
  - days: [1, 2, 3, 4, 5]
    hour: 7
    screen: family_calendar
  - days: [6, 7]
    hours: [9, 14]
    screen: weather

Each rule is {days: [...], hour: N | hours: [N, ...], screen: <name>}. days uses ISO weekday numbers (1 = Monday … 7 = Sunday). Use hour for a single trigger time or hours for several. The server picks whichever rule’s next occurrence is soonest without being in the past, re-evaluating shortly before each scheduled change (see the Runner/Scheduler classes in Python API reference for the exact mechanics) — so a screen effectively stays up until the next rule’s time arrives, in whatever order the rules fire across the week.

This section is ignored when a screen is picked explicitly via the CLI’s -s flag (there’s no equivalent override on the HTTP API — a device always gets whatever the scheduler says is current).