Files
kc868-a2_solar/plan.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

10 KiB
Raw Blame History

Plan de développement — Configuration EPEVER

Basé sur l'analyse de consigne_amelioration_epever_config_md.md et du code existant.


État actuel du projet (base de travail)

Module Fichier État
Modbus RTU (lecture brute) modbus_epever.cpp Fonctionnel à 115 200 bauds
FC03 holding read lireHoldingBruts() Utilisé pour RTC
FC16 holding write ecrireHoldingMultiplesBrut() Utilisé pour RTC
Webserver REST webserver.cpp Pattern AsyncCallbackJsonWebHandler établi
Persistance LittleFS rules.cpp/rules.json Patron JSON réutilisable
Persistance NVS relais, noms, modbus, sleep Patron Preferences établi
UI web (onglets) data/index.html + app.js Architecture multi-onglets existante

Infrastructure à réutiliser sans modification : lireHoldingBruts(), ecrireHoldingMultiplesBrut(), lectureEnCours, AsyncCallbackJsonWebHandler, pattern LittleFS JSON.


Registres Epever cibles (Holding FC03 / FC16)

Deux blocs consécutifs lisibles en une seule trame chacun :

Bloc 1 — 0x9000 à 0x900D (14 registres, facteur ÷100 sauf 0x9000/9001)

Registre Clé JSON Unité Facteur Min Max Écriture
0x9000 battery_type ×1 0 4 (0=User,1=Sealed,2=GEL,3=Flooded,4=Li)
0x9001 battery_capacity Ah ×1 1 9999
0x9002 temp_compensation mV/°C/2V ×1 -9 0
0x9003 overvoltage_disconnect V ÷100 13.0 16.0
0x9004 charging_limit V ÷100 13.0 15.5
0x9005 overvoltage_reconnect V ÷100 13.0 16.0
0x9006 equalize_voltage V ÷100 13.0 15.5
0x9007 boost_voltage V ÷100 13.5 15.0
0x9008 float_voltage V ÷100 13.0 14.5
0x9009 boost_reconnect V ÷100 11.0 13.5
0x900A low_reconnect V ÷100 10.0 13.5
0x900B undervolt_warning V ÷100 10.0 13.0
0x900C low_disconnect V ÷100 9.0 13.0
0x900D discharge_limit V ÷100 9.0 13.0

Bloc 2 — 0x906B à 0x906E (4 registres)

Registre Clé JSON Unité Facteur Min Max Écriture
0x906B rated_voltage ×1 0 2 (0=auto,1=12V,2=24V)
0x906C equalize_duration min ×1 0 180
0x906D boost_duration min ×1 10 180
0x906E bat_discharge_soc % ×1 20 100

Architecture cible — nouveaux fichiers uniquement

src/
  epever_config.cpp     ← NOUVEAU : logique lecture/écriture/persistance config
include/
  epever_config.h       ← NOUVEAU : struct EpeverRegDef, API publique
data/
  epever_config.json    ← NOUVEAU : sauvegarde locale LittleFS (généré à l'usage)

Fichiers modifiés (ajouts uniquement, pas de refactoring) :

Fichier Modification
src/webserver.cpp +6 routes API /api/epever/config*
src/main.cpp +1 appel initConfigEpever() dans setup()
src/modbus_epever.cpp +1 fonction isModbusBusy() pour exposer lectureEnCours
include/modbus_epever.h +1 déclaration isModbusBusy()
data/index.html +1 onglet "Config EPEVER"
data/app.js +section JS onglet config
data/style.css +styles mineurs onglet config

Fichiers non touchés : state.h, rules.cpp, historique.cpp, sleep.cpp, wifi_ap.cpp, buttons.cpp, ota.cpp.


Étapes de développement

Étape 1 — Abstraction registres (backend)

Créer include/epever_config.h et src/epever_config.cpp :

struct EpeverRegDef {
    uint16_t    reg;
    const char *key;
    float       scale;
    float       valMin;
    float       valMax;
    bool        writable;
    const char *unit;
    const char *label;
};

Table statique des ~18 registres des deux blocs.
Pas d'effet sur le comportement du système — compilation et link uniquement.

Test : pio run — vérifier que la compilation passe.


Étape 2 — Lecture config Epever (backend)

Dans epever_config.cpp :

bool lireConfigEpever();          // lit les deux blocs, populate configCache
void getConfigJson(String &out);  // sérialise + métadonnées (lastRead, rs485_ok, erreur)

Utilise lireHoldingBruts() existant. Même garde que reglerHorlogeEpever() :

if (isModbusBusy()) return false;

Cache en RAM (float configCache[18] + bool configValide).

Dans webserver.cpp :

GET /api/epever/config  →  lireConfigEpever() + getConfigJson()

Test : appel depuis navigateur, vérifier JSON avec valeurs cohérentes de l'Epever.


Étape 3 — Validation + écriture (backend)

Dans epever_config.cpp :

bool validerConfig(JsonObject obj, String &erreur);
bool ecrireConfigEpever(JsonObject obj);  // valide puis FC16 par bloc

Règles de validation :

  • plage min/max par registre (table)
  • cohérence inter-registres : float_voltage < boost_voltage < equalize_voltage < overvoltage_disconnect
  • low_disconnect < low_reconnect < undervolt_warning

Écriture en deux passes (bloc 0x9000, puis bloc 0x906B) avec vérification lecture-retour.

Dans webserver.cpp :

POST /api/epever/config  →  body JSON → validerConfig() → ecrireConfigEpever()

Réponse : {"ok": true} ou {"ok": false, "erreur": "Float > Boost"}.

Test : modifier Float Voltage de 0.1V depuis Postman/curl, relire pour confirmer.


Étape 4 — Sauvegarde LittleFS (backend)

Dans epever_config.cpp :

bool sauvegarderConfigJson();    // écrit /epever_config.json depuis configCache
bool restaurerConfigJson();      // lit /epever_config.json → écriture Epever
bool exporterConfigJson(String &out);
bool importerConfigJson(const String &json);

Format fichier identique à l'API (même structure JSON).

Nouvelles routes :

GET  /api/epever/config/saved    →  lire LittleFS
POST /api/epever/config/save     →  sauvegarderConfigJson()
POST /api/epever/config/restore  →  restaurerConfigJson() → ecrireConfigEpever()

Test : sauvegarder, modifier une valeur sur l'Epever, restaurer, relire.


Étape 5 — Interface web (frontend)

Nouvel onglet "Config EPEVER" dans index.html + section dans app.js.

Structure UI :

┌─────────────────────────────────────────────────┐
│ [Lire depuis Epever]  [Sauvegarder]  [Restaurer]│
│ Statut : ✅ Synchronisé — 09:14:22              │
├───────────────────────┬─────────────────────────┤
│ 🔋 Batterie           │ ⚡ Tensions de charge    │
│ Type       [Sealed ▼] │ Boost       [14.4 V]    │
│ Capacité   [100 Ah]   │ Float       [13.6 V]    │
│ Tension    [auto ▼]   │ Equalize    [14.6 V]    │
├───────────────────────┼─────────────────────────┤
│ ⏱ Timing             │ 🌡 Température           │
│ Durée boost [120 min] │ Compensation [-3 mV/°C] │
│ Durée égal. [60 min]  │                         │
└───────────────────────┴─────────────────────────┘
[✏️ Écrire vers Epever]  [⬇ Exporter JSON]  [⬆ Importer]

Comportements :

  • Lire : GET /api/epever/config, remplit les champs
  • Écrire : confirmation modale → POST /api/epever/config
  • Sauvegarder : POST /api/epever/config/save
  • Restaurer : confirmation modale → POST /api/epever/config/restore
  • Exporter : GET /api/epever/config/saved, Blob + <a download>
  • Importer : <input type="file"> → POST /api/epever/config

Aide intégrée (novice) : chaque paramètre a un title HTML + icône avec explication en français courte.

Exemples :

Tension Float : tension de maintien après charge complète. Une valeur trop haute fatigue la batterie ; trop basse ne la charge pas suffisamment. Typique : 13.513.8V pour plomb.

Test : vérifier sur mobile (WiFi AP), formulaire responsive, confirmation avant écriture.


Étape 6 — Gestion des erreurs UI

  • Champ en rouge si valeur hors plage (validation JS temps réel)
  • Alerte si cohérence inter-registres violée avant même d'écrire
  • Toast de succès/erreur après écriture (3s)
  • Indicateur rs485_ok dans le status bar de l'onglet
  • Affichage de la dernière erreur Modbus si rs485_ok = false

Contraintes de non-régression

Risque Mitigation
Conflit accès Serial2 isModbusBusy() — même garde que reglerHorlogeEpever()
Saturation LittleFS /epever_config.json ≈ 500 octets — négligeable
Timeout HTTP long lireHoldingBruts() sur 2 blocs ≈ 200ms — acceptable
Écriture valeur dangereuse Double validation : JS (UX) + C++ (sécurité)
Régression onglets existants Ajouts dans app.js isolés dans une section dédiée

Dead code connu à ne pas toucher : les callbacks cbPV, cbLoad, cbSOC, cbStatus, cbEnergie, cbJourNuit dans modbus_epever.cpp sont inactifs mais laissés en place pour éviter le risque de régression.


Ordre d'implémentation recommandé

Étape 1 : EpeverRegDef + table registres          (~1h)  → pio run
Étape 2 : lireConfigEpever + GET /api/epever/config (~2h)  → test JSON navigateur
Étape 3 : validation + POST /api/epever/config      (~2h)  → test curl
Étape 4 : LittleFS save/restore                     (~1h)  → test navigateur
Étape 5 : UI onglet complet                         (~3h)  → test mobile
Étape 6 : gestion erreurs UI + aide novice          (~1h)  → test cas d'erreur

Total estimé : ~10h de développement incrémental, chaque étape testable indépendamment.


Fonctionnalités futures (hors scope immédiat)

  • Profils batterie prédéfinis : GEL, AGM, Sealed, Lithium (presets JSON)
  • Rollback automatique si la tension batterie tombe anormalement après écriture
  • Historique des modifications de config (date + delta)
  • Synchronisation MQTT / Home Assistant
  • Mode expert : affichage de tous les registres bruts