mardi 15 août 2023

ESP32 : Micro-irrigation Connectée (3ème partie)

 


ESP32 : Micro-irrigation Connectée (3ème partie)


Cet article fait suite à ceux-ci :

ESP32 : Micro-irrigation Connectée (1ère partie)

ESP32 : Micro-irrigation Connectée (2ème partie)

Pour rappel, le projet se trouve ici :

https://bitbucket.org/henri_bachetti/esp32-sprinkle-timer.git

1. Le hardware

Du côté matériel, le capteur d'humidité et le capteur de débit sont présents : 

  • capteur d'humidité : GPIO36 (broche SVP)
  • capteur de débit : GPIO39 (broche SVN)

Contrairement à ce que je pensais, l'ESP32 est tout à fait capable de mesurer une tension analogique de 3.3V, ou plutôt la librairie ARDUINO fait ce qu'il faut pour que cela soit possible. Le pont diviseur R3 R5 disparaît du schéma (paragraphe 5).

En ce qui concerne le capteur de débit, la mesure renvoie des valeurs non nulles pour un débit de zéro. Il faut que je fasse des essais afin de voir s'il ne s'agirait pas d'un problème d'alimentation. Il est alimenté par la broche 5V de l'ESP32 et celui-ci est alimenté par l'USB. Comme il ne reste que 4.7V, ce n'est peut-être pas suffisant.

L'écran OLED est connecté, ainsi que le bouton fonction et arrosage manuel: 

  • SDA : GPIO21
  • SCL : GPIO22
  • bouton fonction : GPIO35
  • bouton arrosage manuel : GPIO34

Comme il n'y a pas de résistance de PULLUP interne sur les GPIOS 35 et 34, il faut en ajouter une sur le schéma entre GPIO35, GPIO34 et 3.3V : 10KΩ.

2. La configuration

2.1. config.ini

Le paramétrage des capteurs a été ajouté :

[moisture]
sensor=36
max=50

[flow]
sensor=39
max=10

2.2 Schedule.ini

Ce fichier reste inchangé, mis à part que deux périodes d'arrosage ont été ajoutées :

[courges.voie1]
schedule1=08:00,15

[massif.voie1]
schedule1=08:30,15

3. L'interface HTML

La page d'accueil comporte maintenant des boutons permettant de modifier les périodes d'arrosage et même d'en ajouter : 

Cliquer sur l'un des boutons CONFIGURE permet d'accéder à un formulaire :

Il suffit de modifier les valeurs et de cliquer sur OK pour enregistrer les changements. Les changements sont stockés dans le fichier schedule.ini.

En cliquant sur le bouton AJOUTER on accède à un formulaire à peine différent :

Le formulaire propose une liste des zones existantes.

Attention il n'y a pas pour l'instant de contrôle de validité sur ces deux formulaires. Il faut bien respecter le format de saisie HH:MM.

Les durées sont exprimées en minutes.

Le bouton maintenance permet d'accéder au menu suivant :

Les actions suivantes sont possibles :

  • tester les relais
  • afficher le fichier config.ini
  • afficher le fichier schedule.ini

Il est donc possible de sauvegarder ces deux fichiers avant une mise à jour des fichiers HTML. Les fichiers HTML et les fichiers de configuration (.ini) sont situés dans le même répertoire data du projet. Les fichiers de configuration seraient donc écrasés à la prochaine mise à jour si l'on ne prend pas de précautions.

4. L'écran OLED

L'afficheur montre la date et l'heure, ainsi que l'humidité et le débit :

Un appui sur le bouton fonction permet l'affichage de l'adresse IP de l'ESP32 pendant 4 secondes, puis de l'heure du prochain arrosage pendant 4 secondes, puis l'affichage revient à la normale.

Un appui sur le bouton d'arrosage manuel provoque l'affichage du premier arrosage manuel possible et de sa durée :

En appuyant plusieurs fois sur ce bouton on peut faire défiler les noms des voies. Un appui sur le bouton fonction déclenche l'arrosage manuel sur la voie choisie.

5. Rappels

Ce logiciel a besoin d'être compilé en utilisant les librairies suivantes :

ESPAsyncWebServer : https://github.com/me-no-dev/ESPAsyncWebServer

SPIFFSIniFile : https://github.com/yurilopes/SPIFFSIniFile

SSD1306 : https://github.com/adafruit/Adafruit_SSD1306

GFX : https://github.com/adafruit/Adafruit-GFX-Library

ezButton : https://github.com/ArduinoGetStarted/button

Quelques constantes peuvent être modifiées dans le code :

// max line length in config file
#define MAX_LINE 250
// max definition length for object names (relays, ways, zones, etc.)
#define MAX_DEF 50
#define MAX_BUF 30

// max ways and relays number
#define MAX_WAY 128
// max zones number
#define MAX_ZONE 12
// max waterings number in a day for each way
#define MAX_SCHEDULE 4
// max waterings number in a day for all ways
#define MAX_WATERING 256

On voit par exemple que le nombre d'arrosages par voie est limité à 4 par jour, ce qui me semble amplement suffisant. On peut bien entendu ajuster certaines valeurs, mais attention, celles-ci ne sont pas modifiables ultérieurement par l'interface HTML.

Pour le reste, relire l'article précédent : 5. Essayer

6. Le code

Le code, comme on peut s'en douter, n'est pas constitué d'un seul sketch, il serait énorme et illisible.

Voici une liste des fichiers :

esp32-sprinkle-timer.ino : le sketch principal
config.cpp, config.h : lecture du fichier de configuration config.ini
constants.h : constantes
flow.cpp, flow.h : capteur de débit
hmi.cpp, hmi.h : interface homme/machine sur l'écran OLED
html.cpp, html.h : interface homme/machine HTML
humidity.cpp, humidity.h : capteur d'humidité
module.cpp, module.h : gestion des modules (GPIOs, MCP23017, etc.)
oled.cpp, oled.h : écran OLED
relay.cpp, relay.h : gestion des relais
schedule.cpp, schedule.h : lecture du fichier de configuration schedule.ini
valve.cpp, valve.h : gestion des vannes
watering.cpp, watering.h : gestion des arrosages
way.cpp, way.h : gestion des voies
zone.cpp, zone.h : gestion des zones

Je veux bien admettre que ce code commence à devenir très conséquent, mais la complexité ne se gère pas avec simplicité. En opérant un découpage en modules simples, on peut toutefois réduire cette complexité et améliorer la lisibilité.

7. Conclusion

Les difficultés sont immenses car ce logiciel est hyper-paramétrable, et le temps manque. En effet, on peut difficilement s'occuper d'un jardin de 45m², récolter, cuisiner, faire des conserves, gérer un poulailler, aménager une nouvelle habitation, modifier son circuit électrique, et faire du développement logiciel en parallèle.

La période hivernale sera certainement plus productive en lignes de code. Patience ...


Cordialement

Henri

8. Mises à jour

18/08/2023 : ajout de l'écran OLED et du bouton fonction
22/08/2023 : ajout du bouton d'arrosage manuel


14 commentaires:

  1. Oui, le pont diviseur peut être modifié comme suit :
    R3 à remplacer par 0Ω, un bout de fil.
    R5 à laisser vide
    C'est vrai qu'un SSD1327 offre plus de surface d'affichage qu'un SSD1306.

    RépondreSupprimer
  2. Merci pour le retour.
    J'ai testé une autre solution qui fonctionne bien même si effectivement elle n'a pas réellement d'intérêt...
    Les valeurs du pont diviseur mettait l'entrée GPIO toujours à la masse car un courant trop fort circulait et par conséquent aucune lecture sur la broche... En employant des valeurs de 39K et 100K ça fonctionne parfaitement. J'ai en outre modifié l'atténuation de l'ADC sur 0db comme cela on une mesure plus précise (4096 points sur 1,1V env).
    Avez-vous pu résoudre/comprendre le problème sur l'entrée du capteur de débit qui n'affichait pas 0 ? Peut -être également des valeurs du pont diviseur trop faibles ?
    Bonne journée

    RépondreSupprimer
  3. Tout dépend certainement du modèle de capteur.
    Je n'ai pas encore eu le temps de voir côté capteur de débit.

    RépondreSupprimer
  4. Bonjour Henri, je souhaiterai tout comme vous avez prévu d'ajouter une irrigation à une voie, pouvoir également en "supprimer" une par un bouton.
    Ma question est donc comment supprimer une des 4 irrigations d'une voie. Faut-il tout simplement mettre la valeur m_duration à 0 ou y a t il d'autres variables à réinitialiser ?
    Autre question :
    J'ai par exemple 3 irrigations pour la voie Jardin.Potager :
    Irrigation N°1 - Index[0] Jardin.Potager 06:00 15min
    Irrigation N°2 - Index[1] Jardin.Potager 20:00 15min
    Irrigation N°3 - Index[2] Jardin.Potager 22:00 15min
    Je supprime l'irrigation N°2. Il me reste donc :
    Irrigation N°1 - Index[0] Jardin.Potager 06:00 15min
    Irrigation N°3 - Index[2] Jardin.Potager 22:00 15min
    Comment faire pour "copier" ou "déplacer" l'irrigation N°3 avec l'index[2] en Irrigation N°2 - Index[1] Jardin.potager 22:00 15min.
    Je pose cette question car contrairement à vous mon interface WEB ouvre et affiche toutes les irrigations d'une voie lorsque je "configure" une voie. Et surtout, mon code lit les irrigations dans l'ordre. D'où mon souhait de ne pas laisser de trous entre les index des irrigations.
    Je ne sais pas si je suis bien clair...
    En fait j'ai reproduit l'application Rain Bird : https://play.google.com/store/apps/details?id=com.rainbird&hl=en_US
    Merci beaucoup.

    RépondreSupprimer
    Réponses
    1. Classiquement, dans un tableau, si l'on veut déplacer un élément on utilise memcpy(destination, source, taille), ensuite memset(source, 0, taille) pour effacer l'élément source.

      Supprimer
    2. Bon je pense comprendre le principe, mais je n'arrive pas à mettre en oeuvre concrètement vos explications... Je bute avec des erreurs sur les fonctions memcpy et memset...
      Si je reprends mon exemple avec 3 irrigations pour la voie Jardin.Potager :
      Irrigation N°1 - Index[0] Jardin.Potager 06:00 15min
      Irrigation N°2 - Index[1] Jardin.Potager 20:00 15min
      Irrigation N°3 - Index[2] Jardin.Potager 22:00 15min
      Irrigation N°4 - Index[3] Jardin.Potager 00:00 0min
      Si je veux supprimer l'irrigation N°2, comment est ce que je fais :
      1- pour supprimer l'irrigation N°2 Index[1]
      2- pour décaler les irrigations N°3 Index[2] et N°4 Index[3] vers leur nouvelle position Index[1] et Index[2]
      3- "recréer" une irrigation libre pour l'index[3]
      Auriez-vous un peut bout de code pour me mettre sur la piste (au moins comment supprimer et copier une irrigation d'une voie).
      Même si j'avais un peu programmé avant, je n'avais jamais fait de C auparavant et du coup c'est compliqué pour moi de tout comprendre... J'arrive à adapter votre code, mais pas toujours à créer des nouvelles fonctions...
      Avec mes remerciements et toutes mes excuses.

      Supprimer
    3. Il faudrait avoir au moins la structure d'une irrigation. Est-ce une structure, une classe ?

      Supprimer
    4. Bonjour, je n'ai pas modifié votre code de ce côté là. J'ai juste adapté quelques fonctions pour mon affichage et mes gestions de dates.
      Donc si j'ai bien compris "mes" irrigations sont "vos" waterings, avec pour chaque way -> 4 irrigations (MAX_SCHEDULE). Donc à priori ce sont des classes avec un tableau[4 ou MAX_SCHEDULE] pour chaque way ?

      Supprimer
    5. Il vaudrait mieux donc implémenter un opérateur de recopie.
      Watering::Watering(const Watering& w) :
      m_way(w.m_way),
      m_hour(w.m_hour), m_minute(w.m_minute),
      m_duration(w.m_duration),
      m_always(w.m_always)
      {
      }
      Mais c'est un peu compliquer les choses. Dans mon cas, à partir du moment où m_duration vaut zéro, je n'affiche pas le watering en question, donc je considère qu'il est libre.

      Supprimer
    6. Bonjour Henri, merci pour votre aide. Grâce à vous j’ai réussi à faire ce que je souhaiterais... Je continue à suivre votre projet avec grand intérêt...

      Supprimer
  5. Bonjour Henri, pour info mes boutons ne marchaient pas sur la carte que j'ai conçue (d'après votre plan). Il faut faire une petite correction. En effet après avoir consulté la datasheet les entrées GPIO 34 et 35 ne possèdent pas de résistances PULLUP intégrées. Il faut donc les prévoir en externe. J'ai mis des 10K et ça fonctionne maintenant parfaitement.

    RépondreSupprimer