Files
kc868-a2_solar/consigne.md
T
gilles a8f0d6ccba Initial commit — KC868-A2 contrôleur solaire ESP32
Fonctionnalités :
- Lecture RS485 Modbus Epever Tracer 4210N (115200 bps, FC03/FC04/FC16)
- Moteur de règles JSON (LittleFS) — commande automatique des relais
- Interface web mobile-first (dashboard, règles, config, historique, EPEVER, debug)
- WiFi AP+STA simultanés avec reconnexion automatique et portail captif
- mDNS configurable (pv.local par défaut)
- Configuration registres EPEVER depuis l'UI (18 registres holding)
- Historique basse/haute résolution avec graphes canvas
- VPN WireGuard optionnel (désactivé par défaut, config via UI)
- OTA firmware + filesystem via ElegantOTA
- Deep sleep / économie d'énergie

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-09 19:25:01 +02:00

573 lines
13 KiB
Markdown

# consigne.md
# Projet : Contrôleur solaire autonome KC868-A2 + Epever 4210N
---
## Rôle de l'assistant
Tu es un expert en développement d'objets IoT ESP32 avec PlatformIO.
Tu emploieras le français pour la discussion. Les commentaires de code seront en français.
---
# 1. Objectif du projet
Développer un système autonome basé sur une carte Kincony KC868-A2 (ESP32) permettant :
* Lecture des données d'un régulateur solaire Epever 4210N via RS485 Modbus
* Pilotage de 2 relais
* Gestion de 2 boutons via contacts secs DI1 / DI2
* Hébergement d'une interface web responsive adaptée smartphone
* Fonctionnement autonome via point d'accès WiFi ESP32
* Mise à jour firmware OTA via interface web
* Moteur de règles programmable depuis l'interface web
* Gestion d'un mode économie d'énergie / sleep
* Système robuste tolérant aux erreurs RS485
Le système doit fonctionner sans internet.
---
# 2. Hardware utilisé
## Carte principale
* Kincony KC868-A2
* ESP32-WROOM-32E intégré
* 2 relais
* RS485 intégré (MAX13487 — direction automatique, pas de pin DE/RE à gérer)
* Entrées contacts secs DI1 / DI2
* Alimentation 12V
## Régulateur solaire
* Epever Tracer 4210N
* Communication Modbus RS485 via RJ45
---
# 3. GPIO KC868-A2
Extraits du schéma bloc officiel de la carte :
| Fonction | GPIO | Notes |
| -------------- | ----- | ---------------------------------------------- |
| Relay 1 | GPIO15 | Actif haut |
| Relay 2 | GPIO2 | ⚠️ Pin de boot — doit être HIGH au démarrage |
| RS485 TXD | GPIO32 | Vers MAX13487 |
| RS485 RXD | GPIO35 | Depuis MAX13487 (input only) |
| DI1 | GPIO36 | Input only, pull-up interne |
| DI2 | GPIO39 | Input only, pull-up interne |
| SDA (I2C) | GPIO4 | Disponible si besoin |
| SCL (I2C) | GPIO5 | Disponible si besoin |
| 1-Wire / DTH1 | GPIO27 | Disponible si besoin |
| DTH2 / LED | GPIO26 | Disponible si besoin |
⚠️ **GPIO2** : relais 2 est sur ce pin de boot. Le relais ne doit pas forcer GPIO2 à LOW au démarrage sous peine de bloquer l'ESP32 en mode flash.
⚠️ **GPIO35 et GPIO36 / GPIO39** : ces pins sont en entrée uniquement (input-only) sur l'ESP32 — pas de sortie possible.
Tous les GPIO sont en logique 3,3V.
---
# 4. Développement logiciel
## Environnement
* Visual Studio Code
* PlatformIO
* Framework Arduino ESP32
## Langages
* C++
* HTML / CSS / JavaScript
---
# 5. Configuration PlatformIO
## platformio.ini
```ini
[env:kc868_a2]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
board_build.filesystem = littlefs
lib_deps =
bblanchon/ArduinoJson
emelianov/modbus-esp8266
me-no-dev/ESPAsyncWebServer
me-no-dev/AsyncTCP
ayushsharma82/AsyncElegantOTA
```
## Commandes utiles
```bash
pio run # Compiler
pio run --target upload # Compiler et flasher
pio run --target monitor # Moniteur série
pio run --target uploadfs # Uploader le filesystem LittleFS (/data)
pio run --target clean # Nettoyer le build
```
---
# 6. Architecture générale
```text
Epever 4210N
└── RS485 (Modbus RTU) ──► ESP32 KC868-A2
┌───────────┼───────────┐
▼ ▼ ▼
Moteur règles Relais 1/2 Boutons DI1/DI2
Interface Web (WiFi AP 192.168.4.1)
Smartphone utilisateur
```
---
# 7. Ordre de développement validé
## Étape 1 — WiFi + Interface Web + OTA
* Point d'accès WiFi actif
* Serveur web async avec pages statiques depuis LittleFS
* OTA via `/update`
## Étape 2 — Pilotage relais
* API REST ON/OFF relais 1 et 2
* Retour état relais dans le dashboard
## Étape 3 — Gestion boutons DI1 / DI2
* Lecture non-bloquante avec anti-rebond
* DI1 : bascule mode auto / manuel
* DI2 : commande manuelle relais
## Étape 4 — Lecture RS485 Epever
* Initialisation Serial2 (GPIO32 TX, GPIO35 RX)
* Lecture périodique non-bloquante des registres Epever
* Mise à jour du `SystemState` global
## Étape 5 — Moteur de règles
* Chargement règles depuis LittleFS (`rules.json`)
* Évaluation périodique des conditions
* Application des actions sur les relais
## Étape 6 — Gestion sleep / économie d'énergie
* Détection mode JOUR / NUIT via état Epever
* Deep sleep la nuit, réveil périodique
---
# 8. Câblage
## 8.1 RS485
```text
EPEVER RS485 A (D+) ───── KC868-A2 A1 / RXI
EPEVER RS485 B (D-) ───── KC868-A2 B1 / TXO
EPEVER GND ───── KC868-A2 GND (recommandé)
```
⚠️ Ne jamais connecter une alimentation provenant du RJ45 Epever.
## 8.2 Boutons (contacts secs)
```text
DI1 ----[Bouton]---- GND
DI2 ----[Bouton]---- GND
```
* DI1 : mode auto / manuel
* DI2 : commande manuelle relais
## 8.3 Relais
* Relay 1 (GPIO15) → charge 1
* Relay 2 (GPIO2) → charge 2
---
# 9. WiFi
## Mode point d'accès (AP)
```text
SSID : KC868_SOLAR
IP : 192.168.4.1
```
Le smartphone se connecte directement à la carte, sans routeur ni internet.
---
# 10. Interface Web
## Objectifs
* Responsive smartphone (mobile-first)
* Interface légère — pas de framework lourd (pas de React, Vue, etc.)
* Mise à jour dynamique par fetch JSON sans rechargement de page
* Vanilla JS + CSS simple
## Sections
```text
[ Dashboard ]
- Tension batterie (V)
- Tension PV (V)
- Courant PV (A)
- Etat jour / nuit
- Etat relais 1 et 2
- Etat RS485 (OK / erreur)
[ Commandes ]
- ON/OFF relais 1 et 2
- Bascule mode auto / manuel
[ Programmation ]
- Liste des règles actives
- Ajout / suppression règle
[ Configuration ]
- Activation sleep
- Seuils batterie
- Intervalle de lecture RS485
- Temporisations règles
[ Firmware ]
- OTA update (upload .bin)
[ Debug ]
- Logs série
- Erreurs RS485
- Etats DI1 / DI2
```
---
# 11. OTA (mise à jour firmware)
```text
http://192.168.4.1/update
```
* Upload fichier `.bin` depuis l'interface web
* Redémarrage automatique après mise à jour
* Protection par mot de passe
---
# 12. Communication Modbus Epever
## Paramètres
* Baudrate : 9600
* Adresse esclave : 1
* Modbus RTU (half-duplex)
* Serial2 : TX=GPIO32, RX=GPIO35
## Registres utiles
| Donnée | Registre | Unité | Facteur |
| --------------------- | -------- | ----------- | ------- |
| Tension PV | 0x3100 | V | ÷100 |
| Courant PV | 0x3101 | A | ÷100 |
| Puissance PV | 0x3102 | W | ÷100 |
| Tension batterie | 0x3104 | V | ÷100 |
| Courant de charge | 0x3106 | A | ÷100 |
| Etat jour/nuit | 0x200C | bit 0 = nuit | — |
| Etat charge batterie | 0x3201 | bits | — |
## Timing de lecture
* Intervalle recommandé : toutes les 5 secondes
* Timeout réponse : 200 ms maximum
* Retry : 2 tentatives maximum
---
# 13. Gestion des erreurs RS485
## Règle critique
Une erreur RS485 ne doit **jamais** bloquer :
* le serveur web
* le pilotage relais
* les boutons
* le moteur de règles
## Interdit
```cpp
// JAMAIS de boucle bloquante
while (!response) { }
delay(x);
```
## Comportement attendu
* Lecture périodique pilotée par `millis()`
* Timeout court (200 ms)
* Maximum 2 retries
* En cas d'échec : conserver la dernière valeur valide, passer `rs485_ok = false`
* L'interface web affiche l'état RS485
---
# 14. Etat système global
```cpp
struct SystemState {
// Données Epever
float battery; // Tension batterie (V)
float pv; // Tension PV (V)
float pvCurrent; // Courant PV (A)
bool sun; // true = jour
// Relais
bool relay1;
bool relay2;
// Boutons
bool di1;
bool di2;
// Santé RS485
bool rs485_ok;
unsigned long last_update; // millis() de la dernière lecture OK
};
```
---
# 15. Pilotage relais
* ON/OFF manuel depuis l'interface web
* Pilotage automatique via moteur de règles
* Pilotage manuel via boutons DI1/DI2
* État affiché en temps réel dans le dashboard
---
# 16. Boutons DI1 / DI2
* Anti-rebond logiciel (50 ms)
* DI1 : bascule mode auto ↔ manuel
* DI2 : en mode manuel, toggle relais 1
* En mode auto : les règles reprennent le contrôle
---
# 17. Moteur de règles
## Structure logique
```text
SI (conditions)
ALORS (action)
AVEC (délai optionnel en secondes)
```
## Conditions possibles
* Soleil (jour/nuit)
* Batterie > seuil
* Batterie < seuil
* Etat relais
* Etat DI
## Actions possibles
* Activer relais 1 ou 2
* Désactiver relais 1 ou 2
## Exemple règle
```text
SI soleil ET batterie > 13V → ALORS relais1 ON
SI soleil ET batterie > 13V → ATTENDRE 3600s → ALORS relais2 ON
```
## Format JSON (stocké dans LittleFS `rules.json`)
```json
[
{
"id": 1,
"enabled": true,
"sun": true,
"battery_min": 13.0,
"battery_max": 0,
"relay": 1,
"state": true,
"delay": 0
}
]
```
| Champ | Type | Description |
| ------------- | ------- | ----------------------------------------- |
| `id` | int | Identifiant unique |
| `enabled` | bool | Règle active ou non |
| `sun` | bool | Condition soleil (true=jour, false=nuit) |
| `battery_min` | float | Seuil min batterie en V (0 = ignoré) |
| `battery_max` | float | Seuil max batterie en V (0 = ignoré) |
| `relay` | int | Numéro relais (1 ou 2) |
| `state` | bool | true = ON, false = OFF |
| `delay` | int | Délai avant action (secondes) |
## Timing des règles
```cpp
// Évaluation pilotée par millis(), jamais par delay()
if (millis() - lastRuleEval > RULE_INTERVAL_MS) {
evaluerRegles();
lastRuleEval = millis();
}
```
---
# 18. Gestion de l'énergie
## Mode JOUR
```text
WiFi ON
Serveur web ON
Lecture Epever active (toutes les 5s)
Règles actives
```
## Mode NUIT
```text
WiFi OFF
Serveur web OFF
Deep sleep
Réveil périodique (configurable, ex: 10 min)
Lecture Epever au réveil
Si toujours nuit → retour deep sleep
```
## Paramètres configurables
* Activation / désactivation du sleep
* Intervalle de réveil (secondes)
* Seuil de détection soleil (valeur registre 0x200C)
* Mode : deep sleep ou light sleep
## Contraintes deep sleep
* Deep sleep = reboot complet de l'ESP32
* UART indisponible pendant le sleep
* Les relais conservent leur état (verrouillage mécanique)
* Variables RAM perdues au réveil → sauvegarder en RTC memory si besoin
---
# 19. Consommation estimée
| Mode | Consommation |
| ------ | ------------ |
| Normal | 1.8 à 4 W |
| Sleep | 0.1 à 0.6 W |
---
# 20. Structure projet PlatformIO
```text
/src
main.cpp ← boucle principale, init, dispatcher
wifi.cpp ← AP WiFi
webserver.cpp ← serveur HTTP async, endpoints REST
ota.cpp ← mise à jour OTA
modbus.cpp ← lecture RS485 Epever non-bloquante
relais.cpp ← contrôle GPIO relais
rules.cpp ← évaluation moteur de règles
sleep.cpp ← gestion deep sleep
buttons.cpp ← lecture DI1/DI2 avec anti-rebond
/include
config.h ← constantes GPIO, SSID, intervalles
state.h ← déclaration SystemState
/data
index.html ← interface web principale
style.css
app.js ← fetch JSON, mise à jour dynamique
rules.json ← règles persistées (LittleFS)
```
---
# 21. Contraintes de conception
## Non-bloquant partout
Toute la logique doit utiliser `millis()` et des machines à états. Jamais de `delay()` ni de boucle d'attente.
## RS485 half-duplex
* Le MAX13487 gère automatiquement la direction (pas de pin DE)
* Ne pas lire trop fréquemment : respecter l'intervalle de 5 secondes
* Bien gérer le timeout de 200 ms par requête Modbus
## GPIO2 (Relay 2)
* GPIO2 est un pin de strapping de boot sur ESP32
* S'assurer que le relais ne tire pas GPIO2 à LOW au démarrage
## LittleFS
* Le filesystem doit être uploadé séparément : `pio run --target uploadfs`
* La partition LittleFS doit être configurée dans `platformio.ini`
---
# 22. Evolutions possibles
* MQTT / Home Assistant
* Historique graphique (Chart.js)
* Mode STA (connexion au routeur existant)
* Accès distant VPN
* Conditions avancées ET / OU dans les règles
* Gestion des priorités entre règles
* Notifications push
---
# 23. Objectif final
Le système final doit être :
* **autonome** — fonctionne sans internet ni serveur externe
* **robuste** — tolérant aux erreurs RS485 et aux redémarrages
* **configurable** — réglable depuis un smartphone
* **optimisé énergie** — mode sleep la nuit
* **extensible** — architecture modulaire facilitant les ajouts
* **maintenable** — code commenté en français, structure claire
---