![]() |
|
Compatibilité compteur connecté EM06P (Meross, Refoss) - Version imprimable +- F1ATB forum (https://f1atb.fr/forum_f1atb) +-- Forum : Forum de F1ATB (https://f1atb.fr/forum_f1atb/forum-3.html) +--- Forum : Routeur Photovoltaïque (https://f1atb.fr/forum_f1atb/forum-4.html) +---- Forum : Evolutions faites, à faire, dont vous rêvez... (https://f1atb.fr/forum_f1atb/forum-10.html) +---- Sujet : Compatibilité compteur connecté EM06P (Meross, Refoss) (/thread-2487.html) |
RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - MousPVSOL - 17-06-2026 Bonjour, j'ai déplacé mon routeur à côté de ma box internet Wifi, le niveau WIFI est maintenant à -50dBm. Maintenant, les pages s'affichent plus rapidement. La Led jaune pulse normalement toutes les 2s. Cependant, lorsque je change entre les différentes pages, on dirait que j'arrive à surcharger le routeur et fini par planté. J'ai fait un test, j'ai chargé la page "Donnée brutes", et je ne change plus de page. Maintenant, j'ai la Led qui pulse normalement et l"ESP ON" est à 1h10min. J'ai 2 mesures de températures et 1 action. Avez-vous une idée de ce qu'il pourrait se passer? Merci RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - MousPVSOL - 18-06-2026 Bonjour, le problème était les fichiers Export qui saturaient la mémoire et faisant plante l'ESP32. J'ai sûrement du générer plein d'erreurs lorsque je faisais mes tests avec MQTT. Maintenant, je suis surpris de la vitesse de chargement des pages du routeur :-) Tout fonctionne bien, je n'ai plus qu'à m'atteler à la programmation des actions. En espérant que mes recherches pourront en aider d'autres. Encore merci André pour ton travail. RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - MousPVSOL - 20-07-2026 Bonjour, j'ai modifié le programme avec l'aide de l'IA Claude afin d'y intégrer mon compteur EM06P. Je me suis inspiré de ce qui était fait pour le Shelly Pro3Em. J'ai fait les modifs en dur avec une pince voie 1 et l'autre voie 4; ca peut ne pas correspondre pour une autre personne. Je mets ici le .ino concernant le compteur EM06P: Code : //*********************************************************************Mes valeurs sont bien remontés sur la page d'accueil. Je pense qu'il faut encore nettoyer le programme. Cependant, la régulation semble moins stable que lorsque j'avais mes données de compteurs reçues via MQTT (voir PJ). Je ne peux plus tester à cette heure, à voir les prochains jours. Est-ce que quelqu'un a une idée d'où pourrait venir le problème? Voici tout le programme en téléchargement: https://www.grosfichiers.com/iauCewnwBBa En espérant que ma version puisse aider un autre utilisateur d'EM06P ;-) RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - H3rv3 - 22-07-2026 Salut, bien vue l'adaptation, 'cest presque un Shelly. à cet endroit du code: p = EM06P_Data.indexOf("{"); if (p < 0) { StockMessage("EM06P : aucune accolade '{' trouvée dans la réponse"); filtre_puissance(); PuissanceRecue = true; return; } les données puissance seraient invalides donc si tu veux garder le reset au cas ou tu ne reçois pas les données il faudrait sûrement juste faire le return sans mettre PuissanceRecue a true et sans filtre_puissance(). RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - MousPVSOL - 24-07-2026 Salut, je réussis à lire les données de mon compteur avec un taux de rafraîchissement d'environ 5 secondes. Je ne sais pas si cela vient d'une limite de ce compteur ou le code. Serait-ce suffisant pour la régulation? En comparaison, quel est le taux de rafraîchissement d'un Shelly ? Merci RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - grostoto - 24-07-2026 salut le shelly est amplement sous la seconde, je crois que le linky est toute les 2s. RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - MousPVSOL - 25-07-2026 Bonjour, j'ai modifié le code et me voici avec un rafraichissement des données toutes les 0,5sec. Maintenant, la régulation semble beaucoup plus stable et la navigation entre les pages est bien plus fluide. Cela pourrait aider pour tout le monde. Si André veut ajouter tout cela dans son programme, ca serait super. Voici les fichiers: https://www.grosfichiers.com/X5Kfp7tF4Y7 Claude m'a résumé les modification du code : # Adaptation du routeur solaire F1ATB au compteur Meross/Refoss EM06P Résumé des évolutions et corrections apportées, dans l'ordre chronologique. ## 1. Contexte et objectif de départ Le programme gérait initialement un compteur **Shelly Pro EM**. L'objectif était de l'adapter pour fonctionner avec un compteur **Meross/Refoss EM06P**, qui utilise le même style de protocole JSON-RPC en HTTP, mais avec : - une structure JSON différente (tableau plat de 6 voies indépendantes, identifiées par `"id":1` à `"id":6`, plutôt que des objets nommés `"em1:0"`, `"em1:1"`... comme chez Shelly) ; - des noms de champs différents (`power` au lieu de `act_power`, etc.) ; - pas de compteur d'énergie cumulé "depuis toujours" (pas de `total_act_energy`), seulement des compteurs `day_energy` / `week_energy` / `month_energy` / `year_energy` (et leurs équivalents `_ret_energy` pour le sens inverse), tous remis à zéro périodiquement par l'appareil lui-même. ## 2. Découverte de l'API réelle La documentation officielle (`docs.refoss.net`) est un site JavaScript non lisible automatiquement. La structure réelle de l'API a été déterminée à partir d'un relevé JSON fourni par l'utilisateur, puis confirmée par un test direct : ``` GET http://<IP>/rpc/Em.Status.Get?id=65535 ``` `id=65535` est un identifiant spécial qui renvoie le statut des 6 voies en une seule requête (pas besoin d'interroger voie par voie). ## 3. Écriture de la fonction `LectureEM06P()` Nouvelle fonction créée sur le modèle de `LectureShellyProEm()`, avec : - une fonction `ExtraitVoieEM06P(id, data)` qui isole le sous-objet JSON d'une voie donnée dans le tableau `"status":[...]` ; - lecture de `power`, `voltage`, `pf`, `year_energy`/`year_ret_energy` et `day_energy`/`day_ret_energy` par voie. ## 4. Bugs corrigés dans le code ### 4.1 Lecture réseau peu robuste La boucle de lecture HTTP initiale s'arrêtait dès qu'il n'y avait momentanément plus de données disponibles, alors que la réponse peut arriver en plusieurs paquets réseau séparés (en-têtes puis corps). Corrigée avec une boucle qui relance le délai d'attente à chaque octet reçu. ### 4.2 Bug dans `ValJson()` (fonction générique de parsing JSON) `ValJson()` retournait **0** lorsque le champ demandé était le **dernier** d'un objet JSON (donc suivi directement de `}` sans virgule après) : le code faisait `min(position_virgule, position_accolade)`, et quand la virgule est absente (`indexOf` renvoie -1), `min(x, -1)` vaut toujours -1, ce qui faisait échouer l'extraction. Ce bug touchait spécifiquement `day_ret_energy` (toujours en dernière position dans chaque objet voie de l'EM06P), d'où "Energie Active du jour → Injectée" bloquée à 0. Corrigé, et potentiellement utile aussi pour d'autres sources utilisant cette même fonction. ### 4.3 Calcul de l'énergie du jour inadapté `EnergieQuotidienne()` calculait l'énergie du jour par **delta** par rapport à une baseline mémorisée à minuit (`EAS_M_J0` etc.), ce qui suppose un compteur strictement croissant. L'EM06P n'ayant pas ce type de compteur, cette logique produisait des valeurs incohérentes. Corrigé en excluant `Source == "EM06P"` de ce calcul par delta, et en utilisant directement les champs `day_energy`/`day_ret_energy` fournis par l'appareil (déjà remis à zéro par l'appareil lui-même chaque minuit). ### 4.4 Convention de signe puissance/énergie Une inversion de signe avait été appliquée par erreur suite à une déduction indirecte, puis annulée après confirmation terrain : sur ce compteur, **puissance positive = soutirage réel, puissance négative = injection réelle** (convention standard, pas d'inversion nécessaire). Confirmé par observation directe en situation d'injection puis de soutirage réel. ### 4.5 Voie secondaire (T) mal choisie, lue une fois sur cinq - La voie secondaire était calculée comme "voie principale + 1", sans lien avec l'installation réelle (PV câblé sur la voie 4). Fixée en dur sur `VOIE_SECONDAIRE_EM06P_ID = 4`. - Le code alternait la lecture entre voie M et voie T sur plusieurs cycles (`ShEm_comptage_appels`), hérité du Shelly qui nécessitait une requête HTTP séparée par voie. Or l'EM06P renvoie déjà les 6 voies en une seule requête : le code a été restructuré pour extraire M **et** T de la même réponse à **chaque** appel, supprimant l'alternance et améliorant la réactivité de la régulation. ### 4.6 Sources d'affichage oubliant `"EM06P"` Plusieurs endroits du code testaient explicitement `Source_data == "ShellyEm" || Source_data == "ShellyPro"` sans inclure `"EM06P"`, empêchant l'affichage correct de la voie secondaire : - `AdaptationSource()` (page Paramètres, JS) : champs de nom de la seconde sonde restaient masqués. - `PageBruteJS2` (switch de la page Données Brutes) : aucune donnée EM06P affichée du tout (tombait dans le `default`). - `handleAjaxData()` (serveur, deux occurrences) : envoyait `"Fake"` au lieu des vraies données de la voie T vers la page d'accueil. - `handleMainJS1()` (serveur) : variable `biSonde` restait à `false`, masquant la colonne entière sur la page d'accueil même avec de bonnes données reçues. Toutes ces conditions ont été complétées avec `Source_data == "EM06P"` / `Source == "EM06P"`. ### 4.7 Titre de la page "Données Brutes" Le titre "Données Shelly Em" était en dur dans le HTML (`PageBrute.h`), partagé par Shelly et EM06P. Ajout d'un `id="titreShellyEm"` sur ce `<div>`, mis à jour dynamiquement en JS selon la source (`case "EM06P":` distinct de `case "ShellyEm"/"ShellyPro":`). ### 4.8 Fuite mémoire / fragmentation heap La lecture réseau construisait la réponse **caractère par caractère** avec un `String` Arduino (`EM06P_Data += (char)...`), ce qui peut déclencher une réallocation complète à chaque ajout. Répété toutes les 300-600ms en continu, ça fragmentait sévèrement la mémoire (RAM libre minimum tombée à ~200 octets, causant des pages web inaccessibles / timeouts). Corrigé avec `EM06P_Data.reserve(2000)` en début de fonction, pour allouer le buffer une seule fois. ### 4.9 Délai artificiel de ~5,5 secondes par lecture (cause principale de l'instabilité de régulation) Un diagnostic de timing (ajouté avec compteur d'appels lents, moyenne et écart-type calculés sur des fenêtres de 200 lectures) a révélé que **100 %** des lectures dépassaient 1 seconde, avec une moyenne très stable autour de 5 500ms (écart-type faible, donc un phénomène régulier, pas aléatoire). Des tests `curl` directs depuis un PC sur le même réseau ont montré que le compteur répondait en réalité en 50-400ms — innocentant le matériel. **Cause identifiée** : la boucle de lecture attendait que `WiFiClient::connected()` devienne `false` pour considérer la lecture terminée. Sur ESP32, cette fonction est connue pour mettre plusieurs secondes à détecter la fermeture réelle d'une connexion TCP par le serveur, même quand toutes les données ont déjà été reçues. **Correction** : lecture désormais basée sur l'en-tête HTTP `Content-Length` — la fonction s'arrête dès que le nombre d'octets annoncé a été reçu, sans attendre la fermeture formelle de la connexion. Résultat observé : temps de lecture moyen passé de ~5 500ms à **~1-460ms** (mesuré via `Charge coeur 0` sur la page Données ESP32 et les messages `EM06P DIAG`). ## 5. Outil de diagnostic ajouté Un système de journalisation périodique (`EM06P DIAG`, toutes les 200 lectures) a été ajouté dans `LectureEM06P()`, donnant : - nombre de lectures dépassant 1 seconde sur la fenêtre ; - durée moyenne ; - écart-type ; - durée maximale observée. Les compteurs sont remis à zéro à chaque rapport (fenêtre glissante), pour rester représentatifs de l'état récent plutôt que d'une moyenne diluée depuis le démarrage. ## 6. Correctif watchdog sur données invalides Dans le cas où aucune donnée JSON valide n'est reçue (pas d'accolade `{` trouvée), le code appelait auparavant quand même `filtre_puissance()` et positionnait `PuissanceRecue = true` — ce qui réinitialisait à tort le watchdog de sécurité (`WDT_TIMEOUT`, 180s) même en cas d'échec de lecture réel et prolongé. Corrigé : ces deux appels sont retirés dans cette branche d'erreur spécifique, pour que le reset de sécurité fonctionne correctement en cas de panne durable du compteur. ## 7. État actuel - Lecture HTTP rapide et fiable (~1-460ms au lieu de ~5 500ms). - Mémoire stable dans le temps (plus de fuite/fragmentation). - Voies M (routeur) et T (PV, voie 4) lues à chaque cycle, sans alternance. - Affichage correct sur toutes les pages (Accueil, Données Brutes, Paramètres) pour la source EM06P. - Énergies jour/total cohérentes avec les données réelles de l'appareil. - Tests de stabilité de la régulation solaire en cours sur plusieurs jours, suite à la correction du délai de lecture (point 4.9), qui était très probablement la cause principale de l'instabilité observée initialement. RE: Compatibilité compteur connecté EM06P (Meross, Refoss) - MousPVSOL - 26-07-2026 Bonjour, voici ma dernière version du programme. C'est très fluide au niveau affichage et la régulation est stable J'ai réussi à résoudre le problème où parfois la page ne s'affiche pas ou même, certains graphiques ne s'affichaient pas. La modification ne serait pas lié à mon compteur EM06P, mais sur le programme en général donc cela pourrait aider tous les utilisateurs. Je vous laisse essayer. Voici les fichiers: https://www.grosfichiers.com/qdBvGGvxahm Voici le résumé des modifications: ## 1. Correctif watchdog sur données EM06P invalides Dans `LectureEM06P()`, quand aucune donnée JSON valide n'est reçue (pas d'accolade `{` trouvée dans la réponse), le code appelait quand même `filtre_puissance()` et positionnait `PuissanceRecue = true` — ce qui réinitialisait à tort le watchdog de sécurité (`WDT_TIMEOUT`, 180s) même en cas d'échec de lecture réel et prolongé. **Corrigé** : ces deux appels sont retirés dans cette branche d'erreur spécifique, pour que le reset de sécurité fonctionne correctement en cas de panne durable du compteur. ## 2. Bug découvert et corrigé sur l'export d'historique annuel (indépendant de l'EM06P) En travaillant sur l'affichage de la page d'accueil, un problème séparé a été identifié : certains graphiques (notamment l'historique annuel) n'apparaissaient pas de façon fiable, avec une erreur navigateur du type `Content-Length header of network response exceeds response Body` sur l'endpoint `/ajax_histo1an`. ### Cause La fonction `envoyerHistoriqueEnergie()` construisait sa réponse JSON via `JsonDocument` (ArduinoJson v7), en ajoutant une par une toutes les lignes de plusieurs fichiers CSV (`doc["EnergieJour"].add(ligne)`). ArduinoJson v7 ne permettant pas de réserver une capacité à l'avance (contrairement à la v6), ces nombreuses petites allocations successives fragmentaient progressivement la mémoire disponible de l'ESP32. Après plusieurs dizaines de minutes à quelques heures de fonctionnement, la mémoire libre minimale chutait jusqu'à des valeurs critiques (~200-800 octets observés), provoquant des réponses vides, des pages incomplètes, voire des redémarrages inattendus de l'ESP32. Ce problème est **préexistant et indépendant de l'EM06P** : il touche un endpoint générique utilisé quel que soit le compteur configuré (Shelly y compris). ### Tentative initiale (abandonnée) Une première correction a consisté à construire le JSON complet en mémoire puis à l'envoyer en une seule fois (`send()` avec `Content-Length` automatique). Cette approche a **provoqué un redémarrage de l'ESP32** (mémoire libre minimale tombée à 216-256 octets) car elle demandait un pic de mémoire encore plus important que l'original. Cette version a été abandonnée et retirée. ### Correctif retenu Réécriture de `envoyerHistoriqueEnergie()` sans `JsonDocument` : le JSON est désormais construit **manuellement, ligne par ligne**, et écrit directement dans le flux de sortie HTTP chunked (via la classe existante `ChunkedWriter`) au fur et à mesure de la lecture des fichiers CSV, sans jamais garder l'ensemble des données en mémoire. Le mécanisme d'envoi chunked d'origine (`setContentLength(CONTENT_LENGTH_UNKNOWN)`, `Transfer-Encoding: chunked`) a été conservé intact. **Résultat observé** : mémoire libre minimale stable autour de 44 000-47 000 octets sur plus de 9h d'uptime (contre des chutes à 200-800 octets avant), endpoint `/ajax_histo1an` fonctionnel de façon fiable, tous les graphiques de la page d'accueil s'affichant correctement sur plusieurs rechargements successifs. |