From df350c10f551f623fb589096eaf56c7440e6acd0 Mon Sep 17 00:00:00 2001 From: Gilles Soulier Date: Sat, 9 May 2026 19:29:55 +0200 Subject: [PATCH] =?UTF-8?q?Ajout=20README.md=20=E2=80=94=20documentation?= =?UTF-8?q?=20compl=C3=A8te=20du=20projet?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Couvre : matériel, brochage, architecture, API REST, bibliothèques, commandes build/flash, configuration runtime, registres Modbus, et section TODO (MQTT, version firmware, audit code mort, PSK WireGuard…) Co-Authored-By: Claude Sonnet 4.6 --- README.md | 270 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 270 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..ed139bd --- /dev/null +++ b/README.md @@ -0,0 +1,270 @@ +# KC868-A2 — Contrôleur Solaire ESP32 + +Système embarqué autonome de supervision et de pilotage d'une installation solaire. +Fonctionne sans internet, sans cloud, sans application mobile — tout passe par une interface web hébergée sur l'ESP32. + +--- + +## Matériel + +| Composant | Référence | +|-----------|-----------| +| Contrôleur | **Kincony KC868-A2** (ESP32-WROOM-32) | +| Régulateur solaire | **Epever Tracer 4210N** (MPPT 40A) | +| Communication | RS485 Modbus RTU | +| Interface | RJ45 8P8C côté Epever | + +### Brochage RS485 + +``` +Epever RJ45 (vue de face, languette bas) KC868-A2 + Pin 3 / 4 → RS485-B (D-) → B− + Pin 5 / 6 → RS485-A (D+) → A+ + Pin 7 / 8 → GND → GND (optionnel) + Pin 1 / 2 → +7.5V ⚠ NE PAS CONNECTER +``` + +**Paramètres Modbus :** esclave 1, 115200 bps, 8N1, RTU, half-duplex. + +### GPIO ESP32 + +| Signal | Pin | Note | +|--------|-----|------| +| Relais 1 | GPIO 15 | | +| Relais 2 | GPIO 2 | Pin de strapping boot — reste HIGH au démarrage | +| RS485 TX | GPIO 32 | | +| RS485 RX | GPIO 35 | Input only | +| Entrée DI1 | GPIO 36 | Input only | +| Entrée DI2 | GPIO 39 | Input only | + +--- + +## Fonctionnalités + +### Acquisition de données (Modbus RTU) +- Tension / courant / puissance panneau solaire (PV) +- Tension / courant / puissance sortie de charge (load) +- Tension, SOC (%), température et statut batterie +- Énergie générée/consommée (jour et total, kWh) +- Détection jour/nuit et horloge interne de l'Epever +- Fréquence de lecture configurable (mode jour / mode nuit) + +### Commande +- **2 relais** commandés manuellement ou automatiquement +- **2 entrées numériques** (DI1, DI2) — contacts secs +- État des relais sauvegardé en NVS (survit aux coupures) + +### Moteur de règles +Règles JSON stockées dans LittleFS. Chaque règle combine : +- Déclencheurs : ensoleillement (jour/nuit), état DI1/DI2 +- Conditions : seuil batterie min/max, seuil PV min/max +- Action : relais ON/OFF avec délai optionnel et hystérésis + +### Interface web (mobile-first) +Accessible sur `http://192.168.4.1` (AP) ou `http://pv.local` (mDNS) : + +| Onglet | Contenu | +|--------|---------| +| Dashboard | Relais, entrées, PV, batterie, load, énergie | +| Règles | Liste, ajout, activation/désactivation, suppression | +| Config | Relais manuels, noms, sleep, OTA, WiFi, WireGuard VPN | +| Historique | Graphes 4h (1 min) et 30h (5 min) exportables CSV | +| Config EPEVER | Lecture/écriture des 18 registres holding du régulateur | +| Debug | Journal série en mémoire | + +### Réseau +- **Mode AP permanent** : `kc868-a2` / `soleil12` → `192.168.4.1` +- **Mode STA optionnel** : connexion à un réseau WiFi existant (scan + NVS) +- **Portail captif** : iOS/Android/Windows ouvrent l'UI automatiquement +- **mDNS** : `pv.local` configurable depuis l'interface + +### VPN WireGuard *(optionnel, désactivé par défaut)* +Tunnel chiffré vers un serveur WireGuard distant. +Configuration complète depuis l'onglet Config — clés, endpoint, IP locale, keepalive. +Actif uniquement quand la STA WiFi est connectée ; l'accès local via AP reste toujours disponible. + +### Deep sleep +Mode économie d'énergie configurable : l'ESP32 se rendort entre les cycles de mesure la nuit (PV < seuil), se réveille périodiquement et évalue les règles. + +### OTA +Mise à jour firmware et filesystem via `http://192.168.4.1/update` (ElegantOTA). + +--- + +## Architecture logicielle + +``` +src/ +├── main.cpp — Init + boucle principale (non bloquante) +├── modbus_epever.cpp — Lecture RS485 Modbus RTU (FC02/03/04/16), CRC manuel +├── epever_config.cpp — Lecture/écriture des 18 registres holding de configuration +├── webserver.cpp — Serveur HTTP async + 30+ routes REST +├── wifi_ap.cpp — WiFi AP+STA, mDNS, portail captif, reconnexion auto +├── wireguard_vpn.cpp — Tunnel WireGuard (optionnel) +├── rules.cpp — Moteur de règles JSON +├── historique.cpp — Historique RAM (hires 4h) + LittleFS (lores 30h) +├── sleep.cpp — Deep sleep + restauration état relais +├── buttons.cpp — Entrées numériques DI1/DI2 avec anti-rebond +├── ota.cpp — ElegantOTA async +└── debug_log.cpp — Journal en mémoire (ring buffer) + +include/ — Headers correspondants + config.h + state.h + +data/ — Assets web (LittleFS) +├── index.html — SPA 6 onglets +├── app.js — Logique JS (~1100 lignes) +└── style.css — Thème sombre mobile-first +``` + +**Principe fondamental :** aucun `delay()` ni boucle bloquante. +Tout le timing passe par `millis()`. Les lectures RS485 ont un timeout court ; en cas d'erreur, le dernier état valide est conservé. + +### API REST (sélection) + +| Méthode | Endpoint | Description | +|---------|----------|-------------| +| GET | `/api/state` | État système complet (JSON) | +| POST | `/api/relay/1/on` | Relais 1 ON | +| POST | `/api/relay/1/toggle` | Toggle + sauvegarde NVS | +| GET | `/api/rules` | Liste des règles | +| POST | `/api/rules` | Ajout de règle (JSON) | +| GET | `/api/epever/config` | Lecture config EPEVER depuis le régulateur | +| POST | `/api/epever/config` | Écriture config EPEVER | +| GET | `/api/wifi/status` | Statut AP + STA | +| GET | `/api/wifi/scan` | Scan réseaux disponibles | +| POST | `/api/wifi/sta` | Connexion à un réseau WiFi | +| GET | `/api/mdns` | Hostname mDNS courant | +| POST | `/api/mdns` | Modification hostname mDNS | +| GET | `/api/wireguard` | Config et statut WireGuard | +| POST | `/api/wireguard` | Sauvegarde config WireGuard | +| GET | `/api/history/hires` | Historique 4h (1 min/point) | +| GET | `/api/history/csv` | Export CSV (30h) | +| GET | `/api/sleep` | Config deep sleep | +| POST | `/api/modbus` | Intervalles de lecture Modbus | + +--- + +## Bibliothèques utilisées + +| Bibliothèque | Version | Rôle | +|-------------|---------|------| +| [ArduinoJson](https://arduinojson.org/) | ^7.0 | Sérialisation JSON | +| [AsyncTCP](https://github.com/me-no-dev/AsyncTCP) | git | TCP non bloquant | +| [ESPAsyncWebServer](https://github.com/me-no-dev/ESPAsyncWebServer) | git | Serveur HTTP async | +| [ElegantOTA](https://github.com/ayushsharma82/ElegantOTA) | ^3.1 | OTA via navigateur | +| [modbus-esp8266](https://github.com/emelianov/modbus-esp8266) | ^4.1 | Modbus RTU (utilisé pour les fonctions bas niveau) | +| [WireGuard-ESP32-Arduino](https://github.com/ciniml/WireGuard-ESP32-Arduino) | git | VPN WireGuard (kc868_a2 uniquement) | + +Intégrées dans le framework ESP32 Arduino : `WiFi`, `DNSServer`, `ESPmDNS`, `Preferences` (NVS), `LittleFS`. + +--- + +## Outils + +- **[PlatformIO](https://platformio.org/)** — build, flash, monitor +- **Framework** : Arduino pour ESP32 (espressif32) +- **Filesystem** : LittleFS + +--- + +## Build et flash + +### Prérequis +- PlatformIO Core ou PlatformIO IDE (VS Code) +- Câble USB pour le premier flash, WiFi pour les suivants (OTA) + +### Commandes + +```bash +pio run # Compiler +pio run -e kc868_a2 --target upload # Flasher par USB +pio run -e kc868_a2 --target uploadfs # Flasher le filesystem (LittleFS) +pio run --target monitor # Moniteur série 115200 bps +pio run -e qemu # Build émulateur (sans WireGuard ni WiFi) +``` + +### OTA (après premier flash) + +Ouvrir `http://192.168.4.1/update` (ou `http://pv.local/update`) : +1. Sélectionner **Firmware** → uploader `.pio/build/kc868_a2/firmware.bin` +2. Sélectionner **Filesystem** → uploader `.pio/build/kc868_a2/littlefs.bin` + +--- + +## Configuration + +### WiFi AP (compile-time) +Dans `include/config.h` : +```cpp +#define WIFI_SSID "kc868-a2" +#define WIFI_PASSWORD "soleil12" +``` + +### WiFi STA (runtime) +Onglet Config → section Connexion WiFi → scanner, choisir le réseau, saisir le mot de passe. + +### Connexion WiFi STA + nom mDNS (runtime) +Onglet Config → section Connexion WiFi. + +### VPN WireGuard (runtime) +Onglet Config → section VPN WireGuard : +- Coller la clé privée de l'interface ESP32 +- Coller la clé publique du serveur +- Renseigner l'endpoint (`mon.domaine.org`) et le port (`51820`) +- IP locale WireGuard (ex. `10.8.0.16`) +- Keepalive recommandé : `25` s pour maintenir le NAT actif +- Activer et sauvegarder + +> **Sécurité :** les clés sont stockées dans la NVS flash de l'ESP32. Ne jamais committer le fichier `.conf` WireGuard dans git (il est dans `.gitignore`). + +### Deep sleep +Onglet Config → Mode économie d'énergie : activer, régler l'intervalle de réveil et le seuil PV. + +--- + +## Registres Modbus lus + +| Registre | Données | Format | +|----------|---------|--------| +| 0x3100 | Tension PV | U16 × 0.01 V | +| 0x3101 | Courant PV | U16 × 0.01 A | +| 0x3104 | Tension batterie | U16 × 0.01 V | +| 0x3105 | Courant batterie | S16 × 0.01 A | +| 0x3106 | Tension load | U16 × 0.01 V | +| 0x3107 | Courant load | U16 × 0.01 A | +| 0x310C | Température batterie | S16 × 0.01 °C | +| 0x311A | SOC batterie | U16 % | +| 0x3201 | Statut batterie | bitfield | +| 0x3302 | Énergie générée jour | U32 × 0.01 kWh | +| 0x3304 | Énergie générée total | U32 × 0.01 kWh | +| 0x3306 | Énergie consommée jour | U32 × 0.01 kWh | +| 0x3308 | Énergie consommée total | U32 × 0.01 kWh | +| 0x200C | État jour/nuit | bitfield | +| 0x9013 | Horloge RTC | 3 × U16 | + +--- + +## TODO + +### Fonctionnalités + +- [ ] **Publication MQTT** — envoi périodique de l'état système vers un broker MQTT (Home Assistant, Mosquitto…). Topics suggérés : `solar/state`, `solar/relay/1`, etc. +- [ ] **Version firmware dans l'UI** — afficher le numéro de version (défini dans `config.h`) sur le dashboard et dans l'en-tête de l'API `/api/state` +- [ ] **Améliorations interface web** — graphes plein écran, export PDF, notifications push navigateur (PWA), mode nuit/jour automatique de l'UI +- [ ] **Support PSK WireGuard** — la bibliothèque `WireGuard-ESP32-Arduino` n'expose pas encore la preshared key dans son API Arduino ; patcher la lib ou utiliser un fork qui le supporte +- [ ] **Alertes** — notification (email, webhook, MQTT) quand la batterie est basse, le RS485 déconnecté, ou un relais en défaut +- [ ] **Gestion multi-règles avancée** — priorité entre règles, règles avec plage horaire + +### Code / qualité + +- [ ] **Audit code mort** — vérifier si `modbus-esp8266` est encore utile (le code Modbus utilise du Serial2 raw + CRC manuel depuis la correction du RS485 ; les fonctions de la lib pourraient être inutilisées) +- [ ] **`backup/`** — le dossier est un instantané manuel ; le supprimer du repo une fois que l'historique git remplit ce rôle +- [ ] **Secrets compile-time** — `WIFI_PASSWORD` et `OTA_PASSWORD` dans `config.h` en clair ; les déplacer dans un fichier `secrets.h` exclu du repo +- [ ] **Tests unitaires** — couvrir le moteur de règles et le décodage Modbus avec des tests PlatformIO (dossier `test/`) +- [ ] **Emulateur QEMU** — vérifier que le build `qemu` et les scripts Python du dossier `emulator/` sont encore synchronisés avec l'état actuel du firmware + +--- + +## Licence + +Usage personnel — aucune licence définie.