Projet station météo

Attention, si tu as pris le même matériel que moi il faut brancher le RJ11 du capteur de vitesse dans la prise du capteur direction du vent. C’est uniquement le câble en sortie de capteur de vent (qui véhicule l’info de la vitesss et de la direction) qu’il faut brancher vers l’ESP32 et couper la prise RJ11.

Cela fait quelques jours que j’ai perdu le signal de ma station. J’ai donc branché l’ESP directement sur mon PC pour voir le log et voici ce que j’ai en boucle.

[20:01:33]ts Jul 29 2019 12:21:46 [20:01:33] [20:01:33]rst:0x10 (RTCWDT_RTC_RESET),boot:0x13ets Jul 29 2019 12:21:46 [20:01:33] [20:01:33]rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT) [20:01:33]configsip: 0, SPIWP:0xee [20:01:33]clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 [20:01:33]mode:DIO, clock div:2 [20:01:33]load:0x3fff0030,len:1184 [20:01:33]load:0x40078000,len:13132 [20:01:33]load:0x40080400,len:3036 [20:01:33]csum err:0x13!=0x03 [20:01:33]ets_main.c 384

J’ai tenté de réinstaller le firmware via esphome mais j’ai un message d’espace insuffisant sur mon ESP32.

La je suis bloqué et je ne comprend pas :cry:

Salut @brocopike

Heureusement que tu me réponds, sinon j’aurais fais une erreur.
Donc j’ai bien enfiché la RJ11 du capteur de vitesse du vent vers le capteur direction du vent (et oui j’ai exactement le même matériel que toi, hormis que je serais sur secteur et non batterie).

Ok je coupe bien la RJ11 du capteur direction du vent pour relier aux borniers et effecteur le câblage.
Pour le pluviomètre, on est d’accord que tu coupes également la RJ11 pour ramener les fils vers les borniers ?

Par contre l’émetteur/récepteur thermo (l’espèce de cylindre), tu l’as raccordé ? Je ne comprends pas trop son utilité.

Merci pour ton aide !

P.S. : Pour ton bug, je ne saurais t’aider, que dit notre ami commun chatGPT ?

EDIT: Si ça peut aider, voici ce que chatGPT suggère avec les différentes infos que j’ai donné (programme dans le premier post, OS, matériel et bug) :

Solution recommandée pour ESPHome sur Windows (avec outil esptool.py)


1. Installe esptool.py si ce n’est pas déjà fait

A. Ouvre un terminal (CMD ou PowerShell)

Tape ceci :

pip install esptool

Si pip n’est pas reconnu, tu dois d’abord installer Python pour Windows.

2. Branche ton ESP32 via USB

  • Note le port COM attribué à ton ESP32 (ex: COM3)

    • Tu peux le voir dans le Gestionnaire de périphériques > Ports (COM & LPT)

    • Note : si le port COM apparaît et disparaît rapidement, il est peut-être en bootloop. Pas grave, on va forcer le mode flash.

3. Efface complètement la mémoire Flash

Dans PowerShell ou CMD, tape (en remplaçant COM3 si besoin) :

Chip is ESP32
Connecting...
Erasing flash...
Chip erase completed successfully

Tu dois voir :

Chip is ESP32
Connecting...
Erasing flash...
Chip erase completed successfully

Si tu vois une erreur comme Failed to connect, tiens le bouton « BOOT » de l’ESP32 pendant la commande, ou appuie rapidement au bon moment.

4. Reflashe ton firmware ESPHome

Toujours dans le terminal, dans le dossier où se trouve ton .yaml, tape :

esphome run ton_fichier.yaml

Choisis COM3 quand demandé
Attends qu’il compile et envoie le firmware
L’ESP redémarre, le capteur devrait revenir dans Home Assistant ou sur le dashboard ESPHome

Problème d’espace mémoire ?

Ton YAML est riche en capteurs et bibliothèques externes. Il est possible que tu sois proche des limites mémoire du firmware (1.3–1.5MB sur 4MB).

Si tu veux gagner de la place :

  • Commente temporairement certains capteurs

  • Change le partition scheme dans ESPHome si besoin

  • Utilise la commande :

    esphome compile ton_fichier.yaml
    

elle te donnera la taille du binaire généré.

Conseils utiles

Sécurité Wi-Fi

Tu utilises une IP manuelle dans ton wifi: :

manual_ip:
  static_ip: X
  gateway: X
  subnet: X

Assure-toi de mettre les vraies adresses IP ici. Sinon le module ne pourra pas se connecter au Wi-Fi après flash.

j’ai aussi coupé le rj11 du capteur de pluie. Alors pour, le truc cylindrique, j’ai retiré le circuit imprimé à l’intérieur et j’ai mis à la place le capteur de température et de pression

hello,

petite nouveauté. J’ai donc effacé le flash avec esptool mais avec les dernières mise à jour de esphome, mon firmware était trop gros sous arduino.

Je suis donc passé sous esp-idf et au passage j’ai vu que maintenant le capteur lps22 était nativement pris en charge par esphome.

j’ai mis a jour mon code dans le premier poste.

Comment intègre tu le capteur de luminosité pour que l’eau ne rentre pas dans le boitier ?

Perso mon boitier est contre un abri de jardin du quel j’ai un mat qui part pour les différentes sondes, vents,… je ne sais pas comment intégrer ce capteur de luminosité.

L’idéal c’est de le mettre sur un mat afin qu’il soit à l’air libre et assez loin d’un mur de source potentielle de chaleur (toit, brique,…)

Pour ça il existe des petits abris solaires. Tu n’as qu’à mettre la sonde dedans. C’est fait pour.

C’est anti UV et ça ne prend pas la chaleur. Les stations météos pro sont faite sur cette base.

Exemple parmi tant d’autres

pour le capteur de luminosité tout est précisé dans mon première poste. Tu peux donc simplement reproduire ce que j’ai fait ou trouver un autre moyen.

Bonjour,

Ça fait un moment que je veux me lancer dans une station météo DIY, le prix du pack pique 75€ avec fdp mais j’ai pas trouver mieux…

Je pense que je vais craquer dans la journée et m’inspirer de ce post, merci pour les infos partagées. Je serais sur secteur.

Bonjour est ce que quelqu’un à déjà travailler sur la conception du dashboard de la station météo?

Bonjour,

Je suis resté sur une carte assez basique avec mes entités en forme de liste

Bonjour,

J’ai reçu ma station et je me suis donc bien inspiré de ce post et j’en profite pour remercier @brocopike et les autres contributeurs. J’ai pris beaucoup de plaisir à dessiner et fabriquer des supports en 3D (bras, support boite capteur, support sonde SHT3x). J’ai pas mal modifié le code en piochant par çi, par là et avec l’IA, il reste à voir à l’usage la véracité des données. J’ai aussi passé du temps à vérifier l’étalonnage du capteur de vent (2 pulse par tour Misol WH-SP-WS01) et du pluviomètre (au final j’ai trouvé une notice fabriquant qui donne 0.3mm par pulse), à voir avec plus de recul !

J’ai alimenté le tout avec un hilink 3,3v, l’ESP32 est monté sur une PCB board avec bornier et j’ai soudé les résistances sous le dessous de la board entre pin et 3,3v.

Pour l’interface sur home assistant, j’ai opté pour cette carte pour le vent windrose

et des plus classiques pour le reste

L’utilisation du capteur de pression atmosphérique LSP22 a été un vrai échec, j’y ai passé un temps fou mais j’ai jamais réussi à le faire fonctionner correctement. Je l’ai retiré.
A ce jour j’ai donc anémomètre (Misol WH-SP-WS01), girouette (Misol MS-WH-SP-WD), pluviomètre (Misol WH-SP-RG), capteur température humidité (SHT35), capteur UV (LTR390), capteur luminosité (BH 1750)

j’ai utilisé ce composant sans problemes:

  - platform: bme280_i2c
    pressure:
      name:  $name Pressure
      id: bme_press

Bonjour,

Après échange avec @Quentin57520 qui est demandeur, je vous met à disposition mon bras supplémentaire à imprimer en 3D et son support de boite pour les capteurs sur mon github en stl et f3d.

J’ai utilisé cette boite qui est un peu juste, j’ai fait aussi un support interne qui se visse dans la boite et les capteurs sur le support


Ce qui donne ceci (les vis qui rouillent ont été remplacés depuis par de l’inox :grin:) et le LSH22 retiré.

Je mets également mon fichier de configuration esphome pour partager ensemble nos remontées d’infos et fiabiliser.

Edit : par exemple ce soir j’ai des rafales à 34km/h alors que météo France annonce 68km/h, donc je pense que mon facteur de multiply d’après ce que j’ai lu et testé en impulsion n’est pas conforme :

- multiply: 0.02 # 1/ 60 / 2 * 2,4 = 0,02 (puisqu'à 2,4 km/h, l'anémomètre effectue un tour complet en une seconde et génère deux impulsions)

Alors que de base dans le code de ce tuto il est de 0,04 ce qui serait cohérent, je vais le changer et donc doubler la vitesse.

Merci pour ton partage de tes fichiers 3D, le bras va bien se fondre dans le décor; il est réussi, pareil pour la boite au couvercle transparent et son support capteur !

La boite étanche provient d’aliexpress je suppose ?

Pour mon fichier yaml, voici le mien, en grande partie inspiré de l’auteur et juste adapté pour ESPHome Builder + 2/3 capteurs et ajuster le uptime en plus :

esphome:
  name: esp32-weatherstation
  friendly_name: ESP32-WeatherStation
  name_add_mac_suffix: false

esp32:
  board: esp32dev
  framework:
    type: arduino
    
# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "*"

# Allow Over-The-Air updates
ota:
  - platform: esphome
    password: "meteo2024secure!"

# Allow provisioning Wi-Fi via serial
improv_serial:

# ===== WiFi =====
wifi:
  ssid: "not today"
  password: "not today"
  min_auth_mode: WPA2
  ap:
    ssid: "ESP32-WeatherStation"
    password: "*"

captive_portal:
  
  # Décommente si tu veux une IP fixe
  # manual_ip:
  #   static_ip: 192.168.1.XXX
  #   gateway: 192.168.1.1
  #   subnet: 255.255.255.0

esp32_improv:
  authorizer: none

web_server:

i2c:
  id: bus_a
  sda: GPIO21
  scl: GPIO22
  scan: true

globals:
  - id: rainfall_total
    type: float
    initial_value: "0.0"  
    
sensor:
#########Capteur signal wifi#######  
  - platform: wifi_signal
    name: "WiFi RSSI"
    update_interval: 5s
    unit_of_measurement: dB
    accuracy_decimals: 0
    force_update: false
    icon: mdi:wifi

#########Capteur durée de fonctionnement#######  
  - platform: uptime
    id: uptime_seconds
    name: "Uptime Sensor"
    update_interval: 5s
    unit_of_measurement: s
    accuracy_decimals: 0
    force_update: false
    icon: mdi:timer

#########Capteur température SHT35#######
  - platform: sht3xd
    i2c_id: bus_a
    temperature:
      name: "Température extérieure"
      device_class: "temperature"
      state_class: "measurement"
      unit_of_measurement: "°C"
      accuracy_decimals: 1
    humidity:
      name: "Humidité extérieure"
    address: 0x44
    update_interval: 5s

##########Capteur luminosité BH1750#######
  - platform: bh1750
    name: "Luminosité BH1750"
    id: sensor_bh1750
    address: 0x23
    update_interval: 5s

##########Capteur luminosité OPT3001 (WCMCU-3001)#######
  - platform: opt3001
    name: "Luminosité OPT3001"
    id: sensor_opt3001
    address: 0x44
    update_interval: 5s
    internal: true

##########Moyenne Capteur luminosité#######
  - platform: template 
    name: "Luminosité" 
    unit_of_measurement: "lx"
    icon: mdi:brightness-5
    update_interval: 5s
    lambda: |- 
          return (id(sensor_bh1750).state + id(sensor_opt3001).state)/2;

##########Capteur pression LPS22HB#######
  - platform: lps22
    temperature:
      name: "LPS22 Température"
      unit_of_measurement: °C
      state_class: measurement
      accuracy_decimals: 1
    pressure:
      name: "Pression atmosphérique"
      unit_of_measurement: hPa
      state_class: measurement
      accuracy_decimals: 2
    address: 0x5C
    update_interval: 5s

##########Capteur vitesse du vent#######  
  - platform: pulse_meter
    pin:
      number: GPIO34
      mode: INPUT
    id: wind_speed
    unit_of_measurement: 'km/h'
    name: "Vitesse du vent"
    icon: 'mdi:weather-windy'
    internal_filter: 10ms
    filters:
      - multiply: 0.04
      - sliding_window_moving_average:
          window_size: 10 
          send_every: 10
      - timeout:
          timeout: 5s
          value: 0

##########Capteur pluviomètre#######   
  - platform: pulse_counter
    pin: GPIO35  
    name: "Précipitation"
    update_interval: 60s  
    filters:
      - multiply: 0.2794
    unit_of_measurement: "mm"
    on_value:
      then:
        - lambda: |-
            id(rainfall_total) += x;
            ESP_LOGD("rain_gauge", "Cumul actuel: %.2f mm", id(rainfall_total));

  - platform: template
    name: "Cumul précipitation"
    unit_of_measurement: "mm"
    accuracy_decimals: 4
    update_interval: 60s
    lambda: |-
      return id(rainfall_total);

#########Capteur orientation du vent####### 
  - platform: adc
    id: wind_direction_adc
    pin: GPIO32
    name: "Direction du vent (tension)"
    attenuation: 12db
    update_interval: 5s
    accuracy_decimals: 3

text_sensor:
#########Informations réseau détaillées#######
  - platform: wifi_info
    ip_address:
      name: "ESP32-WeatherStation - IP"
      icon: "mdi:ip-network"
    ssid:
      name: "ESP32-WeatherStation - SSID"
      icon: "mdi:wifi"
    bssid:
      name: "ESP32-WeatherStation - BSSID"
      icon: "mdi:access-point-network"
    mac_address:
      name: "ESP32-WeatherStation - MAC"
      icon: "mdi:network-outline"

#########Uptime lisible#######
  - platform: template
    name: "Uptime (lisible)"
    icon: mdi:timer
    update_interval: 60s
    lambda: |-
      int seconds = (int) id(uptime_seconds).state;
      int days = seconds / 86400;
      int hours = (seconds % 86400) / 3600;
      int minutes = (seconds % 3600) / 60;
      char buffer[32];
      sprintf(buffer, "%dj %dh %dm", days, hours, minutes);
      return {buffer};

#########Version ESPHome#######
  - platform: version
    name: "ESP32-WeatherStation - ESPHome Version"
    icon: "mdi:chip"

#########Direction du vent#######
  - platform: template
    name: "Direction du vent"
    icon: "mdi:weather-windy"
    id: wind_direction_text
    update_interval: 5s
    lambda: |-
      float direction = id(wind_direction_adc).state;
      if (direction > 2.2 && direction < 2.6) return {"Nord"};
      else if (direction > 1.15 && direction < 1.7) return {"Nord-Est"};
      else if (direction > 0.21 && direction < 0.35) return {"Est"};
      else if (direction > 0.35 && direction < 0.8) return {"Sud-Est"};
      else if (direction > 0.80 && direction < 1.15) return {"Sud"};
      else if (direction > 1.70 && direction < 2.2) return {"Sud-Ouest"};
      else if (direction > 2.9 && direction < 3.1) return {"Ouest"};
      else if (direction > 2.6 && direction < 2.9) return {"Nord-Ouest"};
      else return {"Unknown"};

Si ça peut t’aider :wink:

En revanche, elle n’est pas encore installé donc difficile de dire si tout fonctionne…

EDIT: En regardant ton code j’ai commencé à modifié le mien, tu as des trucs sympa auquel je n’ai pas pensé, idem, bonne idée le capteur UV, je te pique tes idées, ca va compléter mon programme et mon appareil :smiley: .

Je rajouterai le nouveau code demain !

Merci pour le partage, j’ai pas mal travaillé le mien, tu pourras t’en inspirer si tu en as envie, pour les cartes je pourrais aussi te les partager si ça t’intéresse, voir mon post au dessus.
J’ai aussi travailler mes volts (platfomr : ADC) pour bien déterminer le Nord, sud, ouest … en fonction des volts obtenus. Bonne construction

Salut,

Voici le code à jour :

esphome:
  name: esp32-weatherstation
  friendly_name: ESP32-WeatherStation
  name_add_mac_suffix: false
  on_boot:
    priority: -10
    then:
      - sensor.template.publish:
          id: rainfall_cumul
          state: !lambda 'return id(rainfall_total);'

esp32:
  board: esp32dev
  framework:
    type: arduino
    
# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "not today"

# Allow Over-The-Air updates
ota:
  - platform: esphome
    password: "not today"

# Allow provisioning Wi-Fi via serial
improv_serial:

# ===== WiFi =====
wifi:
  ssid: "not today"
  password: "not today"
  min_auth_mode: WPA2
  ap:
    ssid: "ESP32-WeatherStation"
    password: "not today"

captive_portal:
  
  # Décommente si tu veux une IP fixe
  # manual_ip:
  #   static_ip: 192.168.1.XXX
  #   gateway: 192.168.1.1
  #   subnet: 255.255.255.0

esp32_improv:
  authorizer: none

web_server:

i2c:
  id: bus_a
  sda: GPIO21
  scl: GPIO22
  scan: true

# ==============================================================================
# Variables globales
# ==============================================================================

globals:
  # Cumul total de pluie (persistant aux redémarrages)
  - id: rainfall_total
    type: float
    initial_value: "0.0"
    restore_value: true
  
  # Pluie hebdomadaire (reset tous les lundis à minuit)
  - id: rainfall_week
    type: float
    initial_value: "0.0"
    restore_value: true
  
  # Historique vent pour rafales 10 minutes (300 points max = 10 min à 2s d'intervalle)
  - id: wind_history_10m
    type: std::vector<float>
    restore_value: false

  # Rafale du jour (max depuis minuit)
  - id: wind_gust_day
    type: float
    initial_value: "0.0"
    restore_value: false

  # Rafale de la semaine (max depuis lundi minuit)
  - id: wind_gust_week
    type: float
    initial_value: "0.0"
    restore_value: true

  # Température min/max de la semaine
  - id: temp_min_week
    type: float
    initial_value: "100.0"
    restore_value: true
  
  - id: temp_max_week
    type: float
    initial_value: "-100.0"
    restore_value: true

  # Humidité min/max de la semaine
  - id: humidity_min_week
    type: float
    initial_value: "100.0"
    restore_value: true
  
  - id: humidity_max_week
    type: float
    initial_value: "0.0"
    restore_value: true

  # Compteurs pour moyennes hebdomadaires
  - id: temp_sum_week
    type: float
    initial_value: "0.0"
    restore_value: true
  
  - id: temp_count_week
    type: int
    initial_value: "0"
    restore_value: true

  - id: humidity_sum_week
    type: float
    initial_value: "0.0"
    restore_value: true
  
  - id: humidity_count_week
    type: int
    initial_value: "0"
    restore_value: true

  # UV max de la semaine
  - id: uv_max_week
    type: float
    initial_value: "0.0"
    restore_value: true

# ==============================================================================
# Boutons
# ==============================================================================

button:
  - platform: restart
    id: button_restart
    name: "Restart"

  # Bouton pour reset les stats hebdomadaires manuellement
  - platform: template
    name: "Reset statistiques hebdo"
    icon: "mdi:restart"
    on_press:
      - lambda: |-
          id(rainfall_week) = 0.0;
          id(wind_gust_week) = 0.0;
          id(temp_min_week) = 100.0;
          id(temp_max_week) = -100.0;
          id(humidity_min_week) = 100.0;
          id(humidity_max_week) = 0.0;
          id(temp_sum_week) = 0.0;
          id(temp_count_week) = 0;
          id(humidity_sum_week) = 0.0;
          id(humidity_count_week) = 0;
          id(uv_max_week) = 0.0;
          ESP_LOGI("reset", "Stats hebdo réinitialisées");

# ==============================================================================
# Binary Sensors
# ==============================================================================

binary_sensor:
  - platform: status
    name: "Status"

# ==============================================================================
# Sensors
# ==============================================================================

sensor:
#########Capteur signal wifi#######  
  - platform: wifi_signal
    name: "WiFi RSSI"
    update_interval: 60s
    unit_of_measurement: dB
    accuracy_decimals: 0
    force_update: false
    icon: mdi:wifi

#########Capteur durée de fonctionnement#######  
  - platform: uptime
    id: uptime_seconds
    name: "Uptime Sensor"
    update_interval: 60s
    unit_of_measurement: s
    accuracy_decimals: 0
    force_update: false
    icon: mdi:timer

#########Capteur température SHT35#######
  - platform: sht3xd
    i2c_id: bus_a
    temperature:
      id: temp_outdoor
      name: "Température extérieure"
      device_class: "temperature"
      state_class: "measurement"
      unit_of_measurement: "°C"
      accuracy_decimals: 1
      on_value:
        then:
          - lambda: |-
              float t = id(temp_outdoor).state;
              // Min/Max hebdo
              if (t < id(temp_min_week)) id(temp_min_week) = t;
              if (t > id(temp_max_week)) id(temp_max_week) = t;
              // Moyenne hebdo
              id(temp_sum_week) += t;
              id(temp_count_week) += 1;
    humidity:
      id: humidity_outdoor
      name: "Humidité extérieure"
      device_class: "humidity"
      state_class: "measurement"
      on_value:
        then:
          - lambda: |-
              float h = id(humidity_outdoor).state;
              // Min/Max hebdo
              if (h < id(humidity_min_week)) id(humidity_min_week) = h;
              if (h > id(humidity_max_week)) id(humidity_max_week) = h;
              // Moyenne hebdo
              id(humidity_sum_week) += h;
              id(humidity_count_week) += 1;
    address: 0x44
    update_interval: 5s

##########Capteur luminosité BH1750#######
  - platform: bh1750
    name: "Luminosité BH1750"
    id: sensor_bh1750
    address: 0x23
    update_interval: 5s
    internal: true

##########Capteur luminosité OPT3001 (WCMCU-3001)#######
  - platform: opt3001
    name: "Luminosité OPT3001"
    id: sensor_opt3001
    address: 0x45  # ← Changé de 0x44 pour éviter conflit avec SHT35
    update_interval: 5s
    internal: true

##########Moyenne Capteur luminosité#######
  - platform: template 
    name: "Luminosité" 
    unit_of_measurement: "lx"
    icon: mdi:brightness-5
    accuracy_decimals: 1
    update_interval: 5s
    lambda: |- 
      return (id(sensor_bh1750).state + id(sensor_opt3001).state) / 2;

##########Capteur pression LPS22HB#######
  - platform: lps22
    temperature:
      name: "LPS22 Température"
      unit_of_measurement: °C
      state_class: measurement
      accuracy_decimals: 1
      internal: true
    pressure:
      name: "Pression atmosphérique"
      unit_of_measurement: hPa
      state_class: measurement
      accuracy_decimals: 2
      device_class: "pressure"
    address: 0x5C
    update_interval: 5s

##########Capteur UV LTR390#######
  - platform: ltr390
    i2c_id: bus_a
    id: my_ltr390
    uv:
      id: uv_counts
      name: "UV Sensor Counts"
      internal: true
    ambient_light:
      id: als_counts
      name: "Light Sensor Counts"
      internal: true
    gain:
      ambient_light: X9
      uv: X3
    resolution:
      ambient_light: 18
      uv: 13
    address: 0x53
    update_interval: 5s

  # Conversion UV counts → UV Index calibré
  - platform: template
    name: "UV Index"
    id: uv_index
    unit_of_measurement: "UVI"
    icon: "mdi:weather-sunny-alert"
    device_class: "irradiance"
    state_class: "measurement"
    accuracy_decimals: 1
    update_interval: 5s
    lambda: |-
      const float factor = 2300.0;   // valeur recommandée
      float uv = id(uv_counts).state / factor;
      
      // Update UV max de la semaine
      if (uv > id(uv_max_week)) {
        id(uv_max_week) = uv;
      }
      
      return uv;

##########Capteur vitesse du vent#######  
  - platform: pulse_meter
    pin:
      number: GPIO34
      mode: INPUT_PULLUP
    id: wind_speed
    name: "Vitesse du vent"
    icon: 'mdi:weather-windy'
    device_class: "wind_speed"
    state_class: "measurement"
    unit_of_measurement: 'km/h'
    accuracy_decimals: 1
    internal_filter: 10ms
    timeout: 2s
    filters:
      - multiply: 0.04
      - sliding_window_moving_average:
          window_size: 10 
          send_every: 10
    on_value:
      then:
        - lambda: |-
            float v = id(wind_speed).state;

            // --- Historique 10 minutes ---
            id(wind_history_10m).push_back(v);
            const int max_points = 300; // 10 min glissantes (à 2s d'intervalle)
            if (id(wind_history_10m).size() > max_points) {
              id(wind_history_10m).erase(id(wind_history_10m).begin());
            }

            // --- Rafale du jour ---
            if (v > id(wind_gust_day)) {
              id(wind_gust_day) = v;
            }

            // --- Rafale de la semaine ---
            if (v > id(wind_gust_week)) {
              id(wind_gust_week) = v;
            }

  # Rafale 10 minutes glissantes (norme météo)
  - platform: template
    name: "Rafale max 10min"
    id: wind_gust_10m
    device_class: "wind_speed"
    state_class: "measurement"
    unit_of_measurement: 'km/h'
    accuracy_decimals: 1
    icon: 'mdi:weather-windy-variant'
    update_interval: 10s
    lambda: |-
      if (id(wind_history_10m).empty()) return 0.0;
      float max_gust = 0.0;
      for (auto v : id(wind_history_10m)) {
        if (v > max_gust) max_gust = v;
      }
      return max_gust;

  # Rafale du jour (reset à minuit)
  - platform: template
    name: "Rafale max jour"
    id: wind_gust_daily
    device_class: "wind_speed"
    state_class: "measurement"
    unit_of_measurement: 'km/h'
    accuracy_decimals: 1
    icon: 'mdi:weather-windy-variant'
    update_interval: 10s
    lambda: |-
      return id(wind_gust_day);

  # Rafale de la semaine (reset lundi minuit)
  - platform: template
    name: "Rafale max semaine"
    id: wind_gust_weekly
    device_class: "wind_speed"
    state_class: "measurement"
    unit_of_measurement: 'km/h'
    accuracy_decimals: 1
    icon: 'mdi:weather-windy-variant'
    update_interval: 60s
    lambda: |-
      return id(wind_gust_week);

##########Capteur pluviomètre#######   
  - platform: pulse_counter
    pin: GPIO35  
    name: "Précipitation horaire"
    id: rain_hourly
    update_interval: 60s  
    filters:
      - multiply: 0.2794
    unit_of_measurement: "mm/h"
    icon: "mdi:weather-rainy"
    device_class: "precipitation_intensity"
    state_class: "measurement"
    accuracy_decimals: 2
    on_value:
      then:
        - lambda: |-
            id(rainfall_total) += x;
            id(rainfall_week) += x;
            ESP_LOGD("rain_gauge", "Cumul actuel: %.2f mm | Semaine: %.2f mm", id(rainfall_total), id(rainfall_week));
        - sensor.template.publish:
            id: rainfall_cumul
            state: !lambda 'return id(rainfall_total);'

  # Pluie journalière (reset à minuit)
  - platform: pulse_meter
    pin: GPIO35
    name: "Précipitation journalière"
    id: rain_daily
    internal_filter: 500ms
    timeout: 45min
    unit_of_measurement: "mm"
    icon: "mdi:beaker-outline"
    device_class: "precipitation"
    state_class: "total_increasing"
    accuracy_decimals: 2
    filters:
      - multiply: 0.2794

  # Cumul total persistant (survit aux redémarrages)
  - platform: template
    name: "Cumul précipitation total"
    id: rainfall_cumul
    unit_of_measurement: "mm"
    accuracy_decimals: 2
    icon: "mdi:water"
    device_class: "precipitation"
    state_class: "total_increasing"
    update_interval: 60s
    lambda: |-
      return id(rainfall_total);

  # Pluie de la semaine (reset lundi minuit)
  - platform: template
    name: "Précipitation semaine"
    id: rainfall_weekly
    unit_of_measurement: "mm"
    accuracy_decimals: 2
    icon: "mdi:weather-pouring"
    device_class: "precipitation"
    state_class: "total_increasing"
    update_interval: 60s
    lambda: |-
      return id(rainfall_week);

#########Capteur orientation du vent (tension ADC)####### 
  - platform: adc
    id: wind_direction_adc
    pin: GPIO32
    name: "Direction du vent (tension)"
    attenuation: 12db
    update_interval: 5s
    accuracy_decimals: 3
    internal: true
    on_value:
      # Nord
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 2.2
              below: 2.6
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "N"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 0.0
      # Nord-Est
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 1.15
              below: 1.7
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "NE"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 45.0
      # Est
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 0.21
              below: 0.35
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "E"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 90.0
      # Sud-Est
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 0.35
              below: 0.8
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "SE"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 135.0
      # Sud
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 0.80
              below: 1.15
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "S"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 180.0
      # Sud-Ouest
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 1.70
              below: 2.2
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "SO"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 225.0
      # Ouest
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 2.9
              below: 3.1
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "O"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 270.0
      # Nord-Ouest
      - if:
          condition:
            sensor.in_range:
              id: wind_direction_adc
              above: 2.6
              below: 2.9
          then:
            - text_sensor.template.publish:
                id: wind_direction_cardinal
                state: "NO"
            - sensor.template.publish:
                id: wind_direction_degrees
                state: 315.0

  # Direction du vent en degrés (pour Home Assistant)
  - platform: template
    name: "Direction du vent"
    id: wind_direction_degrees
    icon: 'mdi:compass-rose'
    unit_of_measurement: "°"
    accuracy_decimals: 0
    update_interval: never

# ==============================================================================
# STATISTIQUES HEBDOMADAIRES
# ==============================================================================

  # Température moyenne de la semaine
  - platform: template
    name: "Température moyenne semaine"
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    icon: "mdi:thermometer"
    update_interval: 60s
    lambda: |-
      if (id(temp_count_week) == 0) return 0.0;
      return id(temp_sum_week) / id(temp_count_week);

  # Température min de la semaine
  - platform: template
    name: "Température min semaine"
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    icon: "mdi:thermometer-chevron-down"
    update_interval: 60s
    lambda: |-
      if (id(temp_min_week) == 100.0) return 0.0;
      return id(temp_min_week);

  # Température max de la semaine
  - platform: template
    name: "Température max semaine"
    unit_of_measurement: "°C"
    device_class: "temperature"
    state_class: "measurement"
    accuracy_decimals: 1
    icon: "mdi:thermometer-chevron-up"
    update_interval: 60s
    lambda: |-
      if (id(temp_max_week) == -100.0) return 0.0;
      return id(temp_max_week);

  # Humidité moyenne de la semaine
  - platform: template
    name: "Humidité moyenne semaine"
    unit_of_measurement: "%"
    device_class: "humidity"
    state_class: "measurement"
    accuracy_decimals: 1
    icon: "mdi:water-percent"
    update_interval: 60s
    lambda: |-
      if (id(humidity_count_week) == 0) return 0.0;
      return id(humidity_sum_week) / id(humidity_count_week);

  # Humidité min de la semaine
  - platform: template
    name: "Humidité min semaine"
    unit_of_measurement: "%"
    device_class: "humidity"
    state_class: "measurement"
    accuracy_decimals: 1
    icon: "mdi:water-minus"
    update_interval: 60s
    lambda: |-
      if (id(humidity_min_week) == 100.0) return 0.0;
      return id(humidity_min_week);

  # Humidité max de la semaine
  - platform: template
    name: "Humidité max semaine"
    unit_of_measurement: "%"
    device_class: "humidity"
    state_class: "measurement"
    accuracy_decimals: 1
    icon: "mdi:water-plus"
    update_interval: 60s
    lambda: |-
      if (id(humidity_max_week) == 0.0) return 0.0;
      return id(humidity_max_week);

  # UV Index max de la semaine
  - platform: template
    name: "UV Index max semaine"
    unit_of_measurement: "UVI"
    icon: "mdi:weather-sunny-alert"
    device_class: "irradiance"
    state_class: "measurement"
    accuracy_decimals: 1
    update_interval: 60s
    lambda: |-
      if (id(uv_max_week) == 0.0) return 0.0;
      return id(uv_max_week);

# ==============================================================================
# Text Sensors
# ==============================================================================

text_sensor:
#########Informations réseau détaillées#######
  - platform: wifi_info
    ip_address:
      name: "ESP32-WeatherStation - IP"
      icon: "mdi:ip-network"
    ssid:
      name: "ESP32-WeatherStation - SSID"
      icon: "mdi:wifi"
    bssid:
      name: "ESP32-WeatherStation - BSSID"
      icon: "mdi:access-point-network"
    mac_address:
      name: "ESP32-WeatherStation - MAC"
      icon: "mdi:network-outline"

#########Uptime lisible#######
  - platform: template
    name: "Uptime"
    icon: mdi:timer
    update_interval: 60s
    lambda: |-
      int seconds = (int) id(uptime_seconds).state;
      int days = seconds / 86400;
      int hours = (seconds % 86400) / 3600;
      int minutes = (seconds % 3600) / 60;
      char buffer[32];
      sprintf(buffer, "%dj %dh %dm", days, hours, minutes);
      return {buffer};

#########Version ESPHome#######
  - platform: version
    name: "ESPHome Version"
    icon: "mdi:chip"

#########Direction du vent (cardinale)#######
  - platform: template
    name: "Direction cardinale du vent"
    icon: "mdi:windsock"
    id: wind_direction_cardinal
    update_interval: never

# ==============================================================================
# Time synchronization avec Home Assistant
# ==============================================================================

time:
  - platform: homeassistant
    id: esptime
    on_time:
      # Reset à minuit (00:00:00) tous les jours
      - seconds: 0
        minutes: 0
        hours: 0
        then:
          # Reset pluie journalière
          - pulse_meter.set_total_pulses:
              id: rain_daily
              value: 0
          
          # Reset rafale du jour
          - lambda: |-
              id(wind_gust_day) = 0.0;
              ESP_LOGI("midnight_reset", "Reset pluie journalière et rafale du jour");

      # Reset stats hebdomadaires tous les lundis à minuit
      - seconds: 0
        minutes: 0
        hours: 0
        days_of_week: MON
        then:
          - lambda: |-
              // Reset pluie semaine
              id(rainfall_week) = 0.0;
              
              // Reset rafale semaine
              id(wind_gust_week) = 0.0;
              
              // Reset température
              id(temp_min_week) = 100.0;
              id(temp_max_week) = -100.0;
              id(temp_sum_week) = 0.0;
              id(temp_count_week) = 0;
              
              // Reset humidité
              id(humidity_min_week) = 100.0;
              id(humidity_max_week) = 0.0;
              id(humidity_sum_week) = 0.0;
              id(humidity_count_week) = 0;
              
              // Reset UV
              id(uv_max_week) = 0.0;
              
              ESP_LOGI("weekly_reset", " Stats hebdo réinitialisées (nouveau cycle lundi)");

J’ai ajouté tes améliorations, le capteur UV en prévoyance et j’ai mis un historique hebdomadaire au passage, je me suis dis que ca peut être utile.

Tes cartes ont également un très bonne base, dès que tout sera en route, je passerai regarder ça de plus prêt. J’ai commandé la boîte étanche et le capteur UV sur aliexpress, ça arrivera en 2026 :sweat_smile:

Si je comprends bien, tu as mis tes deux capteurs de luminosisté + UV dans la boîte ?

Tu as réussi à régler ton capteur de vitesse de vent ?

Salut,

Dans cette boîte j’ai mis uv ltr390 et bh1750, j’ai retiré le lps22 pression, il m’a posé des problèmes, jamais réussi à le faire fonctionner.
Pour mon capteur de vent j’ai remis mon coefficient à 0.02 et ca colle bcp mieux comparé à MF.
J’ai aussi mis ma sonde de température dans le boîtier origine fournit dans le kit comme ceci avec un support en 3D.



Il y a un câble entre le boîtier sonde et me boîtier des autres capteurs pour utiliser le même i2c.
Je regarderai pour tes valeurs statistiques de la semaine, c’est encore à travailler chez moi.
Pour les cartes je posterais ce que j’ai.

Bonsoir Quentin. Un super travail de ta part, et merci pour le partage. Moi qui débute sous esphome, et qui viens juste de réaliser un petit compteur d’eau connecté HA (mesure avec D1mini + capteur inductif…), ta station météo pour moi c’est vraiment un « travail de pro » !
Du coup, ça m’a donné l’idée d’en faire un, qui remplacerait ma station Netatmo, avec lequel j’ai de plus en plus de soucis (déconexions fréquentes !).
J’ai passé beaucoup de temps à lire et à relire ton code et surtout à essayer de le comprendre… ton code remonte beaucoup de mesures et beaucoup d’infos (journalier, semaine, moyenne, etc…), m’inspirant de ta config j’ai commencé à tester quelques bouts de ton code, sur un ESP32 de fond tiroir, bien sûr avec les modifs adaptés à mes capteurs. Pour la partie mesure de température/Humidité/Pression j’utilise un BME280, et l’anémométre (testé avec des impulsions sur le GPIO34), jusque là tout fonctionne. Par contre, le pluviométre me pose un probléme quand je vérifie (validate) la config sous esphome, j’ai une erreur.
Je remarque que dans la config « capteur pluviométre » je vois que tu utilises le même GPIO35 pour un pulse_counter (« Précipitation horaire ») et un pulse_meter (« Précipitation journalière »), là j’ai du mal à comprendre. Peux-tu m’éclairer là dessus ? Je te remercie.
Dans la semaine je vais commander les composants nécessaires, anémométre, pluviométre, BH1750… je te tiens au courant.
Merci encore pour ton partage et ton aide.
Salutations.

Je crois avoir trouvé l’erreur. Je recompile, je te tiens au courant. A+