morz-infoboard/docs/API-MQTT-VERTRAG.md
Jesko Anschütz 585cb83ed0 MQTT-Playlist-Push: Änderungen erreichen Client binnen 5 Sekunden
Backend published auf signage/screen/{slug}/playlist-changed nach
Playlist-Mutationen (2s Debounce). Agent subscribed und fetcht
Playlist sofort (3s Debounce). 60s-Polling bleibt als Fallback.

Neue Packages: mqttnotifier (Backend), mqttsubscriber (Agent)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 11:35:50 +01:00

3.7 KiB

Info-Board Neu - MQTT-Vertrag

Vertrag zwischen Backend und Agent für die Echtzeit-Synchronisation von Playlist-Änderungen und Gerätebefehlen.


Überblick

Das Messaging-System nutzt MQTT für:

  • Playlist-Mutations-Benachrichtigungen: Backend → Agent
  • Device-Commands: Backend → Agent (zukünftig: reload, restart_player, reboot, display_on/off)
  • Heartbeat & Status: Agent → Backend (siehe PLAYER-STATUS-HTTP.md)

Alle Topics folgen dem Naming-Pattern: signage/{component}/{screenSlug}/{event}


Topics

Backend publishes

signage/screen/{screenSlug}/playlist-changed

Publisher: Backend Subscriber: Agent

Wird nach jeder Mutation der Playlist gepublished (Add, Remove, Reorder, Enable/Disable Item).

Payload:

{
  "ts": 1711268440000
}
  • ts: Unix-Zeitstempel in Millisekunden des Änderungsereignisses auf dem Backend

Verhalten:

  • Backend debounced Änderungen über 2 Sekunden
  • Mehrere schnelle Mutationen werden zu einem Event zusammengefasst
  • Garantiert mindestens ein Event pro logischer Änderung

Agent-Reaktion:

  • Agent empfängt das Event
  • Agent debounced die Verarbeitung über 3 Sekunden
  • Agent startet sofortiges Playlist-Fetch via HTTP GET /api/v1/screens/{screenSlug}/playlist
  • Agent speichert die Playlist lokal und signalisiert dem Browser einen Reload

Implementierung (Agent):

// Pseudocode
func OnPlaylistChanged(msg PlaylistChangedMessage) {
    if debounceTimer.running {
        debounceTimer.reset()
    } else {
        debounceTimer.start(3 * time.Second)
    }
}

func onDebounceExpire() {
    playlist := fetchPlaylistViaHTTP()
    saveToLocalCache(playlist)
    signalBrowserReload()
}

Zukünftige Topics

Die folgenden Topics sind geplant für Phase 5 (Prototyping) und später:

signage/screen/{screenSlug}/device-command

Publisher: Backend Subscriber: Agent

Befehl-Queue für Device-Steuerung.

Payload:

{
  "cmd_id": "uuid",
  "command": "reload|restart_player|reboot|display_on|display_off",
  "ts": 1711268440000
}

Agent-Reaktion:

  • Befehl ausführen
  • ACK via HTTP POST zu PUT /api/v1/screens/{screenSlug}/command-ack

Beispiel-Flow: Playlist-Update

Admin: Click "Speichern" in Playlist-UI
  ↓
Backend: Playlist-Mutation in DB schreiben
  ↓
Backend: `playlist-changed` mit ts=now nach 2s Debounce publifyen
  ↓
Agent: Event empfangen, 3s Debounce starten
  ↓
Agent: Nach 3s → HTTP GET /api/v1/screens/{slug}/playlist
  ↓
Backend: Aktuelle Playlist zurückgeben
  ↓
Agent: Lokal speichern, Browser signalisieren "reload"
  ↓
Browser: Neuer Content geladen und abgespielt

MQTT-Verbindungspezifikation

(Siehe PLAYER-KONZEPT.md und Provisioning-Variablen für Broker-URL, Authentifizierung und Retry-Logik)

  • Broker-Adresse: Über Provisioning konfigurierbar (Standard: tcp://backend:1883)
  • Client-ID: {tenantSlug}/{screenSlug} (eindeutig pro Screen)
  • Username/Password: Device-spezifische Credentials (OAuth-ähnlich)
  • QoS-Level: 1 (At-Least-Once für Critical-Events)
  • Retain: nein (Event-Natur, nicht State)
  • Heartbeat: Separat via HTTP (siehe PLAYER-STATUS-HTTP.md)

Notizen für Implementierer

  1. Replay bei Reconnect: Topics haben retain: false, daher entfallen keine Events bei Trennung. Der Agent synchronisiert sich nach Reconnect via regulärem Status-Endpoint.
  2. Ordering: Mehrere Events zu einem Screen sind ordered; Ordering über Screen-Grenzen hinweg ist nicht garantiert.
  3. Fehlerbehandlung: Fehlgeschlagene Playlisten-Fetches werden vom Agent nach Standard-Retry-Logik wiederholt.
  4. Version der Spec: v1.0 (März 2026)