announcer/.env.example
Kent c4a15799dd Mesh: én sentral fordeler til flere soner
Flere anlegg – hovedscene, resepsjon, crew – og ett sted å sende fra, med
avkryssing for hvilke soner meldingen skal til.

Sentralen er en vanlig announcer med [zones] i config. En sone er en vanlig
announcer med ANNOUNCER_MESH_SECRET. Samme image, ingen mode, og en sone kan
brukes alene hvis sentralen faller ut. Hver avhengighet med C-kode har
aarch64-wheel i uv.lock, så det samme bildet går på en Raspberry Pi uten å
kompilere noe.

Sentralen syntetiserer én gang og sender ferdig WAV (POST /api/play,
multipart). Sonen trenger da verken nett, edge-tts eller Pipers 670 MB for
det den får – Item.wav er hele endringen i avspillingen. Køene forblir per
sone: dispatcheren har egen tråd og egen kø, leverer til hver sone i hver sin
tråd med timeout, og går videre. En opptatt hovedscene holder ikke igjen
resepsjonen, og en sone som er nede feiler alene – synlig per sone i UI og
revisjonslogg.

Auth gjenbrukes: ny leverandør mesh på header X-Mesh-Key (ikke Bearer – den
leses av JWT-leverandøren, som avviser alt som ikke er et JWT før neste får
prøve), med én handling, play. To regler som fulgte med:

- play følger aldri med «alt åpent». Uten det kunne hvem som helst POSTe en
  WAV til en åpen sone og få den spilt. Testen for åpen modus fanget det.
- En legitimasjon som vises fram og er feil gir 401 også der gjester ellers
  har lov. Før slapp en feil PIN i åpen modus stille gjennom som gjest.

mesh teller ikke som innlogging for folk: en sone med bare nøkkelen har
fortsatt åpen side lokalt.

Planlagte sendinger husker sonene sine og fordeles gjennom dispatcheren;
planen ender som sent hvis minst én sone tok imot, med «hovedscene: kø #3,
crew: nede» som note.

Hodeløs Pi: install.sh kjører loginctl enable-linger, ellers finnes ikke
lydsocketen når ingen logger inn. docs/mesh.md tar også raspi-config for
jack framfor HDMI.

38 nye tester, 148 totalt. Fordelingen testes uten nett med stubbet
transport; selve HTTP-en testes mot en levende werkzeug-server, så den
håndrullede multiparten møter Flask sin parser. Verifisert i compose med
sentral og to soner: til alle, bare til én, og én sone stoppet.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-09 02:22:05 +02:00

42 lines
1.3 KiB
Text

# Kopier til .env. install.sh lager den for deg med riktige verdier.
#
# cp .env.example .env
# Bruker-ID som eier lydsocketen på verten. Stemmer ikke denne, kommer det
# ingen lyd. Finn den med: id -u ; id -g
PUID=1000
PGID=1000
XDG_RUNTIME_DIR=/run/user/1000
# Hvilken adresse sida skal svare på. Dette er det som avgrenser tilgang:
# Docker publiserer forbi ufw, så en ufw-regel hjelper ikke her.
# 0.0.0.0 alle nett maskina er på
# 100.75.x.x bare NetBird
# 127.0.0.1 bare maskina selv
BIND_IP=0.0.0.0
ANNOUNCER_PORT=8090
# Tidssone for logg og visning. Planlagte sendinger lagres som absolutt
# tid, så denne kan ikke gjøre dem feil.
TZ=Europe/Oslo
# Lydutgang. Tom = systemets standard. Finn navn med: pactl list short sinks
ANNOUNCER_SINK=
# Overstyrer tittelen uten en config.toml.
ANNOUNCER_TITLE=
# Full URL utenfra. Trengs bare for OIDC bak en omvendt proxy.
ANNOUNCER_PUBLIC_URL=
# Mesh. Samme verdi på sentralen og alle soner. Tom = ingen mesh.
# Lag en: openssl rand -hex 24
ANNOUNCER_MESH_SECRET=
# --- hemmeligheter -------------------------------------------------------
# Tom = av. Se config.example.toml og docs/crew-integration.md.
ANNOUNCER_PIN=
ANNOUNCER_JWT_SECRET=
ANNOUNCER_OIDC_CLIENT_SECRET=
# Tom = genereres og lagres i data/instance/secret_key.
ANNOUNCER_SECRET_KEY=