Eine Kamera am Vogelhaus, ein Rechner der erkennt wer da war — und eine Sammlung, die sich von allein fuellt. Zwei neuronale Netze: eines findet den Vogel im Bild, eines bestimmt die Art. 148 heimische Arten, auf Deutschland eingeschraenkt und neu normiert — ohne diese Einschraenkung wird aus einer Kohlmeise eine nordamerikanische Schwesterart. Daraus entsteht ein Sammelalbum: nummerierte Seiten, gefundene Arten in Farbe, fehlende als Schatten, dazu Erstfang, Punkte, Stufen und 15 Abzeichen. Laeuft vollstaendig auf eigener Hardware. Kein Cloud-Dienst, kein Konto, keine Telemetrie; die Bilder verlassen das eigene Netz nicht. Zwei getrennt deploybare Teile: die Sammlung als Django-Anwendung, die Erkennung als eigener Dienst. Der Erkennungs-Dienst fragt selbst an und braucht deshalb weder eine erreichbare Adresse noch einen offenen Port — er laeuft hinter einem gewoehnlichen Router. Dabei: Firmware fuer Raspberry Pi und ESP32-S3, Anbindung an Home Assistant ueber MQTT, Oberflaeche auf Deutsch und Englisch, Einstellungen je Kamera aus dem Browser, und ein Weg fuer Fotos von unterwegs. AGPL-3.0.
55 lines
1.8 KiB
Bash
Executable File
55 lines
1.8 KiB
Bash
Executable File
#!/bin/sh
|
|
# Firmware über Funk aufspielen. Kein Kabel, kein Aufschrauben.
|
|
#
|
|
# ./ota.sh vogelkamera.local <schluessel>
|
|
#
|
|
# Den Schlüssel zeigt das Gerät beim Start auf der seriellen Leitung
|
|
# ("Schluessel fuer Updates: …") und die Einrichtungsseite. Er bleibt über
|
|
# Neustarts und Updates hinweg derselbe -- er liegt im NVS.
|
|
#
|
|
# ⚠ --limit-rate ist KEIN Schönheitsfehler, sondern Bedingung. Ohne
|
|
# Drosselung kommt der Chip mit dem Schreiben in den Flash nicht
|
|
# hinterher, hört auf vom Socket zu lesen, und beide Seiten warten
|
|
# aufeinander, bis jemand aufgibt. Am 24.09.2026 hat genau das zwei
|
|
# Anläufe gekostet, bevor klar war, dass es nicht am Endpunkt liegt.
|
|
#
|
|
# ⚠ Der Detector muss weg. Der Webserver auf der Kamera hat einen
|
|
# einzigen Arbeiter, und der Stream gibt ihn nie zurück:
|
|
#
|
|
# ssh root@erkennung.local systemctl stop vogelalbum-detector@traenke
|
|
# ./ota.sh …
|
|
# ssh root@erkennung.local systemctl start vogelalbum-detector@traenke
|
|
set -e
|
|
|
|
ZIEL="$1"
|
|
SCHLUESSEL="$2"
|
|
ABBILD="${3:-build/vogelkamera.bin}"
|
|
|
|
if [ -z "$ZIEL" ] || [ -z "$SCHLUESSEL" ]; then
|
|
echo "Aufruf: $0 <adresse> <schluessel> [abbild]" >&2
|
|
exit 2
|
|
fi
|
|
if [ ! -f "$ABBILD" ]; then
|
|
echo "Kein Abbild unter $ABBILD -- erst 'idf.py build'." >&2
|
|
exit 2
|
|
fi
|
|
|
|
echo "Vorher:"
|
|
curl -s -m 5 "http://$ZIEL:8081/status" || echo " (keine Antwort)"
|
|
|
|
echo
|
|
echo "Spiele $(wc -c < "$ABBILD") Bytes auf $ZIEL auf …"
|
|
curl --fail --max-time 300 --limit-rate 150k \
|
|
-w '\n HTTP %{http_code} %{size_upload} Bytes in %{time_total}s\n' \
|
|
-X POST \
|
|
-H "Expect:" \
|
|
-H "X-Vogelkamera-Token: $SCHLUESSEL" \
|
|
--data-binary "@$ABBILD" \
|
|
"http://$ZIEL:8080/update"
|
|
|
|
echo
|
|
echo "Warte auf den Neustart …"
|
|
sleep 12
|
|
echo "Nachher:"
|
|
curl -s -m 8 "http://$ZIEL:8081/status" || echo " (noch nicht zurück -- gleich nochmal schauen)"
|