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.
