# Die Kameraseite Vogelalbum braucht von der Kamera nur eines: einen Stream, den der Detector lesen kann. Alles andere passiert woanders. **Der Pi erkennt nichts.** Ein Pi Zero W schafft das Streamen, aber keine Inferenz — die beiden Modelle brauchen rund 30 ms auf einem N100 und ein Vielfaches davon auf einem Zero. Deshalb streamt der Pi, und der Detector läuft auf einer Maschine mit Rechenleistung im selben Netz. ## Was du brauchst * Raspberry Pi mit Kameraanschluss — ein **Zero W** reicht und ist der sparsamste Weg. Ein Pi 4/5 kann zusätzlich den Detector mitlaufen lassen. * Ein Kameramodul. Getestet mit dem **OV5647** (das ältere 5-MP-Modul). * Raspberry Pi OS (Bookworm oder neuer), WLAN eingerichtet. ## Einrichten ```bash sudo cp vogelkamera.py /opt/vogelkamera_server.py sudo cp vogelkamera.service /etc/systemd/system/ sudo systemctl enable --now vogelkamera journalctl -u vogelkamera -f ``` 🔑 **Kein zusätzliches Paket.** Der Server ruft `rpicam-vid` auf, das bei Raspberry Pi OS ohnehin dabei ist, und liest dessen MJPEG-Ausgabe mit. Die Arbeit passiert im C-Programm; Python schiebt nur Bytes weiter. Auf einem Zero W ist das der Unterschied zwischen läuft und läuft nicht. ⚠️ **Bis zum 25.09.2026 stand hier `python3-picamera2`** — für eine Fassung, die eleganter aussah und **nie auf einem Pi gestartet worden war**. Auf dem Gerät am Vogelhaus lief die ganze Zeit etwas anderes, und picamera2 war dort nicht einmal installiert. Auf den Punkt gebracht: *im Repo lag Code, der nie getestet wurde.* Seitdem steht in diesem Ordner, was tatsächlich läuft — und zwar seit dem 28.08.2026 ununterbrochen. Danach: | Adresse | wozu | |---|---| | `http://:8080/stream` | der MJPEG-Stream — das kommt in `VOGELALBUM_SOURCE` | | `http://:8080/` | Vorschauseite im Browser | | `http://:8080/status` | Bildrate, Funkstärke, Temperatur, Laufzeit als JSON | | `http://:8080/temp` | CPU-Temperatur | | `http://:8080/gesund` | 200, sobald Bilder ankommen | Die drei unteren fassen den Stream **nicht** an — das ist der richtige Weg, eine laufende Kamera zu prüfen. `/status` liefert dieselben Felder wie die ESP32-Kameraseite ([`../esp32cam/`](../esp32cam/README.md)), ein Werkzeug muss also nicht wissen, was am anderen Ende hängt. Hängt die Kamera über Kopf: `--vflip` und `--hflip` stehen im Skript bereits im Aufruf von `rpicam-vid` (`capture_loop`). Beide zusammen ergeben die 180°-Drehung, einzeln spiegeln sie. ## Drei Dinge, die man einmal falsch macht ### Nur ein Zuschauer gleichzeitig Ein Pi Zero W liefert über WLAN rund **2 Mbit/s**. Ein zweiter Client teilt sich diese Strecke — und der Detector fällt in Timeouts, ohne dass irgendwo ein Fehler auftaucht. Die Bildrate halbiert sich einfach. Das ist bei der Entwicklung zweimal passiert: einmal durch ein `curl` auf den Stream, mit dem eine Störung *diagnostiziert* werden sollte, und einmal, weil die Vorschauseite im Browser offen stand. Gemessen: 0,9 statt 1,9 Bilder pro Sekunde, solange ein zweites Fenster mitlas. Deshalb weist `vogelkamera.py` einen zweiten Zuschauer mit **503** ab, statt beide schlecht zu bedienen. Wer selbst zuschauen will, hält kurz den Detector an — oder nimmt `/snapshot`, das kostet nur ein Bild. ⚠️ **Bis zum 09.10.2026 stand das hier und stimmte nicht.** Die Fassung, die auf dem Gerät läuft, hat den zweiten Zuschauer nur **gezählt** und beide bedient; abgewiesen hat ihn nur die ESP32-Kameraseite. Aufgefallen ist es erst beim Nachziehen der Tests, die seit dem 25.09. auf die alte Fassung zeigten. Seitdem tut der Code, was hier steht. Ein Stream, der **15 Sekunden kein Bild** liefert, wird beendet. Das klingt nebensächlich, ist aber die Bedingung dafür, dass die Absage überhaupt funktionieren darf: Ohne neues Bild schreibt der Server nichts und merkt deshalb nicht, dass der Zuschauer schon weg ist — der eine Platz bliebe für immer besetzt und die Kamera wäre durch ihre eigene Schutzsperre dauerhaft stumm. Der Detector verbindet von selbst neu. ### Die Temperatur im Blick behalten Ein Vogelhaus in der Sonne ist ein geschlossener Kasten. Gemessen an einem Septembernachmittag: **72 °C** auf einem Pi Zero W. Ab etwa 80 °C drosselt der Pi von selbst, und die Bildrate fällt — ohne Fehlermeldung. ```bash curl http://:8080/temp ``` Diese Abfrage kostet den Stream nichts, im Gegensatz zu einem Blick auf das Bild. **`ping` taugt hier nicht als Gesundheitsprüfung:** ICMP fällt bei gesättigtem WLAN als Erstes aus, während TCP weiterläuft — eine Entwarnung per `ping` ist Glück, keine Messung. Das vollständige Bild gibt `/status`, ebenfalls ohne den Stream anzufassen: ```bash curl -s http://:8080/status {"kamera":"bereit","bilder":1751409,"fps":3.84,"letztes_bild_s":0.2, "fehler":"0x0","laufzeit_s":401238,"zuschauer":true,"rssi":-58, "temperatur_c":55.1,"speicher_frei":218103808} ``` | Feld | Gesund | Woran es sonst liegt | |---|---|---| | `fps` | stabil über Stunden | fällt → zweiter Zuschauer, Funkstrecke, Hitze | | `rssi` | über −70 dBm | darunter näher ran oder Antenne ausrichten | | `temperatur_c` | unter 70 °C | geschlossener Kasten in der Sonne drosselt | | `letztes_bild_s` | unter 1 s | steht → Kamera liefert nicht mehr | | `zuschauer` | `true` im Normalbetrieb | `false`, obwohl der Detector läuft → er kommt nicht durch | `bilder` und `fps` zählen, was die **Kamera liefert**, nicht was ein Zuschauer abholt. Ein `fps` über null bei `zuschauer: false` heißt also: die Kamera arbeitet, es holt nur niemand ab. Wer den Pi in einen geschlossenen Kasten baut: Schattenseite wählen, Öffnung für Luft lassen, und die Kamera nicht direkt neben den SoC setzen. ### Die Bildrate hängt am Licht, nicht an der CPU Über WLAN ist die Strecke bandbreitenbegrenzt. Ein helles, detailreiches Bild ergibt größere JPEGs und damit **weniger** Bilder pro Sekunde. Gemessen über neun Tage am selben Aufbau: nachts 6,2 fps (fast schwarzes Bild), tagsüber 3,7–4,2 fps. Reicht die Bildrate nicht, ist `--qualitaet` der Hebel — nicht die Auflösung. Die Auflösung braucht man, damit der Vogel groß genug im Bild ist. ## Wie groß muss der Vogel im Bild sein? Das ist die Frage, an der ein Aufbau scheitert, und sie lässt sich vorher beantworten — ohne auf einen echten Vogel zu warten: ```bash python -m detector karte --source http://:8080/stream --ziel karte.jpg ``` Der Detector montiert ein Vogelfoto über ein Raster von Positionen in aktuelle Bilder deiner Kamera und zeigt, wo er anspringt. Details im [Kamera-Kapitel](../docs/kamera.md#hängt-die-kamera-richtig-detector-karte). Die zwei Regeln, die dabei herausgekommen sind: * Ein Vogel braucht **5–8 % der Bildfläche**. Vor ruhigem Hintergrund reichen 5 %, vor einem Baum im Wind sind es 8 %. * Die **Landefläche gehört in die untere Bildmitte, nicht an den unteren Bildrand.** Dort unten findet der Detektor auch einen großen Vogel nicht zuverlässig. Eine Kamera, die flach über das Futterbrett hinwegschaut, legt jeden Gast genau in diese tote Zone.