Vogelalbum 1.0.0
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.
This commit is contained in:
commit
c11fe9ab04
189 files changed
+29806
No files matched your search
@@ -0,0 +1,42 @@
|
||||
"""Umgebungsvariablen lesen.
|
||||
|
||||
Alle Einstellungen heißen ``VOGELALBUM_<NAME>``.
|
||||
|
||||
Diese Datei kennt bewusst **keine** Django-Abhängigkeit — sie wird vom
|
||||
Detektor, von der Web-App und von der Home-Assistant-Brücke gleichermaßen
|
||||
benutzt, und die drei haben nicht dieselben Pakete installiert.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
|
||||
PRAEFIX = "VOGELALBUM"
|
||||
|
||||
|
||||
def hole(name: str, default: str | None = None) -> str | None:
|
||||
"""Liest ``VOGELALBUM_<name>``.
|
||||
|
||||
``name`` ist der Teil hinter dem Präfix, also ``"SOURCE"`` für
|
||||
``VOGELALBUM_SOURCE``.
|
||||
|
||||
🔑 **Ein ausdrücklich leerer Wert schlägt den Vorgabewert.** Das ist kein
|
||||
Zufall, sondern trägt eine Bedeutung: Ein leerer Ingest-Token heißt
|
||||
„Endpunkt zu", nicht „nimm den Standard". Wer hier ``or default``
|
||||
schriebe, machte aus einer bewussten Abschaltung stillschweigend wieder
|
||||
eine Öffnung.
|
||||
"""
|
||||
wert = os.environ.get(f"{PRAEFIX}_{name}")
|
||||
if wert is None:
|
||||
return default
|
||||
return wert
|
||||
|
||||
|
||||
def gesetzt(name: str) -> bool:
|
||||
"""Ob die Variable überhaupt vorhanden ist.
|
||||
|
||||
Nötig, weil ein **leerer** Wert etwas anderes bedeutet als ein fehlender:
|
||||
Ein leerer Ingest-Token schaltet den Endpunkt ab, ein fehlender lässt den
|
||||
Vorgabewert gelten.
|
||||
"""
|
||||
return os.environ.get(f"{PRAEFIX}_{name}") is not None
|
||||
Reference in new issue
Block a user