OK merci Denis, cela sort du champs de mes compétences.
Hâte de voir ton projet final avec une belle interface web
J'y pense, il existe des cartes à base ESP32 qui ont à la fois le WiFi et l'Ethernet.
Il me semble qu'il serait idéal d'avoir les deux, ce serait une très belle amélioration du projet je pense
Le WiFi présente bien des avantages pour ceux qui ont le local technique près de la piscine, et que tirer un câble présente de grosses difficultés, alors qu'un simple répéteur WiFi résout le problème. De plus, la connexion n'a pas besoin d'être très fiable, car la régulation se fait dans le local, on ne fait que consulter ou passer des commandes par le réseau.
Les cartes avec l'Ethernet sont sans doute plus chères, je vais regarder ce qui existe.
Ne te dévalorise pas, ton champ de compétences est déjà très au dessus de la moyenne ![]()
@+
Denis
Bonjour,
Vraiment félicitation pour ce projet !
J'ai un soucis de com en Ethernet, je suis avec meg2560 + Shield Ethernet
La ligne a modifier est bien uniquement celle-ci en enlevant les commentaires ?!
String sArduinoMac;
IPAddress ip(192, 168, 0, 188); //IP address, needs to be adapted depending on local network topology
J'ai testé le matériel avec un programme plus simple et la librairie ethernet , j'arrive a affecter une adresse ip.
Merci d'avance pour votre aide.
Nico
Hello Loïc,
Quelques news de mon avancement.
Ma version dédiée ESP32 fonctionne (sur banc d'essai). Comme dit précédemment, ce sera une version exclusive ESP car les modifs sont trop lourdes pour être gérées à coup de #define.
Résumé des modifs :
- passage en projet PlatformIO multi-fichiers et en .cpp au lieu de .ino ;
- suppression de la fonction Ethernet et du petit serveur web. Réseau WiFi multi (choix du meilleur réseau) ;
- Utilisation des deux cores de l'ESP (par ex. le maintien du WiFi est en asynchrone dans le core 1) ;
- Client MQTT asynchrone (avec des callbacks, comme le reste) ;
- passage en JSON 6 au lieu de 5 ;
- quelques modifs par-ci par là, comme la filtration centrée sur 15h pour filtrer aux heures les plus chaudes de la journée, ou changement des logiques à heure fixe (par exemple dans ta version, le calcul de la durée de filtration est effectué plusieurs fois, tant que les minutes sont à 0...) ;
- adaptations spécifiques ESP : vrai reset à l'envoi de la commande (au lieu de boucler en attente du watch-dog), lecture calibrée des entrées analogiques, stockage NVS atomique (variable par variable), etc.
Je me suis intéressé aussi à la régulation. D'abord le sampletime de l'ORP n'est pas défini, donc par défaut la bibliothèque le met à 100ms. Ensuite, il me semble inutile de réguler plus souvent que la taille de la fenêtre, donc je pense fixer les sampletime à la taille de la fenêtre.
J'ai aussi repris le tableau de bord Node-Red, corrigé quelques petites erreurs dans les fonctions (";" manquants par ex.), agrandi certaines polices et fait en sorte que les paramètres actuels sur le tableau de réglages soient affichés.
A l'init, le Nextion affiche une durée de pompe ORP de 30.2min, qui est mise à jour par la suite. C'est parce qu'il y a quelques variables qui ne sont pas initialisées dans l'onglet "Programs" de Nextion Studio, dont page0.vaphTk, page0.vaOrpTk, page0.vaWT et page0.vaAT.
Je n'ai pas réussi à trouver une carte SD qui fonctionne sur le Nextion, je l'ai donc programmé par la liaison série (?), ce qui prend un certain temps...
Dès que j'ai une version complète je posterai un "fork" sous GitHub.
Au global, ton projet est très bien fait, et je n'ai pas eu de mal à le modifier et à l'adapter à mon besoin. Je vais sans problème ajouter la programmation du robot de nettoyage, cela remplacera le chauffage que je n'ai pas (snif). Encore merci et bravo donc.
@suivre
Denis
Merci pour le retour Denis, content que tu aies pu porter le projet vers ta plateforme sans trop de soucis.
Bien vu pour l'initialisation du SampleTime du Orp, je l'ai rajouté et mis à 5mins. Je ne toucherai pas de mon coté au SampleTime du pH (10mins). De mémoire, s'il est plus court que la taille de la fenêtre, cela a pour conséquence de potentiellement pouvoir corriger en cours de fenêtre la réaction du PID. Je ferai des tests au printemps...
A+
Loic
Hello,
Cette notion de fenêtre fait qu'on n'autorise les corrections calculées par la régulation qu'une fois par fenêtre. Donc toutes les corrections calculées à la fréquence du sampletime sont inhibées jusqu'à la fenêtre suivante (50mn et 1h respectivement par défaut). Je pense que cela a été ajouté pour tenir compte de la grande inertie du processus et du fait que l'on utilise que la correction proportionnelle à l'erreur (Kp). Il me semble qu'on aurait le même effet en mettant le sampletime à 1 heure et en supprimant les fenêtres. Je vais approfondir la bibliothèque PID car j'ai vu qu'il y avait une option proportionnelle, peut-être plus sophistiquée que de simplement mettre Kd et Ki à zéro
@+.
gixy31:
Hello,
Cette notion de fenêtre fait qu'on n'autorise les corrections calculées par la régulation qu'une fois par fenêtre. Donc toutes les corrections calculées à la fréquence du sampletime sont inhibées jusqu'à la fenêtre suivante (50mn et 1h respectivement par défaut). Je pense que cela a été ajouté pour tenir compte de la grande inertie du processus et du fait que l'on utilise que la correction proportionnelle à l'erreur (Kp). Il me semble qu'on aurait le même effet en mettant le sampletime à 1 heure et en supprimant les fenêtres. Je vais approfondir la bibliothèque PID car j'ai vu qu'il y avait une option proportionnelle, peut-être plus sophistiquée que de simplement mettre Kd et Ki à zéro
@+.
La librairie PID est assez optimisée et sous un aspect plutôt simple de prime abord (peu de code) il m'a fallut la relire à tête reposée plusieurs fois afin d'en saisir toutes les subtilités.
La notion de fenêtre est identique à tous les processus, quelque soit leur rapidité/inertie. Dans le cas du pH, et plus encore, du Redox, effectivement c'est lent, donc j'ai choisi des fenêtres larges. La rapidité de réaction de ce processus chimique peu dépendre de plusieurs paramètres donc il est bon de vérifier le sien. Pour cela, il suffit de lancer la filtration de sa piscine, logger les mesures de pH et/ou Redox, puis d'ajouter à un instant T0 un demi- verre d'acide ou de chlore liquide dans l'eau et voir l'effet que cela a sur les mesures, et à quelle rapidité. Il faut noter le temps que cela a pris pour atteindre 90% de la valeur finale, cela nous donne une indication de la "constante de temps" du système (sa réactivité).
Revenons à la librairie PID: le fonctionnement de la librairie et la notion de fenêtre peuvent être assimilées au fonctionnement d'un signal PWM. La pleine largeur de la fenêtre est 100% du duty cycle. Lorsque le PID calcule une différence/erreur par rapport à la consigne, il le convertit en action (un relais de pompe Orp fermé par ex.) pendant un % de temps de la largeur de la fenêtre. Si l'erreur est très grande, il peut être amené à fermer le relais pendant 100% de la fenêtre (duty cycle de 100% de mon signal PWM). A contrario, une petite erreur peut amener à fermer le relais un petit instant (eg. duty cycle de 3% de mon signal PWM). Si l'erreur ne change pas et que le PID est seulement proportionnel, la pompe/relais va s'enclencher pendant 3% du temps de la fenêtre, à chaque cycle de fenêtre.
La où je ne suis pas d'accord avec toi sur la durée du sample time, c'est que si tu choisis un sample time plus petit que la durée de la fenêtre, comme je l'ai fait, le PID peut alors être amené à changer la valeur de la correction (le duty cycle) pendant un même cycle de fenêtre, ce qui est à mon avis utile.
Loin de moi l'idée de mettre en question ta logique
Simplement en lisant ton code, je vois :
if(storage.PhPIDOutput < millis() - storage.PhPIDWindowStartTime)
PhPump.Stop();
else
PhPump.Start();
C'est à dire que dès que le temps courant depuis le démarrage de la fenêtre a dépassé la durée de la régulation (quelle qu'elle soit), la pompe est arrétée (normal) mais ne pourra plus être remise en marche jusqu'à la fenêtre suivante où le WindowStartTime va être décalé d'une valeur de fenêtre. Donc (sauf erreur de ma part), il ne peut y avoir qu'une régulation par fenêtre. De plus cette notion de fenêtre est extérieure à la librairie qui n'en tient donc pas compte et pourrait donc fausser les calculs dans le cas où l'on utiliserait Kd et Ki.
Loin de moi encore une fois l'intention de polémiquer, j'essaye juste de bien comprendre pour ajuster au mieux les paramètres. Je vais simuler une configuration en mettant le sampletime égal à la largeur de fenêtre, ce qui annule l'effet de celle-ci.
gixy31:
Loin de moi l'idée de mettre en question ta logiqueSimplement en lisant ton code, je vois :
if(storage.PhPIDOutput < millis() - storage.PhPIDWindowStartTime)
PhPump.Stop();
else
PhPump.Start();C'est à dire que dès que le temps courant depuis le démarrage de la fenêtre a dépassé la durée de la régulation (quelle qu'elle soit), la pompe est arrétée (normal) mais ne pourra plus être remise en marche jusqu'à la fenêtre suivante où le WindowStartTime va être décalé d'une valeur de fenêtre. Donc (sauf erreur de ma part), il ne peut y avoir qu'une régulation par fenêtre. De plus cette notion de fenêtre est extérieure à la librairie qui n'en tient donc pas compte et pourrait donc fausser les calculs dans le cas où l'on utiliserait Kd et Ki.
Loin de moi encore une fois l'intention de polémiquer, j'essaye juste de bien comprendre pour ajuster au mieux les paramètres. Je vais simuler une configuration en mettant le sampletime égal à la largeur de fenêtre, ce qui annule l'effet de celle-ci.
No worries.
La valeur de "storage.PhPIDOutput" est justement recalculée par la fonction PhPID.Compute() tous les "sampleTime"; donc si le SampleTime est plus court que la Window et que l'erreur avec la consigne a augmentée, tu peux avoir un cas où la pompe est remise en route pour dans une même window.
Par ailleurs la notion de Window vient de l'exemple RELAY de la librairie. C'est grâce à elle que tu as un fonctionnement de type PWM lorsque tu utilises des relais pour réguler
C'est même pire que ça, je viens de constater que la valeur de sortie varie à chaque appel de compute(), ce qui n'est pas normal, car dans le code de la librairie, on renvoie false tant que on n'a pas sampletime entre deux appels. Je vais investiguer et mettre un test sur la validité de compute(). Merci pour les infos, je vais me plonger dans tout ça (pas dans l'acide toutefois)...
gixy31:
C'est même pire que ça, je viens de constater que la valeur de sortie varie à chaque appel de compute(), ce qui n'est pas normal, car dans le code de la librairie, on renvoie false tant que on n'a pas sampletime entre deux appels. Je vais investiguer et mettre un test sur la validité de compute(). Merci pour les infos, je vais me plonger dans tout ça (pas dans l'acide toutefois)...
Hmm, je ne vois pas trop ce que tu veux dire.
Pour info le créateur de la librairie Brett Beauregard répond aux questions sur ce forum Google: https://groups.google.com/u/1/g/diy-pid-control
Résultat de l'analyse : j'avais oublié de définir le sampletime de l'Orp (alors que j'avais vu qu'il n'était pas défini...), raison pour laquelle la sortie évoluait. Mais tu as raison, si la fenêtre est plus grande que le sampletime et que malgré la régulation l'erreur augmente, on peut avoir une remise en route de la pompe : c'est une situation où un phénomène extérieur à perturbé la correction, comme par exemple des baigneurs ou un orage. On peut aussi arrêter la pompe plus tôt si l'erreur diminue. Toutefois dans l'exemple du relais, la durée de la fenêtre est égale au maxi autorisé de la sortie, donc la sortie varie entre 0 et la durée de la fenêtre (pour avoir un PWM de 0 à 100%). Dans notre cas, cela signifie qu'il faudrait soit avoir une fenêtre de 10 minutes au lieu d'une heure ou bien une fenêtre d'une heure avec un maxi autorisé d'une heure aussi.
Dans ma situation, je remplis la piscine avec l'eau du puits qui est acide, donc il faut que j'ajoute du PH+. Pour le volume de la piscine, il faut théoriquement 3/4 de litre pour monter le pH de 0,4. Avec une pompe à 1,5l/h, cela ferait 1,25h pour un écart de pH de 1, soit une correction de 75*60000 = 4500000. Une méthode heuristique préconise de commencer avec la moitié de cette valeur, soit environ 2000000, qui est la valeur que tu utilises ! Je pense alors commencer mes essais avec fenêtre et maxi à 1 heure, avec sampletime à 10 minutes. Ensuite, la théorie voudrait qu'on ne règle l'ORP que lorsque le pH est stabilisé. Je vais faire des relevés avec InfluxDB et Grafana car je sens que c'est pas gagné cette affaire !!!
Bonjour à tous,
je suis avec intérêt les développements de ce superbe projet.
La discussion sur la régulation en revanche me dépasse complètement.
J'ai renoncé à remplacer l'accès Ethernet par une carte sim800l en raison de trop nombreuses déconnexions et de la difficulté de se reconnecter ensuite.
Je voudrais à présent piloter mon électrolyseur au lieu d'une pompe doseuse.
Je pense conserver la régulation OrpPid et m'inspirer de la fonction chauffage avec la bibliothèque pump
Qu'en pensez-vous ?
gixy31:
Toutefois dans l'exemple du relais, la durée de la fenêtre est égale au maxi autorisé de la sortie, donc la sortie varie entre 0 et la durée de la fenêtre (pour avoir un PWM de 0 à 100%).
Il n'est pas nécessaire, pour que la régulation fonctionne, que la valeur max de l'output corresponde à 100% de la fenêtre, ces deux choses sont indépendantes dans notre cas. Il faut également s'assurer qu'on ne verse pas trop de chlore à la fois pour des raisons de sécurité.
Et oui, il faut commencer par équilibrer le pH (et tous les autres paramètres de l'eau tels que dureté, alcalinité, etc) avant de réguler l'Orp.
ParisBrest:
Bonjour à tous,
je suis avec intérêt les développements de ce superbe projet.
La discussion sur la régulation en revanche me dépasse complètement.
J'ai renoncé à remplacer l'accès Ethernet par une carte sim800l en raison de trop nombreuses déconnexions et de la difficulté de se reconnecter ensuite.
Je voudrais à présent piloter mon électrolyseur au lieu d'une pompe doseuse.
Je pense conserver la régulation OrpPid et m'inspirer de la fonction chauffage avec la bibliothèque pump
Qu'en pensez-vous ?
Salut, oui c'est la manière de faire et ça ne doit pas être trop compliqué. Ça dépend de ce dont a besoin ton électrolyseur. Si tu dois gérer le bas niveau à savoir inverser sa polarité à chaque fois qu'il démarre, etc. c'est plus compliqué. Si tu dois juste l'allumer N heures par jour et le stopper si l'Orp dépasse un seuil ou le mettre en mode lent lorsque le volet est fermé, c'est plus simple et je te conseille de plutôt te baser sur le code du chauffage que le code du OrpPID car je ne sais pas si ces cellules d'électrolyse apprécient d'être allumées/éteintes plusieurs fois par jour.
Loulou74:
Salut, oui c'est la manière de faire et ça ne doit pas être trop compliqué. Ça dépend de ce dont a besoin ton électrolyseur. Si tu dois gérer le bas niveau à savoir inverser sa polarité à chaque fois qu'il démarre, etc. c'est plus compliqué. Si tu dois juste l'allumer N heures par jour et le stopper si l'Orp dépasse un seuil ou le mettre en mode lent lorsque le volet est fermé, c'est plus simple et je te conseille de plutôt te baser sur le code du chauffage que le code du OrpPID car je ne sais pas si ces cellules d'électrolyse apprécient d'être allumées/éteintes plusieurs fois par jour.
Merci pour ces précisions.
Du coup, j'ai laissé tomber la régulation OrpPID.
L'électrolyseur se déclenche quand la valeur d'ORP est inférieure à 90% de la consigne et s'arrête quand on dépasse 105%.
J'ai un peu modifié la remise à zéro que tu fais à minuit pour qu'elle ne s'exécute qu'une seule fois.
A 00:00, le fonctionnement de l'électrolyseur est inhibé afin d'inverser la polarité. , et il est autorisé à nouveau, à 00:01
Désormais, il ne reste plus qu'à modifier les écrans du Nextion
ParisBrest:
Merci pour ces précisions.
Du coup, j'ai laissé tomber la régulation OrpPID.
L'électrolyseur se déclenche quand la valeur d'ORP est inférieure à 90% de la consigne et s'arrête quand on dépasse 105%.
J'ai un peu modifié la remise à zéro que tu fais à minuit pour qu'elle ne s'exécute qu'une seule fois.
A 00:00, le fonctionnement de l'électrolyseur est inhibé afin d'inverser la polarité. , et il est autorisé à nouveau, à 00:01
Désormais, il ne reste plus qu'à modifier les écrans du Nextion
Parfait. Pour le Nextion une fois qu'on a compris le fonctionnement ça va mais il faut s'y pencher un peu. Une partie du code tourne sur le Nextion, on y accède via l'éditeur Nextion. Il y a un certain nombre d'écrans auxquels correspondent du code et des variables globales. Il y a du code qui correspond à des évènements du style un appui bouton ou alors l'initialisation d'un écran. De manière générale il faut limiter les échanges entre l'Arduino et le Nextion afin de ne pas surcharger l'Arduino, donc faire tourner autant de code que possible sur le Nextion.
Pour intercepter dans l'Arduino un évènement issu du Nextion , on écrit un code (unique à cet évènement) sur le port série comme "printh 23 02 54 05" et la librairie EasyNextion y fait correspondre un callback dans le code de l'Arduino. Ce sont les fonctions trigger1(), trigger2(), etc
Enfin, dans le code de l'Arduino, j'ai créé des variables (structure TFTStruct) qui reflètent l'état de chaque variable du Nextion. A chaque appel de la fonction UpdateTFT() ces valeurs sont comparées aux valeurs correspondantes dans l'Arduino et seules celles qui ont changé sont mises à jour dans le Nextion, toujours dans le but de ne pas surcharger les échanges entre Arduino et Nextion
J'ai commencé à me pencher sur le Nextion.
J'ai rajouté quelques instructions sur le clavier virtuel que tu fais apparaître.
A chaque appel de ce clavier, je définis s'il peut y avoir une virgule ou pas, et empêche d'en saisir plus qu'autorisée.
Par contre, j'avais évité les interactions avec l'Arduino. Je vais donc m'y pencher avec ces explications.
Je pense que je vais en profiter pour utiliser le RTC du Nextion avec une synchro quotidienne.
Cela allégera toujours les échanges.
ParisBrest:
J'ai commencé à me pencher sur le Nextion.
J'ai rajouté quelques instructions sur le clavier virtuel que tu fais apparaître.
A chaque appel de ce clavier, je définis s'il peut y avoir une virgule ou pas, et empêche d'en saisir plus qu'autorisée.
Par contre, j'avais évité les interactions avec l'Arduino. Je vais donc m'y pencher avec ces explications.
Je pense que je vais en profiter pour utiliser le RTC du Nextion avec une synchro quotidienne.
Cela allégera toujours les échanges.
Bonnes idées, encore mieux si tu les partages via un pull request ![]()