Initial commit: Crumbforest Architecture Refinement v1 (Clean)

This commit is contained in:
2025-12-07 01:26:46 +01:00
commit 6c38ed680b
633 changed files with 61797 additions and 0 deletions

View File

@@ -0,0 +1,243 @@
Hier ist **`crumb_byte.md`** im schlanken Crumbforest-Format copy-paste-sicher, ohne Sonderzeichen.
(Enthält Definition, Topics, Edge-Code, Node-RED-Snippet, ACL, Tests, CO2, Troubleshooting.)
---
# Crumb Byte (CB) der zaehlbare Funke
**Ziel**
Ein CB ist ein sicher geloggter Lern-Funke: Kind handelt -> Ereignis wird mit Zeitstempel, Consent und Bestaetigung gespeichert.
CB macht Lernen messbar, ohne persoenliche Daten.
**Status**: v1
**Scope**: ESP-Wald (VLAN50), lokaler Broker, Node-RED/DB optional
**Abhaengigkeiten**: MQTT 3.1.1+, Uhrzeit (Broker/Node-RED), Netz erreichbar
---
## 1. Definition
Ein **Crumb Byte (CB)** ist 1 abgeschlossener Mikro-Zyklus:
1. Ereignis am Rand (Button/Sensor/Frage)
2. Payload mit ts (ms), device\_id, consent=true
3. Broker nimmt an
4. Server bestaetigt Persistenz (ACK)
**Kein PII.** Nur pseudonyme device\_id.
---
## 2. Broker-Parameter (Beispiel)
* Broker IP: `192.168.50.10`
* Port: `1883`
* User (ESP): `esp1` (nur write auf incr, read auf ack)
* User (Dashboard/Node-RED): `dash` (read alles, write ack/agg)
---
## 3. MQTT Topics
```
crumb/cb/incr # Edge -> Broker (einzelner Funke)
crumb/cb/ack # Server -> Edge (Persistenz bestaetigt)
crumb/cb/agg/min # Server -> Dashboard (Rollup pro Minute)
crumb/cb/alert # Server -> Dashboard (z.B. Flood-Guard)
```
**Payload incr (JSON):**
```json
{"id":"esp-hex-01","scene":"A","consent":true,"ts":1720000000}
```
**Payload ack (JSON):**
```json
{"ok":true,"id":"esp-hex-01","ts":1720000050}
```
---
## 4. Edge (ESP / MicroPython) Minimaler Sender
```python
# file: main.py
import ujson as json, utime
from umqtt.simple import MQTTClient
BROKER = "192.168.50.10"
PORT = 1883
ID = "esp-hex-01"
c = MQTTClient(ID, BROKER, PORT, keepalive=60)
c.connect()
def cb_funke(scene="A"):
msg = {
"id": ID,
"scene": scene,
"consent": True,
"ts": utime.ticks_ms()
}
c.publish(b"crumb/cb/incr", json.dumps(msg))
# Beispiel: einmal senden
# cb_funke("hex")
```
---
## 5. Node-RED Mini-Flow (60s Aggregation, Flood-Guard, ACK)
**Knoten**
* mqtt-in: topic `crumb/cb/incr`
* function: Logik (unten)
* mqtt-out: `crumb/cb/agg/min`
* mqtt-out: `crumb/cb/alert`
* mqtt-out: `crumb/cb/ack`
* storage: SQLite/Influx (optional)
**Function Node Code (3 Ausgaenge):**
```js
// Outputs:
// 1 -> crumb/cb/agg/min
// 2 -> crumb/cb/alert
// 3 -> crumb/cb/ack
const now = Date.now();
const W = 60000; // 1 min window
let start = context.get('windowStart') || now;
let cnt = context.get('cbCount') || 0;
if (now - start >= W) {
node.send([{payload:{t:start, count:cnt}}, null, null]);
start = now; cnt = 0;
}
const p = (typeof msg.payload === "string") ? JSON.parse(msg.payload) : (msg.payload||{});
const id = p.id || "unknown";
// Flood guard: max 10 CB per second per device
const bucket = Math.floor(now/1000);
const key = `flood:${id}:${bucket}`;
let secCnt = context.get(key) || 0;
if (secCnt > 10) {
node.send([null, {payload:{reason:"flood", id, ts:now}}, null]);
return null;
}
context.set(key, secCnt+1);
// Count + ack
cnt += 1;
context.set('windowStart', start);
context.set('cbCount', cnt);
node.send([null, null, {payload:{ok:true, id, ts:now}}]);
return null;
```
---
## 6. Mosquitto Minimal-Config (Ausschnitt)
`/etc/mosquitto/mosquitto.conf`
```
persistence true
persistence_location /var/lib/mosquitto/
log_dest file /var/log/mosquitto/mosquitto.log
listener 1883 0.0.0.0
allow_anonymous false
password_file /etc/mosquitto/passwd
acl_file /etc/mosquitto/acl
include_dir /etc/mosquitto/conf.d
```
`/etc/mosquitto/acl`
```
user esp1
topic write crumb/cb/incr
topic read crumb/cb/ack
user dash
topic read crumb/cb/#
topic write crumb/cb/ack
topic write crumb/cb/agg/min
topic write crumb/cb/alert
```
**Test lokal**
```
mosquitto_sub -h 127.0.0.1 -t 'crumb/#' -u dash -P '***' -v
mosquitto_pub -h 127.0.0.1 -t 'crumb/cb/incr' -m '{"id":"t1","consent":true,"ts":1}' -u esp1 -P '***'
```
---
## 7. Visualisierung (kindtauglich)
* Sparkline: Balken je Minute (CB/min)
* Funke-Ring (LED): 1 Puls pro CB, sanft Rot bei Alert, dann Reset
* Integrity-Badge: green >=95%, yellow 80-95%, red <80%
---
## 8. CO2 pro CB (ehrlich, grob)
Formel je Zeitraum:
```
CO2_per_CB = (Wh_total * Emissionsfaktor_gCO2_pro_Wh) / CB_gesamt
```
Wh\_total = Summe Leistung (Broker + AP + Edge) \* Zeit.
Ziel: CO2/CB runter, Integrity rauf.
---
## 9. Governance / Schutz
* Whitelist device\_id, keine PII in Payloads
* Flood guard soft (cooldown 10 s)
* Consent Flag muss true sein, sonst verwerfen
* Tgl. Report: CB Summe, Integrity %, Median Latenz, Alerts
---
## 10. Testplan (schnell)
1. Broker offen: `nc -zvw3 192.168.50.10 1883`
2. Sub: `mosquitto_sub -h 192.168.50.10 -t 'crumb/#' -u dash -P '***' -v`
3. Edge sendet `cb_funke("hex")`
4. Erwartet: `crumb/cb/incr` und `crumb/cb/ack` erscheinen innerhalb < 500 ms
5. Nach 60 s: `crumb/cb/agg/min` mit count
---
## 11. Troubleshooting (kurz)
* `OSError 113/116` am ESP: Broker-IP/Port/Firewall checken, Ping vom ESP zur Broker-IP, 2.4 GHz RSSI > -70 dBm
* Broker startet nicht: doppelte persistence\_location entfernen, Logs ansehen
* Keine Acks: Node-RED-Flow aktiv? Topic-Namen exakt? JSON gueltig?
* Fluten: `crumb/cb/alert` pruefen, Sensor entprellen
---
## 12. Glossar
* **CB**: Crumb Byte, 1 gezaehlter Funke mit Bestaetigung
* **Integrity %**: Anteil CB mit ts+consent+persistent OK
* **Flood Guard**: Schutz gegen ungewollte Event-Stuerme
---
**Warum das wichtig ist**
CB zaehlt nicht Klicks, sondern **vertrauenswuerdige Lernmomente**.
Klein, pruefbar, freundlich genau das, was ein Wald braucht.