8.1 KiB
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 1–4 betreffen ausschließlich appRobotDriver und sind vollständig umgesetzt.
Schritte 5–7 betreffen appRobotHoming und appRobotRendering — separate Tickets/Sessions.
Umsetzungsschritte
Schritt 1 — Datei anlegen (appRobotDriver) ✅
- Verzeichnis
data/robot/anlegen - Default-
robot.jsonwird vom Nutzer geliefert und dort abgelegt .gitignore-Eintrag fürdata/robot/robot_*.json(Snapshots gehören nicht ins Repo,robot.jsonselbst 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:
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:
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):
// 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.jsonmit 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 durchROBOT_DRIVER_URLersetzen (z.B.https://appRobotDriver:2098)- Neue Hilfsfunktionen
fetchRobotJson()/pushRobotJson(data)(HTTP GET/PUT mit API-Key) - Alle
fsPromises.readFile(ROBOT_JSON)-Aufrufe durchawait fetchRobotJson()ersetzen - Nach jeder editRobot.js-Transformation:
await pushRobotJson(updated) editRobot.jsbleibt 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 anpassenROBOT_JSON-Env-Variable aus docker-compose-Dateien entfernen,ROBOT_DRIVER_URLhinzufü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/robotgemacht werden)