morz-infoboard/API-MQTT-VERTRAG.md
2026-03-22 13:06:31 +01:00

11 KiB

Info-Board Neu - API- und MQTT-Vertrag

Ziel

Dieses Dokument beschreibt die technische Arbeitsteilung zwischen HTTPS-API und MQTT.

Grundregel:

  • HTTPS fuer Daten, Uploads, Konfiguration und Authentifizierung
  • MQTT fuer Ereignisse, Heartbeats, Status und Fernsteuerung

Architekturprinzip

Der Player arbeitet autonom aus lokalem Zustand.

Das bedeutet:

  • die API liefert Konfiguration, Playlist und Medieninformationen
  • der Player cached diese Daten lokal
  • MQTT informiert ueber Aenderungen und traegt leichte Steuerkommandos
  • bei Ausfall der Verbindung laeuft der Player mit dem letzten gueltigen Stand weiter

HTTPS-API

Authentifizierung

Die Web-Oberflaechen nutzen benutzerbezogene Sessions oder Tokens.

Die Player nutzen ein geraetebezogenes Token.

Empfohlene Aufteilung:

  • Browser-UI: Cookie-Session oder JWT
  • Player: statischer oder rotierbarer API-Token je Screen

API-Bereiche

1. Auth

Zweck:

  • Login
  • Logout
  • Session-Pruefung

Beispiel-Endpunkte:

  • POST /api/v1/auth/login
  • POST /api/v1/auth/logout
  • GET /api/v1/auth/me

2. Tenants und Benutzer

Zweck:

  • Verwaltung von Firmen und Benutzern

Beispiel-Endpunkte:

  • GET /api/v1/tenants
  • POST /api/v1/tenants
  • GET /api/v1/tenants/:tenantId/users
  • POST /api/v1/tenants/:tenantId/users

3. Screens

Zweck:

  • technische und fachliche Verwaltung der Monitore

Beispiel-Endpunkte:

  • GET /api/v1/screens
  • GET /api/v1/screens/:screenId
  • PATCH /api/v1/screens/:screenId
  • GET /api/v1/screens/:screenId/status
  • GET /api/v1/screens/:screenId/snapshots/latest

3a. Provisionierung

Zweck:

  • neue Screens im Admin-Backend anlegen und technisch ausrollen
  • Provisionierungslaeufe starten, beobachten und auswerten

Beispiel-Endpunkte:

  • POST /api/v1/screens/provision
  • GET /api/v1/provisioning-jobs
  • GET /api/v1/provisioning-jobs/:jobId
  • POST /api/v1/provisioning-jobs/:jobId/retry
  • POST /api/v1/provisioning-jobs/:jobId/cancel

4. Medien

Zweck:

  • Uploads
  • Listenansicht
  • Loeschen
  • Metadatenbearbeitung

Beispiel-Endpunkte:

  • GET /api/v1/media
  • POST /api/v1/media/upload
  • POST /api/v1/media/import-url
  • PATCH /api/v1/media/:mediaId
  • DELETE /api/v1/media/:mediaId

5. Playlists

Zweck:

  • Playlist lesen und bearbeiten
  • Reihenfolge und Zeitfenster verwalten

Beispiel-Endpunkte:

  • GET /api/v1/screens/:screenId/playlist
  • PUT /api/v1/screens/:screenId/playlist
  • POST /api/v1/screens/:screenId/playlist/items
  • PATCH /api/v1/screens/:screenId/playlist/items/:itemId
  • DELETE /api/v1/screens/:screenId/playlist/items/:itemId

5a. Globale Templates und Kampagnen

Zweck:

  • globale monitoruebergreifende Templates verwalten
  • Kampagnen konfigurieren, aktivieren und deaktivieren
  • Screens gezielt global uebersteuern

Beispiel-Endpunkte:

  • GET /api/v1/templates
  • POST /api/v1/templates
  • GET /api/v1/templates/:templateId
  • PATCH /api/v1/templates/:templateId
  • POST /api/v1/templates/:templateId/scenes
  • PATCH /api/v1/templates/:templateId/scenes/:sceneId
  • POST /api/v1/campaigns
  • PATCH /api/v1/campaigns/:campaignId
  • POST /api/v1/campaigns/:campaignId/activate
  • POST /api/v1/campaigns/:campaignId/deactivate
  • PUT /api/v1/campaigns/:campaignId/assignments

6. Player-Sync

Zweck:

  • geraeteseitiger Abruf von Konfiguration und Daten
  • differenzieller Sync ueber Revisionen

Beispiel-Endpunkte:

  • POST /api/v1/player/register
  • GET /api/v1/player/config
  • GET /api/v1/player/playlist
  • GET /api/v1/player/campaign
  • GET /api/v1/player/media-manifest
  • GET /api/v1/player/media/:mediaId/download
  • POST /api/v1/player/status
  • POST /api/v1/player/snapshot

7. Admin-Kommandos

Zweck:

  • Ausloesen von Fernaktionen

Beispiel-Endpunkte:

  • POST /api/v1/screens/:screenId/commands/reload
  • POST /api/v1/screens/:screenId/commands/restart-player
  • POST /api/v1/screens/:screenId/commands/reboot
  • POST /api/v1/screens/:screenId/commands/display-on
  • POST /api/v1/screens/:screenId/commands/display-off

Provisionierungs-API

POST /api/v1/screens/provision

Legt einen neuen Screen an und startet einen Provisionierungsjob.

Erwartete Eingaben mindestens:

  • screen_slug oder display_id
  • screen_name
  • tenant_id optional, falls direkt zugeordnet werden soll
  • target_ip
  • target_port optional, Default 22
  • remote_user, Default root
  • auth_mode
  • password oder private_key_ref fuer die Erstverbindung
  • optionale technische Parameter wie rotation, resolution, fallback_dir

Serverseitiger Ablauf:

  1. Screen-Datensatz anlegen
  2. Provisionierungsjob anlegen
  3. Secret nur kurzlebig oder referenziert speichern
  4. Worker/Jobrunner startet Ansible- oder SSH-gestuetzten Rollout
  5. nach Erfolg meldet sich der Screen kuenftig regulaer ueber seinen Agenten

Antwort mindestens:

  • screen_id
  • provisioning_job_id
  • status

GET /api/v1/provisioning-jobs/:jobId

Liefert:

  • Jobstatus
  • aktuelle Stage
  • Zeitstempel
  • letzte Meldungen
  • Fehlerursache bei Fehlschlag

API-Antworten fuer den Player

GET /api/v1/player/config

Liefert:

  • screen_id
  • screen_slug
  • config_revision
  • player_settings
  • fallback_dir
  • snapshot_interval_seconds
  • offline_overlay_enabled
  • rotation

GET /api/v1/player/playlist

Liefert:

  • playlist_id
  • playlist_revision
  • default_duration_seconds
  • fallback_enabled
  • items[]

Jedes Item enthaelt mindestens:

  • id
  • type
  • src
  • duration_seconds
  • load_timeout_seconds
  • cache_policy
  • on_error
  • retry_count
  • valid_from
  • valid_until
  • enabled

GET /api/v1/player/campaign

Liefert die fuer den Screen aktuell relevante globale Uebersteuerung.

Liefert:

  • campaign_revision
  • active_campaign nullable

Wenn active_campaign gesetzt ist, enthaelt es mindestens:

  • campaign_id
  • template_id
  • name
  • priority
  • valid_from
  • valid_until
  • override_mode
  • scenes[]

Jede Scene enthaelt mindestens:

  • id
  • type
  • src
  • duration_seconds
  • load_timeout_seconds
  • cache_policy
  • on_error
  • layout_json

GET /api/v1/player/media-manifest

Liefert:

  • media_revision
  • assets[]

Jeder Asset-Eintrag enthaelt mindestens:

  • id
  • type
  • source_kind
  • download_url nullable
  • original_url nullable
  • checksum
  • size_bytes
  • mime_type
  • cache_required

MQTT-Verwendung

MQTT dient nur der schnellen, leichten Signal- und Statuskommunikation.

Nicht ueber MQTT transportieren:

  • Datei-Uploads
  • grosse JSON-Payloads fuer komplette Medienlisten
  • eigentliche Mediendateien

MQTT-Topics

Heartbeat

  • signage/screen/<screen-id>/heartbeat

Payload-Beispiel:

{
  "screen_id": "info01",
  "ts": "2026-03-22T12:00:00Z",
  "online": true,
  "server_connected": true,
  "mqtt_connected": true,
  "player_version": "0.1.0",
  "uptime_seconds": 86400
}

Status

  • signage/screen/<screen-id>/status

Payload-Beispiel:

{
  "screen_id": "info01",
  "ts": "2026-03-22T12:00:00Z",
  "current_item_id": "pli_123",
  "current_item_type": "image",
  "current_item_label": "Begruessung",
  "current_item_started_at": "2026-03-22T11:59:45Z",
  "current_item_duration_seconds": 20,
  "overlay_state": "online",
  "cache_state": "ok",
  "error_code": null,
  "error_message": null
}

Events

  • signage/screen/<screen-id>/event

Typische Events:

  • playlist_changed
  • campaign_changed
  • sync_completed
  • sync_failed
  • item_failed
  • browser_restarted
  • snapshot_uploaded

Commands

  • signage/screen/<screen-id>/command

Payload-Beispiel:

{
  "command_id": "cmd_456",
  "type": "reload",
  "payload": {},
  "requested_at": "2026-03-22T12:00:00Z"
}

ACK

  • signage/screen/<screen-id>/ack

Payload-Beispiel:

{
  "command_id": "cmd_456",
  "screen_id": "info01",
  "ts": "2026-03-22T12:00:02Z",
  "result": "ok",
  "message": "playlist reloaded"
}

QoS- und Broker-Hinweise

Empfehlung:

  • Heartbeat: QoS 0 oder 1
  • Status: QoS 0 oder 1
  • Commands: QoS 1
  • ACK: QoS 1

Zusatzempfehlungen:

  • Last-Will fuer Offline-Erkennung nutzen
  • retained Messages nur sparsam und gezielt einsetzen
  • kein Missbrauch von retained Commands

Trennung von Pull und Push

Pull ueber HTTPS

Der Player holt aktiv:

  • Konfiguration
  • Playlist
  • Medienmanifest
  • eigentliche Medien

Push ueber MQTT

Der Server signalisiert aktiv:

  • es gibt neue Konfiguration
  • es gibt neue Playlist-Daten
  • fuehre einen Befehl aus

Die eigentliche Erstprovisionierung laeuft nicht ueber MQTT, sondern ueber einen serverseitigen Job mit SSH/Ansible.

Beispielablauf bei Playlist-Aenderung:

  1. Benutzer speichert Playlist in der Web-UI
  2. Server erhoeht playlist_revision
  3. Server sendet Event oder Command reload
  4. Player ruft GET /api/v1/player/playlist ab
  5. Player synchronisiert fehlende Medien
  6. Player bestaetigt erfolgreichen Reload

Beispielablauf bei Aktivierung einer globalen Kampagne:

  1. Admin aktiviert eine Kampagne
  2. Server erhoeht campaign_revision
  3. Server sendet Event oder Command reload
  4. Player ruft GET /api/v1/player/campaign ab
  5. Player synchronisiert kampagnenbezogene Medien
  6. Player setzt den Inhaltsmodus auf campaign
  7. Nach Deaktivierung oder Ablauf faellt der Player wieder auf tenant_playlist oder fallback zurueck

Offline-Verhalten

Wenn HTTPS ausfaellt

  • Player nutzt letzte lokale Konfiguration
  • Player nutzt letzte lokale Playlist
  • Player nutzt lokalen Mediencache
  • Overlay signalisiert Offline-Zustand

Wenn MQTT ausfaellt

  • Player laeuft normal weiter
  • periodischer HTTPS-Sync erkennt spaetere Aenderungen trotzdem
  • Admin-Kommandos werden ggf. verzoegert, aber nicht die Anzeige selbst

Wenn beides ausfaellt

  • Player bleibt autonom betriebsfaehig
  • keine frischen Inhalte oder Befehle mehr
  • bestehende Playlist/Fallback laufen weiter

Web-Inhalte und Fehlerstrategie

Webseiten sind der stoeranfaelligste Medientyp.

Regeln:

  • Chromium zeigt immer nur die lokale player-ui
  • player-ui bettet Web-Inhalte kontrolliert ein
  • jedes Web-Item hat einen load_timeout_seconds
  • bei Fehler gilt on_error

Typische Fehlerpfade:

  • 404 oder DNS-Problem -> skip oder fallback
  • langsamer Ladevorgang -> Timeout -> retry oder skip
  • Renderer-Fehler -> lokaler Watchdog startet den Renderer neu

Screenshot-Upload

Der Player erstellt Screenshots:

  • bei Item-Wechsel
  • zyklisch
  • auf Admin-Anforderung

Ablauf:

  1. Player erzeugt Bild lokal
  2. Player sendet es per HTTPS an POST /api/v1/player/snapshot
  3. Server speichert das Bild und aktualisiert die letzte Vorschau des Screens

Sicherheitsgrundsaetze

  • jeder Player hat eine eigene technische Identitaet
  • API und MQTT werden authentifiziert
  • Tenant-Benutzer sehen nur tenantbezogene Objekte
  • Admin-Kommandos werden serverseitig protokolliert
  • Screenshots und Statusdaten sind nur fuer berechtigte Nutzer sichtbar

Minimale API-Frequenzen

Sinnvolle Startwerte:

  • Heartbeat alle 30 Sekunden
  • Status-Update bei Item-Wechsel und zusaetzlich alle 60 Sekunden
  • Konfigurations-/Playlist-Poll als Fallback alle 5 Minuten
  • Snapshot alle 60 Sekunden oder bei Item-Wechsel

V1-Abgrenzung

Fuer Version 1 bewusst nicht zwingend enthalten:

  • Live-Video-Stream der Monitore
  • komplexe Kampagnenlogik mit Prioritaeten
  • Multi-Screen-Synchronisation auf Frame-Ebene
  • serverseitiges Video-Transcoding

Empfohlene naechste Dokumente

Als direkte Folge sollten entstehen:

  • technisches Player-Konzept
  • Server-Komponentenplan
  • Ansible-Deploymentplan
  • Rechte- und Authentifizierungskonzept