Files
christian c11fe9ab04 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.
2026-10-15 14:30:02 +00:00

43 lines
1.8 KiB
HTML

{% load static i18n dex_extras %}{% get_current_language as LANG %}<!doctype html>
<html lang="{{ LANG }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Vogelalbum</title>
<link rel="stylesheet" href="{% static_v 'css/vogelalbum.css' %}">
<style>
/* Im iframe gibt es keine Navigation und keinen Seitenrand. */
body { background: transparent; }
.wrap { padding: 0; max-width: none; }
.widget { display: flex; gap: 14px; align-items: center;
background: var(--card); border: 1px solid var(--line);
border-radius: var(--radius); padding: 14px; }
.widget img { width: 96px; height: 74px; object-fit: cover;
border-radius: 10px; background: #0b120e; flex-shrink: 0; }
</style>
</head>
<body>
<div class="wrap">
<div class="widget">
{% if latest %}
{% if latest.kachel_url %}<img src="{{ latest.kachel_url }}" alt="{{ latest.effective_species.name }}">{% endif %}
<div style="min-width:0">
<div class="sub">{% trans "Zuletzt gesehen" %}</div>
<div style="font-weight:700; font-size:18px; margin:2px 0 4px">{{ latest.effective_species.name }}</div>
<div class="sub">{{ latest.started_at|zeitpunkt }} · {% widthratio latest.confidence 1 100 %}% {% trans "sicher" %}</div>
</div>
{% else %}
<div>
<div class="sub">Vogelalbum</div>
<div style="font-weight:700; font-size:18px">{% trans "Noch kein Gast" %}</div>
</div>
{% endif %}
<div style="margin-left:auto; text-align:right; flex-shrink:0">
<div style="font-weight:800; font-size:22px">{{ progress.species_seen }}<span class="sub" style="font-size:15px">/{{ progress.species_total }}</span></div>
<div class="sub">{% trans "Arten" %}</div>
</div>
</div>
</div>
</body>
</html>