J’ouvre ce sujet afin de partager et d’échanger autour de l’intégration de la passerelle Enphase au GX par communication Modbus TCP.
Il y a quelques semaines Guilhem (@Guizmon) annonçait avoir rencontré quelques problèmes en réalisant cette intégration (voir Mulitplus Modbus + enphase = production solaire bloqué à 1kW). Finalement, ce n’était qu’une question de paramètres mal réglés suite à de multiples tests.
Enphase a produit une note technique à ce sujet, datant de janvier 2025, dans laquelle ils disent qu’il faut contacter le support EMEA (support_emea@enphaseenergy.com) pour demander une mise à jour du firmware. En réalité, il est probable que la passerelle soit déjà avec un firmware suffisamment récent car la fonctionnalité est disponible depuis la version 7.6.168 (actuellement 8.3.5167). Ce qu’ils ne disent pas et qui m’a fait perdre 2 semaines, c’est qu’après avoir demandé cette mise à jour probablement inutile, il faut contacter le support API (api@enphaseenergy.com) pour demander l’activation de la fonctionnalité. De plus, il ne faut pas transférer un mail venant du support EMEA vers le support API car il reviendra chez EMEA. Tout n’est pas facile avec Enphase.
Une fois la fonctionnalité activée, le GX est capable de trouver la passerelle via Modbus TCP comme décrit dans la note technique.
La régulation de production PV a été introduite en juin 2025 avec la version 3.60 du Venus OS (GX) qui supporte désormais la SunSpec 123 et 704.
J’ai réalisé des tests de régulation de la puissance au départ du GX. Le résultat ne fut pas très concluant. Ça fonctionne mais ce n’est pas du tout réactif. Pour mieux comprendre, j’ai analysé la communication entre le GX et la passerelle. J’ai découvert que la passerelle prend énormément de temps à traiter une demande de modification (environ 30s) et met en attente les demandes en lecture. Ceci signifie que le GX donne l’instruction à la passerelle Enphase de produire plus ou moins afin de réguler l’énergie produite pour se conformer aux paramètres, tels que la consigne réseau ou la limitation de puissance exportée, alors que la passerelle ne les applique que 30s plus tard. Avec une météo variable ou des consommations variables, il n’est pas possible de maîtriser l’exportation d’énergie avec cette technologie. Ceci pourrait changer à l’avenir si Enphase améliore son serveur Modbus afin de traiter immédiatement les demandes de modification.
Les compteurs d’énergie supportés par Victron ont des délais de rafraîchissement allant de 0,1 à 2s (cfr Selection Guide - Energy Meters). On peut facilement comprendre que le GX ne peut pas faire correctement son job avec une mesure qui est rafraîchie toutes les 30s. De mémoire, le GX n’interroge la passerelle que toutes les 10s. Donc, si le traitement des demandes de modification devenait instantané, le délais de rafraîchissement tomberait à 10s ce qui est mieux mais ça ne vaut pas un véritable compteur.
Durant mes tests, j’ai également mis le port de communication Modbus (TCP 502) sur la passerelle Enphase plusieurs fois en erreur totale n’acceptant plus aucune nouvelle communication même après un redémarrage de la passerelle. Je suppose qu’un client (le GX ou le module Node-RED) envoie un TCP ACK pour maintenir la session ouverte et bloque le port de la passerelle. Je n’ai pas suffisamment cherché à identifier la source du problème mais la conséquence a été qu’un matin, le GX n’était plus capable de réguler la production. L’analyse réseau a montré un échange en boucle de TCP ACK entre le client (le GX ou le module Node-RED) et la passerelle empêchant la passerelle d’accepter de nouvelles demandes d’ouverture de session (TCP SYN). Il y a dès lors un défaut de traitement des communications TCP/IP qui devrait être corrigé. C’est bon à savoir si subitement plus rien ne fonctionne. On peut espérer qu’Enphase apporte les corrections nécessaires dans les prochaines mises à jour. Encore, faut-il leur signifier le problème ce qui signifie correctement identifier ce qui produit le problème.
Vu ces problèmes, j’ai abandonné l’idée de réguler ma production avec le GX pour la réaliser en Node-RED grâce au module node-red-contrib-modbus et les références SunSpec. Lorsque je ne veux pas ou ne peux pas exporter, je ralenti progressivement la production pour la caler au plus proche de la consommation vers un SoC à 97%. Ainsi, je parviens à maintenir le SoC et à maintenir l’exportation ou l’importation conformément à la consigne réseau.
Voici la base du code Node-RED. Attention, les adresses Modbus pourraient évoluer avec les mises à jour d’Enphase. A ce moment, il faudra réaliser un processus de découverte pour obtenir les bonnes adresses des SunSpec 702 et 704.
[{"id":"cc1ff62cbeafe5d7","type":"modbus-read","z":"77403a7b4cd9572e","name":"SunSpec 704","topic":"SunSpec 704","showStatusActivities":false,"logIOActivities":false,"showErrors":true,"showWarnings":true,"unitid":"126","dataType":"HoldingRegister","adr":"40296","quantity":"67","rate":"1","rateUnit":"m","delayOnStart":false,"startDelayTime":"92","server":"3df6c636aa6cabec","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":true,"x":130,"y":140,"wires":[[],["7e8c688972c35b7b"]]},{"id":"7ac9b7ddb4f0cdce","type":"modbus-read","z":"77403a7b4cd9572e","name":"SunSpec 702","topic":"SunSpec 702","showStatusActivities":false,"logIOActivities":false,"showErrors":true,"showWarnings":true,"unitid":"126","dataType":"HoldingRegister","adr":"40225","quantity":"52","rate":"1","rateUnit":"m","delayOnStart":false,"startDelayTime":"91","server":"3df6c636aa6cabec","useIOFile":false,"ioFile":"","useIOForPayload":false,"emptyMsgOnFail":true,"x":130,"y":100,"wires":[[],["22a286cb05e5bddf"]]},{"id":"7e8c688972c35b7b","type":"function","z":"77403a7b4cd9572e","name":"Set flow variable sunspec_704","func":"let sunspec = { data: msg.payload.data, buffer: msg.payload.buffer, datetime: Date.now() };\n\nsunspec.valid = sunspec.data[0] == 704 && sunspec.data[1] == 65 && sunspec.data.length == 67;\n\nlet msg1 = null;\n\nif (sunspec.valid) {\n node.status({ fill: \"grey\", shape: \"dot\", text: 'Limit ' + (sunspec.data[14] == 1 ? sunspec.data[15] + '%' : 'disabled')});\n \n sunspec.w_max_lim_ena = sunspec.data[14];\n sunspec.w_max_lim_pct = sunspec.data[15];\n sunspec.w_max_lim_rvrt_ena = sunspec.data[17];\n sunspec.w_max_lim_rvrt_pct = sunspec.data[16];\n sunspec.w_max_lim_rvrt_tms = sunspec.data[18];\n\n let prod_limit = '-';\n if (sunspec.w_max_lim_ena) {\n let ss702 = flow.get('sunspec_702');\n if (typeof ss702 === 'object' && ss702.datetime > Date.now() - 180000) {\n prod_limit = Math.round(ss702.w_max*sunspec.w_max_lim_pct/100);\n } else {\n prod_limit = sunspec.w_max_lim_pct + '%'\n }\n }\n \n msg1 = { topic: 'Victron/Settings/Prod Limit', payload: prod_limit };\n} else {\n node.status({ fill: 'red', shape: 'dot', text: 'Invalid data' });\n}\n\nflow.set('sunspec_704', sunspec);\n\nreturn msg1;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":140,"wires":[[]]},{"id":"22a286cb05e5bddf","type":"function","z":"77403a7b4cd9572e","name":"Set flow variable sunspec_702","func":"let sunspec = { data: msg.payload.data, buffer: msg.payload.buffer, valid: false, datetime: Date.now() };\n\nsunspec.valid = sunspec.data[0] == 702 && sunspec.data[1] == 50 && sunspec.data.length == 52;\n\nlet msg1 = null\n\nif (sunspec.valid) {\n sunspec.w_max = sunspec.data[2];\n node.status({ fill: \"grey\", shape: \"dot\", text: 'Max ' + sunspec.data[2] + 'W'});\n msg1 = { topic: 'Victron/Settings/Prod Max', payload: sunspec.w_max }\n} else {\n node.status({ fill: 'red', shape: 'dot', text: 'Invalid data' });\n}\n\nflow.set('sunspec_702', sunspec);\n\nreturn msg1;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":370,"y":100,"wires":[[]]},{"id":"93891e2e7ae13fb4","type":"comment","z":"77403a7b4cd9572e","name":"Collecter les SunSpec depuis la passerelle Enphase","info":"","x":290,"y":60,"wires":[]},{"id":"441880e62df86138","type":"modbus-write","z":"77403a7b4cd9572e","name":"Limit Prod","showStatusActivities":true,"showErrors":true,"showWarnings":true,"unitid":"126","dataType":"MHoldingRegisters","adr":"40310","quantity":"5","server":"3df6c636aa6cabec","emptyMsgOnFail":false,"keepMsgProperties":false,"delayOnStart":false,"startDelayTime":"","x":300,"y":260,"wires":[[],[]]},{"id":"fa08059df2e441c5","type":"comment","z":"77403a7b4cd9572e","name":"Modifier la puissance de passerelle Enphase","info":"","x":270,"y":180,"wires":[]},{"id":"bfc20bd206637f9e","type":"inject","z":"77403a7b4cd9572e","name":"0%","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"0","payloadType":"num","x":110,"y":220,"wires":[["441880e62df86138"]]},{"id":"c5e751d86817c322","type":"inject","z":"77403a7b4cd9572e","name":"25%","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"25","payloadType":"num","x":110,"y":260,"wires":[["441880e62df86138"]]},{"id":"83ed3b888ad03a6e","type":"inject","z":"77403a7b4cd9572e","name":"100%","props":[{"p":"payload"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"100","payloadType":"num","x":110,"y":300,"wires":[["441880e62df86138"]]},{"id":"3df6c636aa6cabec","type":"modbus-client","name":"Enphase Gateway","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"failureLogEnabled":true,"tcpHost":"192.168.219.12","tcpPort":"502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","serialAsciiResponseStartDelimiter":"0x3A","unit_id":"126","commandDelay":"5","clientTimeout":"60000","reconnectOnTimeout":true,"reconnectTimeout":"120000","parallelUnitIdsAllowed":true,"showErrors":true,"showWarnings":true,"showLogs":true}]
En conclusion, cette technologie est intéressante et permet bien d’intégrer la passerelle Enphase au système Victron mais elle a encore des défauts qui pourraient poser des problèmes aux personnes souhaitant réguler leur production avec le GX. Ceci est certainement une raison pour laquelle la gestion de la limitation de puissance peut être désactivée sur le GX.


