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>
136 lines
3.7 KiB
Markdown
136 lines
3.7 KiB
Markdown
# 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:**
|
|
```json
|
|
{
|
|
"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):**
|
|
```go
|
|
// 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:**
|
|
```json
|
|
{
|
|
"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)
|