Bon, avec les travaux dans la maison j’avais pas eu le temps de me lancer dans la gestion des onduleurs plus tôt, mais avant toute chose, je suis grand novice autant dans jeedom qu’avec la programmation, mais rien n’est impossible, si j’y arrive, tout le monde peut… (ok j’y ai passé presque 1 semaine complète tellement je suis mauvais…)
pour rappel, mes contraintes:
=> 3 onduleurs wks evo 5kva car triphasé
=> volonté de pouvoir jouer sur la/les sources externes d’alimentation
=> bat pylontech
=> 2 parcs solaires
ce que je veux faire:
=>Pouvoir surveiller l’état de la batterie = ok
=>Pouvoir surveiller l’état de la production = ok
=>Pouvoir surveiller l’état de la consommation = ok
=> déclencher la charge des bat par l’utilitaire choisi en fonction de paramètre externe (HP/HC, Groupe électrogène, temps à J / J+1…)=> en cours
=> déclencher le chauffe eau en cas de surproduction => en cours
matériels utilisés (en plus de l’installation de base)
=> Cartes compatibles Mega 2560 R3 :
=> Carte ethernet à base de W5100:
=> 3 RS323 vers TTL
=> 3 cables RJ45 (moi j’ai utilisé les câbles SERIAL, fournis avec les onduleurs)
=> 1 alimentation pour arduino
=> 1 cable réseau
du fait de d’avoir 3 onduleurs (triphasé) j’ai choisi un clone de MEGA 2560 car il dispose de 4 ports « sérial » je pense qu’il doit être possible de partir sur 1 uno avec 1 seul convertisseur de signal avec une répartition logiciel, mais ca dépasse de loin mes compétences de programmation.
Le fait d’avoir choisi un protocole Ethernet et non wifi vient du fait que mon local technique est blindé et que le wifi ne passe pas mais que je dispose de ma baie informatique et que je ne veux pas faire de frais à rajouter des répétiteur/box de signal wifi.
j’ai volontairement choisi de souder en définitif les différents éléments par paranoïa car j’ai toujours peur qu’une connexion se barre… (faut dire que prendre du fil rigide n’est pas non plus une bonne idée, j’ai eu plein de casse de fil lors des test, et que tenter de faire des soudures sur la carte avec un fer de 100w 1er prix est aussi utile que prendre un 33T pour aller chercher sa baguette… ca doit fonctionner mais c’est pas donné à tout le monde…)
les onduleurs WKS EVO (et visiblement consort génériquement appelé PIP):
les onduleurs WKS Evo ont la particularité d’avoir une interfacabilité de merde (faut dire que pour le prix) et à ce que j’ai compris un mode de fonctionnement pas ou peu « WAF » nativement: il est possible de faire plein de paramétrages, mais une fois que c’est fait, c’est difficile de faire des changements à la volé (encore plus quand on a 3 onduleurs).
l’onduleur puise constamment dans la batterie , donc celle ci doit être suffisante pour fonctionner H24.
il est possible de charger via les PV et/ou via un utilitaire (ERDF ou groupe ou …)
il existe donc plusieurs paramètre SBU, SUB, USB, UCb , UdC(S= solaire, U = utilitaire, B = Batterie) pour l’ordre de priorité, perso j’ai choisi SBU UCb. (L’énergie solaire fournit la puissance aux charges en tant que première priorité. Si l’énergie solaire n’est pas suffisante pour alimenter toutes les charges connectées, l’énergie de la batterie alimentera les charges en même temps. Le service public fournit de l’énergie aux charges uniquement lorsque la tension de la batterie chute à un niveau bas la tension d’avertissement ou le point de réglage du programme 12 ou le solaire et la batterie ne sont pas suffisants.et autorise à l’utilitaire de charger la batterie)
SBU UdC => extinction en cas de bat faible (arrivé 2 fois au début) bien que paramètre conseillé par le vendeur lors de la mise en place.
SUB UdC => pas d’intérêt d’avoir un gros parc batterie (sauf en cas d’absence de S et U) et une consommation S ou U en tout ou rien => si S < consommation, S = 0% et U = 100% avec un risque d’avoir une coupure en cas de bat faible car uniquement rechargé par le S
SUB UCb => fonctionne comme un ASI classique mais avec une possibilité de solaire dans certain cas…
USB UdC => ASI avec possibilité de non charge !!!
USB UCb => ASI solaire qui n’utilise pas le solaire??
sachant qu’il n’y a pas de possibilité de mettre plusieurs choix en fonction de l’heure par ex, la solution de base SBU UCb fixe que je consomme en priorité sur le solaire ET les batterie, (donc normalement pas de U bien que souvent je me retrouve quand meme avec une consommation U avec de la B restante… ) mais que si la B est basse, alors l’U la charge, mais quelque soit l’heure de jour ou de la nuit… je me trouve donc a charger la batterie en journée (en HP) et la décharger en HC… c’est quand même un comble…
je domotise donc manuellement (oui je sais c’est volontaire de dire une absurdité) en ayant une alerte SMS quand la B est Faible en journée pour appuyer sur l’interrupteur tétrapolaire dans le local technique qui relie le réseau aux onduleurs… et en mettant tout les soirs l’utilitaire en route…(enfin quand j’oublie pas ce qui provoque au mieux une conso en journée, au pire une extinction du réseau…
Pour Palier a ce désagrément, je vais acheter un contacteur de puissance tétrapolaire (avec bobine en 230v) car il y a un contact sec (3A / 250VAC) sur le panneau arrière qui sera certainement utilisé pour fournir un signal au contacteur de puissance lorsque la tension de la batterie atteint le niveau d’alerte (redondance/perte domotique) en plus de l’utilisation d’un relais de l’IPX sur le contacteur (à voir en fonction des possibilité)
schéma de câblage
(à venir)
rien de compliqué:
=> on relie les 2 cartes en faisant attention à ce que les broches correspondent
=> on relie les 3 GND au GND de la carte,
=> on relie les 3 Ucc au +5V de la carte
=> on relie les TX et RX
=> on relie les cables série aux broches
(attention c’est la vue de face du connecteur, avec le fil derrière (comment ca j’y ai passé 2 jours à comprendre ca… quand je vous dis que je suis un boulet…) donc sur ma carte, en haut à gauche, c’est le 6 et pas le 1!!!
programme arduino:
il n’est pas optimisé mais il à la mérite de fonctionner:
// liste des bibliothèques nécessaires:
#include <SPI.h>
#include <Ethernet.h>
String QPIGS = "\x51\x50\x49\x47\x53\xB7\xA9\x0D"; //Lecture live data
//définitions des variables, possible de mettre ce qu'on veut en texte, ici PIP1 (pour onduleur 1) puis le nom anglais de la variable, mais A1,A2 fonctionnerai tout aussi bien, ce qui compte c'est de savoir ce que ca veut dire pour vous.
float PIP1_Grid_Voltage=0;
float PIP1_Grid_frequence=0;
float PIP1_output_Voltage=0;
float PIP1_output_frequence=0;
int PIP1_output_apparent_power=0;
int PIP1_output_active_power=0;
int PIP1_output_load_percent=0;
int PIP1_BUS_voltage=0;
float PIP1_Battery_voltage=0;
float PIP1_battery_charge_current=0;
float PIP1_battery_capacity=0;
float PIP1_Inverter_heat_sink_temperature =0;
float PIP1_PV_current=0;
float PIP1_PV_voltage=0;
float PIP1_Battery_voltage_from_SCC =0;
float PIP1_battery_discharge_current=0;
int PIP1_status;
float PIP2_Grid_Voltage=0;
float PIP2_Grid_frequence=0;
float PIP2_output_Voltage=0;
float PIP2_output_frequence=0;
int PIP2_output_apparent_power=0;
int PIP2_output_active_power=0;
int PIP2_output_load_percent=0;
int PIP2_BUS_voltage=0;
float PIP2_Battery_voltage=0;
float PIP2_battery_charge_current=0;
float PIP2_battery_capacity=0;
float PIP2_Inverter_heat_sink_temperature =0;
float PIP2_PV_current=0;
float PIP2_PV_voltage=0;
float PIP2_Battery_voltage_from_SCC =0;
float PIP2_battery_discharge_current=0;
int PIP2_status;
float PIP3_Grid_Voltage=0;
float PIP3_Grid_frequence=0;
float PIP3_output_Voltage=0;
float PIP3_output_frequence=0;
int PIP3_output_apparent_power=0;
int PIP3_output_active_power=0;
int PIP3_output_load_percent=0;
int PIP3_BUS_voltage=0;
float PIP3_Battery_voltage=0;
float PIP3_battery_charge_current=0;
float PIP3_battery_capacity=0;
float PIP3_Inverter_heat_sink_temperature =0;
float PIP3_PV_current=0;
float PIP3_PV_voltage=0;
float PIP3_Battery_voltage_from_SCC =0;
float PIP3_battery_discharge_current=0;
int PIP3_status;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // donner une MAC qui n'est pas dans votre réseau
IPAddress ip(192, 168, x, xxx); // taper une adresse ip qui soit libre et hors du DHCP de votre routeur
EthernetServer server(80); // le port 80 par défaut pour le HTTP):
void setup() {
Serial1.begin(2400); // pour branchement de l'onduleur 1 sur les broches 19 et 18
Serial2.begin(2400); // pour branchement de l'onduleur 2 sur les broches 17 et 16
Serial3.begin(2400); // pour branchement de l'onduleur 3 sur les broches 15 et 14
Serial.print("server is at "); // pour connexion en USB uniquement pour vérifier le fonctionnement.
Serial.println(Ethernet.localIP());
Ethernet.begin(mac, ip);
server.begin();// ouverture du serveur
}
void loop() {
//verificaition si un client est connecté (si vous avez appelez la page internet ou si votre jeedom lance la requete)
EthernetClient client = server.available();
if (client) {
Serial.println("new client");
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
if (c == '\n' && currentLineIsBlank) {
//interrogation des onduleurs en cas de connexion:
Serial1.print(QPIGS); //interrogation onduleur 1
Serial1.flush(); // attente que l'envoie soit terminé
if (Serial1.find("(")) { // si réception d'un message, mise dans les valeurs en fonction des varialbles défini en 1er partie
PIP1_Grid_Voltage=Serial1.parseFloat();
PIP1_Grid_frequence=Serial1.parseFloat();
PIP1_output_Voltage=Serial1.parseFloat();
PIP1_output_frequence=Serial1.parseFloat();
PIP1_output_apparent_power=Serial1.parseInt();
PIP1_output_active_power=Serial1.parseInt();
PIP1_output_load_percent=Serial1.parseInt();
PIP1_BUS_voltage=Serial1.parseFloat();
PIP1_Battery_voltage=Serial1.parseFloat();
PIP1_battery_charge_current=Serial1.parseFloat();
PIP1_battery_capacity=Serial1.parseInt();
PIP1_Inverter_heat_sink_temperature =Serial1.parseInt();
PIP1_PV_current=Serial1.parseFloat();
PIP1_PV_voltage=Serial1.parseFloat();
PIP1_Battery_voltage_from_SCC =Serial1.parseFloat();
PIP1_battery_discharge_current=Serial1.parseFloat();
PIP1_status=Serial1.parseInt();
}
Serial2.print(QPIGS); //interrogation onduleur 2
Serial2.flush();
if (Serial2.find("(")) {
PIP2_Grid_Voltage=Serial2.parseFloat();
PIP2_Grid_frequence=Serial2.parseFloat();
PIP2_output_Voltage=Serial2.parseFloat();
PIP2_output_frequence=Serial2.parseFloat();
PIP2_output_apparent_power=Serial2.parseInt();
PIP2_output_active_power=Serial2.parseInt();
PIP2_output_load_percent=Serial2.parseInt();
PIP2_BUS_voltage=Serial2.parseFloat();
PIP2_Battery_voltage=Serial2.parseFloat();
PIP2_battery_charge_current=Serial2.parseFloat();
PIP2_battery_capacity=Serial2.parseInt();
PIP2_Inverter_heat_sink_temperature =Serial2.parseInt();
PIP2_PV_current=Serial2.parseFloat();
PIP2_PV_voltage=Serial2.parseFloat();
PIP2_Battery_voltage_from_SCC =Serial2.parseFloat();
PIP2_battery_discharge_current=Serial2.parseFloat();
PIP2_status=Serial2.parseInt();
}
Serial3.print(QPIGS); //interrogation onduleur 3
Serial3.flush();
if (Serial3.find("(")) {
Serial.println("DATA-3eme onduleur-------");
PIP3_Grid_Voltage=Serial3.parseFloat();
PIP3_Grid_frequence=Serial3.parseFloat();
PIP3_output_Voltage=Serial3.parseFloat();
PIP3_output_frequence=Serial3.parseFloat();
PIP3_output_apparent_power=Serial3.parseInt();
PIP3_output_active_power=Serial3.parseInt();
PIP3_output_load_percent=Serial3.parseInt();
PIP3_BUS_voltage=Serial3.parseFloat();
PIP3_Battery_voltage=Serial3.parseFloat();
PIP3_battery_charge_current=Serial3.parseFloat();
PIP3_battery_capacity=Serial3.parseInt();
PIP3_Inverter_heat_sink_temperature =Serial3.parseInt();
PIP3_PV_current=Serial3.parseFloat();
PIP3_PV_voltage=Serial3.parseFloat();
PIP3_Battery_voltage_from_SCC =Serial3.parseFloat();
PIP3_battery_discharge_current=Serial3.parseFloat();
PIP3_status=Serial3.parseInt();
}
// pour affichage dans la page HTML:
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // permet de fermer la connexion quand la transmission est terminé
client.println("Refresh: 50"); // rafraichissement de la page toutes les 50s
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
// ecriture des valeurs
client.print("<div class='A1'>");client.print(PIP1_Grid_Voltage);client.println("</div>");
client.print("<div class='B1'>");client.print(PIP1_Grid_frequence);client.println("</div>");
client.print("<div class='C1'>");client.print(PIP1_output_Voltage);client.println("</div>");
client.print("<div class='D1'>");client.print(PIP1_output_apparent_power);client.println("</div>");
client.print("<div class='E1'>");client.print(PIP1_output_active_power);client.println("</div>");
client.print("<div class='F1'>");client.print(PIP1_output_load_percent);client.println("</div>");
client.print("<div class='G1'>");client.print(PIP1_battery_capacity);client.println("</div>");
client.print("<div class='H1'>");client.print(PIP1_BUS_voltage);client.println("</div>");
client.print("<div class='I1'>");client.print(PIP1_Battery_voltage);client.println("</div>");
client.print("<div class='J1'>");client.print(PIP1_battery_charge_current);client.println("</div>");
client.print("<div class='K1'>");client.print(PIP1_battery_capacity);client.println("</div>");
client.print("<div class='L1'>");client.print(PIP1_Inverter_heat_sink_temperature);client.println("</div>");
client.print("<div class='M1'>");client.print(PIP1_PV_current);client.println("</div>");
client.print("<div class='N1'>");client.print(PIP1_PV_voltage);client.println("</div>");
client.print("<div class='O1'>");client.print(PIP1_Battery_voltage_from_SCC);client.println("</div>");
client.print("<div class='P1'>");client.print(PIP1_battery_discharge_current);client.println("</div>");
client.print("<div class='Q1'>");client.print(PIP1_status);client.println("</div>");
client.print("<div class='A2'>");client.print(PIP2_Grid_Voltage);client.println("</div>");
client.print("<div class='B2'>");client.print(PIP2_Grid_frequence);client.println("</div>");
client.print("<div class='C2'>");client.print(PIP2_output_Voltage);client.println("</div>");
client.print("<div class='D2'>");client.print(PIP2_output_apparent_power);client.println("</div>");
client.print("<div class='E2'>");client.print(PIP2_output_active_power);client.println("</div>");
client.print("<div class='F2'>");client.print(PIP2_output_load_percent);client.println("</div>");
client.print("<div class='G2'>");client.print(PIP2_battery_capacity);client.println("</div>");
client.print("<div class='H2'>");client.print(PIP2_BUS_voltage);client.println("</div>");
client.print("<div class='I2'>");client.print(PIP2_Battery_voltage);client.println("</div>");
client.print("<div class='J2'>");client.print(PIP2_battery_charge_current);client.println("</div>");
client.print("<div class='K2'>");client.print(PIP2_battery_capacity);client.println("</div>");
client.print("<div class='L2'>");client.print(PIP2_Inverter_heat_sink_temperature);client.println("</div>");
client.print("<div class='M2'>");client.print(PIP2_PV_current);client.println("</div>");
client.print("<div class='N2'>");client.print(PIP2_PV_voltage);client.println("</div>");
client.print("<div class='O2'>");client.print(PIP2_Battery_voltage_from_SCC);client.println("</div>");
client.print("<div class='P2'>");client.print(PIP2_battery_discharge_current);client.println("</div>");
client.print("<div class='Q2'>");client.print(PIP2_status);client.println("</div>");
client.print("<div class='A3'>");client.print(PIP3_Grid_Voltage);client.println("</div>");
client.print("<div class='B3'>");client.print(PIP3_Grid_frequence);client.println("</div>");
client.print("<div class='C3'>");client.print(PIP3_output_Voltage);client.println("</div>");
client.print("<div class='D3'>");client.print(PIP3_output_apparent_power);client.println("</div>");
client.print("<div class='E3'>");client.print(PIP3_output_active_power);client.println("</div>");
client.print("<div class='F3'>");client.print(PIP3_output_load_percent);client.println("</div>");
client.print("<div class='G3'>");client.print(PIP3_battery_capacity);client.println("</div>");
client.print("<div class='H3'>");client.print(PIP3_BUS_voltage);client.println("</div>");
client.print("<div class='I3'>");client.print(PIP3_Battery_voltage);client.println("</div>");
client.print("<div class='J3'>");client.print(PIP3_battery_charge_current);client.println("</div>");
client.print("<div class='K3'>");client.print(PIP3_battery_capacity);client.println("</div>");
client.print("<div class='L3'>");client.print(PIP3_Inverter_heat_sink_temperature);client.println("</div>");
client.print("<div class='M3'>");client.print(PIP3_PV_current);client.println("</div>");
client.print("<div class='N3'>");client.print(PIP3_PV_voltage);client.println("</div>");
client.print("<div class='O3'>");client.print(PIP3_Battery_voltage_from_SCC);client.println("</div>");
client.print("<div class='P3'>");client.print(PIP3_battery_discharge_current);client.println("</div>");
client.print("<div class='Q3'>");client.print(PIP3_status);client.println("</div>");
client.println("</html>");
break;
}
if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
delay(1);
client.stop();
Serial.println("client disconnected");
}
}
pour la partie affichage HTML, j’ai suivi la méthode de @Alex50 en la modifiant:
client.print(« <div class=‹ nom de la classe ›> »);client.print(nom de la variable);client.println(« </div> »);
l’utilisation de <div class=‹ nom de la classe ›> permet faire le lien avec script de jeedom c’est pour cela que mes class sont simple (mais non explicite) pour gagner du temps et éviter les erreurs lors de la création du script
création du script
penser a sauvegarder entre chaque (j’ai eu des pb comme quoi la variable existait deja par moment quand je n’enregistrais pas pour 1 seule ligne)
mettre autant de ligne que vous voulez d’information dans jeedom
/!\ pour la batterie, ne prendre que sur l’onduleur où est branché le cable pyl (quand on est avec des PYL)
création du virtuel
j’ai juste mis la production solaire en W (multiplication des valeurs PV voltage par PV ampère )
conclusion:
quand on sait faire c’est simple, si quelqu’un veut l’améliorer je me ferai un plaisir de mettre à jour…
lancez vous, au pire vous y arrivez…