Files
2026-10-16 01:52:41 +02:00

227 lines
15 KiB
Markdown
Raw Permalink 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.
# Modul `halloween/`
Hier liegt die erste Pi-WebUI. `run.py` im Projektstamm startet sie.
- `camera.py` liefert ein gemeinsames MJPEG-Bild für mehrere Betrachter.
`--demo` erzeugt ausdrücklich gekennzeichnete Testbilder; echte Kamera
läuft nur über Picamera2 auf dem Pi. Kamerafehler sichtbar melden.
- `controller.py` enthält bislang ausschließlich die simulierte
Effekt-Zustandslogik. Stopp bleibt bis zum Rücksetzen bestehen; nach Start
oder Rücksetzen muss erst der Bereich frei sein und dann ein neuer Trigger
kommen. Beschädigte Einstellungen schalten auf `aus`.
- `web.py` bietet WebUI und API; `index.html` ist die Grabseite, `camera.html` die getrennte Kameraseite. `run.py`
bindet an `127.0.0.1`, Zugriff vom Laptop erfolgt per SSH-Tunnel.
Für den vom Nutzer gewünschten direkten Heimnetzzugriff kann Uvicorn
`halloween.web:create_app` als Factory auf `0.0.0.0:8000` starten;
siehe `SOFTWARE.md`. `run.py` bleibt bei Loopback; systemd nutzt die
beim Upload gewählte Bind-Adresse, initial Loopback.
- `event_store.py` verwaltet `data/events.sqlite3`. Erfolgreiche manuelle
Testauslösungen werden als Ereignisse gespeichert; Profile besitzen
Kennungen und können Ereignissen zugeordnet werden. Profil-Löschen entfernt
die Zuordnung, nicht das Ereignis. Auto-Profile können Merkmalsvektoren
aufnehmen und verfallen 30 Tage nach letzter Sichtung. Start, stündlicher
Lauf und Lesezugriffe räumen abgelaufene Profile auf; die Kamera liefert
derzeit noch keine Merkmalsvektoren.
- Automatische Profilzuordnung per Kamera ist ein neuer Nutzerwunsch, aber
noch nicht implementiert. Eine künftige Erkennung muss Unsicherheit und
mögliche Fehlzuordnungen sichtbar machen und am echten Pi geprüft werden.
- Der Header `X-Halloween-UI` ist nur eine einfache Schranke für
Schreibaufrufe, kein echter Zugangsschutz. Der direkte Heimnetzzugriff ist
auf Nutzerwunsch für den aktuellen Test ohne Login vorgesehen; öffentliche
Internetfreigabe ist nicht beauftragt. Zugangsschutz bleibt offen.
- Laufzeitdaten liegen standardmäßig unter `data/` und werden weder
hochgeladen noch in Git aufgenommen.
- Echte GPIO-/Grabaktorsteuerung erst nach geklärter Mechanik, Versorgung,
sicherem Stopp und den Hardwaretests aus `PLAN.md` ergänzen.
Bei Änderungen an Zustandsübergängen oder Endpunkten die zugehörigen Tests
unter `tests/` und die Bedienhinweise in `SOFTWARE.md` prüfen.
## Personendetektion
- `detection.py` wertet den gemeinsamen Kamerastream mit OpenCV DNN/NanoDet aus.
Optionales Modell und OpenCV fehlen im Demo-Grundsetup bewusst. Kein Download
im Server; geprüfte Modellmetadaten in `nanodet-model.json`.
- Nur neue, zeitlich gültige Frames auswerten. Hintergrundinferenz hält keine
UI-/Zustandssperre; separater Watchdog sperrt aktivierte Automatik nach zwei
Sekunden ohne gültiges Ergebnis. Fehler verlangen bewusstes Rücksetzen.
- Linienüberquerung nutzt bestätigte flüchtige Tracks und Fußpunkte, Richtung,
endliches Segment und 3-%-Hysterese. Gruppen verlangen freien Bereich und
Sperrzeit; Konfigurations-/Controllerwechsel verwerfen alte Beobachtungen.
- `/api/detection` liefert synchrones Bild und Rahmen; `/api/detection/config`
speichert normierte Geometrie und Aktivierung unter `data/`. Erste Aktivierung
ist bewusst, nach Neustart immer neue Bereichsfreigabe. UI zeichnet/editiert
mit Canvas; keine Tracking-ID als Besucherprofil verwenden.
- Automatische Ereignisse tragen `person_line_crossing`, ohne Profilzuordnung.
Die vorhandene Steuerung bleibt ausschließlich simuliert.
## Bewegungs-Test
- `motion.py` bietet OpenCV-Optical-Flow im gewählten Bereich ohne Personenmodell.
Zwei aufeinanderfolgende gerichtete Bewegungen entlang der Pfeilnormalen
bestätigen einen Trigger; die Linie muss dabei nicht überquert werden.
- `method=motion_test` ausdrücklich als Test kennzeichnen; `person_line` bleibt
der Default und die Migration für alte gespeicherte Konfigurationen/Clients.
Beide Methoden speichern Geometrie/Aktivierung unter data/detection.json.
- Beim Test bedeutet Bereichsfreigabe zwei Sekunden Bildruhe, KEINE bestätigte
Personenfreiheit. Zehn Sekunden Sperrzeit, Stopp, bewusster Reset und Watchdog
beibehalten. Nach Konfigurations-/Controllerwechsel neue Bildbasis verlangen;
veraltete Inferenzfehler und Resultate dürfen den neuen Modus nicht beeinflussen.
- Ereignisse getrennt als motion_direction_test, ohne Profile; mit Auslösebild
gemäß den folgenden Bildregeln.
Aktoren bleiben simuliert; keine Zusage für Außenbetrieb, Licht oder Kostüme.
- Kleine Nahbereichbewegung nicht durch einen prozentual großen Mindestanteil
am gesamten Rechteck verwerfen; Schwellen mit kleinem/langsamem synthetischem
Stimulus regressionsprüfen, Gegenrichtung/Lichtwechsel weiter ablehnen.
- Bewegungswerte enthalten flüchtige Bildänderung, Hinweis und bestätigte
Frames. UI zeigt diese zur Diagnose und verwendet bei aktivierter Automatik
deren Freigabe für die Bereitschaftsanzeige. Manuelles Bereich-frei ersetzt
diese nicht; Sequenz, Stopp und Sperrzeit behalten ihren Vorrang.
## Auslösebilder
- Automatische akzeptierte Trigger speichern den grünen Bereich des auslösenden
Frames als JPEG unter data/event-images/, ohne EXIF/Originalbild außerhalb
des Rechtecks. Konfiguration beim Trigger kopieren; keine neuere Kameraaufnahme
oder später geänderte Geometrie verwenden. Manuelle Tests speichern kein Bild.
- SQLite migriert image_filename; öffentlicher Abruf nur über Ereignis-ID und
geprüfte generierte Dateinamen. Keine statische Freigabe des data/-Ordners.
Ordner 0700, Dateien 0600; Bilder nicht cachen. Bildspeicherung/SQLite außerhalb
des Detection-Locks, Fehler nutzen die bestehende Fehlersperre.
- Nutzerwahl: bis manuelle Löschung behalten. UI bietet Vorschau, Ansehen und
bestätigtes Bildlöschen; Ereignis/Profilzuordnung bleiben bestehen. Löschen
betrifft den aktiven Bestand, keine Upload-Sicherungen. Keine automatische
Alterslöschung von Bildern und keine Änderung der Auto-Profil-Frist.
## Kamera folgt einem Farbpunkt
- `follow.py` bietet lokale Pillow-HSV-Erkennung ohne OpenCV/Training und einen
optional bewusst gestarteten PCA9685-Kameratest. Vorschau und Demo greifen
niemals auf I²C zu; Demo lehnt Hardwarestart ab. Echte Ausgabe nur CH0/CH1,
Bus 1 / 0x40, nominal 50 Hz. Platine für diesen Test ausschließlich dafür nutzen.
- Farbwert, Toleranz, Achsrichtungen und Pulsgrenzen atomar in data/follow.json;
Beispielfoto und Analysebilder nur flüchtig. Bildauswahl nutzt Token und exakt
das fotografierte Bild; keine neuen Ereignisse, Profile oder Trainingsbilder.
- `/` und `/grab` liefern nur Grabsteuerung/-Polling; `/kamera` liefert nur
Kamera/Farbpunkt/Einrichtung mit eigenem Polling und sofortigem MJPEG-Livebild.
Beide nutzen denselben Kameraproduzenten. Keine versteckten Fremdbedienelemente.
- Farbvorschau und Grabautomatik dürfen gleichzeitig laufen. Nur echte
Kamerabewegung und automatische Grab-Auslösung gegenseitig ausschließen;
Start bei Konflikt ablehnen, keine gespeicherten Einstellungen umschalten.
- Follow verändert Controller/Modus nicht. Grab-Stopp/-Reset unter
`/api/grave/stop` und `/api/grave/reset` verändert Follow nicht. Kamera-Stopp
wirkt nur auf Follow. Explizites „Alles stoppen“ nutzt `/api/stop`; bisheriges
`/api/reset` bleibt für alte Clients als globale Abschaltung erhalten.
- Start braucht frische Kamera und explizite Hardware-/Mechanikbestätigung.
Jede Achse startet beim Mittel ihrer gespeicherten Followgrenzen (halbe µs
aufrunden; möglicher Sprung, vorab entkoppelt prüfen).
Defaults Nachführung 1400–1600, Einrichtung 1100–1900,
Nachführtempo 40–800 µs/s (neu 400; alte gespeicherte Konfiguration ohne
Tempo behält 80). Tempo/Farbe/Richtung nur gestoppt speichern. Nachführung
begrenzt den Zeitschritt auf 100 ms statt große Bildlücken nachzuholen;
Einrichtung/Mittelstellungsbutton bleiben 40 µs/s. Regelverstärkung ist mit
`FOLLOW_GAIN` (600 µs/s je Bildanteil) begrenzt, Tempo nur Obergrenze: Delay
der Kamera ließ 800 µs/s im Stillstand pendeln (Simulation, Pi nicht gemessen).
- Pi-Kamera zielt auf 15 Bilder/s (FrameDurationLimits, keine Altbild-Queue),
Demo bleibt bei ca. 5. Producer-FPS und Follow-Auswertungsrate gleitend messen;
`locate()` prüft Masken von streng (Sättigung ≥140) nach locker (≥100); der
kräftigste eindeutige Fleck gewinnt, blasse ähnliche Flächen (bläuliches Papier)
verdecken ihn nicht. `locate()` dekodiert per JPEG-`draft` direkt auf 160×120 und maskiert ohne
Python-Pixelschleife; Ergebnisse müssen mit den Tests übereinstimmen.
Farberkennungsdauer separat ausgeben, keine CPU-/Sensor-FPS daraus ableiten.
MJPEG prüft neue Frames alle 20 ms, Follow-UI fragt alle 100 ms nach einer
abgeschlossenen Antwort erneut ab. Kein garantierter Pi-Durchsatz.
- Sitzung startet nie automatisch. Startender Browser erneuert geheimen
Sitzungsschlüssel; 1,5 s ohne Heartbeat oder 1 s ohne Bild/Auswertung
schaltet PWM aus. Reiner Punktverlust beendet die Sitzung nicht. Stale Resultate
und alte Heartbeats dürfen keine neu gestartete Sitzung steuern.
- PWM-Abschaltfehler sichtbar melden; keine sichere Hardwareabschaltung aus
Softwaretests ableiten. I²C-Ausfall/harter Prozessabbruch können PWM stehen
lassen. Keine unabhängige OE-Sperre; nur beaufsichtigter Test.
- `operation=setup` ist ein eigener manueller Einrichtmodus derselben exklusiven
Kamerasitzung. Kein Farbzielsuchen/-verluststopp; Kamera und Heartbeat bleiben
erforderlich. Richtungstaste halten: maximal 40 µs/s, Lease 0,35 s und steigende
Sequenznummer gegen verspätete Befehle. Loslassen hält die Sollposition per
PWM; globaler/Kamerastopp beendet PWM.
- Einrichtung darf Follow-Grenzen überschreiten, begrenzt durch gespeicherte
pan_setup_min/max und tilt_setup_min/max.
Grenzspeicherung braucht passende Sitzung und beendete Bewegung; Richtungs-
umkehr beachten, 10 µs nach innen speichern, atomar in follow.json. Keine
Anschlagerkennung behaupten; nur Sollwerte, beide Achsen vor Anschlag stoppen.
- Endpunkt-UI: vier Richtungs-Karten zeigen
ausschließlich Serverwerte und den Kandidaten mit Innenabstand. Speichern
nur auf passender Seite der festen Startmitte dieser Sitzung (setup_origin), Fehler/Bestätigung im Einrichtbereich.
Farb-/Richtungsspeicherung darf Endpunkte nicht aus alten Formularfeldern
überschreiben. Start speichert nichts; Änderungen vorher explizit speichern.
Verspätete Statusantworten nach einer Speicherung verwerfen (configEpoch).
- Zusätzliche sichtbare Min-/Max-Eingabe für PAN/TILT mit eigenem Speichern und
Verwerfen. Nur gestoppt bedienbar; Entwurf und gespeicherte Werte getrennt
anzeigen. Polling darf ungespeicherte Eingaben nicht überschreiben; Start
verlangt deren Speichern/Verwerfen. Farben/Drehrichtung separat erhalten.
Einrichtgrenzen pro Achse gestoppt im WebUI einstellbar (technische Hülle
500–2500 µs, kein bestätigter mechanischer Weg). Nachführgrenzen müssen darin
liegen; Minimum <= Maximum, keine Bindung an 1500 µs. Setup langsam erweitern, keine Bewegung
beim Speichern. Alte Konfiguration ohne Setupfelder erhält 1100–1900;
keine automatische Erweiterung. PCA-Treiber prüft ebenfalls 500–2500.
- Bedienabläufe/Bezeichnungen bei Änderungen mit README.md und SOFTWARE.md
abgleichen; aktuelle Grenze im PLAN.md von historischen Zwischenständen
unterscheiden. Anschlussänderungen in VERDRAHTUNG.md/SVG synchron halten.
- `setup_origin` wird beim expliziten Start aus gespeicherten Followgrenzen
berechnet und im Status geliefert. Endpunktspeichern ändert ihn nicht und
bewegt keine Achse. Erneuter Start berechnet neu; Dienststart bleibt inaktiv.
WebUI zeigt zusätzlich die nächste Startmitte aus gespeicherter Konfiguration.
- `center(session, sequence)` nur in freigegebener Setup-Sitzung: aktuellen
Endpunktmittelwert als flüchtiges Ziel setzen, im Prozesszyklus beide Achsen
mit höchstens 40 µs/s ohne Überschwingen annähern. Gleiche Sequenzfolge wie
Jog; neuere Jog-/Loslassbefehle brechen ab, alte Centerbefehle dürfen nichts
reaktivieren. Kamera/Heartbeat/Auswertungswatchdog gelten weiterhin.
`centering` im Status; Remember während Fahrt ablehnen, UI-Speichern sperren.
Der feste Sitzungsbezug setup_origin und gespeicherte Konfiguration bleiben.
Expliziter „Bewegung anhalten“-Knopf sendet auch ohne Jog-Timer einen Stopp.
- `search_enabled` wird als bool persistiert, fehlendes Feld migriert zu false.
Nur echte Follow-Sitzung und zuvor erkanntes Ziel erlauben Suche nach 1,5 s
Verlust. Ein Durchlauf auf aktueller TILT-Höhe und beiden TILT-Endpunkten,
erste PAN-/TILT-Richtung aus letztem Bildpunkt und Achsumkehr. Jeder Sollwert
auf Follow-Min/Max begrenzen, niemals Setupgrenzen. Tempo min(follow_speed,200),
vorhandener 100-ms-Zeitschritt bleibt. Kein Endloslauf: Durchlaufende oder 60 s
seit Suchbeginn beendet nur die Suchfahrt, danach auf denselben Farbpunkt
warten; bestehende Watchdogs haben Vorrang.
- Erste Wiedererkennung hält Suchbewegung an, zwei aufeinanderfolgende Resultate
übernehmen Tracking. Fehlresultat setzt Bestätigungszähler zurück. Neuer
Verlust darf neuen Durchlauf beginnen. Start/Halt löschen gesamten Suchzustand;
kein Fund seit Start: an der Startposition warten. Preview/Setup suchen nie.
- Status `searching`, `reacquiring`, `search_seconds`, `waiting_for_target` im UI anzeigen. Suchoption
nur gestoppt speichern, ungespeicherte Änderung blockiert Start. Bestehende
Grenzen und Tempo erhalten. Suchfeldabdeckung und reale Wiedererkennung
erst nach Pi-Test bestätigen; die Farberkennung ist keine Objektidentität.
- Responsive Bedienoberfläche: beide Seiten bis 1800 px breit, ab 1000 px
Bild und Bedienung nebeneinander; schmal einspaltig ohne horizontales Scrollen.
Kamera: Status/Start/Stopp rechts, Farbe/Tempo/Suche aufklappbar; Endpunkte
und manuelle Einrichtung gemeinsam darunter, geöffnet zweispaltig.
Grab: Auslöseeinstellungen, Ereignisse und Profile aufklappbar. IDs, API und
Canvas-Koordinaten unverändert; Bild und Canvas immer im selben 4:3-Rahmen.
Desktopkopf mit Alles-Stopp bleibt sichtbar; mobil normale Seitenrolle.
- Gewählte Farbe bleibt in follow.json bis zur bewussten Farbwahl, auch nach
Punktverlust, Stopp und Neustart. Kein Foto/Objektprofil speichern. Nach
beendetem Suchdurchlauf oder 60 s sowie ohne Suchoption bleibt die gesunde
Hardware-Sitzung in `waiting_for_target` aktiv, ohne neue Bewegungsbefehle;
vorhandene PWM hält Position. Zwei aufeinanderfolgende Funde setzen Tracking
fort. Keine automatischen weiteren Suchrunden ohne erneuten Fund.
Stopp/Fehler/Neustart beenden weiterhin die Freigabe und lassen die Farbe stehen.
- Gestaltung beider Seiten schwarz/blau, Glow über statische CSS-Schatten.
Keine Animationsschleifen, externen Schriftarten, Bilder oder UI-Bibliotheken.
Kurze Hover-Übergänge respektieren prefers-reduced-motion. Stopp rot und
Hinweise amberfarben lassen; Canvas-Erkennungsfarben/Koordinaten unverändert.