Files
appRobotDriver/doc/ToDo_14_robot_json_service.md
2026-06-12 17:03:38 +02:00

185 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Roadmap: robot.json als zentraler Service
## Ist-Zustand (Problem)
`robot.json` existiert aktuell an mindestens zwei unabhängigen Orten:
| App | Pfad | Rolle |
|-----|------|-------|
| `appRobotHoming` | `scripts/robot_<ts>.json` (Env: `ROBOT_JSON`) | Lesen + Schreiben (editRobot.js) |
| `appRobotRendering` | `data/robot/robot.json` | Lesen (Rendering) |
| `appRobotDriver` | — | Armlängen hardcodiert (`250, 264, 100`) |
Es gibt keine Versionierung, keinen Single Point of Truth, und wenn Homing die Geometrie kalibriert, bekommen Driver und Rendering davon nichts mit.
---
## Ziel-Architektur
`appRobotDriver` ist das **Zentrum des Systems** (er steuert die Hardware). Er besitzt daher auch die `robot.json` und stellt sie über einen REST-Endpunkt bereit. Alle anderen Apps lesen/schreiben ausschließlich über diesen Endpunkt.
```
appRobotDriver
└── data/robot/
├── robot.json ← aktueller Stand (Single Source of Truth)
├── robot_20260101_143522.json ← Snapshot vor jeder Änderung
└── robot_20260115_091010.json
appRobotHoming ──GET/PUT──► appRobotDriver :2098/api/robot
appRobotRendering ──GET──────► appRobotDriver :2098/api/robot
appRobotSimulation ──GET────► appRobotDriver :2098/api/robot
```
Der InfoServer (Port 2098) bekommt die neuen Endpunkte. Der WebSocket-Server (Port 2095) bleibt unverändert.
---
## API-Design
Alle Endpunkte unter dem bereits laufenden InfoServer auf Port 2098.
```
GET /api/robot → robot.json als JSON (kein Auth nötig)
PUT /api/robot → ersetzt robot.json, legt vorher Snapshot an (Auth nötig)
GET /api/robot/history → Liste aller Snapshots [{ filename, timestamp }]
GET /api/robot/history/:ts → einen bestimmten Snapshot abrufen
```
### Sicherheit (trivial, da Netz sicher)
PUT-Requests brauchen einen statischen API-Key als HTTP-Header:
```
Authorization: Bearer <ROBOT_API_KEY>
```
Key wird per Umgebungsvariable konfiguriert (`ROBOT_API_KEY`). Fehlt die Variable, wird ein zufälliger Key generiert und beim Start geloggt. Für GET braucht es keinen Key — Lesen ist überall erlaubt.
Das ist die einzige Absicherung. Kein JWT, keine Sessions, kein Rate-Limiting — Netz ist sicher, und ein versehentlicher Schreib-Request aus einem Browser soll trotzdem nicht funktionieren.
---
## Status
| Schritt | Bereich | Status |
|---------|---------|--------|
| 1 — Datei anlegen | appRobotDriver | ✅ erledigt |
| 2 — RobotConfigService | appRobotDriver | ✅ erledigt |
| 3 — Registrierung InfoServer | appRobotDriver | ✅ erledigt |
| 4 — Driver liest Armlängen | appRobotDriver | ✅ erledigt (→ ToDo 3) |
| 4a — InfoServer auf Express umgestellt | appRobotDriver | ✅ erledigt |
| 4b — UI: Robot.json + History in index.html | appRobotDriver | ✅ erledigt |
| 5 — appRobotHoming umstellen | appRobotHoming | ⬜ offen |
| 6 — appRobotRendering umstellen | appRobotRendering | ⬜ offen |
| 7 — Aufräumen | alle Repos | ⬜ offen |
Die Schritte 14 betreffen ausschließlich `appRobotDriver` und sind vollständig umgesetzt.
Schritte 57 betreffen `appRobotHoming` und `appRobotRendering` — separate Tickets/Sessions.
---
## Umsetzungsschritte
### Schritt 1 — Datei anlegen (appRobotDriver) ✅
- Verzeichnis `data/robot/` anlegen
- Default-`robot.json` wird vom Nutzer geliefert und dort abgelegt
- `.gitignore`-Eintrag für `data/robot/robot_*.json` (Snapshots gehören nicht ins Repo, `robot.json` selbst schon)
- Driver startet mit Defaults (`l1: 250, l2: 264, l3: 100`) wenn Datei fehlt, loggt Warnung
### Schritt 2 — RobotConfigService (appRobotDriver) ✅
Neue, **in sich geschlossene** Datei `server/RobotConfigService.js`. Sie hat keine Abhängigkeiten auf andere Teile des Drivers und kann in jeden Express- oder `https.createServer`-basierten Server mit einer Zeile eingehängt werden:
```js
const robotConfigService = require('./server/RobotConfigService');
robotConfigService.register(app, { apiKey: process.env.ROBOT_API_KEY });
// fertig — alle /api/robot*-Routen sind registriert
```
Das Modul kapselt intern:
```
readRobotJson() → Promise<object>
writeRobotJson(data) → Promise<{ snapshotFile }> // legt robot_<ts>.json an + pruning
listHistory() → Promise<{ filename, day, timestamp }[]>
readSnapshot(ts) → Promise<object>
pruneSnapshots() → löscht überschüssige Snapshots (s. Regel unten)
```
**Snapshot-Pruning-Regel:** Pro Tag maximal 100 Snapshots. Sind es mehr, wird nur der neueste des Tages behalten. Diese Bereinigung läuft automatisch nach jedem Schreibvorgang.
Timestamp-Format: `YYYYMMDD_HHmmss` (konsistent mit appRobotHoming).
**API-Key:** Wird per Option übergeben. Fehlt der Key (undefined), generiert das Modul beim ersten Start einen zufälligen Key, loggt ihn einmalig und speichert ihn in `data/robot/.apikey` (nicht im Repo). So funktioniert es ohne Konfiguration, ist aber trotzdem nicht offen.
### Schritt 3 — Registrierung in InfoServer.js (appRobotDriver) ✅
`InfoServer.js` wurde auf Express umgestellt. Registrierung mit einer Zeile:
```js
robotConfigService.register(app, { apiKey: options.apiKey });
```
### Schritt 4 — Driver liest Armlängen aus robot.json ✅
Ausgelagert nach `robot/RobotConfig.js` (→ ToDo 3). Liest beim Start synchron `data/robot/robot.json`, leitet l1/l2/l3 aus `links.*.skeleton.to` ab (nicht mehr aus `size`):
```js
// links.Arm1.skeleton.to[1] → l1 (Math.abs)
// links.Arm2.skeleton.to[1] → l2 (Math.abs)
// links.Ellbow.skeleton.to[0] → l3
```
Fallback auf Defaults wenn Datei fehlt. Controller-IPs/-Ports/-Achsen ebenfalls aus `robot.json` (keine hardcodierten Werte mehr in `startRobot.js`).
### Schritt 4a — InfoServer auf Express umgestellt ✅
`server/InfoServer.js` nutzt jetzt Express statt rohem `https.createServer`. Ermöglicht saubere Router-Registrierung und ist Grundlage für alle weiteren API-Endpunkte.
### Schritt 4b — UI: Robot.json + History in index.html ✅
Zwei neue Panels im InfoServer-Frontend (`public/index.html` + `app.js`):
- **Robot.json** — zeigt aktuelle `robot.json` mit aufklappbaren Top-Level-Abschnitten (`<details>`). Aktualisiert sich automatisch, solange kein Snapshot ausgewählt ist. Label (`_label`-Feld) wird oben angezeigt.
- **Robot.json History** — listet alle Snapshots aus `GET /api/robot/history`. Klick auf Eintrag lädt diesen Snapshot in das Robot.json-Panel. Klick auf „aktuell" schaltet zurück auf Live-Ansicht.
### Schritt 5 — appRobotHoming auf Driver-API umstellen ⬜
`server/server.js` in appRobotHoming:
- `ROBOT_JSON`-Env-Variable durch `ROBOT_DRIVER_URL` ersetzen (z.B. `https://appRobotDriver:2098`)
- Neue Hilfsfunktionen `fetchRobotJson()` / `pushRobotJson(data)` (HTTP GET/PUT mit API-Key)
- Alle `fsPromises.readFile(ROBOT_JSON)`-Aufrufe durch `await fetchRobotJson()` ersetzen
- Nach jeder editRobot.js-Transformation: `await pushRobotJson(updated)`
- `editRobot.js` bleibt unverändert (pure Transformationen, kein File-IO)
### Schritt 6 — appRobotRendering auf Driver-API umstellen ⬜
`robot.json` wird einmalig beim Start vom Driver geholt und gecacht. Cache wird per `GET /api/robot` aktualisierbar. Env-Variable `ROBOT_DRIVER_URL`.
### Schritt 7 — Aufräumen ⬜
- Lokale `robot.json`-Kopien in appRobotHoming und appRobotRendering entfernen
- `.gitignore`-Einträge in den betroffenen Repos anpassen
- `ROBOT_JSON`-Env-Variable aus docker-compose-Dateien entfernen, `ROBOT_DRIVER_URL` hinzufügen
---
## Entschiedene Punkte
| Frage | Entscheidung |
|-------|-------------|
| Driver-Start ohne robot.json | Mit Defaults starten + Warnung loggen |
| Snapshot-Limit | Max. 100 pro Tag; danach pro Tag nur die letzte Version behalten |
| Caching in Clients | Ja, erlaubt — Ziel ist API-only-Zugriff, kein direktes File-IO |
| Port InfoServer | 2098 bleibt; weitere Endpunkte werden dort angehängt |
---
## Nicht in dieser Roadmap
- Konflikte bei gleichzeitigen Schreibzugriffen (mutex) — vorerst nicht nötig, Homing ist der einzige Schreiber
- Diff-Anzeige zwischen Snapshots
- Rollback-Endpunkt (kann manuell über `GET /api/robot/history/:ts` + `PUT /api/robot` gemacht werden)