Install Tesserae¶
Tesserae is the server: it serves the admin UI, renders dashboards, and publishes frames out to your panels. It runs on macOS, Linux, Raspberry Pi, and Windows. Most clients (Pi / ESP32) consume frames via MQTT, so for those you'll want an MQTT broker (e.g. Mosquitto, or the one built into Home Assistant) and at least one client to paint a panel. TRMNL / KOReader devices poll the server over HTTP instead, no broker required.
Or use Docker (or Home Assistant)
If you'd rather not touch Python, the Docker install path
has you running with one docker compose up -d. Running Home Assistant?
See the Home Assistant integration page, Tesserae
can install as an HA Add-on (Ingress-tabbed inside HA's sidebar) and
publish MQTT discovery so every device shows up as an HA entity.
Quick install¶
The installer:
- Sanity-checks
git+ Python 3.11+ - Clones the repo (default
~/tesserae, override withTESSERAE_DIR) - Creates a venv and installs the project
- Asks for a port (default
8765) - Installs Chromium via Playwright for webpage rendering (with a system-browser fallback, see below)
- Writes a
run.sh(orrun.ps1) shortcut in the install dir
When it finishes, start the server with ./run.sh (or .\run.ps1) from the
install dir and open http://localhost:8765/.
Manual install¶
If you'd rather do it by hand (or already cloned the repo):
git clone https://github.com/dmellok/tesserae.git
cd tesserae
python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m app.main # production: waitress, port 8765
.venv/bin/python -m app.main --dev # Flask dev server: auto-reload + debugger
python -m app.main runs under
waitress, a pure-Python
production WSGI server, the same command works on a Raspberry Pi appliance, no
nginx required for a single-user install. --dev opts into Flask's dev server
when you're hacking on the admin.
Windows line endings
If .\install.ps1 fails to parse on PowerShell 5.1, your checkout may have
LF line endings. git pull to get the .gitattributes fix, or run the
manual steps above with .venv\Scripts\python.exe -m app.main.
First run¶
- Open
http://127.0.0.1:8765/, on first boot you're sent to/setupto pick an admin password. - Sign in at
/login. The onboarding wizard walks you through pointing Tesserae at your MQTT broker (if any), registering your first device, and composing your first dashboard, the same screens you'd reach via Settings if you skipped it. - Settings → Server holds the post-onboarding knobs: broker host / credentials, base URL the panel uses to fetch frames, optional mDNS broadcast of
tesserae.local, and Chromium fallback for webpage rendering. - Renderers and plugins that declare settings show up as their own sections, generated from their manifests.
To preview a single widget without composing a dashboard, run --dev, sign
in, then open
http://127.0.0.1:8765/_test/render?plugin=clock_analog&size=md in your
browser. /_test/render needs the dev (or test) server and a logged-in
session, it isn't loopback-exempt. The loopback bypass is only for
/compose/, /renders/, and /plugins/<id>/<asset>, which the in-process
Playwright renderer fetches without a session.
Chromium for webpage rendering¶
The Send → Webpage tab and the webpage widget screenshot pages with
headless Chromium via Playwright. Playwright ships its own binaries for most
platforms; on 32-bit Raspberry Pi OS it doesn't, so the installer falls back to
a system browser. To point at one yourself:
…or write the path to data/core/.chromium (single line). If no browser is
found, everything except webpage rendering still works.
Webhook push¶
External systems (Home Assistant automations, cron, GitHub Actions, shortcuts apps, anything that speaks HTTP) can trigger an on-demand re-render + push without going through the admin UI.
- Settings → System → Webhook. Click Generate token the first time, or Rotate to invalidate the old one. The token is shown masked after creation; copy it once.
-
Call the endpoint:
-
Response:
200once the request is queued (the actual render happens asynchronously);401if the token is wrong;404if the named page doesn't exist;429if you're hitting it too fast.
The endpoint re-renders the named page and publishes the frame to
every device bound to it. Useful patterns: an HA automation that pings
/api/v1/push when a person leaves home so the next refresh shows an
empty-house mode; a cron that triggers a fresh render at sunset so
dusk lighting widgets repaint promptly. The token lives at
data/core/settings.json under webhook.token and is masked on disk.
Backup, export, import¶
Settings → System → Data exports your full Tesserae state (pages, themes, devices, plugin settings, secrets) as a single ZIP suitable for moving to another install or restoring after a wipe.
- Export: clicks straight to a
tesserae-export-<timestamp>.zipdownload. The ZIP includes every page JSON, theme definition, font pick, device registration, and per-plugin settings (with secrets embedded, treat the file like a credential). - Import: upload a ZIP from another install. The server validates every file against the matching JSON Schema before writing, then replaces state atomically. On Docker / HA Add-on installs the in-place restart happens automatically; on a venv install the page flashes a "stop and restart" hint so nothing is left mid-flight.
The two endpoints land under /settings/system/data/export and
/settings/system/data/import; they're admin-only.
mDNS, tesserae.local¶
tesserae.local is the friendly hostname Tesserae can broadcast on
your LAN so panels and clients don't need a hard-coded IP. Toggle it
via Settings → Server → mDNS (off by default, the broadcast
needs UDP multicast on port 5353, which some hosting setups disallow).
When enabled, both the admin UI and the panel-side /compose/ /
/renders/ routes are reachable at http://tesserae.local:8765/.
Clients with their own captive portal (ESP32) use a different scheme:
tesserae-<device-id>.local for the portal, then they connect out to
the server URL you give them.
Running the tests¶
The renderer, transport, push pipeline, auth, and settings flow are all covered with no broker or Chromium dependency.
Next steps¶
- Install a client for your panel hardware
- Set up a device, register it, calibrate orientation, bind a dashboard
- Home Assistant integration, HA Add-on install + MQTT auto-discovery
- Browse the widgets you can place on a dashboard