README auf den gemergten Stand gebracht
Ergaenzt: Splashscreen als dritte Monitoransicht und Standard beim Start, Team-Datenbank, Debugfenster, Spiegelung des Adminpanels, Steuerung des Kiosk-Browsers, die zugehoerigen etc-, db- und score-Endpunkte sowie der Hinweis zur PORT-Variable. Korrigiert: Portangabe, Projektstruktur, Antwortformate und die Abhaengigkeitsliste. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
a3519f11d4
commit
a1cea9c37d
1 changed files with 124 additions and 25 deletions
147
README.md
147
README.md
|
|
@ -10,16 +10,24 @@ Das System besteht aus zwei Teilen:
|
||||||
|
|
||||||
| Teil | URL | Beschreibung |
|
| Teil | URL | Beschreibung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| **Monitor** | `http://<host>:3000/` | Vollbildanzeige für den Beamer/Monitor (Timer + Score) |
|
| **Monitor** | `http://<host>:3000/` | Vollbildanzeige für den Beamer/Monitor |
|
||||||
| **Admin-Panel** | `http://<host>:3000/admin` | Steuerung von Timer und Scoreboard |
|
| **Admin-Panel** | `http://<host>:3000/admin` | Steuerung von Timer, Scoreboard und Anzeige |
|
||||||
|
|
||||||
Alle Änderungen vom Admin-Panel werden über **WebSockets (Socket.IO)** in Echtzeit auf dem Monitor angezeigt — ohne Seiten-Reload.
|
Alle Änderungen vom Admin-Panel werden über **WebSockets (Socket.IO)** in Echtzeit auf dem Monitor angezeigt — ohne Seiten-Reload.
|
||||||
|
|
||||||
|
Der Monitor rendert je nach Serverzustand eine von drei Ansichten:
|
||||||
|
|
||||||
|
| Ansicht | Template | Wann |
|
||||||
|
|---|---|---|
|
||||||
|
| Splashscreen | `splashscreen.hbs` | Solange der Splashscreen aktiv ist (Standard beim Start) |
|
||||||
|
| Timer + Score | `indexScore.hbs` | Splashscreen aus, Scoreboard aktiv (Standard) |
|
||||||
|
| Nur Timer | `index.hbs` | Splashscreen aus, Scoreboard deaktiviert |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Voraussetzungen
|
## Voraussetzungen
|
||||||
|
|
||||||
- Node.js (v18 oder neuer empfohlen)
|
- Node.js (v18 oder neuer)
|
||||||
- npm
|
- npm
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -35,6 +43,18 @@ npm start
|
||||||
Der Server startet mit `nodemon` und ist anschließend unter Port **3000** erreichbar.
|
Der Server startet mit `nodemon` und ist anschließend unter Port **3000** erreichbar.
|
||||||
Der Socket.IO-Server läuft separat auf Port **3001**.
|
Der Socket.IO-Server läuft separat auf Port **3001**.
|
||||||
|
|
||||||
|
### Port ändern
|
||||||
|
|
||||||
|
Der HTTP-Port lässt sich über die Umgebungsvariable `PORT` setzen:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PORT=80 npm start
|
||||||
|
```
|
||||||
|
|
||||||
|
Auf dem Anzeige-Rechner (Raspberry Pi) wird Port **80** verwendet, damit der
|
||||||
|
Kiosk-Browser die Seite ohne Portangabe unter `http://localhost` öffnen kann.
|
||||||
|
Port 80 erfordert erhöhte Rechte.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Projektstruktur
|
## Projektstruktur
|
||||||
|
|
@ -43,27 +63,34 @@ Der Socket.IO-Server läuft separat auf Port **3001**.
|
||||||
scoreboard/
|
scoreboard/
|
||||||
├── app.js # Express-App, Middleware, Routen
|
├── app.js # Express-App, Middleware, Routen
|
||||||
├── bin/www # HTTP-Server, startet die App
|
├── bin/www # HTTP-Server, startet die App
|
||||||
|
├── db.json # Persistente Liste bekannter Teamnamen
|
||||||
├── controllers/
|
├── controllers/
|
||||||
│ ├── socketio.js # Socket.IO-Server (Port 3001)
|
│ ├── socketio.js # Socket.IO-Server (Port 3001)
|
||||||
│ ├── timer.js # Timer-Logik (Start, Pause, Reset, IncDec)
|
│ ├── timer.js # Timer-Logik (Start, Pause, Reset, IncDec)
|
||||||
│ ├── score.js # Score-Logik (Punkte, Teams, Seitenwechsel)
|
│ ├── score.js # Score-Logik (Punkte, Teams, Seitenwechsel)
|
||||||
│ └── cli.js # CLI-Controller (aktuell Testcode)
|
│ ├── db.js # Lesen/Schreiben der Teamnamen in db.json
|
||||||
|
│ ├── etc.js # Splashscreen-Status
|
||||||
|
│ └── cli.js # Start/Stop des Kiosk-Browsers auf dem Anzeigerechner
|
||||||
├── routes/
|
├── routes/
|
||||||
│ ├── admin.js # REST-Endpunkte für das Admin-Panel
|
│ ├── admin.js # REST-Endpunkte für das Admin-Panel
|
||||||
│ └── index.js # Monitor-Ansicht + WebSocket-Verbindungshandler
|
│ └── index.js # Monitor-Ansicht + WebSocket-Verbindungshandler
|
||||||
├── views/
|
├── views/
|
||||||
│ ├── admin.hbs # Admin-Panel (Handlebars-Template)
|
│ ├── admin.hbs # Admin-Panel (Handlebars-Template)
|
||||||
│ ├── index.hbs # Monitor ohne Scoreboard (nur Timer)
|
│ ├── splashscreen.hbs # Monitor: Vereinslogo
|
||||||
│ └── indexScore.hbs # Monitor mit Scoreboard (Timer + Score + Teamnamen)
|
│ ├── index.hbs # Monitor: nur Timer
|
||||||
|
│ └── indexScore.hbs # Monitor: Timer + Score + Teamnamen
|
||||||
└── public/
|
└── public/
|
||||||
|
├── img/ # Logos für den Splashscreen
|
||||||
├── javascripts/
|
├── javascripts/
|
||||||
│ ├── admin.js # Frontend-Logik Admin-Panel
|
│ ├── admin.js # Frontend-Logik Admin-Panel
|
||||||
│ ├── index.js # Frontend-Logik Monitor (ohne Score)
|
│ ├── index.js # Frontend-Logik Monitor (ohne Score)
|
||||||
│ └── indexScore.js # Frontend-Logik Monitor (mit Score)
|
│ ├── indexScore.js # Frontend-Logik Monitor (mit Score)
|
||||||
|
│ └── splashscreen.js # Frontend-Logik Splashscreen (nur Refresh-Handler)
|
||||||
└── stylesheets/
|
└── stylesheets/
|
||||||
├── admin.css
|
├── admin.css
|
||||||
├── index.css
|
├── index.css
|
||||||
├── indexScore.css
|
├── indexScore.css
|
||||||
|
├── splashscreen.css
|
||||||
└── seven-segment.css # Seven-Segment-Display-Schrift für den Timer
|
└── seven-segment.css # Seven-Segment-Display-Schrift für den Timer
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -81,11 +108,10 @@ scoreboard/
|
||||||
|
|
||||||
### Scoreboard
|
### Scoreboard
|
||||||
|
|
||||||
- Punktestand für **Team A** und **Team B**
|
- Punktestand für **Team A** und **Team B**, direkt im Admin-Panel über +1/-1 steuerbar
|
||||||
- Punkte einzeln erhöhen (+1) oder verringern (-1)
|
|
||||||
- Score direkt auf einen bestimmten Wert setzen
|
- Score direkt auf einen bestimmten Wert setzen
|
||||||
- Score zurücksetzen (beide Teams auf 0)
|
- Score zurücksetzen (beide Teams auf 0)
|
||||||
- **Scoreboard ein-/ausblenden:** Der Monitor wechselt zwischen Timer-only-Ansicht (`index.hbs`) und Timer+Score-Ansicht (`indexScore.hbs`)
|
- **Scoreboard ein-/ausblenden:** Der Monitor wechselt zwischen Timer-only-Ansicht und Timer+Score-Ansicht
|
||||||
|
|
||||||
### Teams konfigurieren
|
### Teams konfigurieren
|
||||||
|
|
||||||
|
|
@ -97,13 +123,47 @@ Jedes Team hat folgende Felder:
|
||||||
| `name2` | Zweiter Name (nur bei Spielgemeinschaft) |
|
| `name2` | Zweiter Name (nur bei Spielgemeinschaft) |
|
||||||
| `isSpielgemeinschaft` | Wenn aktiv, werden beide Namen untereinander angezeigt |
|
| `isSpielgemeinschaft` | Wenn aktiv, werden beide Namen untereinander angezeigt |
|
||||||
|
|
||||||
|
Die Namen können frei eingetippt oder per Dropdown aus der **Team-Datenbank** gewählt werden.
|
||||||
|
|
||||||
|
### Team-Datenbank
|
||||||
|
|
||||||
|
Häufig verwendete Teamnamen werden in `db.json` gespeichert und stehen im
|
||||||
|
Konfigurationsdialog als Auswahl zur Verfügung. Teams lassen sich im
|
||||||
|
Debugfenster hinzufügen und löschen.
|
||||||
|
|
||||||
### Seitenwechsel (Halbzeit)
|
### Seitenwechsel (Halbzeit)
|
||||||
|
|
||||||
Über "Seitenwechsel" werden Team A und Team B auf dem Monitor die Seiten tauschen — der Spielstand bleibt unverändert, nur die Anzeigepositionen (links/rechts) wechseln.
|
Über "Seitenwechsel" tauschen Team A und Team B auf dem Monitor die Seiten — der Spielstand bleibt unverändert, nur die Anzeigepositionen (links/rechts) wechseln.
|
||||||
|
|
||||||
|
### Spiegelung des Admin-Panels
|
||||||
|
|
||||||
|
Sitzt die Bedienung **hinter** dem Monitor, stimmt die Links/Rechts-Zuordnung im
|
||||||
|
Admin-Panel nicht mehr mit der Sicht auf die Anzeigetafel überein. Der Schalter
|
||||||
|
"Teamanzeige im Adminpanel spiegeln" im Debugfenster dreht die Darstellung im
|
||||||
|
Admin-Panel um — inklusive der +1/-1-Buttons, die dann dem jeweils richtigen Team
|
||||||
|
zugeordnet werden. Die Monitoranzeige bleibt davon unberührt.
|
||||||
|
|
||||||
|
### Splashscreen
|
||||||
|
|
||||||
|
Standardmäßig zeigt der Monitor beim Start das Vereinslogo. Über den Schalter im
|
||||||
|
Debugfenster wird zwischen Splashscreen und Spielanzeige umgeschaltet.
|
||||||
|
|
||||||
|
### Debugfenster
|
||||||
|
|
||||||
|
Sammelt die selten benötigten Schalter: Spiegelung, Scoreboard ein/aus,
|
||||||
|
Splashscreen ein/aus, Monitor neu laden, Kiosk-Browser starten/stoppen sowie die
|
||||||
|
Verwaltung der Team-Datenbank.
|
||||||
|
|
||||||
|
### Kiosk-Browser steuern
|
||||||
|
|
||||||
|
Auf dem Anzeige-Rechner (Raspberry Pi) kann der Chromium-Browser aus dem
|
||||||
|
Admin-Panel heraus im Kiosk-Modus gestartet und wieder beendet werden. Die
|
||||||
|
Funktion ist Linux-spezifisch und setzt einen Benutzer `pi` mit Zugriff auf
|
||||||
|
Display `:0` voraus.
|
||||||
|
|
||||||
### Monitor neu laden
|
### Monitor neu laden
|
||||||
|
|
||||||
Der Button "Monitor neu laden" im Admin-Panel sendet ein `refresh`-Event an alle verbundenen Clients und löst einen Seiten-Reload des Monitors aus. Nützlich z.B. nach dem Ein-/Ausblenden des Scoreboards.
|
Der Button "Monitor neu laden" sendet ein `refresh`-Event an alle verbundenen Clients und löst einen Seiten-Reload des Monitors aus. Nötig, wenn zwischen zwei Ansichten gewechselt wurde.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -118,19 +178,25 @@ Admin-Panel (Browser)
|
||||||
routes/admin.js
|
routes/admin.js
|
||||||
│
|
│
|
||||||
├── controllers/timer.js ──┐
|
├── controllers/timer.js ──┐
|
||||||
└── controllers/score.js ──┤
|
├── controllers/score.js ──┤
|
||||||
│ io.sockets.emit(event, data)
|
├── controllers/etc.js ──┤
|
||||||
▼
|
├── controllers/db.js ──┐ │
|
||||||
Socket.IO-Server :3001
|
└── controllers/cli.js │ │ io.sockets.emit(event, data)
|
||||||
|
│ ▼
|
||||||
|
db.json Socket.IO-Server :3001
|
||||||
│
|
│
|
||||||
WebSocket-Verbindung
|
WebSocket-Verbindung
|
||||||
│
|
│
|
||||||
┌───────────────┴───────────────┐
|
┌──────────────────────┼──────────────────────┐
|
||||||
▼ ▼
|
▼ ▼ ▼
|
||||||
Monitor (index.hbs) Monitor (indexScore.hbs)
|
Monitor (splashscreen) Monitor (index) Monitor (indexScore)
|
||||||
index.js indexScore.js
|
splashscreen.js index.js indexScore.js
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Der gesamte Spielzustand (Timer, Score, Teams, Schalter) liegt **im
|
||||||
|
Arbeitsspeicher** der Controller. Ein Serverneustart setzt ihn zurück; einzig die
|
||||||
|
Teamnamen in `db.json` bleiben erhalten.
|
||||||
|
|
||||||
### WebSocket-Events
|
### WebSocket-Events
|
||||||
|
|
||||||
| Event | Richtung | Beschreibung |
|
| Event | Richtung | Beschreibung |
|
||||||
|
|
@ -152,6 +218,20 @@ Alle Endpunkte sind unter `/admin` erreichbar.
|
||||||
| Methode | Endpunkt | Beschreibung |
|
| Methode | Endpunkt | Beschreibung |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| GET | `/admin/refreshMonitor` | Sendet `refresh` an alle Monitors |
|
| GET | `/admin/refreshMonitor` | Sendet `refresh` an alle Monitors |
|
||||||
|
| GET | `/admin/openBrowser` | Startet den Kiosk-Browser auf dem Anzeigerechner |
|
||||||
|
| GET | `/admin/killBrowser` | Beendet den Kiosk-Browser |
|
||||||
|
|
||||||
|
### Anzeige (etc)
|
||||||
|
|
||||||
|
| Methode | Endpunkt | Beschreibung |
|
||||||
|
|---|---|---|
|
||||||
|
| GET | `/admin/etcGetValues` | Aktuellen Splashscreen-Status abrufen |
|
||||||
|
| GET | `/admin/etcToggleSplashscreen` | Splashscreen ein-/ausblenden |
|
||||||
|
|
||||||
|
Antwortformat:
|
||||||
|
```json
|
||||||
|
{ "splashscreenEnabled": true }
|
||||||
|
```
|
||||||
|
|
||||||
### Timer
|
### Timer
|
||||||
|
|
||||||
|
|
@ -163,12 +243,15 @@ Alle Endpunkte sind unter `/admin` erreichbar.
|
||||||
| POST | `/admin/timerIncDec` | `{ value: <Sekunden> }` | Timer erhöhen (positiv) / verringern (negativ) |
|
| POST | `/admin/timerIncDec` | `{ value: <Sekunden> }` | Timer erhöhen (positiv) / verringern (negativ) |
|
||||||
| GET | `/admin/timerGetValues` | — | Aktuelle Timer-Werte abrufen |
|
| GET | `/admin/timerGetValues` | — | Aktuelle Timer-Werte abrufen |
|
||||||
|
|
||||||
|
`timerStart` und `timerPause` antworten mit **406**, wenn die Aktion nicht möglich
|
||||||
|
ist (Timer läuft bereits, ist bereits pausiert oder abgelaufen).
|
||||||
|
|
||||||
Antwortformat `timerGetValues`:
|
Antwortformat `timerGetValues`:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"isPaused": true,
|
"isPaused": true,
|
||||||
"duration": "<ISO 8601>",
|
"duration": "PT7M",
|
||||||
"durationLeft": "<ISO 8601>",
|
"durationLeft": "PT7M",
|
||||||
"print": "07:00"
|
"print": "07:00"
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
@ -181,6 +264,7 @@ Antwortformat `timerGetValues`:
|
||||||
| GET | `/admin/scoreGetValues` | — | Aktuelle Score-Werte abrufen |
|
| GET | `/admin/scoreGetValues` | — | Aktuelle Score-Werte abrufen |
|
||||||
| GET | `/admin/scoreClearScore` | — | Spielstand beider Teams auf 0 |
|
| GET | `/admin/scoreClearScore` | — | Spielstand beider Teams auf 0 |
|
||||||
| GET | `/admin/scoreToggleSideswitch` | — | Seiten der Teams tauschen |
|
| GET | `/admin/scoreToggleSideswitch` | — | Seiten der Teams tauschen |
|
||||||
|
| GET | `/admin/scoreToggleReferenceMirrored` | — | Admin-Panel-Darstellung spiegeln |
|
||||||
| POST | `/admin/scoreSetScore` | `{ team, score }` | Score direkt setzen |
|
| POST | `/admin/scoreSetScore` | `{ team, score }` | Score direkt setzen |
|
||||||
| POST | `/admin/scoreAlterScore` | `{ team, dir }` | Score um 1 ändern (`dir`: `"inc"` / `"dec"`) |
|
| POST | `/admin/scoreAlterScore` | `{ team, dir }` | Score um 1 ändern (`dir`: `"inc"` / `"dec"`) |
|
||||||
| POST | `/admin/scoreConfigTeams` | `{ teamA: { name, name2, isSpielgemeinschaft }, teamB: { ... } }` | Teams konfigurieren |
|
| POST | `/admin/scoreConfigTeams` | `{ teamA: { name, name2, isSpielgemeinschaft }, teamB: { ... } }` | Teams konfigurieren |
|
||||||
|
|
@ -190,14 +274,29 @@ Antwortformat `timerGetValues`:
|
||||||
Antwortformat `scoreGetValues`:
|
Antwortformat `scoreGetValues`:
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"enabled": false,
|
"enabled": true,
|
||||||
"teamA": { "name": "Team A", "name2": "", "score": 0, "isSpielgemeinschaft": 0 },
|
"teamA": { "name": "Team A", "name2": "", "score": 0, "isSpielgemeinschaft": 0 },
|
||||||
"teamB": { "name": "Team B", "name2": "", "score": 0, "isSpielgemeinschaft": 0 },
|
"teamB": { "name": "Team B", "name2": "", "score": 0, "isSpielgemeinschaft": 0 },
|
||||||
"sideswitch": false,
|
"sideswitch": false,
|
||||||
"print": "0:0"
|
"referenceMirrored": false,
|
||||||
|
"print": "0:0",
|
||||||
|
"teams": ["Arheilgen", "Prechtal"]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Team-Datenbank
|
||||||
|
|
||||||
|
| Methode | Endpunkt | Body | Beschreibung |
|
||||||
|
|---|---|---|---|
|
||||||
|
| GET | `/admin/dbGetValues` | — | Alle gespeicherten Teamnamen abrufen |
|
||||||
|
| POST | `/admin/dbAddTeam` | `{ teamName }` | Teamnamen hinzufügen (Duplikate und Leerstrings werden ignoriert) |
|
||||||
|
| POST | `/admin/dbDeleteTeam` | `{ teamName }` | Teamnamen löschen |
|
||||||
|
|
||||||
|
Antwortformat:
|
||||||
|
```json
|
||||||
|
{ "teams": ["Arheilgen", "Prechtal"] }
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Abhängigkeiten
|
## Abhängigkeiten
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue