---

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/<id>/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.
