# Endpoint für die Zeitmessung (Lichtschranke) > Der **Mess-Pi-Client selbst ist nicht Teil dieses Projekts** — dieses Dokument > beschreibt nur den **Endpoint**, den ein beliebiger Client (der zweite Raspberry > Pi an der Lichtschranke) bespielt. Fachlicher Hintergrund: `plan.md` §3.6 / §6.2. ## Authentifizierung Alle Geräte-Endpunkte erwarten einen **Geräte-Token** (nicht den Auswerter-Login): ``` Authorization: Bearer ``` Token anlegen (interne Admin-Session): ``` POST /api/v1/admin/geraete { "bezeichnung": "lichtschranke-ziel-01", "typ": "lichtschranke" } → 201 { "id": 1, "bezeichnung": "...", "token": "oamc_dev_…" } # Token nur hier einmalig ``` Token neu ausgeben: `POST /api/v1/admin/geraete/{id}/token` · Gerät sperren: `POST /api/v1/admin/geraete/{id}/sperren` ## Ablauf auf dem Client (empfohlen) 1. `POST /api/v1/geraete/heartbeat` alle ~15 s → Statusanzeige + `aktives_turnier_id` 2. `GET /api/v1/geraete/konfiguration` → Entprellzeit, Messpunkte, Plausibilitätsgrenzen 3. `GET /api/v1/turniere/aktiv/startliste` (ETag-fähig) → Startreihenfolge für die Anzeige 4. Pro Durchfahrt eine Messung lokal puffern, dann als **Batch** senden: `POST /api/v1/zeitmessungen` 5. `GET /api/v1/turniere/aktiv/anzeige` (SSE) → Live-Stream für die Anzeige am Parcours ## `POST /api/v1/zeitmessungen` — Batch, idempotent ```jsonc { "geraet": "lichtschranke-ziel-01", // informativ "messungen": [ { "id": "9f2c1e7a-4d38-4b6e-9a11-5c0b2d7e8f30", // UUID VOM GERÄT → Idempotenz "turnier_id": 42, "startnummer_gemeldet": 32, // Hinweis, kein Fremdschlüssel "messpunkt": "durchgang-1", "dauer_sekunden": 159.16, // vom Gerät berechnet (monotone Zeit) "gemessen_am": "2026-05-31T10:14:02.482+02:00", "monotonic_ns": 884213771004, "roh": { "trigger_start_ns": 884054611004, "trigger_ziel_ns": 884213771004 } } ] } ``` ### Antwort — jede Messung wird **einzeln** quittiert ```jsonc { "quittungen": [ { "id": "9f2c1e7a-…", "status": "angenommen", "start_id": 512, "hinweis": null } ], "angenommen": 1, "duplikate": 0, "unzugeordnet": 0, "unplausibel": 0 } ``` | `status` | Bedeutung | Client-Reaktion | |----------------|-----------|-----------------| | `angenommen` | gespeichert und einem Start zugeordnet | aus lokaler Queue löschen | | `duplikat` | UUID war schon da (Nachlieferung nach Timeout) | aus lokaler Queue löschen | | `unzugeordnet` | gespeichert, aber `startnummer_gemeldet` nicht auflösbar → manuelle Zuordnung im Frontend | aus lokaler Queue löschen | | `unplausibel` | gespeichert, Dauer außerhalb der Grenzen → im Frontend markiert | aus lokaler Queue löschen | | `fehler` | z. B. `turnier_id` unbekannt | **in der Queue behalten**, später erneut | **Grundregeln** (Server-seitig umgesetzt): * **Idempotent über `id`** — ein doppelt gesendeter Batch erzeugt keine Dubletten. Ein abgebrochener Request darf gefahrlos wiederholt werden. * Die **Dauer kommt fertig vom Gerät** — der Server rechnet **keine** Differenz aus zwei Wanduhr-Zeitstempeln (NTP-Sprung auf einem Pi ohne RTC). * Eine Messung **ohne** zuordenbare Startnummer wird **nie verworfen**, sondern als `unzugeordnet` gespeichert und im internen Frontend zur Zuordnung angeboten. * Plausibilitätsverstöße werden **markiert**, nicht abgelehnt. Grenzen: `OAMC_MESS_MIN_SEKUNDEN` / `OAMC_MESS_MAX_SEKUNDEN` bzw. je Gerät in `geraet.konfiguration`. * `gemessen_am` weit in der Vergangenheit → die Messung wird als *nachgeliefert* markiert und trotzdem angenommen. ## Fehlmessung nachträglich verwerfen ``` POST /api/v1/zeitmessungen/{id}/verwerfen { "grund": "Zuschauer hat die Schranke ausgelöst" } ``` Die Messung bleibt mit Grund gespeichert (Status `verworfen`), zählt aber nicht in die `summe_zeit`. ## Was der Server aus den Messungen macht `ergebnis.summe_zeit` wird bei der Auswertung als **Summe aller gültigen, zugeordneten Einzelmessungen** eines Starts gebildet (`oamc.wertung.service.summe_zeit_fuer_start`). Aus Einzelmessungen lässt sich die Summe jederzeit bilden — der umgekehrte Weg existiert nicht, deshalb speichert der Server jede Einzelmessung. ## Offene Punkte (aus `plan.md` §10), die den Endpoint noch betreffen * **O-13** Was misst die Lichtschranke genau (eine Gesamtdurchfahrt, mehrere Durchgänge, einzelne Abschnitte)? → bestimmt `messpunkt` und die Summenbildung. * **O-14** Woher kennt der Client die Startnummer? → bis geklärt: `startnummer_gemeldet` als Hinweis, Server löst gegen die Startliste auf. * **O-16** Geforderte Messgenauigkeit / eine oder zwei Lichtschranken.