Files
vogelalbum/esp32cam/main/netz.h
T
christian cc9e0786c2 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-14 18:55:23 +00:00

117 lines
4.4 KiB
C

// WLAN: Zugangsdaten im NVS, Verbindung als Station, Einrichtung als
// Zugangspunkt. Wer die Daten hat, verbindet sich; wer keine hat, macht
// sein eigenes Netz auf.
//
// Uebernommen aus Hey Fred (firmware/main/netz.c) am 23.09.2026. Dort ist
// es erprobt; hier geaendert wurden der NVS-Bereich und der Name des
// Einrichtungsnetzes.
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "esp_err.h"
#define NETZ_SSID_MAX 32
#define NETZ_PASS_MAX 64
// Name des Zugangspunkts zur Einrichtung. ⚠ Anders als bei Fred NICHT
// fest: Die letzten beiden Bytes der MAC haengen hinten dran, also etwa
// "Vogelkamera-A4F2". Zwei Kameras im selben Garten -- Futterhaus und
// Traenke -- wuerden sich sonst denselben Namen teilen, und man wuesste
// beim Einrichten nicht, welche man gerade vor sich hat.
#define NETZ_SETUP_PRAEFIX "Vogelkamera"
// Der tatsaechliche Name, erst zur Laufzeit bekannt.
const char *netz_setup_ssid(void);
// Das Geheimnis fuer Updates ueber WLAN.
//
// ⚠ Bewusst NICHT einkompiliert (so macht es Hey Fred in secrets.h). Fuer
// ein Geraet, das als Bausatz weitergegeben wird, waere das derselbe
// Fehler wie eingebackene WLAN-Daten: Jeder muesste die Firmware selbst
// uebersetzen, und alle Geraete haetten dasselbe Geheimnis.
//
// Stattdessen: Beim ersten Start wuerfelt sich jedes Geraet sein eigenes
// und legt es im NVS ab. Zu sehen bekommt man es im Einrichtungsnetz --
// wer dort steht, steht ohnehin vor dem Geraet.
const char *netz_ota_token(void);
typedef struct {
char ssid[NETZ_SSID_MAX + 1];
int8_t rssi;
bool verschluesselt;
} netz_fund_t;
// Einmal beim Start aufrufen, vor allem anderen.
void netz_init(void);
// Liegen Zugangsdaten im NVS?
bool netz_zugang_vorhanden(void);
// Der gespeicherte Netzname, oder "" wenn keiner da ist. Fuer die Anzeige
// auf der Einrichtungsseite: Erst damit sieht man, ob das Speichern
// ueberhaupt ankommt -- ohne Kabel, ohne Raten.
const char *netz_gespeicherte_ssid(void);
// Gibt false zurueck, wenn das Schreiben scheitert -- der Grund steht dann
// in *fehler. ⚠ Frueher brach das Geraet bei einem Fehler einfach ab
// (ESP_ERROR_CHECK): Es startete mitten im Absenden neu, der Browser blieb
// haengen, nichts war gespeichert, und niemand erfuhr warum.
bool netz_zugang_speichern(const char *ssid, const char *passwort,
esp_err_t *fehler);
void netz_zugang_loeschen(void);
// Verbindet mit den gespeicherten Daten. Blockiert bis zum Erfolg oder bis
// die Versuche aufgebraucht sind. Gibt false zurück, wenn es nicht klappt —
// dann gehört Fred in den Einrichtungsmodus.
bool netz_verbinden(void);
// Öffnet den Zugangspunkt für die Einrichtung. Danach ist Fred unter
// 192.168.4.1 erreichbar.
void netz_setup_ap_start(void);
// Sucht Netze in der Umgebung. Schreibt bis `max` Funde nach `ziel` und gibt
// die Anzahl zurück. Doppelte SSIDs werden übersprungen, der stärkste
// Fund gewinnt.
int netz_suchen(netz_fund_t *ziel, int max);
// Sucht EINMAL und merkt sich das Ergebnis.
//
// ⚠ Der Grund ist unangenehm und kostet sonst Stunden: Eine WLAN-Suche
// wechselt den Funkkanal. Laeuft gleichzeitig der eigene Zugangspunkt,
// fliegen die verbundenen Geraete dabei raus. Sucht man also, waehrend
// jemand das Formular betrachtet, verliert genau dieser Jemand die
// Verbindung -- und sein Absenden kommt nie an. Am 23.09.2026 genau so
// passiert, an Handy wie an Mac.
//
// Deshalb: einmal suchen, bevor der erste Besucher da ist, und danach
// nur noch die Liste ausliefern.
int netz_funde_holen(netz_fund_t *ziel, int max);
void netz_funde_auffrischen(void);
// IP als Zeichenkette, leer wenn nicht verbunden.
const char *netz_ip(void);
// Wie oft die Verbindung seit dem Start abgerissen ist, und warum zuletzt.
// Der Grund ist der Code des WLAN-Treibers: 15 und 204 stehen für ein
// falsches Passwort, 201 für „Netz nicht gefunden", 2 bis 4 zeigen auf
// Verschlüsselung und Management-Frames.
int netz_trennungen(void);
int netz_letzter_grund(void);
// Läuft die Verbindung gerade?
bool netz_verbunden(void);
// Holt die Uhrzeit per SNTP und stellt sie auf deutsche Zeit. Blockiert
// nicht — das Ergebnis trudelt im Hintergrund ein.
void zeit_holen(void);
// Steht die Uhr schon auf einer plausiblen Zeit?
bool zeit_steht(void);
// Empfangsstaerke zum Zugangspunkt in dBm (negativ; naeher an null ist
// besser). 0 heisst: nicht ermittelbar.
int netz_feldstaerke(void);