Tuto : abreuvoir à niveau constant électronique

 Répondre au sujet
Auteur
703 vues - 6 réponses - 2 j'aime - 2 abonnés

Equinoxe88

Expert
   

Trust : 118  (?)


  Mon site internet
  M'écrire un MP

Genre : 
Messages : 968
Tuto : abreuvoir à niveau constant électronique
Posté le 20/01/2019 à 12h06

Bonjour,

Il y a 2 ans je vous proposais un montage qui permettait de faire un circuit d'abreuvoir antigel. Aujourd'hui, toujours dans les abreuvoirs, je vous présente un petit bricolage de niveau constant électronique. Il n'intéressera sans doute pas grand monde, mais je propose quand même, qui sait ça servira peut-être à quelqu'un un jour.

Pour la petite histoire, c'est une amélioration d'un montage que j'ai déjà fait il y'a 15 ans et qui à fonctionné sans problème depuis tout ce temps. J'ai eu mon premier cheval en 2000 et quelques années plus tard mes parents déménageaient pour une propriété permettant d'avoir les chevaux à la maison. J'ai donc construit des boxs et rapidement le besoin d'y installer des abreuvoirs s'est fait sentir.
J'ai opté pour des abreuvoirs à niveau constant. Déjà parce que je doutais de la faculté de mon cheval à comprendre le fonctionnement des abreuvoirs à palette (c'est sans doute faux, mais c'est dingue comme on a toujours tendance à douter des capacités intellectuelle de son cheval !) et ensuite parce que je trouve que le débit des abreuvoirs à palette trop faible, généralement ça coule beaucoup moins vite que ce que peut absorber un cheval. Ça les frustre et du coup ils boivent moins que ce qu'ils devraient.

Peut-être que j'avais choisi une mauvaise marque, mais rapidement j'ai eu le problème que tous les utilisateurs d'abreuvoir à niveau constant doivent connaitre : le robinet à flotteur qui fuit et l'abreuvoir qui déborde !
L'appareil n'avait que quelque mois ce qui dénotait un manque flagrant de fiabilité. Plutôt que de faire jouer la garantie, pour le voir remplacer par un autre abreuvoir qui aurait sans doute rapidement le même problème, j'ai décidé de modifier complètement le système.
A l'époque je travaillais comme électrotechnicien dans l'industrie agroalimentaire, et dans mon travail je voyais beaucoup de cuves, citernes, bac, etc... dont le remplissage (ou la vidange) était géré par des capteurs de niveau, des électrovannes, des pompes, etc... Je n'avais donc qu'à reproduire le principe pour mes abreuvoirs.
C'est ce que j'ai fait, et c'est donc ce qui à fonctionné sans problème pendant 15 ans.

Moi entre temps, j'ai déménagé et acheté ma propre maison, et aménagé ma propre écurie. Dans mes boxs j'ai à nouveau installé des abreuvoirs à niveau constant (d'une marque plus connue et plus sérieuse que la première) mais après quelques années j'ai de nouveau eu un petit problème de fuite et alors l'idée de refaire le même montage que chez mes parents à fait son chemin. Par manque de temps, et parce que la fuite n'est finalement pas très importante (environ 60 litres par an) je n'avais rien fait.
Et puis l'autre jour, un de mes chevaux à eu la mauvaise idée d'aller se gratter les fesses contre son abreuvoir. Il l'a à moitié arraché du mur et partiellement cassé.
Le matin j'ai retrouvé l'abreuvoir coulant à plein et le box complètement inondé. Je l'ai bien sûr rafistolé comme j'ai pu, mais depuis, et sans que j'en trouve la raison, le flotteur fuyait de façon importante et sans parler de gaspillage d'eau, ça me pourrissait le box en moins de deux (avec le cheval qui passe la nuit sur une litière à moitié trempé alors que je le rentre justement pour qu'il soit quelques heures par jour les pieds au sec...)

Je me suis donc mis sérieusement sur un système d'abreuvoir à niveau constant électronique.
Le cahier des charges était le suivant :
- Gérer le remplissage de l'abreuvoir en fonction de son niveau (c'est quand même la base !)
- Arrêter le remplissage si un problème est détecté afin d'éviter d'inonder le box (et/ou d'arroser le cheval) toute la nuit parce qu'un couillon de poney a tout arraché.
- Surveiller la quantité d'eau consommée par l'animal au cour de la journée (parce qu'avec un abreuvoir automatique, il est très difficile d'estimer la quantité bue et je pense que c'est un renseignement qui peut être utile quand on se soucie de la bonne santé de son animal)

Pour les 2 premières fonctions j'aurais très bien pu refaire le même système que chez mes parents, à base de relais temporisés. C'était simple et fiable, mais pas franchement bon marché car ce genre de relais coute vite assez cher. Et puis la fonction de surveillance de consommation aurait été compliquée à ajouter. Mettre un compteur d'eau par abreuvoir aurait été une solution, mais ce genre d'appareil à un cout non négligeable et il ne donne qu'une information globale, si on veut connaitre la consommation jour par jour, il faut relever le compteur tous les jours.
J'aurais pu aussi utiliser un petit automate programmable industriel, les plus petit modèles sont tout à fait adaptés à ce genre de fonction. Par contre ils sont cher (plusieurs centaines d'euros) et demandent généralement l'achat d'un logiciel spécifique et d'un câble pour pouvoir les programmer.
Je suis donc parti sur une solution à base de microcontrôleur et pour ce faire j'ai choisit un Arduino car en plus d'être lui même très bon marché, le système de développement est libre et gratuit, n'importe qui peut l'utiliser très facilement et donc reproduire mon système sans grandes difficultés ni logiciel spécifique à acheter.

Je vais commencer par vous présenter le système dans ses grandes lignes et je rentrerais dans les détails de la réalisation plus tard.

L'élément principal c'est bien sûr l'abreuvoir. Ici c'est donc un abreuvoir à niveau constant "La Gée" que mon gros à généreusement bien amoché et que j'ai donc modifié. La seule grosse modification nécessaire est l'ajout d'un petit interrupteur de niveau à l'intérieur de la partie protégé de l'abreuvoir. Le robinet à flotteur est naturellement supprimé et on le remplace par un simple raccord permettant de tenir le tuyau d'arrivé d'eau.
Ici j'ai opté pour une solution élégante de raccord coudé "traversée de cloison" qui s'adapte parfaitement bien au projet (je détaillerais le matériel utilisé dans un autre post)
Une fois le couvercle d'origine remis en place, l'abreuvoir à exactement le même aspect qu'a l'origine, juste un petit câble en plus.





L'autre élément important c'est bien sûr l'électrovanne qui se charge d'ouvrir ou de fermer l'eau pour remplir l'abreuvoir en fonction de l'information donné par le capteur de niveau. Cette électrovanne est associée à un clapet anti-retour de mise à l'atmosphère dont le but est de permettre au tuyau entre l'électrovanne et l'abreuvoir de se vider une fois le remplissage fini. Le but de cette vidange est la protection contre le gel. S'il n'y pas d'eau dans le tuyau celle-ci ne risque pas de geler... Naturellement on place le système électrovanne-clapet en hauteur, hors de porté du cheval, et on protège celui-ci contre le gel (avec le principe que je vous ai proposé il y a 2 ans par exemple)
Ainsi l'alimentation de l'abreuvoir reste hors gel sans qu'il y'ai ni besoin d'un cordon chauffant qui passe dans le box, ni d'un système de circulation et son surplus de tuyauterie.
(Naturellement pour les régions très froides, ça n'empêche pas l'eau présente dans l'abreuvoir de geler... dans ce cas un vrai abreuvoir chauffant reste la seule solution)



Et finalement pour gérer tout ça, il faut un boitier de contrôle. c'est la que se trouve "l'intelligence" du système. Dans la version actuelle, il peut gérer jusqu'a 4 abreuvoirs (le prototype actuel n'en gère qu'un mais le programme tourne comme s'il y en avait 4)
Donc comme déjà dit plus haut, la fonction de base c'est déjà de remplir les abreuvoirs en fonction de l'info donné par les capteurs de niveau.
J'ai ajouté des petites temporisations pour éviter les remplissages intempestifs et les à-coups de l'électrovanne. En effet, lors du remplissage (ou simplement quand un cheval trempe son foin avant de le manger) il se produit des vagues qui induisent une information instable du capteur de niveau. Une temporisation lisse le signal et permet une fermeture et une ouverture franche de l'électrovanne.
Une autre temporisation, plus longue (ici j'ai mis 1 minute) évite les débordements et autres accidents du genre en cas de problème avec l'abreuvoir (capteur défectueux ou bloqué par du foin, abreuvoir arraché, fil du capteur coupé, etc...) Simplement, si le capteur indique un niveau bas de l'abreuvoir pendant plus d'une minute, le remplissage est arrêté car ce n'est pas normal qu'un abreuvoir mette aussi longtemps à se remplir (même si un cheval boit en même temps)
Le système compte aussi le temps que met l'abreuvoir à se remplir (mesure du temps entre l'ouverture de l'électrovanne et la fermeture) pour cumuler un temps de remplissage journalier et moyennant une calibration indiquer grossièrement une quantité d'eau en litre, consommée pour la journée en cours et pour la veille.
On peut aussi choisir d'arrêter spécifiquement un abreuvoir du système (box vide dans lequel on ne veut pas que l'eau de l'abreuvoir stagne par exemple) et une petite fonction de diagnostique permet de visualiser l'état des capteurs de niveau et de forcer l'ouverture des électrovannes quelque soit l'état des capteurs.
Le système fonctionne entièrement en 12V ainsi il n'y a aucun moment de tension dangereuse dans un élément du système (même si le fil du capteur venait à baigner dans l'abreuvoir, on ne sentirait strictement rien en mettant les mains dans l'eau) Il peut être alimenté soit par un convertisseur 230V/12V comme ici, soit par exemple par une batterie de voiture et un petit panneau solaire.



Je reviendrais plus tard pour expliquer plus en détails la réalisation de chaque élément. Je ne sais pas encore par quoi je vais commencer. Si vous voulez voir quelque chose en premier dites le en commentaires. pareils si vous avez des questions et des remarques. J'y répondrais dans mon prochaine message.

Equinoxe88

Expert
   

Trust : 118  (?)


  Mon site internet
  M'écrire un MP

Genre : 
Messages : 968
1 j'aime    
Tuto : abreuvoir à niveau constant électronique
Posté le 23/01/2019 à 21h17

Première partie du tuto à proprement parlé : La modification de l'abreuvoir.

C'est l’élément principal du système et c'est aussi le plus simple.

Si vous partez d'un abreuvoir à niveau constant en résine comme le miens, il vous faudra démonter le robinet à flotteur d'origine et le remplacer par un simple raccord permettant d'y connecter le tuyau d'arrivé d'eau.

L'autre action consiste à ajouter un capteur de niveau. Il existe quantité de systèmes permettant de détecter ou de mesurer le niveau d'un liquide. Pour notre application, le plus simple ira très bien : un simple petit contact à flotteur.
Celui que j'ai choisi est constitué d'un petit flotteur en plastique contenant un aimant. Quand le flotteur est aligné avec le corps du capteur, l'aimant active un petit interrupteur à lame souple (ILS) qui établi le contact.
Vous trouverez ce type de capteur de niveau très facilement sur le net sur des sites comme aliexpress, amazon, ebay, banggood, etc... avec des mots clés comme "interrupteur de niveau" ou "float switch" "water level switch" (c'est mieux en anglais)
Il faut choisir un modèle qui se monte sur le côté (side mount) mais il existe des modèles qui se montent par le haut (ou par le bas) si ça peut être plus adapté à votre abreuvoir.
Il vous en coutera entre 2 et 5 € par capteur suivant le site, le vendeur, la quantité acheté.
Il existe au moins 6 modèles différents qui se ressemblent beaucoup, la différence si situant principalement dans le mode de montage (par l’intérieur ou par l’extérieur, etc..) Sur les sites de e-commerce asiatiques faites attention de bien lire la description car la photo présentée ne montre pas forcement l'article vendu.
Pour ma part j'ai opté pour un modèle qui se monte par l’intérieur avec écrou à l’extérieur.



Le montage ne présente pas de difficulté particulière. Il suffit de percer un trou sur le côté de l'abreuvoir, en dessous du raccord d'arrivé d'eau. Le plus compliqué est de trouver la bonne hauteur. Il faut prendre en compte le fait qu'il y a une petite temporisation entre la détection du niveau et l'arrêt du remplissage, et qu'il y a aussi le tuyau entre l’électrovanne et l'abreuvoir qui va se vider et donc apporter encore un certain volume d'eau après l'arrêt (si comme moi vous optez pour un système de purge automatique antigel) le volume du tuyaux dépendant naturellement de sa longueur et de son diamètre.

Si comme pour le miens votre abreuvoir est constitué d'une double paroi, il faudra percer l'enveloppe extérieur d'un diamètre suffisant pour passer l'écrou.
Pour le trou extérieur une petite scie cloche (ou trépan) est le meilleur outils. Pour le trou de l'enveloppe intérieur, destiné à recevoir le capteur, l'utilisation d'un forêt à étage est idéal car ça fait un trou bien rond et sans bavure (important pour l'étancheïté du joint)
Ensuite on enfile le capteur par l’intérieur (sans oublier le joint), l'écrou par l’extérieur et on sert modérément (ça reste du plastique...)



Pour le capteur il y a deux possibilité de montage différent :
- Soit flotteur vers le bas (horizontal quand le niveau est bon) (flèche sur le côté du capteur qui pointe vers le haut) dans ce cas le contact est établi quand le niveau est atteint et coupé quand le niveau est bas. Le niveau de remplissage correspond donc approximativement à celui du trou du capteur. C'est ce montage que j'ai choisi
- Soit flotteur vers le haut (horizontal quand le niveau est bas) dans ce cas le contact est établi quand le niveau est bas et coupé quand le niveau est bon. Le niveau de remplissage s’établit donc au dessus du trou de capteur (celui-ci est immergé quand l'abreuvoir est plein)
Le programme peut prendre en compte les 2 configurations différente, il faudra juste faire les ajustements nécessaires avant de le télécharger dans l’Arduino.

Attention, ce genre de capteur n'est pas du tout fait pour faire passer la moindre puissance électrique. La fiche technique indique généralement 10W maxi, mais c'est vraiment le maxi. En réalité il faut s'abstenir de l'utiliser pour commuter plus que quelques milliampères, donc vraiment un signal électronique et rien de plus.
N'essayez surtout pas de l'utiliser pour piloter directement une électrovanne (ni même un relais) !

La suite dans quelques jours...

Édité par equinoxe88 le 23-01-2019 à 21h21



Equinoxe88

Expert
   

Trust : 118  (?)


  Mon site internet
  M'écrire un MP

Genre : 
Messages : 968
0 j'aime    
Tuto : abreuvoir à niveau constant électronique
Posté le 26/01/2019 à 16h50

2eme partie de ce tuto. Aujourd'hui je vais aborder la partie "plomberie" de ce système d'abreuvoir.
C'est un peu plus compliqué et ça demande un peu plus de matériel que la modification de l'abreuvoir en lui même.
Il y a aussi pas mal de possibilités. Je montre ici la solution que j'ai mis en œuvre mais le principe est applicable à d'autres techniques. Par exemple il est tout à fait possible d'appliquer le principe en restant sur une tuyauterie "en dur" genre acier galvanisé ou cuivre. Le tuyau PE est aussi une alternative.
Je vous présente donc ici une solution à base de tuyau souple type "tubclair" (ou tuyau d'arrosage...)

En ce qui concerne l'approvisionnement, pour l’électrovanne j'ai acheté sur internet car c'est un produit courant que l'on trouve facilement sur tous les grands sites de e-commerce (on prend les mêmes que pour l'interrupteur de niveau : amazon, ebay, aliexpresse, banggood, etc...)
Vous trouverez facilement avec le mot clé "electrovanne" ou "electric valve" (étonnamment, ici on trouve des résultats plus pertinents avec le mot en français).
J'ai choisi une électrovanne en plastique, en 3/4" (20/27) bobine 12V, on la trouve entre 3 et 8 € suivant le site et le vendeur.
Les plus bricoleurs pourront utiliser une électrovanne de récupération d'un lave-linge, mais celles-ci étant en 230V il faudra adapter la commande et prendre les précautions nécessaires pour le câblage et l'emplacement. Franchement vu le prix d'une EV en 12V sur les sites asiatiques, j'ai préféré jouer la sécurité.
Le reste du matériel peut très certainement aussi se trouver sur le même genre de site. Moi étant donné que je travail dans le machinisme agricole, j'ai utilisé des pièces que l'on trouve sur les pulvérisateurs (des pièces neuves hein, parce que vu les pesticides utilisés j'ai pas envie d'empoisonner mes chevaux)
Je fournirais à la fin de cette partie le nom du fournisseur et la référence des pièces utilisés, et un fournisseur alternatif avec les références équivalentes.

Globalement il faut a peu prêt toutes ces pièces

On a donc de gauche à droite et de haut en bas :
- Un capteur de niveau (pour l'abreuvoir, vu dans la partie précédente)
- Un / des coude(s) cannelé(s) suivant la disposition entre l’électrovanne et l'abreuvoir.
- Une électrovanne 12V
- Un raccord cannelé fileté mâle 3/4"
- Un Té égal fileté femelle 3/4"
- Un clapet anti-retour fileté femelle 1/2"
- Un mamelon réduit mâle 1/2" - mâle 3/4"
- Du tuyau souple (non présent sur la photo, j'ai utilisé du tubeclair en 12/16)

Le but est ensuite d'assembler tout ça en suivant ce schéma de principe :


Attention au sens de montage de l’électrovanne et du clapet, il y a une flèche de gravée sur le corps. Pour l’électrovanne la flèche doit aller du réseau d'eau vers l'abreuvoir. Et pour le clapet elle doit aller de l’extérieur vers l'abreuvoir.
Comme expliqué dans le premier message, le but c'est de placer l'ensemble électrovanne / clapet en hauteur, si possible hors de porté des animaux. Du coup, quand l’électrovanne s'ouvre, l'eau s’écoule vers l'abreuvoir, le sens du clapet fait que l'eau ne sort pas vers l’extérieur.
Quand l’électrovanne se ferme, le clapet permet une entrée d'air et ainsi le tuyau vers l'abreuvoir se vide par gravité (à condition qu'il ne reste pas de boucles ou de point plus bas que l'abreuvoir dans le circuit)




Pour revenir plus concrètement sur la liste du matériel maintenant :
J'ai acheté le miens chez "Agriplus" (dans le 77) normalement vous pourrez acheter ces articles chez bon nombres de concessionnaires en machines agricoles. Contactez celui le plus proche de chez vous et demandez un devis. C'est en principe le matériel le plus cher de ce tuto, vous en aurez pour environ 20 à 30 €

- coude cannelé diam 12 ref. R5CE5
- embout cannelé mâle 3/4" - 11/13 ref. MA1032313
- té égal fileté femelle 3/4" ref. MA1302030
- clapet anti-retour fileté femelle 1/2" ref. RCPA12
- mamelon réduit mâle 1/2" - mâle 3/4" ref. MA2402032
- coude cannelé 11-13 avec écrou 1/2" ref. MA118213 (raccord pour entrée d'eau abreuvoir)

Un autre fournisseur est Bedouelle, sans doute lui aussi distribué chez les concessionnaires en machines agricoles (par contre leur catalogue est disponible en ligne)

- coude cannelé diam 12 ref.42453
- embout cannelé mâle 3/4" - 11/13 ref. 42023
- té égal fileté femelle 3/4" ref. 42299
- clapet anti-retour fileté femelle 1/2" ref. 45026
- mamelon réduit mâle 1/2" - mâle 3/4" ref. 42169
- coude cannelé 11-13 avec écrou 1/2" ref.42496 (raccord pour entrée d'eau abreuvoir)

Voilà pour cette partie. La prochaine fois j'aborderais la partie électronique; rien de bien compliqué mais ça restera quand même la partie la plus technique de ce tuto je pense.

Equinoxe88

Expert
   

Trust : 118  (?)


  Mon site internet
  M'écrire un MP

Genre : 
Messages : 968
0 j'aime    
Tuto : abreuvoir à niveau constant électronique
Posté le 03/02/2019 à 12h08

Troisième partie de ce tuto : l'électronique

Il vous faudra :
- Un Arduino Uno R3 et son câble USB (version officielle ou non, pas d'importance) : entre 1 et 5€, un peu plus si le câble USB est fournit (mais on a tous un câble USB d'imprimante qui traine dans un coin...)
- Un "LCD keypad shield" type DF-Robot ou un clone : entre 3 et 8 €. Choisissez plutôt un modèle avec un écran "vert/jaune" plutôt que bleu comme moi, car les bleus ne sont pas très lisibles.
- Une alimentation 230VAC-12VDC de 1 à 3 A (12 à 36W) suivant le nombre d'abreuvoir à piloter : de 4 à 15€
- Une grosse boite de dérivation qui servira de boitier à tout ça : voir en magasin de bricolage, prix très variable en fonction de la marque.
- 2 boutons poussoir à contact momentané pour montage sur panneau (étanche c'est mieux). Pas trop "cheap", c'est a dire pas comme les miens qui sont vraiment de la camelote : entre 0.5 et 2 € le bouton

Il vous faudra aussi réaliser une carte d'interface et pour ça vous aurez besoin de :
- Une plaque de bakélite / époxy à pastille ou à bandes
- Un peu de fil électrique fin
- 1 Bornier à vis double pour circuit imprimé
Puis en autant d'exemplaires qu'il y a d'abreuvoir à piloter :
- 1 Bornier à vise triple pour circuit imprimé
- 3 diodes de redressement type 1N4001
- 2 résistances de 1 kilo-ohms
- 1 résistance de 1.5 kilo-ohms
- 1 résistance de 220 ohms
- 1 résistance de 4.7 kilo-ohms
- 1 condensateur type MKT entre 10 et 100 nano-Farad
- 1 Transistor MOSFET ou Linéaire IRF740 ou BD139-16 (voir explication plus bas)
éventuellement :
- 1 résistance de 10 ohms / 1 Watts
- 1 diode transil type 1.5KE6.8A


(Ici je n'ai pas utilisé de diodes 1N4001 mais des diodes Schottky en boitier CMS, pour l'application qui nous intéresse la fonction est la même)

En ce qui concerne le choix du transistor maintenant. Ici j'ai mis un IRF740 qui est un modèle "obsolète" car c'est ce que j'avais en stock. Ici le choix n'est pas critique, il suffit de faire attention à 2 ou trois paramètres (par contre ici on parle de type N, c'est les plus courant mais il ne faut pas se tromper):
- Le courant de Drain (Id) doit être au minimum de 5A
- Le Gate Threshold Voltage (Vgs) doit être au max de 5V
- La tension Drain-Source max (Vds) doit être minimum de 50V (mais c'est pratiquement toujours le cas)
Si vous ne trouvez pas de IRF740 ni d’équivalent, un RCX200N20, ou un MDP10N60GTH ou encore un IRFB5615 (et leurs équivalent bien sûr) iront très bien aussi.

Vous pouvez aussi utiliser un transistor linéaire type NPN, c'est moins bien mais si vous avez ça sous le coude ça peut faire l'affaire sans problème.
Ici je propose un BD139-16 mais un équivalent ira aussi (un BD135 ou BD137 aussi sans doute, j'ai pas essayé). Il faut faire attention à 2 paramètres :
- Le courant de collecteur (Ic) qui doit être aussi de 1A minimum
- Le gain (hFE) qui doit être au minimum de 40

Pour réaliser l'interface je ne vais pas détailler point par point, ce serait trop long et pas forcement très pertinent. En plus mon montage est un prototype, il est loin d'être optimisé au niveau du placement et du routage. Et comme j'ai utilisé quelques composant CMS (composant miniature de surface) il faudrait aussi que vous utilisez les mêmes, et c'est pas forcement conseillé pour des gens n'ayant pas une grande expérience en électronique.
Il y a peu de composants, et en utilisant des composants "classiques" (traversant) avec un peu de réflexion n'importe qui peut réaliser ce circuit en suivant le schéma (à conditions de savoir lire un schéma électronique je suis d'accord... mais sinon vous avez forcement quelqu'un dans votre entourage qui pourrait vous bricoler ça)
Le schéma est ici :

L'alimentation, l'Arduino et son shield LCD keypad ne sont présent qu'en un seul exemplaire, le reste est à reproduire autant de fois que nécessaire en fonction du nombre d'abreuvoir (1 à 4)
Les bornes Arduino A1/D2 sont pour l'abreuvoir N°1, A2/D3 pour le N°2, A3/D11 pour le N°3 et A4/D12 pour le N°4
On utilisera des bouts de fils souples (ici j'ai utilisé un bout d'une ancienne nappe de disque dur IDE) pour faire la liaison entre l'Arduino et la carte d'interface.


Quand la carte d'interface est réalisée et qu'elle est reliée à l'Arduino, il reste une petite modification à apporter sur la carte "lcd kepad shield", en effet, cette carte comporte 5 boutons + le reset. Ces boutons ne sont pas très facile d'utilisation (très petit) et il serait compliqué de faire un système pour les activer à travers le boitier. On ne va pas non plus utiliser 5 boutons pour l'application qui nous intéresse, 2 seront suffisants. Je les ai appelé "selection" (select) et "défilement" (defil) (toute ressemblance avec l’appellation des boutons présent sur un compteur EDF est purrement voulue...)
Avec des petits bouts de fil, on va donc relier nos 2 boutons que l'on placera en face avant avec 2 boutons de la carte, il suffira simplement de les connecter en parallèle.
Le bouton "select" du shield deviendra le bouton "defil" du système d'abreuvoir, et le bouton "up" du shield deviendra le bouton "select" du système.


A ce stade il est possible de faire éventuellement un essai en branchant l'Arduino sur USB et en téléchargeant le programme (que je vous présenterais dans la dernière partie de ce tuto)


Si rien n'a fumé et que tout semble fonctionner correctement, reste plus qu'a installer tout ça dans un boitier.
Ici j'ai donc utilisé un grosse boite de dérivation pour installation électrique et les éléments sont fixé avec un pistolet à colle. Rien n'empêche de faire votre propre boitier, ou d'utiliser autre chose.


Il ne reste plus qu'a utiliser les 3 bornes restantes pour brancher le capteur de niveau entre le +12V et la borne "In" (CN2 sur le schéma) et l’électrovanne entre le +12V et la borne "Out" (CN3). Le +12V commun au deux éléments permettant d'économiser 1 fil si l'abreuvoir est loin du boitier de commande.

Alors j'ai bien conscience que c'est une partie un peu technique et compliquée. Il faut avoir quelques notions d’électronique et c'est pas forcement un loisir pratiqué par une grosse majorité de la population. Mais si ce n'est pas le cas, il y aura surement quelqu'un dans votre entourage qui pourra vous aider (peut-être que votre neveu de 13 ans fait déjà des bidouilles à base d'Arduino...)
Il faut aussi se dire que non, l’électronique c'est pas que un truc de mec ! (certaines pourraient penser ça, je le sais...) de nombreuses femmes travaillent dans ce milieu, et certaines en on fait leur loisir.
Voir la chaine youtube de Heliox par exemple
https://www.youtube.com/channel/UCPFChjpOgkUqckj3378jt5w

Il faut aussi se souvenir que cette version est un prototype. Il fonctionne sans aucun problème sous cette forme (en ce moment mon cheval boit entre 20 et 30 litres par jour) mais il est destiné à être amélioré.
Dans les semaines/mois à venir je vais dessiner un circuit imprimé qui intégrera directement l'interface pour 4 abreuvoirs. Je reviendrais ici pour partager cette amélioration.

Si vous avez des questions, des remarques ou des difficultés, rien ne vous empêche de me contacter en réponse ici ou par message privé, je ferrais mon possible pour y répondre.

A bientôt pour la dernière partie concernant le programme (qui sera bien plus simple que celle-ci)

Equinoxe88

Expert
   

Trust : 118  (?)


  Mon site internet
  M'écrire un MP

Genre : 
Messages : 968
0 j'aime    
Tuto : abreuvoir à niveau constant électronique
Posté le 09/02/2019 à 09h24

Quatrième et dernière partie de ce tuto : le programme

Pour commencer il vous faudra l'environnement de développement (IDE) Arduino. Il se télécharge gratuitement et facilement sur le site officiel Arduino et il est disponible aussi bien pour Windows, Linux ou Mac.
Sur le site Arduino il suffit d'aller sur "Software" puis "Download" et de choisir votre version en fonction de votre système puis de l'installer.
Si vous utilisez un Arduino Uno R3 officiel il n'y a rien d'autre de spécial à faire.
Si vous utilisez un clone chinois, il faudra sans doute installer un driver supplémentaire : le clones chinois utilisent souvent un convertisseur USB<->Serie différent, généralement un CH341. Sur le site où vous l'avez acheté, regardez à la partie "questions/réponses" de l'article acheté, bien souvent le vendeur fournit un liens pour télécharger le bon driver.
Quand la partie logiciel est prête, il ne vous reste plus qu'a brancher votre Arduino Uno sur un port USB de l'ordinateur utilisé. Comme déjà indiqué dans ce tuto, le câble est identique aux imprimantes USB, c'est un câble USB Type A mâle vers Type B mâle.
La première fois que vous allez le brancher, votre ordinateur vas normalement "reconnaitre" votre Arduino et lui affecter un numéro de port série.
Dans l'IDE Arduino dans le menu "Outils" vous allez sélectionner à "type de carte" l'option "Arduino/Genuino Uno"
Puis toujours dans le même menu à "Port" vous allez sélectionner le numéro de port com qui correspond à votre carte Arduino Uno (normalement supérieur à COM2 bien souvent plutôt COM8 ou plus)
(COM c'est pour Windows, sous d'autres systèmes ça peut s'afficher d'une autre façon)

Pour vérifier que l'Arduino est bien connecté et reconnu, dans le menu "Outils" vous pouvez utiliser la fonction "Récupérer les informations de la carte"

Dans la partie éditeur, l'IDE Arduino vous propose toujours le "squelette" d'un programme Arduino avec les fonctions setup et loop. Il faut effacer complètement le contenu de l’éditeur car ces fonctions sont naturellement déjà présente dans mon programme.

Il ne reste plus qu'a copier/coller le code ci-dessous dans l'IDE Arduino.
Normalement si vous allez à la dernière ligne du programme l’éditeur doit vous indiquer que c'est la ligne 883 (en bas à gauche de la fenêtre) si ce n'est pas le cas le copier-coller ne s'est pas bien passé.
Alors ce forum n'étant pas un forum d'informatique, il n'est pas possible de présenter ici du code avec la mise en forme habituelle, vous n'aurez donc pas les indentations que l'on place normalement pour rendre un programme plus lisible. Si vous voulez le fichier original (.ino) me contacter en privé.

Vous pouvez ensuite téléverser ce programme tel-quel dans l'Arduino de votre abreuvoir, ou procéder à quelques ajustements. Voir les explications après le pavé de code.


Citation :

#include <EEPROM.h>
#include <LiquidCrystal.h>

/*
Abreuvoir

*/

// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Déclaration des entrées/sorties
#define ledPin LED_BUILTIN // onboard LED port D13
#define Backlit 10 // retroeclairage LCD
#define EV1 2 // Electrovanne abreuvoir #1 sur port D2
#define Niveau1 A1 // Capteur niveau abreuvoir #1 sur port A1
#define EV2 3 // Electrovanne abreuvoir #2 sur port D3
#define Niveau2 A2 // Capteur niveau abreuvoir #2 sur port A2
#define EV3 11 // Electrovanne abreuvoir #3 sur port D11
#define Niveau3 A3 // Capteur niveau abreuvoir #3 sur port A3
#define EV4 12 // Electrovanne abreuvoir #4 sur port D12
#define Niveau4 A4 // Capteur niveau abreuvoir #4 sur port A4
// Déclaration des variables

int adc_key_in = 0;
int last_lcd_key = 0;
int fr_lcd_key = 0;
int page_menu = 0;
int secondes = 0;
int minutes = 0;
int heures = 0;
int cal[4] = {0,0,0,0}; //Valeur de calibration des abreuvoir

unsigned long previousMillis = 0; //Tempo clignotement LED
unsigned long refreshLCD = 0; //Tempo rafraichissement afficheur LCD
unsigned long debButtons = 0; //Tempo anti-rebond boutons interface
unsigned long debTempsLvl[4] = {0,0,0,0}; //Tempo anti-rebond capteur niveau
unsigned long timeoutLvl[4] = {0,0,0,0}; //Tempo time-out remplissage abreuvoir
unsigned long tempobacklit = 0; //Tempo pour extinction automatique retroeclairage

unsigned long debut[4] = {0,0,0,0}; //valeur timer début remplissage
unsigned long fin[4] = {0,0,0,0}; //valeur timer fin remplissage
unsigned long total[4] = {0,0,0,0}; //temps total remplissage journée en cours
unsigned long totalJMN[4] = {0,0,0,0}; //temps total remplissage de la veille

bool ledState = LOW;
bool backlitState = true;
bool inpNiveau[4];
bool LastinpNiveau[4];
bool EVState[4] = {LOW,LOW,LOW,LOW};
bool ErrorLvl[4] = {false,false,false,false};
bool frupEV[4] = {false,false,false,false};
bool frdownEV[4] = {false,false,false,false};
bool forcageEV[4] = {false,false,false,false};
bool stopEV[4] = {false,false,false,false};


// Déclaration des constantes d'ajustement
const long interval = 1000;
const int DebTimeLvl = 2500; //durée anti-rebond capteur abreuvoir
const long ToutTimeLvl = 60000; //durée time-out remplissage abreuvoir
const long tempsbacklit = 45000; //Durée d'allumage retroeclaire après dernière action sur le clavier

// Déclaration des autres constantes
#define btnRIGHT 1
#define btnUP 2
#define btnDOWN 3
#define btnLEFT 4
#define btnSELECT 5
#define btnNONE 0



//-------------------------------------
// Routines et fonctions annexes
//-------------------------------------

// Lecture du clavier associé à l'afficheur LCD
int read_LCD_buttons()
{
int lcd_key = 0;
adc_key_in = analogRead(0); // Lecture entrée analogique clavier
// Sur mon shield les differents boutons correspondent à ces valeurs: 0, 99, 256, 410, 641
// on ajoute une fourchette de +/- 50 environs pour tester les valeurs
if (adc_key_in > 1000) lcd_key = btnNONE;
if (adc_key_in < 700) lcd_key = btnSELECT;
if (adc_key_in < 600) lcd_key = btnLEFT;
if (adc_key_in < 300) lcd_key = btnDOWN;
if (adc_key_in < 200) lcd_key = btnUP;
if (adc_key_in < 50) lcd_key = btnRIGHT;

unsigned long currentTimer = millis(); // Rafraichissement timer

if (lcd_key != last_lcd_key){ //Tant que 2 lectures d'affilée ne donnent pas la même valeur
debButtons = currentTimer; //la tempo anti-rebond est mise à zero
}
last_lcd_key = lcd_key;

if (currentTimer - debButtons >= 20){ //Si la lecture est identique pendant au moins 20ms
//création de front pour ne retourner la touche appuyée qu'une seule fois à l'enfoncement.
if (lcd_key != fr_lcd_key){
fr_lcd_key = lcd_key;
return lcd_key;
}
}

return btnNONE; // Si tout les autres cas ont échoués !
}

//Routine d'affichage du nombre de litres équivalent en fonction du temps et de la valeur de calibration
//L'affichage se fait là où se trouve le curseur du LCD
void LCD_litres(long Tempsms, int ValeurCalibration){

long volcalcul = Tempsms / ValeurCalibration; // La calibration est une valeur en milisecondes par decilitre (ms/dl)
int a = volcalcul / 10;
int b = volcalcul % 10;
lcd.print(a); //affichage de la partie entière
lcd.print("."); //affichage du separateur decimal
lcd.print(b); //affichage de la partie décimale

}


//Routine de remise à zero compteurs journaliers et horloge
//S'efectue automatiquement toutes les 24h
//ou manuellement depuis le menu LCD

void RAZ_count(){
secondes = 0;
minutes = 0;
heures = 0;
for (int i=0 ; i < 4; i++){
totalJMN[i] = total[i]; //transfert du total de la journée dans l'indicateur du total de la veille
total[i] = 0; //mise à zero compteur journalier.
}
}


//Routine de sauvegarde de l'arrêt des abreuvoirs en EEPROM
//Evite une remise en route non voulu d'un abreuvoir arrêté en
//cas de coupure secteur et/ou reset intenpestif

void SaveStop(){
int vts = 0;
int oldvts =0;
for (int i = 0; i < 4; i++){
if (stopEV[i]) bitSet(vts,i);
}
oldvts = EEPROM.read(0); //lecture de l'ancienne valeur des blocages abreuvoirs
if (vts != oldvts)EEPROM.write(0,vts); //ecriture seulement si la valeur à changé (limite cycle d'écriture en EEPROM)
}

//Routine de recuperation de l'arrêt des abreuvoirs en EEPROM
//et ecriture dans les variables correspondantes
// inverse de la fonction SaveStop()
void RestStop(){
int vtr = 0;
vtr = EEPROM.read(0);
for (int i = 0 ; i < 4 ; i++){
stopEV[i]=bitRead(vtr,i);
}
}

//Routine de sauvegarde des valeurs de calibrations en EEPROM
//Appelée uniquement à l'issue d'une routine de calibration
void SaveCal(){
int offset = 0;
int vtrh = 0;
int vtrl = 0;
for (int i = 0; i < 4; i++){
vtrh = cal[i]/256; //calcul de l'octet de poids fort
vtrl = cal[i] % 256; //calcul de l'octet de poids faible
offset = i * 2 + 2; //calcul de l'adresse du byte de poids fort
EEPROM.write(offset, vtrh);
EEPROM.write(offset + 1, vtrl);

}
}

//Routine de recuperation des valeurs de calibration enregistrées en EEPROM
//et écriture dans les variables correspondantes
void RestCal(){
int offset = 0;
int vtrh = 0;
int vtrl = 0;
for (int i = 0; i < 4; i++){
offset = i * 2 + 2; //calcul de l'adresse du byte de poids fort
vtrh = EEPROM.read(offset);
vtrl = EEPROM.read(offset + 1);
cal[i] = vtrh * 256; //octet de poids fort
cal[i] += vtrl; //octet de poids faible
}
}
//*************************************************************************************************
// Routine de calibration des abreuvoirs
// permet de mesurer le débit spécifique de chacune des installations d'abreuvoirs
// afin d'obtenir une valeur en millisecondes par décilitre (ms/dc) qui servira à l'affichage des
// compteurs journaliers
//*************************************************************************************************

void Calibrate(){
int index = 0; //variable pour traiter les 4 abreuvoirs
int page_calib = 0; //variable pour progression dans étapes calibrations
int decilitres = 0; //variable pour entrer volume par utilisateur
int litres = 0; //variable pour entrer volume par utilisateur
int volcal = 0; //variable temporaire pour calcul valeur calibration
unsigned long tempscal; //variable temporaire pour calcul valeur calibration
unsigned long timecursor; //pour tempo clignotement curseur
bool fincal = false; //pour sortir de la boucle sans fin de rafraichissement du menu
bool etape = true; //pour valider les étapes du menu de calibration
bool redo = false; //pour recommencer une étape
bool blinkcursor = false; //pour le activer clignotement du curseur dans les phases de saisie
bool cursorstatus; //pour le clignotement du curseur

do { // la routine tourne en boucle à partir d'ici tant que les 4 abreuvois ne sont pas calibrés correctement.
// Lecture des boutons pour navigation dans les menus
int touche = read_LCD_buttons();
unsigned long currentMillis = millis(); //rafraichissement variable timer
if (touche > btnNONE){
switch (touche){
case btnSELECT: //Bouton "Défilement"
{
if (etape){
etape = false; //on bloque le passage à la prochaine étape du menu, c'est les pages qui autorisent le passage ou non
page_calib++;
if (page_calib == 5){ // Si on arrive à la dernière page du menu
index++; //on passe à l'EV suivante...
if (index < 4){
page_calib = 1; //et tant qu'on à pas fait les 4 EV, on revient au début du menu.
litres = 0; //remise à zero des variables pour la calibration à venir
decilitres = 0;
}
}
}

break;
}
case btnUP: //Bouton "Séléction"
{

if (page_calib == 1){
if (EVState[index] == true) {
EVState[index] = false;
page_calib = 2;
} else {
EVState[index] = true;
}
break;
}

if (page_calib == 2){
if (redo){
page_calib = 1;
EVState[index] = false;
} else {
decilitres++;
if (decilitres > 9) decilitres = 0;
}
break;
}
if (page_calib == 3){
litres++;
if (litres > 29) litres = 0;
break;
}

if (page_calib == 4){
if (redo){
redo = false;
page_calib = 1;
}
}

if (page_calib == 5) fincal = true;
break;
}
}
}
// Fin des boutons


//Enregistrement temps début et fin remplissage

currentMillis = millis(); // Rafraichissement timer
// Detection front montant sortie EV
if( EVState[index] == HIGH && EVState[index] != frupEV[index]){
debut[index] = currentMillis; //enregistrement timming début du remplissage
}
frupEV[index] = EVState[index];

//Detection front déscendant sortie EV1
if (EVState[index] == LOW && EVState[index] != frdownEV[index]){
fin[index] = currentMillis; //enregistrement timming fin du remplissage
tempscal = fin[index] - debut[index]; //calcul durée du remplissage
}
frdownEV[index] = EVState[index];


//Application des états logiques aux sorties correspondantes
digitalWrite(EV1, EVState[0]);
digitalWrite(EV2, EVState[1]);
digitalWrite(EV3, EVState[2]);
digitalWrite(EV4, EVState[3]);

//---------------------------------------------------------------------------
// Rafraichissement afficheur
//---------------------------------------------------------------------------


//Tempo pour rafraichissement LCD

if (currentMillis - refreshLCD >= 100){ // Rafraichissement toutes les 100ms
refreshLCD = currentMillis;
lcd.clear();
if (page_calib == 0){ //Page de confirmation d'entrée du menu calibration
lcd.print("Menu calibration");
lcd.setCursor(0,1);
lcd.print("appuyez DEFIL");
}
if (page_calib == 1){ //premiere étape du menu de calibration
lcd.print("Calibration EV");
lcd.print(index + 1);
lcd.setCursor(0,1);
if (EVState[index] == false){
lcd.print("SEL = Ouvrir");
} else {
lcd.print("SEL = Fermer");
}
}
if (page_calib == 2){
if (tempscal < 5000){
redo = true;
lcd.print("Temps trop court");
lcd.setCursor(0,1);
lcd.print("Reprendre : SEL");
} else {
redo = false;
etape = true; //on autorise à passer à l'étape suivante avec le bouton défilement
lcd.print("Entrez volume ");
lcd.print(index + 1);
lcd.setCursor(1,1);
lcd.print("0.");
lcd.print(decilitres);
lcd.print(" litres");
lcd.setCursor(3,1);
blinkcursor = true;
}
}
if (page_calib == 3){ //troisième étape du menu calibration
etape = true; //on autorise à passer à l'étape suivante avec le bouton défilement
lcd.print("Entrez volume ");
lcd.print(index + 1);
lcd.setCursor(1,1);
if (litres > 9) lcd.setCursor(0,1); //si on depasse 9 litres il faut decaler le debut de l'affichage pour les dizaines
lcd.print(litres);
lcd.print(".");
lcd.print(decilitres);
lcd.print(" litres");
lcd.setCursor(1,1);
blinkcursor = true;
}
if (page_calib == 4){ //quatrième étape du menu calibration
blinkcursor = false;
volcal = litres * 10 + decilitres;
if (volcal > 0) {
cal[index] = tempscal / volcal;
etape = true; //on autorise à passer à l'étape suivante avec le bouton défilement
lcd.print("cal ");
lcd.print(index + 1);
lcd.print("=");
lcd.print(cal[index]);
lcd.setCursor(0,1);
lcd.print("Suite : DEFIL");

} else {
redo = true;
lcd.print("Volume nul !");
lcd.setCursor(0,1);
lcd.print("Reprendre : SEL");
}
}
if (page_calib == 5){ //cinquième étape du menu calibration
lcd.print("Calibrations OK");
lcd.setCursor(0,1);
lcd.print("SEL pour sortir");
}
}

//Clignotement du curseur si besoin
if (blinkcursor){
if (currentMillis - timecursor >= 500){
timecursor = currentMillis;
if (cursorstatus){
cursorstatus = false;
lcd.noCursor();
} else {
cursorstatus = true;
lcd.cursor();
}
}
} else {
lcd.noCursor();
}


} while (!fincal);
for (int j = 0 ; j < 4 ; j++){
debut[j] = 0; //remise à zero des variables de compteur
fin[j] = 0; //... pour eviter des faux comptes en sortie de calibration
EVState[j] = false;
frdownEV[j] = false;
}
SaveCal(); //Appel de routine de sauvegarde des calibrations en EEPROM

} //Fin routine calibration

// ----------------------------------------------------------------------------
// |-------------------------------------------------------------------------| |
// | Fonction d'initialisation au demarrage | |
// |-------------------------------------------------------------------------| |
// ----------------------------------------------------------------------------
void setup() {
// Initialisation des entrées/sorties
pinMode(ledPin, OUTPUT);
pinMode(Backlit, OUTPUT);
pinMode(EV1, OUTPUT);
pinMode(EV2, OUTPUT);
pinMode(EV3, OUTPUT);
pinMode(EV4, OUTPUT);
pinMode(Niveau1, INPUT);
pinMode(Niveau2, INPUT);
pinMode(Niveau3, INPUT);
pinMode(Niveau4, INPUT);
digitalWrite(Backlit, HIGH);
lcd.begin(16, 2); // start the library
lcd.setCursor(0,0);
lcd.print("Abreuvoir v1.0");
delay(3000); // Temporisation pour laisser le temps d'appeler le menu de calibration
int emc = analogRead(0);
if (emc < 200){ //Si on appuie sur le bouton SEL pendant le demarrage
delay(20); //antirebond
emc = analogRead(0);
if (emc < 200){
Calibrate();
}
}

RestStop(); //Appel de fonction de recuperation des blocages abreuvoirs
RestCal(); //Appel de fonction de recuperation des calibrations
if (cal[0] == -1){ //Si la memoire EEPROM est vierge (0xff) alors le système n'a jamais été calibré
Calibrate(); //Appel de la routine de calibration à la première mise en service.
}
tempobacklit = millis(); //remise à zero tempo retroeclairage (utile surtout en sortie de menu calibration)
}

// Boucle principale du programme
void loop() {
//Faire clignoter la led et compter le temps qui passe
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) { //Base de temps de l'horloge programme
previousMillis = currentMillis;
secondes++;
if (secondes >= 60){
minutes++;
secondes = 0;
}
if (minutes >= 60){
heures++;
minutes = 0;
}
if (heures >= 24){
RAZ_count(); //appel de la routine de remise à zéro des compteurs journaliers
}

// Changement d'état pour faire clignoter la LED onboard (temoin deroulement programme OK)
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
digitalWrite(ledPin, ledState);
}


// ---------------------------------------------------------------------
// Gestion des E/S et tempos Abreuvoirs
//----------------------------------------------------------------------

// Lecture des entrées
inpNiveau[0] = digitalRead(Niveau1);
inpNiveau[1] = digitalRead(Niveau2);
inpNiveau[2] = digitalRead(Niveau3);
inpNiveau[3] = digitalRead(Niveau4);

inpNiveau[0] = !inpNiveau[0]; //Commenter cette ligne ou non en fonction du sens de montage de l'inter de niveau (flotteur en haut ou flotteur en bas)
inpNiveau[1] = !inpNiveau[1]; //Commenter cette ligne ou non en fonction du sens de montage de l'inter de niveau (flotteur en haut ou flotteur en bas)
inpNiveau[2] = !inpNiveau[2]; //Commenter cette ligne ou non en fonction du sens de montage de l'inter de niveau (flotteur en haut ou flotteur en bas)
inpNiveau[3] = !inpNiveau[3]; //Commenter cette ligne ou non en fonction du sens de montage de l'inter de niveau (flotteur en haut ou flotteur en bas)

for (int i = 0 ; i <4 ; i++){ //boucle pour traiter les 4 abreuvoirs à la suite

// Prise en compte de la configuration arrêt de l'abreuvoir pour eviter de faux time-out remplissage
if (stopEV[i] == true){
inpNiveau[i] = false;
}

// Anti-rebond Entrée Abreuvoir
//reset du timer à chaque fois que l'entrée change d'état
if (inpNiveau[i] != LastinpNiveau[i]){
debTempsLvl[i] = currentMillis;
if (inpNiveau[i] == LOW){
ErrorLvl[i] = false; //au front descendant de l'entrée, l'enventuel drapeau d'erreur est effacé
}
}
LastinpNiveau[i] = inpNiveau[i];

// Si l'état est stable pendant la durée determinée
if (currentMillis - debTempsLvl[i] >= DebTimeLvl){
if (inpNiveau[i] == HIGH){ // ... alors on applique la commande correspondante à l'EV
EVState[i] = true;
} else {
EVState[i] = false;
}
}

// Time-out remplissage abreuvoir
if (EVState[i] == false) { // Dès que la commande d'EV passe à vraie...
timeoutLvl[i] = currentMillis; // ...la valeur reste figée
}

if (currentMillis - timeoutLvl[i] >= ToutTimeLvl){ // Si temps depassé
EVState[i] = LOW; //Forçage de la commane d'EV à zero
ErrorLvl[i] = true; //Drapeau erreur abreuvoir
}


//Enregistrement temps début et fin remplissage
currentMillis = millis(); // Rafraichissement timer
// Detection front montant sortie EV1
if( EVState[i] == HIGH && EVState[i] != frupEV[i]){
debut[i] = currentMillis; //enregistrement timming début du remplissage
}
frupEV[i] = EVState[i];

//Detection front déscendant sortie EV1
if (EVState[i] == LOW && EVState[i] != frdownEV[i]){
fin[i] = currentMillis; //enregistrement timming fin du remplissage
unsigned long resultat = fin[i] - debut[i]; //calcul durée du remplissage
total[i] += resultat; //ajout du temps du dernier remplissage au total journalier
}
frdownEV[i] = EVState[i];


if (forcageEV[i] == true){ //prise en compte du forçage du menu diagnostique
EVState[i] = true;
}

if (stopEV[i] == true){ //prise en compte de l'arrêt du menu diag
EVState[i] = false;
}
}
//Application des états logiques aux sorties correspondantes
digitalWrite(EV1, EVState[0]);
digitalWrite(EV2, EVState[1]);
digitalWrite(EV3, EVState[2]);
digitalWrite(EV4, EVState[3]);

//--------------------------------------------------------------------------------------
// Navigation dans les pages de menu et activation des fonctions IHM
//--------------------------------------------------------------------------------------
int touche = read_LCD_buttons();
if (touche > btnNONE){
if (backlitState == false) goto endtouches; //Si l'écran est eteind on ne fait rien sauf l'allumer
switch (touche)
{
case btnSELECT: //Bouton "Défilement"
{
page_menu++;
if (page_menu == 7){ //Fin du menu principal
page_menu = 0;
}
if (page_menu == 15){ //fin du menu diagnostique
page_menu = 8;
}
break;
}
case btnUP: //Bouton "Séléction"
{
if (page_menu == 3 && heures > 1){ //Si menu sur la page correspondante et que la dernière RAZ à plus d'une heure
// Tranfert des valeurs en memoire, et remise à zero horloge
RAZ_count();
}

if (page_menu == 6){
page_menu = 8; //Entrée dans le menu diagnostique
}

if (page_menu == 9){

if (forcageEV[0] == true && stopEV[0] == false){ //Forcage sortie EV1
forcageEV[0] = false;
stopEV[0] = true;
} else if (stopEV[0] == true){
stopEV[0] = false;
} else {
forcageEV[0] = true;
}

}

if (page_menu == 10){
if (forcageEV[1] == true && stopEV[1] == false){ //Forcage sortie EV1
forcageEV[1] = false;
stopEV[1] = true;
} else if (stopEV[1] == true){
stopEV[1] = false;
} else {
forcageEV[1] = true;
}
}

if (page_menu == 11){
if (forcageEV[2] == true && stopEV[2] == false){ //Forcage sortie EV1
forcageEV[2] = false;
stopEV[2] = true;
} else if (stopEV[2] == true){
stopEV[2] = false;
} else {
forcageEV[2] = true;
}
}

if (page_menu == 12){
if (forcageEV[3] == true && stopEV[3] == false){ //Forcage sortie EV1
forcageEV[3] = false;
stopEV[3] = true;
} else if (stopEV[3] == true){
stopEV[3] = false;
} else {
forcageEV[3] = true;
}
}

if (page_menu == 14){
for (int i = 0 ; i < 4; i++){ //Suppression des forçages en sortant du menu diag
forcageEV[i] = false;
}
SaveStop(); //Sauvegarde des forçages d'arrêt
page_menu = 0; //Retour au menu principal depuis le menu diagnostique
}
break;
}
default:
{
break;
}
}
endtouches:
tempobacklit = currentMillis; // raz tempo retroeclairage
digitalWrite(Backlit, HIGH); //Allumage retroeclairage
backlitState = true;
}
//Extinction retroeclairage
if (currentMillis - tempobacklit >= tempsbacklit){
digitalWrite(Backlit,LOW);
backlitState = false;
}

//Si un abreuvoir est en erreur, faire clignoter l'écran
bool gerr = ErrorLvl[0] | ErrorLvl[1] | ErrorLvl[2] | ErrorLvl[3];
if (gerr){
digitalWrite(Backlit,ledState);
}

//---------------------------------------------------------------------------
// Rafraichissement afficheur
//---------------------------------------------------------------------------
if (currentMillis - refreshLCD >= 100){ // Rafraichissement toutes les 100ms
refreshLCD = currentMillis;
lcd.clear();

if (page_menu ==0){ //Menu prinipal - vue globale compteurs abreuvoirs
//lcd.setCursor(0,0);
lcd.print("1");
lcd.write(0x7E);
if (stopEV[0] == true){
lcd.write("STOP");
}else if (ErrorLvl[0]){
lcd.write("Err");
} else {
LCD_litres(total[0],cal[0]); //Affichage Total Abreuvoir #1 journée en cours
}
lcd.setCursor(8,0);
lcd.print("2");
lcd.write(0x7E);
if (stopEV[1] == true){
lcd.write("STOP");
}else if (ErrorLvl[1] == true){
lcd.write("Err");
} else {
LCD_litres(total[1],cal[0]); //Affichage Total Abreuvoir #2 journée en cours
}
lcd.setCursor(0,1);
lcd.print("3");
lcd.write(0x7E);
if (stopEV[2] == true){
lcd.write("STOP");
}else if (ErrorLvl[2] == true){
lcd.write("Err");
} else {
LCD_litres(total[2],cal[0]); //Affichage Total Abreuvoir #3 journée en cours
}
lcd.setCursor(8,1);
lcd.print("4");
lcd.write(0x7E);
if (stopEV[3] == true){
lcd.write("STOP");
}else if (ErrorLvl[3] == true){
lcd.write("Err");
} else {
LCD_litres(total[3],cal[0]); //Affichage Total Abreuvoir #4 journée en cours
}
}
if (page_menu == 1){ //Menu prinipal - Vue compteurs Abreuvoir 1
lcd.print(" Abreuvoir 1");
lcd.setCursor(0,1);
lcd.print("J=");
LCD_litres(total[0],cal[0]); //Affichage Total Abreuvoir #1 journée en cours
lcd.setCursor(8,1);
lcd.print("J-1=");
LCD_litres(totalJMN[0],cal[0]); //Affichage total Abreuvoir#1 de la veille
}

if (page_menu == 2){ //Menu prinipal - Vue compteurs Abreuvoir 2
lcd.print(" Abreuvoir 2");
lcd.setCursor(0,1);
lcd.print("J=");
LCD_litres(total[1],cal[0]); //Affichage Total Abreuvoir #2 journée en cours
lcd.setCursor(8,1);
lcd.print("J-1=");
LCD_litres(totalJMN[1],cal[0]); //Affichage total Abreuvoir#2 de la veille
}

if (page_menu == 3){ //Menu prinipal - Vue compteurs Abreuvoir 3
lcd.print(" Abreuvoir 3");
lcd.setCursor(0,1);
lcd.print("J=");
LCD_litres(total[2],cal[0]); //Affichage Total Abreuvoir #3 journée en cours
lcd.setCursor(8,1);
lcd.print("J-1=");
LCD_litres(totalJMN[2],cal[0]); //Affichage total Abreuvoir#3 de la veille
}

if (page_menu == 4){ //Menu prinipal - Vue compteurs Abreuvoir 4
lcd.print(" Abreuvoir 4");
lcd.setCursor(0,1);
lcd.print("J=");
LCD_litres(total[3],cal[0]); //Affichage Total Abreuvoir #4 journée en cours
lcd.setCursor(8,1);
lcd.print("J-1=");
LCD_litres(totalJMN[3],cal[0]); //Affichage total Abreuvoir#4 de la veille
}

if (page_menu == 5){ //Menu prinipal - Page de remise à zero des compteurs
lcd.print("Reset compteurs?");
if (heures > 1){
lcd.setCursor(0,1);
lcd.print("appuyez SEL");
} else {
lcd.setCursor(6,1);
lcd.print("FAIT");
}

}

if (page_menu == 6){ //Menu prinipal - Selection entrée menu Diagnostique
lcd.print("Diagnostique ?");
lcd.setCursor(0,1);
lcd.print("appuyez SEL");
}

if (page_menu == 8){ //Menu diagnostique - Lecture des entrées
lcd.print("INPUT:");
lcd.setCursor(0,1);
lcd.print("1=");
if (digitalRead(Niveau1) == HIGH){
lcd.print("H");
} else {
lcd.print("L");
}
lcd.setCursor(4,1);
lcd.print("2=");
if (digitalRead(Niveau2) == HIGH){
lcd.print("H");
} else {
lcd.print("L");
}
lcd.setCursor(8,1);
lcd.print("3=");
if (digitalRead(Niveau3) == HIGH){
lcd.print("H");
} else {
lcd.print("L");
}
lcd.setCursor(12,1);
lcd.print("4=");
if (digitalRead(Niveau4) == HIGH){
lcd.print("H");
} else {
lcd.print("L");
}
}

if (page_menu == 9){ //Menu diagnostique - Forçage EV1
lcd.print("Forcage EV1=");
if (forcageEV[0] == true){
lcd.print("OUI");
} else if (stopEV[0] == true){
lcd.print("STOP");
} else {
lcd.print("NON");
}
lcd.setCursor(0,1);
lcd.print("SEL pour forcer");
}

if (page_menu == 10){ //Menu diagnostique - Forcage EV2
lcd.print("Forcage EV2=");
if (forcageEV[1] == true){
lcd.print("OUI");
} else if (stopEV[1] == true){
lcd.print("STOP");
} else {
lcd.print("NON");
}
lcd.setCursor(0,1);
lcd.print("SEL pour forcer");
}

if (page_menu == 11){ //Menu diagnostique - Forcage EV3
lcd.print("Forcage EV3=");
if (forcageEV[2] == true){
lcd.print("OUI");
} else if (stopEV[2] == true){
lcd.print("STOP");
} else {
lcd.print("NON");
}
lcd.setCursor(0,1);
lcd.print("SEL pour forcer");
}

if (page_menu == 12){ //Menu diagnostique - Forcage EV4
lcd.print("Forcage EV4=");
if (forcageEV[3] == true){
lcd.print("OUI");
} else if (stopEV[3] == true){
lcd.print("STOP");
} else {
lcd.print("NON");
}
lcd.setCursor(0,1);
lcd.print("SEL pour forcer");
}
if (page_menu == 13){ //Menu diagnostique - Affichage horloge interne
lcd.print("Horloge interne");
lcd.setCursor(5,1);
lcd.print(heures);
lcd.print(":");
lcd.print(minutes);
lcd.print(":");
lcd.print(secondes);
}
if (page_menu == 14){ //Menu diagnostique - Sortir du menu diagnostique
lcd.print("Sortir Diag ?");
lcd.setCursor(0,1);
lcd.print("appuyez SEL");
}
}



}//fin loop



Plusieurs ajustements peuvent être fait dans ce programme pour l'adapter à votre installation.

La première concerne le sens de montage des capteurs de niveau. Si vos capteurs sont monté comme les miens, c'est à dire flotteur vers le bas (contact établi quand le niveau d'eau est haut) alors il n'y a rien à faire. Par contre si votre capteur de niveau est dans l'autre sens (flotteur vers le haut) alors il faut inverser le signal.
ça se fait aux lignes 495 à 498 du programme.
vous trouverez une ligne de la forme

Citation :
inpNiveau[x] = !inpNiveau[x];

avec x de 0 à 3 qui correspond aux abreuvoirs de 1 à 4. Pour inverser le sens du capteur il suffit de mettre en commentaire la ligne qui correspond à l'abreuvoir concerné. Un commentaire c'est une double barre oblique //
ce qui donne par exemple

Citation :
//inpNiveau[0] = !inpNiveau[0];

si on veut inverser le capteur de l'abreuvoir N°1

Un autre ajustement concerne la durée de temporisation "anti-rebond" des capteurs des abreuvoirs. Cette durée est la même pour les 4 abreuvoirs. Par défaut elle est de 2.5 secondes.
Pour modifier celle-ci il faut se rendre à la ligne 60, c'est à dire

Citation :
const int DebTimeLvl = 2500; //durée anti-rebond capteur abreuvoir

Ici la valeur est en millisecondes. Si vous voulez réduire pour mettre par exemple 1/2 secondes, il faut donc écrire 500.
Évitez de descendre en dessous de 100ms sans quoi cette temporisation deviendrait franchement inutile, et n'allez pas non plus trop haut, au delà de 3 à 5 secondes vous risquez quand même un débordement.
Ici la variable est un "integer" il ne faut normalement rien mettre qui dépasse 32768 (ni de nombre négatif...)

A la ligne du dessous (61) vous pouvez modifier le délais de remplissage d'un abreuvoir sur le même principe. Ici il est réglé à 60 secondes. Pour cette consigne on travail avec un "long", la valeur max est donc de 2147483648 soit environ 596 heures, si votre abreuvoir met plus longtemps pour se remplir, c'est que vous avez un sérieux problème de plomberie !

A la ligne encore en dessous (62) on peut modifier si besoin la durée pendant laquelle le rétroéclairage de l'écran LCD reste allumé depuis le dernier appuis sur une des touches.
Évitez de le laisser allumé pendant des heures, cela consomme de l’énergie et fait chauffer inutilement le régulateur de tension intégré à l'Arduino. Ici 45 secondes c'est largement suffisant.

A la première ligne de cette section du programme (59) vous trouverez une consigne qui pourra éventuellement servir à ajuster l'horloge interne du programme si vous êtes tatillons et patient.
En effet, cette consigne sert à compter les secondes (d'où sa valeur de 1000ms) pour calculer le temps qui passe et remettre automatiquement les compteurs à zéro toutes les 24 heures.
Mais cette horloge interne est loin d'être une horloge "temps réel", vu l'application ce n'est pas justifié. Il y aura donc forcement une légère dérive de quelques secondes à quelques minutes tous les jours.
En jouant sur la valeur de "interval" on peut donc allonger ou raccourcir la durée de la seconde interne du programme.
Par exemple, si on met 997 à le place de 1000, on gagne 3ms par seconde, la remise à zéro des compteurs interviendra donc théoriquement 259.2 secondes plus tôt.
Et naturellement même chose dans l'autre sens : indiquer 1003 provoquera une remise à zéro 259.2 secondes plus tard...

Pour finir, entre les ligne 85 et 90 on peut ajuster les valeurs analogiques des boutons du "lcd keypad shield" si jamais le programme reconnaissait mal les deux boutons qui nous intéressent. Ce serait trop long à expliquer ici comment faire.
Si jamais quelqu'un réalise ce montage et qu'il est face à un problème de boutons pas ou mal reconnu, j'écrirais un petit programme qui détermine ces valeurs pour vous.

Voilà globalement les ajustements que vous auriez besoin de faire dans le programme.
Bien sûr vous pourrez téléverser le programme plusieurs fois dans l'Arduino (normalement au minimum 100.000 fois) donc il est tout à fait possible de faire des essais et de corriger si nécessaire.

Il me reste encore à vous expliquer l'utilisation de tout ça, principalement la partie calibration pour les compteurs. Je vais faire ça dans une réponse à la suite car celle-ci commence à être vraiment longue.

Édité par equinoxe88 le 09-02-2019 à 20h03



Equinoxe88

Expert
   

Trust : 118  (?)


  Mon site internet
  M'écrire un MP

Genre : 
Messages : 968
0 j'aime    
Tuto : abreuvoir à niveau constant électronique
Posté le 09/02/2019 à 10h40

Partie 4 bis : Calibration et utilisation

Une vois le programme téléchargé dans l'Arduino, le boitier de commandé installé et les abreuvoirs raccordés électriquement et hydrauliquement, vous aurez besoin de calibrer l'installation.
Cette calibration à pour but de mesurer le débit d'eau de chaque abreuvoir afin d'indiquer une valeur d'eau consommées en litre par jour.
Cette valeur n'est qu'indicative puisqu'elle ne sera juste que si les conditions de remplissage de l'abreuvoir concerné sont toujours identiques à celles ou s'est effectué la calibration, ce qui sur un réseau d'eau domestique est tout simplement impossible à cause des variations de pression en fonction de l'utilisation d'autres points d'eau.
Elle dépend aussi de la précision avec laquelle vous faites cette calibration.
Une calibration approximative ne pourra donner qu'une consommation approximative !

Quand on met l'installation sous tension, pendant 3 secondes l'écran devrait afficher

Citation :
Abreuvoir v1.0


Si vous utilisez un Arduino neuf ou dont l'EEPROM est vierge, le programme devrait ensuite entrer automatiquement en mode calibration.
Sinon, vous devez appuyer et maintenir le bouton Sélection pendant l'affichage de ce message jusqu’à ce que l'écran indique

Citation :
Menu calibration
appuyez DEFIL


Vous devez donc appuyer sur le bouton Défilement.
L'écran indique alors

Citation :
Calibration EV1
SEL = Ouvrir


A ce moment là, la méthode la plus simple et la plus précise pour calibrer un abreuvoir, est d'ouvrir son bouchon de vidange et de placer un gros récipient en dessous.
Une fois ceci fait, appuyer sur le bouton Sélection. Si tout se passe bien, l’électrovanne s'ouvre et l'eau devrait commencer à couler.
L'écran indique alors

Citation :
Calibration EV1
SEL = Fermer


Attendez au moins 5 secondes et un temps suffisant pour qu'il se soit écoulé entre 10 et 20 litres (mais pas plus de 29 litres) puis appuyez sur Sélection.
L'électrovanne se ferme et l'eau arrête de couler. Attendez un peu que tout s’égoutte correctement dans le récipient et mesurer précisément le volume d'eau qu'il contient.
L'écran indique alors

Citation :
Entrez volume 1
0.0 litres

avec le curseur clignotant sous le zéro derrière le point.

En appuyant sur le bouton Sélection, on fait monter d'un point à chaque appuis ce chiffre derrière la virgule. Si on arrive à 9 il retombe ensuite à zéro.
Entrez donc la partie décimale correspondante à votre mesure de volume.
Appuyez ensuite sur Défilement pour passer à la partie entière.
L'écran affiche alors
L'écran indique alors

Citation :
Entrez volume 1
0.x litres

avec le curseur clignotant sous le zéro devant le point et le chiffre après la virgule étant celui que vous avez entré à l'étape précédente.
Entre alors le nombre de litres mesurés en utilisant le même principe qu'a l'étape précédente. Ici la limite est fixée à 29, dépasser 29 fait revenir à 0 (on peut modifier cette limite à la ligne 263 du programme)
Validez ensuite avec Défilement.

L'écran indique alors

Citation :
cal 1=x
Suite : DEFIL

La première ligne donne la valeur calculée pour la calibration de cette abreuvoir. C'est une valeur interne affichée uniquement pour contrôle et qui correspond à des millisecondes par décilitre. Vous ne la verrez que là, vous ne pouvez pas la modifier ni l'afficher ailleurs.

Le programme refusera un volume de calibration nul (0.0 litres) et vous le ferra savoir par cette écran

Citation :
Volume nul !
Reprendre : SEL

Il faudra alors appuyer sur Sélection pour revenir à la première étape de la calibration de cet abreuvoir et recommencer (mesure de volume, etc...)

De même, si pendant la mesure de volume, vous n'attendez par 5 secondes et appuyez trop tôt sur Sélection pour fermer l'eau, le programme vous le ferra savoir par cet écran

Citation :
Temps trop court
Reprendre : SEL

Il faut donc appuyer sur Sélection pour reprendre au début la calibration de cet abreuvoir.

Une fois le premier abreuvoir calibré, le programme passe au suivant en suivant les mêmes étapes jusqu'a e que les 4 soient fait.
Si vous n'avez pas 4 abreuvoirs il faut quand même calibrer les 4, et faire une fausse calibration pour celui ou ceux qui ne sont pas raccordé.
C'est obligatoire sans quoi il se produit une division par zéro dans le programme... et en informatique une division par zéro fait planter le processeur.
Pour faire une fausse calibration, on procédè de la même manière que pour une vraie sauf que rien ne coule et qu'on entre donc un volume fictif.

Quand les 4 abreuvoirs sont calibrés, l'écran affiche alors

Citation :
Calibrations OK
SEL pour sortir

On appuie donc sur Sélection pour valider la calibration. Les valeurs de calibration seront donc sauvegardées en EEPROM et donc conservée même en cas de coupure de courant ou de reset.

On se retrouve alors sur l'interface utilisateur normale du système
La première page indique le volume consommé pour la journée en cours des 4 abreuvoirs du système

Citation :
1->0.0 2->0.0
3->0.0 4->0.0


Si un abreuvoir est arrêté parce qu'il n'est pas utilisé ou pas branché (voir plus bas) "STOP" sera affiché à la place du volume.
Et si un abreuvoir est en erreur, parce que le temps de remplissage est dépassé "Err" sera affiché à la place du volume et le rétroéclairage clignotera pour attirer l'attention.

En appuyant sur Défilement, on passe sur les écrans individuelles de chaque abreuvoir

Citation :
Abreuvoir x
J=0.0 J-1=0.0

avec x = numero d'abreuvoir en cours d'affichage
J= volume consommé pour la journée en cours (depuis la dernière remise à zéro par l'horloge interne)
J-1= volume consommé pour la veille

Après le dernier abreuvoir un écran permet de forcer la remise à zéro des compteurs (la valeur en cours passe dans la valeur de la veille puis la valeur en cours passe à zéro)

Citation :
Reset compteurs?
appuyez SEL

Il suffit d'appuyer sur Sélection pour effectuer cette remise à zéro. Cette action à aussi pour effet de remettre à zéro l'horloge interne du programme, donc la prochaine mise à zéro automatique se produira donc 24 h plus tard, et à la même heure les jours suivants (sauf reset forcé ou coupure de courant)
Si la dernière remise à zéro à moins de 2 heures, le programme interdit d'en faire une autre. Il affiche alors

Citation :
Reset compteurs?
FAIT


En appuyant à nouveau sur Défilement on arrive sur la dernière page de ce menu qui propose de rentrer en mode diagnostique

Citation :
Diagnostique ?
appuyez SEL

On appuie sur Défilement pour revenir à la première page, ou sur Sélection pour rentrer dans le mode diagnostique.

La première page du menu diagnostique permet d'indiquer le niveau logique des entrées des capeurs

Citation :
INPUT:
1=H 2=H 3=H 4=H

avec H ou L correspondant donc à ce niveau logique.

En appuyant sur Défilement on passe ensuite aux pages qui permettent de tester ou bloquer les sorties électrovanne

Citation :
Forcage EVx=NON
SEL pour forcer

avec x correspondant toujours au numéro d'abreuvoir et l'indication à droite du égal qui peut prendre 3 valeurs :
NON : Aucun forçage ou blocage, l'abreuvoir fonctionne correctement
en appuyant une fois sur Sélection la valeur passe alors à
ON : L’électrovanne est pilotée ouverte, de l'eau doit normalement s'écouler quelque soit l'état du capteur de niveau. Utiliser pour tester l'installation, purger le système ou nettoyer un abreuvoir par exemple. La tempo de remplissage ne s'applique pas ici et l'eau continuera de couler tant que l'on reste dans le menu diagnostique ou que l'on ne place pas l'indication sur une autre valeur.
En appuyant à nouveau sur Sélection l'indication passe à
STOP : L'abreuvoir est arrêté, l’électrovanne ne sera jamais pilotée même si le capteur de niveau le demande. C'est sur cette valeur que doit être placé les abreuvoirs qui ne sont pas branchés sans quoi l'écran principale affichera un défaut.

En sortant du menu diagnostique (voir la suite) le forçage "ON" est automatiquement désactivé et l'abreuvoir revient à un fonctionnement normal. Par contre le forçage "STOP" est conservé et l'abreuvoir reste arrêté jusqu'a ce que l'on change cette valeur. Le forçage "STOP" est sauvegardé en EEPROM, il sera conservé même en cas de coupure de courant ou de reset de l'Arduino.

Quand le diagnostique des 4 sorties est fait en utilisant le bouton Défilement. L'écran indique alors la valeur actuelle de l'horloge interne

Citation :
Horloge interne
23:59:59

C'est à cet endroit que l'on peut savoir de quand date le dernier reset ou de calculer quand aura lieu le prochain.
En appuyant à nouveau sur Défilement on arrive sur la page permettant de sortir du menu diagnostique

Citation :
Sortir Diag ?
appuyez SEL

En appuyant sur Sélection on retourne au menu principal (affichage des 4 compteurs), en appuyant sur Défilement, on revient à la première page du menu diagnostique (affichage du niveau logique des entrées)

Voilà, je pense vous avoir présenté la totalité de ce système dans ses moindres détails.
C'est un projet qui m'a occupé pendant plusieurs semaines (surtout le programme qui à été très long à écrire) mais dont je suis très satisfait. Il fonctionne sans problème depuis que le j'ai installé et je pense l'étendre à mes autres abreuvoirs.
Si vous avez des commentaires, des critiques (constructives) ou des questions, je reste naturellement ouvert.
Si j’apporte des améliorations à mon système je vous en ferrais part ici.

Fandada

Membre ELITE Or
  

Trust : 1036  (?)



  M'écrire un MP

Genre : 
Messages : 19287
0 j'aime    
Tuto : abreuvoir à niveau constant électronique
Posté le 09/02/2019 à 10h40

pffiou !!! beau boulot !
Tuto : abreuvoir à niveau constant électronique
 Répondre au sujet