> ⚠️ **Funktioniert nicht. Konflikt zwischen mehreren SPI nicht von Claude in
> angemessener Zeit lösbar.**

# VL53L5CX an ESP32-C3 (0.42" OLED Board) anschließen

Diese Anleitung beschreibt die Verkabelung des VL53L5CX (8×8 Time-of-Flight
Multizonen-Sensor) an das **ESP32-C3 0,42-Zoll OLED Development Board**
(Type-C, Keramikantenne — verschiedene Hersteller/AliExpress-Listings, häufig
unter "01Space ESP32-C3 0.42 OLED" geführt) für die [firmware.ino](firmware.ino)
in diesem Verzeichnis.

## Wichtig: dieses Board hat nur EINEN I2C-Bus

Das eingebaute 0,42″-OLED (72×40 Pixel sichtbar, SSD1306-Controller,
I2C-Adresse `0x3C`) ist auf diesem Exemplar intern fest auf **GPIO5 (SDA) /
GPIO6 (SCL)** verdrahtet (so verlötet, OLED läuft damit). Der ESP32-C3 hat
aber nur eine I2C-Hardware-Peripherie — es gibt **keinen zweiten, freien
I2C-Bus** für den externen Sensor.

**Lösung (Versuch):** Der VL53L5CX wurde an die **gleichen** Pins (GPIO5/GPIO6)
gehängt wie das OLED. Das sollte funktionieren, weil beide Geräte
unterschiedliche I2C-Adressen haben (OLED `0x3C`, VL53L5CX `0x29`) — mehrere
Geräte am selben I2C-Bus sind Standard, kein Konflikt. **In der Praxis bisher
ohne Erfolg** — der Sensor wird über `/i2c` (Adresse `0x29`) nicht gefunden,
trotz korrekt verlötetem LPN (3.3V) und geprüften Lötstellen.

## Benötigte Hardware

- ESP32-C3 0.42" OLED Development Board (Type-C, wie oben beschrieben)
- VL53L5CX Breakout-Board mit I2C/Qwiic-Anschluss (z.B. SparkFun SEN-18642
  oder vergleichbar). **Wichtig:** ein Breakout-Board verwenden, kein nacktes
  VL53L5CX-Die — das Breakout enthält den nötigen 3.3V-Spannungsregler.

## Pin-Belegung

| VL53L5CX Pin   | ESP32-C3 Pin   | Beschreibung                                              |
|----------------|----------------|------------------------------------------------------------|
| `VIN` / `3V3`  | `3V3`          | Versorgungsspannung (3.3 V)                                |
| `GND`          | `GND`          | Masse                                                       |
| `SDA`          | `GPIO5`        | I2C Datenleitung — **gleicher Pin wie das eingebaute OLED** |
| `SCL`          | `GPIO6`        | I2C Taktleitung — **gleicher Pin wie das eingebaute OLED**  |
| `LPN`          | `3V3`          | Enable, **active-LOW** (LOW = I2C deaktiviert). Viele Breakouts haben hier schon einen 47kΩ-Pull-up; feste 3.3V-Verbindung ist trotzdem robuster |
| `INT`          | *offen / nicht verbunden* | Interrupt-Pin — wird in dieser Firmware nicht benötigt (Polling per `isDataReady()`) |

> **Anderes Board?** Falls du statt des 0.42"-OLED-Boards ein anderes
> ESP32-C3-Devboard verwendest (ohne eingebautes Display), prüfe dessen
> Pinout-Diagramm und passe `SDA_PIN`/`SCL_PIN` ganz oben in
> [firmware.ino](firmware.ino) entsprechend an.

> **Pull-up-Widerstände:** Die meisten VL53L5CX-Breakout-Boards haben bereits
> Pull-up-Widerstände (4.7 kΩ) für SDA/SCL integriert. Bei kurzen Kabeln
> (< 20 cm) sind keine zusätzlichen Widerstände nötig.

## ASCII-Schaubild

```
   ESP32-C3 0.42" OLED Board                 VL53L5CX Breakout (I2C / Qwiic)
  ┌─────────────────────────┐               ┌───────────────────────────┐
  │   ┌─────────┐            │               │                           │
  │   │ 0.42"   │            │               │                           │
  │   │ OLED    │◄── intern ─┼─ GPIO5 (SDA)  │                           │
  │   │ 0x3C    │◄── intern ─┼─ GPIO6 (SCL)  │                           │
  │   └─────────┘            │               │                           │
  │                          │               │                           │
  │   3V3   ●────────────────┼───────────────►  VIN / 3V3                │
  │   GND   ●────────────────┼───────────────►  GND                      │
  │ GPIO5 ● ┼─── (selber Pin wie OLED-SDA) ──►  SDA   (Adresse 0x29)      │
  │ GPIO6 ● ┼─── (selber Pin wie OLED-SCL) ──►  SCL                      │
  │                          │               │                           │
  │                          │     3V3 ──────►  LPN   (Enable, high)     │
  │                          │     offen ────►  INT   (nicht verwendet)  │
  └─────────────────────────┘               └───────────────────────────┘
            ▲
           USB-C (5V, 3.3V wird onboard erzeugt)
```

I2C-Bus mit zwei Teilnehmern an denselben Leitungen (GPIO5/GPIO6), unterschieden
durch ihre Adresse:

```
        GPIO5/SDA ───┬─────────────────┬──────────────► OLED (0x3C)
        GPIO6/SCL ───┤                 │
                      └─────────────────┴──────────────► VL53L5CX (0x29)
```

### Draufsicht / Übersicht des Aufbaus

```
   ┌────────────┐        I2C-Bus (GPIO5/6 + 3V3/GND)        ┌──────────────┐
   │  ESP32-C3  │  ════════════════════════════════════════ │  VL53L5CX    │
   │ + 0.42"    │  ════════════════════════════════════════ │  (8x8 ToF)   │
   │  OLED      │                                            └──────┬───────┘
   └─────┬──────┘                                                   │
         │                                                          │
         │ WLAN (STA → vorhandenes Netz, oder AP → eigenes Netz)    │ Sichtfeld
         ▼                                                          ▼
   ┌────────────┐                                            ░░░░░░░░░░░░░░
   │  Browser   │  <─ WS Push (Port 81, sofort) ────────────  64 (od. 16)
   │ (Landing-  │  <─ HTTP Fallback ────────────────────────  Distanzwerte
   │  Page)     │     GET /api/points (JSON-Array)             (mm), 8x8/4x4
   └────────────┘
```

## Software / Bibliotheken (Arduino IDE)

1. **Boardverwalter:** „esp32“ von Espressif Systems installieren, Board
   **„ESP32C3 Dev Module“** auswählen.
2. **Bibliotheksverwalter:** folgende Bibliotheken installieren:
   - „**SparkFun VL53L5CX**“ von SparkFun Electronics
   - „**WebSockets**“ von Markus Sattler (Links2004) — für den Push-Kanal auf Port 81
   - „**U8g2**“ von oliver (olikraus) — für das eingebaute 0.42"-OLED
3. In [firmware.ino](firmware.ino) ganz oben anpassen (nur als Erst-Boot-Default,
   siehe „Inbetriebnahme“ unten — danach alles über `/config` änderbar):
   - `DEFAULT_WIFI_SSID` / `DEFAULT_WIFI_PASSWORD` — das WLAN, das zuerst versucht wird
   - `AP_SSID` / `AP_PASSWORD` — Name/Passwort des Fallback-Access-Points
   - `SDA_PIN` / `SCL_PIN` — auf `5`/`6` voreingestellt (passend zum 0.42"-OLED-Board); nur ändern, wenn ein anderes Board ohne eingebautes Display verwendet wird

## Inbetriebnahme (Provisioning) ohne erneutes Flashen

WLAN-Zugangsdaten, Sensor-Frequenz und Sensor-Auflösung sind **nicht mehr nur
Compile-Konstanten**, sondern werden persistent im Flash (Preferences/NVS)
gespeichert und über die Konfigurationsseite geändert:

1. Erstes Flashen mit den `DEFAULT_*`-Werten (oder einfach Default lassen).
2. Findet der ESP32 das hinterlegte WLAN nicht, startet er den Access Point
   `VL53L5CX-ESP32` (Passwort `tofsensor`).
3. Mit diesem AP verbinden, Browser öffnen: `http://192.168.4.1/config`
4. Dort echtes WLAN, Sensor-Auflösung (8×8/4×4) und Frequenz eintragen,
   **Speichern & Neustart** klicken — der ESP32 bootet neu und verbindet
   sich mit dem eingetragenen WLAN.
5. Ab da ist die Seite jederzeit über `/config` (im STA-Modus z.B.
   `http://vl53l5cx.local/config`) erreichbar, um Werte zu ändern.

> Die Konfigurationsseite läuft über **unverschlüsseltes HTTP ohne
> Login** — nur fürs lokale (Heim-)Netz gedacht, nicht ins Internet exponieren.

## Verhalten der Firmware (Kurzfassung)

- **Boot-Log:** Über die serielle Schnittstelle (115200 Baud) wird beim Start
  ausführlich geloggt: Chip-Infos, geladene Konfiguration, alle gefundenen
  WLAN-Netze inkl. RSSI/Kanal (mit Markierung `[ZIEL]` falls das konfigurierte
  Netz dabei ist), gewählter Modus (STA/AP) mit IP/MAC, sowie der
  Sensor-Initialisierungsstatus.
- Der VL53L5CX wird **nur dann aktiv ausgelesen**, wenn in den letzten 5
  Sekunden jemand die Landing-Page (`/`) oder die API (`/api/points`)
  aufgerufen hat, **oder** mindestens ein WebSocket-Client verbunden ist.
  Ist niemand da, wird das Ranging gestoppt.
- **WebSocket-Push (Port 81):** Jeder verbundene Client (`ws://<ip>:81/`)
  bekommt jeden neu ausgelesenen Frame **sofort** nach dem Lesen als JSON
  gepusht — kein Polling-Delay. Die Landing-Page nutzt diesen Kanal
  automatisch und fällt nur bei Verbindungsabbruch auf HTTP-Polling
  (`/api/points`) zurück.
- Die Landing-Page zeigt die Distanzwerte als farbiges Grid (Größe passt sich
  automatisch an 8×8 oder 4×4 an) sowie als rohes JSON-Array an.
- **Eingebautes OLED:** zeigt durchgehend WLAN-Modus (`STA`/`AP`), die aktuelle
  IP-Adresse und den Sensor-Status (`aktiv` / `idle` / `---` falls nicht
  gefunden) an. Wird einmal direkt nach WLAN-Verbindung/Sensor-Init aktualisiert
  und danach jede Sekunde aufgefrischt, damit "aktiv"/"idle" live mitgeht.
- **I2C-Übersicht (`/i2c`):** Debug-Seite, scannt beim Aufruf den gesamten
  I2C-Bus (Adressen `0x01`–`0x7E`) und listet alle antwortenden Geräte auf
  (bekannte Adressen wie `0x3C` = OLED, `0x29` = VL53L5CX werden benannt).
  Zeigt zusätzlich den aktuellen `sensorFound`-Status und bietet einen Button
  „Sensor erneut initialisieren“, der `myImager.begin()` neu auslöst — ohne
  dass das Gerät neu starten muss. Aktueller Befund: hier erscheint nur
  `0x3C` (OLED), `0x29` (VL53L5CX) fehlt.
- API-Antwort von `GET /api/points` bzw. WebSocket-Push (Beispiel, 8×8):

```json
{
  "active": true,
  "ranging": true,
  "sensorFound": true,
  "hz": 10,
  "resolution": 64,
  "rows": 8,
  "cols": 8,
  "wsClients": 1,
  "timestampMs": 123456,
  "wifiMode": "STA (ZyXEL7A9E80)",
  "ip": "10.0.0.54",
  "distanceMm": [1200, 1185, ...],
  "status": [5, 5, ...]
}
```

### Hinweis zur bestehenden Node.js-Bridge (`room.config`)

Das übergeordnete Projekt (`server.js` / `room.config`) erwartet aktuell einen
ESP32-WebSocket unter `ws://<ip>/ws` (Port 80, Pfad `/ws`, CSV-Frames). Diese
Firmware nutzt bewusst einen **eigenständigen** WebSocket auf **Port 81**
(Pfad `/`, JSON statt CSV), da das die einfachste/stabilste Bibliothek auf dem
ESP32-C3 ist. Falls die bestehende Node-Bridge direkt mit dieser Firmware
sprechen soll, müsste entweder `room.config` (`esp.wsUrl`) auf
`ws://<ip>:81/` angepasst werden, oder die Firmware auf Port 80 + Pfad `/ws`
+ CSV-Format umgestellt werden — sag Bescheid, falls das gewünscht ist.
