Kundendisplay
Das Kundendisplay (de.profipos.kundendisplay, WPF / .NET 8, Fullscreen)
spiegelt live den Warenkorb der gepaarten Kasse, zeigt einen großen
Restbetrag während des Bezahlvorgangs und fährt im Leerlauf eine
Werbe-Slideshow. Live-Build seit 13.06.2026: Jenkins #8 (Commit
6968655).
Modi (DisplayStateService)
| Modus | Inhalt |
|---|---|
| Werbung | Slideshow (Bild + Video) oder Idle-Standby („Willkommen“ / „Schönen Aufenthalt“) |
| Warenkorb | Live-Positionsliste (Menge · Bezeichnung · Einzelpreis · Zwischensumme), Bon-Nr + Tisch, Summe + Rabatt |
| Bezahlung | NFC-Ellipse (Statusfarbe) + großer Restbetrag (Viewbox) + Hinweistext |
| Pairing | QR-Code (DeviceUuid) + Server-Info + Status |
MQTT-Topic-Schema
Base: profipos/{mandant_uuid}/{standort_uuid}/anzeige/{kasse_uuid_or_device_uuid}/
| Suffix | DTO | Aktion |
|---|---|---|
warenkorb_update | WarenkorbUpdateEvent | Spiegelt Positionsliste, schaltet auf Warenkorb-Modus |
bezahlung_update | BezahlungUpdateEvent | 5 Status: warten / verarbeitung / erfolg / fehler / abgebrochen |
session_close | SessionCloseEvent | Zurück zu Werbung |
werbung_set | WerbungSetEvent | Setzt neue Slideshow-Medien |
befehl | BefehlEvent | Custom-Befehle (Reset, Refresh, …) |
pair_event | PairEvent | Pairing-Bestätigung mit MQTT-Creds + Kasse/Mandant/Standort |
Vor Pairing abonniert der Client Wildcard
profipos/+/+/anzeige/{deviceUuid}/+, nach Pairing wechselt er auf
profipos/{mandant}/{standort}/anzeige/{kasse}/+.
Pairing-Flow
Siehe Pairing-Architektur. Kurzform:
DeviceUuidaus%LOCALAPPDATA%\ProfiPOS\Kundendisplay\settings.json.- UDP-Discovery (Magic
PROFIPOS-DISCOVER-V1, Port 34567). - Parallel: REST-Poll
POST /api/v1/anzeige/pair(5 s) und MQTT-Subpair_event. Wer zuerst kommt, gewinnt (TaskCompletionSource). SchreibePairingAsync→ Settings →MqttClientServicereconnect.
Services (Dependency-Injection)
- Singleton:
SettingsStore,ServerApiClient,ServerStatusService,MqttClientService,UdpDiscoveryService,PairingCoordinator,DisplayStateService,MediaCacheService, alle 5 VMs,MainWindow. - Hosted:
ServerStatusService,MqttClientService,HeartbeatService. - HttpClientFactory: Named Clients
server-apiundmedia.
Heartbeat
HeartbeatService (BackgroundService, 30 s) →
POST /api/v1/heartbeat/anzeige mit
{device_uuid, modus, uptime_sek, version}. 404 wird leise toleriert
(Endpoint optional).
MediaCache
- Cache-Dir:
%LOCALAPPDATA%\ProfiPOS\Kundendisplay\media - Filename = SHA256(Url) — Hash-Verify bei jedem Treffer
- FIFO bei
MaxCacheMb(Default 500 MB) — ältestes File löschen - Atomic write
.tmp→ move
Window-Spezifika
WindowStyle=None,ResizeMode=NoResize,WindowState=Maximized.MonitorIndexaus Settings positioniert auf gewähltem Monitor.- ESC schließt App (Failsafe-Exit).
Cursor.Nonenur in Werbung + Pairing.- Statusleiste 38 px am unteren Rand: Server + MQTT + Modus + AppVersion.
Settings
// %LOCALAPPDATA%\ProfiPOS\Kundendisplay\settings.json
{
"Mqtt": { "Host": "10.1.1.20", "Port": 1883, "User": "...", "Pass": "...", "KeepAlive": 30 },
"ServerApi": { "BaseUrl": "http://10.1.1.20:8080", "TimeoutSeconds": 15 },
"Anzeige": { "MonitorIndex": 1, "IdleSekunden": 30 },
"Werbung": { "MaxCacheMb": 500, "SlideSekunden": 8 },
"Discovery": { "Port": 34567, "MagicString": "PROFIPOS-DISCOVER-V1" },
"DeviceUuid": "...",
"KasseUuid": "...",
"MandantUuid": "...",
"StandortUuid": "..."
}
IstGepairt = KasseUuid + MandantUuid + StandortUuid sind alle nicht leer.
Verwandte Themen
- Kasse (sendet die
warenkorb_update-Events) - Pairing
- MQTT-Topics