--- title: 🌲 Finale – Waldbau ohne Burnout slug: finale\_waldbau\_kernel\_pattern lang: de summary: Was wir heute erlebt, gebaut und verstanden haben – als wiederholbares Muster über Debian, Mint & macOS hinweg. Ohne Rust, mit Haltung. tags: \[Crumbforest, Playbook, MQTT, MikroTik, ESP32, Debian, Mint, macOS, Kernel-Regeln] ----------------------------------------------------------------------------------------- # 🌥️ Worum es heute ging Ein Tag zwischen Container, Router, ESP und Wald. Wir haben Dinge kaputt-gemacht (unabsichtlich), gefixt (absichtlich) und daraus ein **Pattern** destilliert, das sich morgen wiederholen lässt – **ohne neue Baustellen** und **ohne Rust**. Leitstern: *kleine Patches, sichtbare Beweise, jederzeit Revert*. --- ## 🎛️ Heute gelernt (kurz) * **Mosquitto**: lief nicht wegen doppelter `persistence_location`. Entfernen → Dienst startet, **1883 lauscht**, Sub/Pub klappt. * **Firewall-Reihenfolge** ist alles: Mit einer zu harten `input`-Regel haben wir uns kurz ausgesperrt. Lektion: **Safe-Mode**, **Allow-Regeln ganz nach oben**, erst **danach** Drop. * **ESP32**: WLAN/Heartbeat klappt stabil, wenn **SSID, PSK, Broker, User/Pass** konsistent sind **und** 2,4 GHz erzwungen wird. * **Beweis statt Bauch**: `mosquitto_sub/pub`, `nc -vz`, `tcpdump` – jedes „läuft“ bekommt **einen Log**. --- ## 🛠️ Was steht jetzt stabil * **Broker (1883)**: `allow_anonymous false`, `password_file` gesetzt, Log unter `/var/log/mosquitto/mosquitto.log`, testbar per `mosquitto_sub/pub`. * **MikroTik**: Minimal-Filter * Management von Admin-Netz (WinBox/SSH) * `ESP-VLAN → Broker:1883` erlaubt * `established,related` erlaubt * `drop` zuletzt (Reihenfolge geprüft, Safe-Mode benutzt.) * **ESP32 MicroPython**: Mini-`main.py` publisht `crumb/esp//heartbeat`. * **Cross-OS**: Debian/Mint/macOS jeweils ein klarer Weg (siehe Patterns). --- ## 🧭 Was wir verstanden haben * **Kernel-Regeln** (unser Stil): 1. Beweis vor Behauptung • 2) Kleine Patches • 3) Revert jederzeit • 2. Interfaces stabil (Topics/Ports sind Verträge) • 5) Least Privilege • 3. Deterministische Tests • 7) Erklärbar in 3 Sätzen. * **Reality-Gap schließen**: Kein „Visionstheater“. Wir zeigen Logs, nicht Meinungen. * **Haltung statt Hektik**: Kinder zuerst → **Risikominimierung** schlägt Tempo. --- ## 📦 Muster ohne Rust – nur Bash, Make & Python Ziel: **ein Repo /tools**, das auf **Debian, Mint, macOS** gleich funktioniert. **Ordnerstruktur** ``` tools/ mqtt_smoketest.sh # Broker-Echo in <10s esp_push.py # mpremote/rshell Fallback rsc/ # MikroTik .rsc (apply / rollback) makefile # Ein-Klick-Ziele ``` **Makefile (Ausschnitt)** ```make BROKER ?= 192.168.88.227 USER ?= esp1 PASS ?= geheim smoke: ./tools/mqtt_smoketest.sh $(BROKER) $(USER) $(PASS) esp-push: python3 tools/esp_push.py main.py router-apply: @echo "Bitte in WinBox im Safe-Mode sein." # .rsc Datei importieren (GUI) – oder per ssh/winbox-cli logs: tail -n 100 /var/log/mosquitto/mosquitto.log ``` **Debian/Mint – Minimalpakete** ```bash sudo apt update sudo apt install -y mosquitto mosquitto-clients python3-venv python3-pip python3 -m venv .venv && source .venv/bin/activate pip install --upgrade pip mpremote esptool ``` **macOS (Homebrew)** ```bash brew install mosquitto python mpremote esptool brew services start mosquitto ``` **Einheitliche Checks** * Broker: `./tools/mqtt_smoketest.sh 192.168.88.227 esp1 geheim` * Port: `nc -vz 192.168.88.227 1883` * Wire: `sudo tcpdump -ni any tcp port 1883 -vv` --- ## 🔐 MikroTik – Minimal & sicher (ohne neue Baustellen) **Prinzip**: Erst erlauben, was **zwingend** ist, dann „drop“. **Regeln nach oben**. * Management: `input accept` für WinBox/SSH aus Admin-Netz * State-Keep: `established,related` * **ESP-VLAN → Broker:1883** erlauben (nur TCP 1883, nur Broker-IP) * **Drop** am Ende Test: * Aus dem ESP-VLAN: `nc -vz 192.168.88.227 1883` → `Connected` * `mosquitto_sub` auf Broker empfängt Heartbeat --- ## 🧪 ESP32 – 10-Zeilen-Heartbeat ```python import network, time, binascii, machine from umqtt.simple import MQTTClient SSID="ESP-Wald"; PSK="" # oder deine SSID/PSK BROKER="192.168.88.227" USER=b"esp1"; PASS=b"geheim" sta=network.WLAN(network.STA_IF); sta.active(True) if not sta.isconnected(): sta.connect(SSID, PSK) for _ in range(40): if sta.isconnected(): break time.sleep_ms(250) cid=b"esp-"+binascii.hexlify(machine.unique_id()) topic=b"crumb/esp/%s/heartbeat"%cid c=MQTTClient(cid,BROKER,user=USER,password=PASS,keepalive=60) c.connect(); c.publish(topic,b"hi"); c.disconnect() print("✅", sta.ifconfig(), topic) ``` --- ## 🔭 Nächste kleine Schritte (keine neuen Berge) 1. **Broker-IP fixen** (DHCP-Lease statisch) & Host-Firewall dokumentieren. 2. **Node-RED Hello-Flow**: `mqtt in → debug` (ein Topic, ein Tab). 3. **ESP-ID im Topic** standardisieren und in `README.md` notieren. 4. **Rollback-.rsc** ablegen (vier Zeilen, um die Allow-Regeln zu entfernen/disable). 5. **One-Pager „Troubleshoot“**: 10 häufige Fehler → eine Zeile Fix je Fehler. --- ## ❓„Würden wir den Wald ohne kleinen Krümel Linus bauen?“ Ja – **wenn wir seine Prinzipien leben**: kleine, prüfbare Schritte, Respekt vor dem System, Reverts immer parat. Nicht der Name baut den Wald, **die Haltung** tut es. --- ## 📎 Anhänge (Copy-Paste ready) **A1 – mqtt\_smoketest.sh** ```bash #!/usr/bin/env bash set -euo pipefail BROKER="${1:-127.0.0.1}"; USER="${2:-esp1}"; PASS="${3:-geheim}" TOPIC="crumb/test"; MSG="ping-$RANDOM" timeout 5s mosquitto_sub -h "$BROKER" -t "$TOPIC" -u "$USER" -P "$PASS" -C 1 -v > /tmp/mqtt_out.$$ mosquitto_pub -h "$BROKER" -t "$TOPIC" -m "$MSG" -u "$USER" -P "$PASS" sleep 1 grep -q "$MSG" /tmp/mqtt_out.$$ && echo "✅ MQTT ok @ $BROKER ($MSG)" || (echo "❌ MQTT fail"; cat /tmp/mqtt_out.$$; exit 1) rm -f /tmp/mqtt_out.$$ ``` **A2 – Mosquitto Pass anlegen** ```bash sudo mosquitto_passwd -c /etc/mosquitto/passwd esp1 sudo systemctl restart mosquitto && sudo tail -n 50 /var/log/mosquitto/mosquitto.log ``` **A3 – Minimaler MikroTik-Filter (Reihenfolge!)** ```rsc /ip firewall filter add chain=input action=accept protocol=tcp dst-port=8291 src-address=192.168.88.0/24 comment="mgmt winbox" add chain=input action=accept protocol=tcp dst-port=22 src-address=192.168.88.0/24 comment="mgmt ssh" add chain=input action=accept connection-state=established,related comment="state keep" add chain=input action=accept protocol=tcp dst-port=1883 src-address=192.168.50.0/24 dst-address=192.168.88.227 comment="ESP->Broker 1883" add chain=input action=drop comment="DROP last" ``` --- ## 🌳 Schluss Heute war kein „nice Demo“, sondern **Erdsprung**: weniger Vermutung, mehr Beweis. So wächst der Wald – **leise, wiederholbar, mit Heimweg**. Kinder atmen, Maschinen antworten, und wir halten die Ordnung klein & klar.