Introduction

Présentation du Projet

Ce projet est né de mon intérêt pour l’électronique, la domotique, l’IoT et le travail artisanal. C’est un vieux rêve que j’ai de posséder toutes sortes d’automates connectés contrôlés à distance.

Objectif

Ces dispositifs doivent avoir un certain niveau d’autonomie, ils doivent fonctionner à l’énergie solaire et être dotés d’une forme de conscience énergétique pour agir en conséquence.

  • Rapporter les données du capteur de manière régulière.
  • Faible consommation d’énergie.
  • Conscience énergétique et prise de mesures.
  • Capacité de mises à jour via les ondes (sans fil).

Cartes ESP32 et Compatibilité

Cartes prises en charge

Espressif possède une plateforme appelée ESP-IDF qui est mise à jour avec leurs nouvelles annonces et matériels, ainsi qu’avec les nouvelles fonctionnalités et les changements de sécurité. Ces mises à jour sont ensuite reflétées en aval dans PlatformIO et le framework Arduino, mais avec un délai significatif. Cela entraîne des incompatibilités entre les fichiers de configuration. Une de ces incompatibilités s’est manifestée lorsque j’ai essayé d’utiliser le fichier de configuration d’un ESP32 sur une carte ESP32C3.

Référence Externe pour le Capteur ADC

Problème avec le Capteur ADC sur l’ESP32C3

Il y a un problème lors de l’utilisation de l’ADC sur le module ESP32C3. Le bug est lié au type d’entier utilisé dans la bibliothèque du module ADC pour l’ESP32, qui est différent de celui de l’ESP32C3, entraînant une incompatibilité.

Mise en place de la Référence Externe1

Le problème est rapidement résolu avec la ligne de code suivante dans le fichier YAML :

external_components:
  - source: github://pr#5151
    components: [adc]

Mise en Œuvre du Projet

Composants Matériels

Je vous recommande vivement d’acquérir un adaptateur TTL UART ou un adaptateur série vers USB si vous ne l’avez pas déjà. Cela sera d’une grande aide pour le débogage. lien vers le produit

Je poste les liens vers ces produits uniquement à titre de référence technique. Je ne suis pas rémunéré pour les afficher, et je ne les recommande pas de manière particulière. Je les ai choisis pour leur fonctionnalité et leur prix à ce moment-là. La batterie est récupérée à partir d’un ancien module d’ordinateur portable.

Conception du Circuit

Le circuit est plutôt simple, j’ai 2 composants passifs, le panneau solaire et la batterie, puis j’ai les 3 composants actifs :

  • Le MPPT ou régulateur du point de puissance maximale (paneau solaire)

L'énergie solaire est directement influencée par la couverture du soleil et l'intensité lumineuse. Par conséquent, un chargeur de batterie simple placé directement entre un panneau solaire et une batterie ne fonctionnera que pendant une heure par jour, le reste du temps, il consommera trop d'énergie et "court-circuitera le panneau" dans le processus. C'est là que le MPPT se démarque, le module correspond à la meilleure tension avec l'intensité maximale, puis la convertit en 4,2 volts, la tension de charge nécessaire pour les batteries Li-Po.

  • L’élévateur de tension (step-up booster) de 3,7 à 5, 8 ou 12 volts

Les modules ESP32 fonctionnent à 3,3 volts ou à 5 volts, rien entre les deux, donc ils ont besoin d'une source de courant fiable. J'ai choisi ce module en raison des multiples options de tension de sortie.

  • Le chargeur de batterie micro USB 5 volts

Sachant que l'hiver approche, j'ai choisi d'investir dans une méthode de charge de secours. C'est une option simple mais efficace et fiable.

Ensuite, il y a aussi le microcontrôleur: ESP32C3-wroom-mini et le capteur BME280 pour la température, la pression et l’humidité.

schema

Configuration Logicielle

Comme mentionné, la plateforme utilisée pour ce projet est ESPHome. Elle fonctionne avec des fichiers de configuration au format YAML qui sont analysés, puis le projet est compilé et construit.

Après quelques semaines d’essais et d’erreurs, j’ai finalement abouti à un fichier de configuration pas si mal. Je vais montrer ici seulement les parties que je trouve intéressantes. Pour le fichier YAML complet, rendez-vous sur : https://git.cabivr.net/radu/solar-power_weather_station

La configuration commence avec la commande “on_boot” qui déclenche un script via un commutateur de variable globale (global variable switch).

esphome:
    name: $device
    friendly_name: $device
    on_boot:
      then:
        - delay: 10s
        - switch.turn_on: session_switch

Que nous trouvons déclaré ici :

  - platform: template
      id: session_switch
      name: "session_switch"
      lambda: |-
        if (id(session)) {
          return true;
        } else {
          return false;
        }                
      turn_on_action:
        - lambda: |-
                        id(session) = 1;                        
      turn_off_action:
        - lambda: |-
                        id(session) = 0;                        
      on_turn_on:
        then:
          - logger.log: "'********************** Script en cours d'exécution *************************'"
          - script.execute: check_stuff

Et ici:

globals:
    - id: ota_mode
      type: int
      restore_value: True
      initial_value: '0'
    - id: session
      type: int
      restore_value: True
      initial_value: '1'
    - id: naptime
      type: int
      restore_value: True
      initial_value: '15'
    - id: updates
      type: int
      restore_value: no
      initial_value: '0'

Le script déclenché active à nouveau la variable et commence à scanner les capteurs avec la condition d’attendre jusqu’à ce que tout soit terminé. Ensuite, il détermine le temps de sommeil après avoir vérifié le niveau de charge de la batterie.

script:
    - id: check_stuff
      then:
        - logger.log: "Démarrage de l'exécution du script"
        - lambda: |-
                        id(session) = 1;                        
        - lambda: |-
            id(updates) = 0;
            id(bat).update();
            id(bme280_sensor).update();                        
        - wait_until:
            lambda: |-
                            return(id(updates) >= 2);                            
        - logger.log:
            format: "Mises à jour terminées : %d"
            args: ['id(updates)']
        - lambda: |-                    
          float df = abs(id(bat_lev).state);
          if ((df <= 100) && (df >= 80)) {         // 100% - 80% de charge restante
            id(naptime) = $t_100;
          } else if ((df <= 80) && (df >= 60)) {  // 80% - 60% de charge restante
            id(naptime) = $t_80;
          } else if ((df <= 60) && (df >= 40)) {  // 60% - 40% de charge restante
            id(naptime) = $t_60;
          } else if ((df <= 40) && (df >= 20)) {  // 40% - 20% de charge restante
            id(naptime) = $t_40;
          } else if ((df <= 20) && (df >= 10)) {  // 20% - 10% de charge restante
            id(naptime) = $t_20;
          } else if (df < 10) {                     // under 10% de charge restante
            id(naptime) = $t_10;          
        - logger.log:
            format: "En cours de mise en veille pour %d minutes | OTA : %d"
            args: ['id(naptime)', 'id(ota_mode)']

Ensuite, on vérifie le drapeau OTA (Over-The-Air) qui, s’il est activé, empêchera l’appareil d’entrer en mode veille.

- if:
            condition:
              lambda: 'return id(ota_mode) == 0;'
            then:
              - logger.log:
                  format: "Condition remplie, entrée en mode veille. ota_mode = %d"
                  args: ['id(ota_mode)']
              - sensor.template.publish:
                  id: nap
                  state: !lambda 'return id(naptime);'
              - deep_sleep.enter:
                  id: deep_sleep_1
                  sleep_duration: !lambda |-
                    return id(naptime) * 60000;
            else:
              - logger.log:
                  format: "Condition remplie, la veille est empêchée. ota_mode = %d"
                  args: ['id(ota_mode)']
              - deep_sleep.prevent: deep_sleep_1

Ici, le script se termine, ce qui suit sont les déclarations des capteurs qui ont l’attribut update_interval défini sur never, donc ils ne seront pas appelés. Par conséquent, l’appareil entrera soit en mode veille, soit il attendra une mise à jour du micrologiciel en annonçant sa présence en ligne via l’API.

 sensor:
    - platform: bme280
      id: bme280_sensor
      update_interval: never
      temperature:
        name: "BME280 Température"
        id: temp
        on_value:
          lambda: |-
                        id(updates)++;                        
    ...

Implémentation de la mise à jour du micrologiciel via OTA

Créer un commutateur (switch) ciblant une variable globale nous offre l’opportunité de créer un service accessible depuis Home Assistant via l’API.

api:
    encryption:
      key: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    services:
      - service: start_ota
        then:
          - switch.turn_on: ota_switch
          - logger.log: "Signal OTA reçu ! Démarrage de l'OTA"
      - service: start_session
        then:
          - switch.turn_on: session_switch
          - logger.log: "Signal de session reçu ! Démarrage de la session"

Le seul problème est que si nous activons le commutateur (switch) lorsque l’appareil est en veille, cela n’aura aucun effet. Effectivement, une automatisation peut venir à la rescousse.

J’ai créé un commutateur (input boolean) ou un assistant bascule (toggle helper) dans le menu de Home Assistant sous “Appareils, Intégrations et Aides”, puis j’ai créé une automatisation qui écoute l’état du commutateur lorsque celui-ci passe de la position “éteint” (off) à la position “allumé” (on), puis attend que l’appareil cible se connecte en ligne et active le mode ota_mode via un appel de service. Une fois la commande envoyée, elle effectue un appel de service au commutateur (toggle) et le remet dans la position initiale “éteint” (off).

- id: '1690982182366'
  alias: Start OTA w-station0
  description: Attendre que l'appareil se connecte en ligne afin d'envoyer le drapeau de prévention du sommeil.
  trigger:
  - platform: state
    entity_id:
    - input_boolean.start_ota_w-station0
    from: "off"
    to: "on"
  condition: []
  action:
  - wait_for_trigger:
    - platform: state
      entity_id:
        - binary_sensor.w-station0.state
      from: "off"
      to: "on"  
  - service: esphome.w-station0_start_ota
    data: {}
  
  - service: input_boolean.turn_off
    data: {}
    target:
     entity_id:
     - input_boolean.start_ota_w-station0
  mode: single

Tous ces paramètres fonctionnent à merveille, c’est très stable et fiable. Ce que j’ai trouvé être un obstacle, c’est le délai avant que le script ne démarre au démarrage, actuellement de 10 secondes. Avec seulement 5 secondes de délai, l’OTA n’est pas activé en permanence, ce qui le rend peu fiable.

Résultats du Projet

Même si ce n’est pas une station météo complète qui calcule la vitesse du vent, dispose d’un pluviomètre et de toutes les options avancées, ce projet est quand même très bien compte tenu du coût et de l’expérience d’apprentissage.

Voici quelques photos de l’une des stations météo que j’ai réalisées ainsi que du tableau de bord. J’en ai effectivement fabriqué 3 et j’ai l’intention d’en faire une autre sans panneau solaire pour la cave. outside inside dashboard

Conclusion

Leçons Apprises

J’ai appris à utiliser le framework ESPHome, un peu de soudure et la conception et mise en œuvre de circuits. Bien sûr, je n’aurais pas pu le savoir sans faire des recherches sur les problèmes que les panneaux solaires peuvent avoir et qui, s’ils ne sont pas pris en compte, pourraient les rendre inefficaces.

Améliorations Futures

Je prévois de créer un fichier commun comon.yaml qui contiendra toutes les configurations identiques pour tous les appareils. Et peut-être ajouter quelques capteurs supplémentaires.

Références

Ressources en Ligne

https://ncrmnt.org/2021/12/06/optimizing-esp8266-esphome-for-battery-power-and-making-an-ice-bath-thermometer-as-well/

https://esphome.io/