# Émulateur QEMU ESP32 — KC868-A2 Émulation du firmware sur QEMU ESP32 (fork Espressif, GPL). Interface de débogage 3 volets : GPIO / terminal série / webserver ESP32. ## Architecture ``` Docker ├── qemu-system-xtensa (ESP32 firmware + WiFi + réseau) │ UART0 → stdout (logs Serial.print → terminal) │ UART2 → TCP:1235 (Modbus RTU ← stub Python) │ NIC → slirp (hostfwd port 10080 → ESP32:80) │ ├── modbus_stub.py (émulateur Modbus RTU slave Epever) │ Se connecte à TCP:1235, répond aux FC04 avec données simulées │ └── server.py (interface web débogage, port 8888) / → UI 3 volets /serial → SSE flux UART0 /api/* → proxy vers webserver ESP32 (port 10080) ``` ## Prérequis - Docker + Docker Compose - Firmware compilé avec PlatformIO : `pio run` ## Lancement ### Option 1 — Serveur de simulation (recommandé) Sert les vrais fichiers `data/` + simule tous les `/api/*` en mémoire. L'état des relais, règles et config sleep sont modifiables via l'interface. L'historique s'alimente toutes les 5 secondes (= 5 min en temps réel). ```bash # Sans Docker (Python 3 requis) : cd emulator && python3 sim.py # Avec Docker : cd emulator && docker compose up sim ``` Accès : **http://localhost:8087** --- ### Option 2 — Émulateur QEMU (boot séquence + terminal série) Exécute le vrai binaire compilé. Montre le boot ESP32 et les logs Serial. Le firmware crashe au démarrage de WiFi (hardware non émulé) — normal. ```bash # 1. Compiler le firmware pio run && pio run -t buildfs # 2. Copier les binaires cp .pio/build/kc868_a2/*.bin emulator/firmware/ # 3. Démarrer cd emulator && docker compose up --build emulator ``` Accès : - **Interface de débogage** : http://localhost:8888 - **WebServer ESP32** : http://localhost:10080 (si WiFi démarre) ## Mise à jour de la version QEMU Si le téléchargement échoue, vérifier la dernière version disponible sur : https://github.com/espressif/qemu/releases Modifier `QEMU_TAG` et `QEMU_ARCHIVE` dans le `Dockerfile`. ## Correctif registres WiFi (LoadStorePIFAddrError) Le QEMU Espressif standard n'émule pas les registres matériels WiFi modem (`0x60033C00`). Sans correctif, le firmware crash en boucle avec `LoadStorePIFAddrError` dès l'initialisation WiFi. **Solution** : le `Dockerfile` utilise un build multi-étapes : 1. **`rom-extractor`** — télécharge le binaire pré-compilé, extrait les ROM blobs ESP32 (fichiers binaires propriétaires) 2. **`qemu-builder`** — clone le source Espressif QEMU, applique `wifi_stub_patch.py`, compile uniquement la cible xtensa 3. **Image finale** — ROM blobs de l'étape 1 + binaire patché de l'étape 2 `wifi_stub_patch.py` injecte un appel `create_unimplemented_device()` dans `hw/xtensa/esp32.c` qui mappe silencieusement la plage `0x60033C00–0x60043BFF` (64 Ko, WiFi MAC + baseband) : toutes les lectures retournent 0, les écritures sont ignorées, plus de fault CPU. > **Note** : le build initial prend 15–30 min (compilation QEMU). Docker met > les layers en cache — les rebuilds suivants sont instantanés. ## Limites connues | Fonctionnalité | État | |---|---| | WiFi AP mode (softAP) | Registres stubés (pas de WiFi réel) — le firmware démarre | | Webserver ESP32 (port 80) | Accessible via hostfwd → port 10080 si WiFi s'initialise | | Modbus RS485 | Émulé par `modbus_stub.py` (données sinusoïdales) | | GPIO physiques (DI1/DI2) | Non émulés — toujours à 0 | | Deep sleep | Non supporté dans QEMU | | OTA | Non testé | ## Modbus simulé Le stub `modbus_stub.py` répond aux lectures FC04 des registres Epever Tracer 4210N : | Registre | Valeur simulée | |---|---| | 0x3100 PV tension | ~18.72 V (variation sinusoïdale) | | 0x3101 PV courant | ~4.20 A | | 0x3104 Batterie | ~13.45 V | | 0x310E Load | 26.80 W | | 0x311A SOC | 75 % | | 0x3200 Statut | Float charge | | 0x200C Jour/Nuit | Jour | ## Arrêt ```bash docker compose down ``` Pour quitter la console QEMU (dans le terminal) : `Ctrl+A` puis `X`.