// Wächter 3 – Einbruchschutz, Teil B: ESP32 mit WLAN (z. B. ESP32-S3 oder ESP32-C3), hängt per UART an Teil A // LiSoftware · lisoftware.de/sicherheit · GPL-3.0 · KONZEPT – übersetzt mit arduino-esp32 3.3.12, aber nicht auf echter Hardware geprüft: vor dem Einsatz testen! // // Bei „ALARM …“ von Teil A geht zuerst ein Alarm mit höchster Stufe aufs Handy (ntfy, wie alarm-ntfy.sh), dann wird der DNS-Eintrag deiner Homepage auf die Rückfallebene umgestellt: eine Kopie der Homepage, die // GitHub Pages aus deinem öffentlichen Repository ausliefert (Branch gh-pages oder Actions). Der Eintrag zeigt dann auf // .github.io statt auf deinen Server. Das klappt nur, wenn der DNS-Eintrag eine kurze TTL hat (60–300 s). // // Sicherheit: Nimm ein API-Token, das NUR diesen einen Eintrag ändern darf (die meisten DNS-Anbieter erlauben das, // z. B. Cloudflare „Edit zone DNS“ auf eine Zone, Hetzner DNS oder INWX mit eigenem API-Benutzer). // Das Token liegt im Flash dieses Geräts – also Gerät im verschlossenen Gehäuse, Flash-Verschlüsselung einschalten. #include #include #include const char *WLAN_NAME = "DEIN-WLAN"; const char *WLAN_PASS = "DEIN-PASSWORT"; // --- dein DNS-Anbieter: eine einzige HTTPS-Anfrage, die den Eintrag umstellt (Beispiel im Stil von Cloudflare) --- const char *DNS_URL = "https://api.example-dns.net/zones/ZONE_ID/dns_records/RECORD_ID"; const char *DNS_METHODE = "PATCH"; const char *DNS_TOKEN = "NUR-FUER-DIESEN-EINTRAG"; const char *DNS_BODY = "{\"type\":\"CNAME\",\"name\":\"www.example.org\",\"content\":\"benutzer.github.io\",\"ttl\":60}"; // Wurzelzertifikat des Anbieters (PEM) – damit niemand die Umschaltung abfangen kann. Nie setInsecure() verwenden. const char *DNS_CA = R"(-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----)"; // --- Alarm aufs Handy: ntfy mit Priorität „urgent“ (eigener ntfy-Server, Topic lang und zufällig, Token mit Schreibrecht) --- const char *NTFY_URL = "https://ntfy.example.org/alarm-7Hq2xV9kLm"; const char *NTFY_TOKEN = "tk_NUR-SCHREIBEN-AUF-DIESES-TOPIC"; const char *NTFY_CA = R"(-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----)"; const int PIN_UART_RX = 16, PIN_UART_TX = 17; bool umgeleitet = false, gemeldet = false; bool handyAlarm(const String &grund) { WiFiClientSecure tls; tls.setCACert(NTFY_CA); HTTPClient http; if (!http.begin(tls, NTFY_URL)) return false; http.addHeader("Authorization", String("Bearer ") + NTFY_TOKEN); http.addHeader("Title", "Einbruchsalarm Serverschrank"); http.addHeader("Priority", "urgent"); http.addHeader("Tags", "rotating_light,warning"); String text = grund + " - Server wird in 20 s abgeschaltet, Homepage auf GitHub umgeleitet."; int code = http.POST(text); http.end(); Serial.printf("ntfy-Alarm: HTTP %d\n", code); return code >= 200 && code < 300; } bool umleiten() { WiFiClientSecure tls; tls.setCACert(DNS_CA); HTTPClient http; if (!http.begin(tls, DNS_URL)) return false; http.addHeader("Authorization", String("Bearer ") + DNS_TOKEN); http.addHeader("Content-Type", "application/json"); int code = http.sendRequest(DNS_METHODE, (uint8_t *)DNS_BODY, strlen(DNS_BODY)); http.end(); Serial.printf("DNS-Umleitung: HTTP %d\n", code); return code >= 200 && code < 300; } void setup() { Serial.begin(115200); Serial1.begin(9600, SERIAL_8N1, PIN_UART_RX, PIN_UART_TX); WiFi.mode(WIFI_STA); WiFi.begin(WLAN_NAME, WLAN_PASS); } void loop() { if (Serial1.available()) { String zeile = Serial1.readStringUntil('\n'); zeile.trim(); Serial.println("Teil A: " + zeile); if (zeile.startsWith("ALARM") && !(umgeleitet && gemeldet)) { for (int versuch = 0; versuch < 5 && !(umgeleitet && gemeldet); versuch++) { // WLAN kann gestört sein: mehrmals versuchen if (WiFi.status() != WL_CONNECTED) { WiFi.reconnect(); delay(3000); } if (!gemeldet) gemeldet = handyAlarm(zeile); if (!umgeleitet) umgeleitet = umleiten(); if (!(umgeleitet && gemeldet)) delay(2000); } } } delay(20); }