Private
Public Access
227 lines
15 KiB
Markdown
227 lines
15 KiB
Markdown
# 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.
|