Station météo

Bonsoir à tous,

Je vous partage un petit projet de station météo en cours de réalisation. Une majorité du projet est de la récup.


  • Les capteurs sur mat sont une récup de déchetterie, l’anémomètre était cassé (env. 20€ sur ali, fdp incl.), j’ai juste oublié le bouclier Stevenson donc à venir.
  • Dans le boitier qui est de récup au taff, une pile 18V 15Ah qui contient 12 piles type « D » 1.5V donc petit atelier mise en dérivation d’ensemble de 3 piles série et paf ça donne une pile 4.5V. Le bornier c’est du fond de tiroir. Seule la partie électronique (prototype) est « presque » neuve.

Pour le code, sous ESPhome, j’ai un peux fouillé à droite et a gauche sur le web et j’ai tout mixé avec des ajouts pour m’entrainer aux fonctions ESPhome.

#####################
## CONFIG:
## INA 3221 Puissance, Tension et Intensité du circuit
## WH-SP-WS02 Anémomètre, Girouette et Pluviomètre
## BME280 Température, Humidité et Pression atmosphérique
## BH1750 intensité lumineuse
## en cours ADS1115 Multiplexeur Analog>I²C
## à faire SI1145 Ultraviolets librairie à ajouter
## à faire SDS011 Particules fines
## à faire MHZ19 CO2
## à faire Geiger
#####################
## CONFIG E/S
## A0 - ADC0   - Girouette
## D0 - GPIO16 -
## D1 - GPIO5  - I²C SCL
## D2 - GPIO4  - I²C SDA
## D3 - GPIO0  - Pluviomètre
## D4 - GPIO2  - Anémomètre
## D5 - GPIO14
## D6 - GPIO12  
## D7 - GPIO13
## D8 - GPIO15
#####################
## ADRESSES I²C
## 0x23 BH1750
## 0x40 INA3221
## 0x48 ADS1115
## 0x76 BME280
substitutions:
  system_name: weatherstation
  friendly_name: Station Météo
  device_description: "Station Météo"

packages:
  device: !include devices/esp01_1m.yaml

i2c:
  frequency: 100kHz

ads1115:
  - address: 0x48

#####################
## SENSORS:
#####################

sensor:

  #####################
  ## WIFI
  #####################
    
  - platform: ina3221
    address: 0x40
    channel_1:
      shunt_resistance: 0.1 ohm
      current:
        name: "INA3221 Channel 1 Current"
      power:
        name: "INA3221 Channel 1 Power"
      bus_voltage:
        name: "INA3221 Channel 1 Bus Voltage"
      shunt_voltage:
        name: "INA3221 Channel 1 Shunt Voltage"
    #channel_2:
      # ...
    #channel_3:
      # ...
    update_interval: 60s
    
  - platform: uptime
    name: Uptime Sensor
    id: uptime_sensor
    update_interval: 60s
    on_raw_value:
      then:
        - text_sensor.template.publish:
            id: uptime_human
            state : !lambda |-
              int seconds = round(id(uptime_sensor).raw_state);
              int days = seconds / (24 * 3600);
              seconds = seconds % (24 * 3600);
              int hours = seconds / 3600;
              seconds = seconds % 3600;
              int minutes = seconds /  60;
              seconds = seconds % 60;
              return (
                (days ? to_string(days) + "d " : "") +
                (hours ? to_string(hours) + "h " : "") +
                (minutes ? to_string(minutes) + "m " : "") +
                (to_string(seconds) + "s")
              ).c_str();
    
  - platform: ads1115
    multiplexer: 'A0_GND'
    gain: 4.096
    name: "ADS1115 Channel A0-GND"
    
  #####################
  ## CLIMAT EXT
  #####################

  - platform: bme280
    temperature:
      name: "Température extérieure"
      id: bme280_temperature
      oversampling: 16x
    pressure:
      name: "Pression atmosphérique"
      id: bme280_pressure
    humidity:
      name: "Humidité extérieure"
      id: bme280_humidity
    address: 0x76
    update_interval: 60s
    
  - platform: template
    name: "Altitude"
    lambda: |-
      const float STANDARD_SEA_LEVEL_PRESSURE = 1013.25; //in hPa, see note
      return ((id(bme280_temperature).state + 273.15) / 0.0065) *
        (powf((STANDARD_SEA_LEVEL_PRESSURE / id(bme280_pressure).state), 0.190234) - 1); // in meter
    update_interval: 15s
    icon: 'mdi:signal'
    unit_of_measurement: 'm'
    
  - platform: template
    name: "Humidité absolue"
    lambda: |-
      const float mw = 18.01534;    // molar mass of water g/mol
      const float r = 8.31447215;   // Universal gas constant J/mol/K
      return (6.112 * powf(2.718281828, (17.67 * id(bme280_temperature).state) /
        (id(bme280_temperature).state + 243.5)) * id(bme280_humidity).state * mw) /
        ((273.15 + id(bme280_temperature).state) * r); // in grams/m^3
    accuracy_decimals: 2
    update_interval: 15s
    icon: 'mdi:water'
    unit_of_measurement: 'g/m³'
    
  - platform: template
    name: "Point de rosée"
    lambda: |-
      return (243.5*(log(id(bme280_humidity).state/100)+((17.67*id(bme280_temperature).state)/
      (243.5+id(bme280_temperature).state)))/(17.67-log(id(bme280_humidity).state/100)-
      ((17.67*id(bme280_temperature).state)/(243.5+id(bme280_temperature).state))));
    unit_of_measurement: °C
    icon: 'mdi:thermometer-alert'
    
  - platform: template
    name: "Pression relative 1"
    icon: "mdi:gauge"
##formule esphome.io possiblement fausse
    lambda: |-
      const float STANDARD_ALTITUDE = 8; // en metres
      return id(bme280_pressure).state / powf(1 - ((0.0065 * STANDARD_ALTITUDE) /
        (id(bme280_temperature).state + (0.0065 * STANDARD_ALTITUDE) + 273.15)), 5.257); // in hPa
    update_interval: 15s
    unit_of_measurement: 'hPa'
    
  - platform: template
    name: "Pression relative 2"
    icon: "mdi:gauge"
##formule possiblement vraie
    lambda: |-
      const float STANDARD_ALTITUDE = 8; // in meters, see note
      return (id(bme280_pressure).state)/powf((1-((float)(STANDARD_ALTITUDE))/44330), 5.255);
    update_interval: 60s
    unit_of_measurement: 'hPa'

      
  #####################
  ## LUMIOSITE EXT
  #####################
  
  - platform: bh1750
    name: "Luminosité"
    address: 0x23
    update_interval: 60s

  #####################
  ## ANEMOMETRE
  #####################

  - platform: pulse_counter
    pin:
      number: GPIO2
      mode: INPUT_PULLUP
    unit_of_measurement: 'm/s'
    name: "vent vitesse m/s"
    id: wind_meter_mps
    icon: 'mdi:weather-windy'
    count_mode:
      rising_edge: DISABLE
      falling_edge: INCREMENT
    internal_filter: 13us
    update_interval: 60s
    ## rotations_par_sec = impulsions / 2 / 60
    ## circ_m = 0.09 * 2 * 3.14 = 0.5652
    ## mps = 1.18 * circ_m * rotations_par_sec
    ## mps = 1.18 * 0.5652 / 2 / 60 = 0.0055578
    filters:
      - multiply: 0.0055578
      #- sliding_window_moving_average:
      #    window_size: 2
      #    send_every: 1
      
  - platform: template
    name: 'vent vitesse km/h'
    icon: 'mdi:weather-windy'
    id: wind_meter_kmph
    lambda: return id(wind_meter_mps).state;
    unit_of_measurement: 'km/h'
    ## convertion des m/s en km/h pour une meilleure perception de la vitesse
    ## 1 m/s = 3.6 km/h
    filters:
      - multiply: 3.6
      
  - platform: template
    name: 'vent vitesse noeud'
    icon: 'mdi:weather-windy'
    id: wind_meter_knot
    lambda: return id(wind_meter_mps).state;
    unit_of_measurement: 'nd'
    update_interval: 60s
    ## convertion des m/s en noeud avec indication de l'échelle de Beaufort
    ## 1 m/s = 1.94384 nd
    filters:
#      - throttle_average: 5s
      - multiply: 1.94384
    on_value:
      lambda: |-
        if (id(wind_meter_knot).state < 1) {
          id(wind_scale).publish_state("Calme");
        } else if (id(wind_meter_knot).state >= 1 && id(wind_meter_knot).state < 3) {
          id(wind_scale).publish_state("Très légère brise");
        } else if (id(wind_meter_knot).state >= 3 && id(wind_meter_knot).state < 7) {
          id(wind_scale).publish_state("Légère brise");
        } else if (id(wind_meter_knot).state >= 7 && id(wind_meter_knot).state < 11) {
          id(wind_scale).publish_state("Petite brise");
        } else if (id(wind_meter_knot).state >= 11 && id(wind_meter_knot).state < 16) {
          id(wind_scale).publish_state("Jolie brise");
        } else if (id(wind_meter_knot).state >= 16 && id(wind_meter_knot).state < 21) {
          id(wind_scale).publish_state("Bonne brise");
        } else if (id(wind_meter_knot).state >= 21 && id(wind_meter_knot).state < 27) {
          id(wind_scale).publish_state("Vent frais");
        } else if (id(wind_meter_knot).state >= 27 && id(wind_meter_knot).state < 34) {
          id(wind_scale).publish_state("Grand frais");
        } else if (id(wind_meter_knot).state >= 34 && id(wind_meter_knot).state < 41) {
          id(wind_scale).publish_state("Coup de vent");
        } else if (id(wind_meter_knot).state >= 41 && id(wind_meter_knot).state < 48) {
          id(wind_scale).publish_state("Fort coup de vent");
        } else if (id(wind_meter_knot).state >= 48 && id(wind_meter_knot).state < 56) {
          id(wind_scale).publish_state("Tempête");
        } else if (id(wind_meter_knot).state >= 56 && id(wind_meter_knot).state < 64) {
          id(wind_scale).publish_state("Violente tempête");         
        } else if (id(wind_meter_knot).state >= 64) {
          id(wind_scale).publish_state("Ouragan");
        } else {
          id(wind_scale).publish_state("Null");
        }

  #####################
  ## PLUVIOMETRE
  #####################

  - platform: pulse_counter
    pin:
      number: GPIO0
      mode: INPUT_PULLUP
    unit_of_measurement: 'mm'
    name: "pluviomètre"
    icon: 'mdi:weather-rainy'
    id: rain_gauge
    internal: true
    count_mode:
      rising_edge: DISABLE
      falling_edge: INCREMENT
    internal_filter: 13us
    update_interval: 60s
    filters:
      # Each 0.011" (0.2794mm) of rain causes one momentary contact closure
      - multiply: 0.2794
    accuracy_decimals: 4

  - platform: integration
    name: "pluie par min"
    id: rain_per_min
    time_unit: min
    unit_of_measurement: 'mm'
    icon: 'mdi:weather-rainy'
    sensor: rain_gauge

  - platform: total_daily_energy
    name: "pluie journalière"
    power_id: rain_gauge
    unit_of_measurement: 'mm'
    icon: 'mdi:weather-rainy'
    # x60 To convert to aggregated rain amount
    filters:
      - multiply: 60
      
  #####################
  ## GIROUETTE
  #####################

  - platform: adc
    id: source_sensor
    pin: A0
    name: ADC
    internal: true
    update_interval: 60s
    accuracy_decimals: 1
    filters:
      - multiply: 0.846153 # 3.9 -> 3.3V


  - platform: resistance
    sensor: source_sensor
    id: resistance_sensor
    configuration: DOWNSTREAM
    resistor: 10kOhm
    internal: true
    name: Resistance Sensor
    reference_voltage: 3.9V
    accuracy_decimals: 1
    filters:
      - median:
          window_size: 7
          send_every: 4
          send_first_at: 3
      - heartbeat: 30s
    on_value:
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 2061
              below: 2082
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "N"
            - sensor.template.publish:
                id: wind_heading
                state: 0.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 987
              below: 1008
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "NNE"
            - sensor.template.publish:
                id: wind_heading
                state: 22.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 1130
              below: 1150
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "NE"
            - sensor.template.publish:
                id: wind_heading
                state: 45.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 193
              below: 212
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "ENE"
            - sensor.template.publish:
                id: wind_heading
                state: 67.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 215
              below: 234
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "E"
            - sensor.template.publish:
                id: wind_heading
                state: 90.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 153
              below: 174
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "ESE"
            - sensor.template.publish:
                id: wind_heading
                state: 112.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 432
              below: 453
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "SE"
            - sensor.template.publish:
                id: wind_heading
                state: 135.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 288
              below: 309
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "SSE"
            - sensor.template.publish:
                id: wind_heading
                state: 157.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 683
              below: 704
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "S"
            - sensor.template.publish:
                id: wind_heading
                state: 180.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 575
              below: 596
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "SSO"
            - sensor.template.publish:
                id: wind_heading
                state: 202.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 1592
              below: 1613
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "SO"
            - sensor.template.publish:
                id: wind_heading
                state: 225.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 1505
              below: 1526
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "OSO"
            - sensor.template.publish:
                id: wind_heading
                state: 247.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 2556
              below: 2577
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "O"
            - sensor.template.publish:
                id: wind_heading
                state: 270.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 2183
              below: 2204
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "ONO"
            - sensor.template.publish:
                id: wind_heading
                state: 292.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 2368
              below: 2389
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "NO"
            - sensor.template.publish:
                id: wind_heading
                state: 315.0
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 1810
              below: 1831
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "NNO"
            - sensor.template.publish:
                id: wind_heading
                state: 337.5
      - if:
          condition:
            sensor.in_range:
              id: resistance_sensor
              above: 2770
              below: 2780
          then:
            - text_sensor.template.publish:
                id: wind_dir_card
                state: "erreur"
            - sensor.template.publish:
                id: wind_heading
                state: "400"

  - platform: template
    name: "vent angle"
    id: wind_heading
    unit_of_measurement: "°"
    
  - platform: template
    name: "résistance anémomètre"
    id: resistance_sensor_value
    lambda: return id(resistance_sensor).state;
    unit_of_measurement: 'ohm'

#####################
## TEXT SENSOR
#####################

text_sensor:

  #####################
  ## ECHELLE DE BEAUFORT
  #####################
  
  - platform: template
    name: 'vent échelle de Beaufort'
    icon: 'mdi:tailwind'
    id: wind_scale
    update_interval: 60s

  #####################
  ## VENT VITESSE
  #####################
  
  - platform: template
    name: "vent direction cardinale"
    id: wind_dir_card
    update_interval: 60s
    
  - platform: template
    name: Uptime Human Readable
    id: uptime_human
    icon: mdi:clock-start
    
  
#####################
## INTERVAL
#####################

interval:
  - interval: 60s
    then:
      - sensor.integration.reset: rain_per_min

Le projet va évoluer : capteur UV, gaz, … Si vous avez des idées je suis preneur et si vous trouvez des erreurs je suis prenneur également.

[MàJ 22-04-22 Mise à dispo du câblage]
Voici le câble de la V1


Le schéma fritzing est pour le principe les couleurs ne correspondent pas à la réalité et les contacts reed symbolisent les capteurs. Les couleurs sont spécifiées dans la partie borniers dans le schéma ci dessous.

11 « J'aime »

Bonjour
FELICITATION, elle est superbe ; on a hâte de voir de belles courbes !!

perso, j ai mis un petit hygromètre chez moi, c’est marrant. (une DHT22 one-wire)
Pourquoi une alim en 18V ?

C’est une pile que j’avais sous la main et que je peux avoir facilement. Elle est composée de 12 piles 1.5V de type D qui étaient en série. Come l’ESP peux tourner en 4.5V j’ai coupé les nappes des pilles par groupe de 3 pour avoir une tension de 4.5V et avec la mise en parallèle je peux utiliser la pile entière. Je voulais éviter d’utiliser un circuit abaisseur de type LM1117 5V car plus on ajoute de composants dans un circuit plus augmente ca conso.

Salut,
Trés joli :slight_smile:
J’ai a peu près la mème chose avec luminosité, température, humidité, pression, CO2, particule fines et compteur geiger.
Tu as prévu un retour d’état pour tes piles afin de savoir quand elles commences à être faibles?

Bonjour,
Ce boitier est très propre ! C’est beau à voir :star_struck:
Comptes tu installer un pluviomètre ?

Je serais intéressé par les capteurs que tu as installé. Le retour d’état de la pile est prévu pour la V2 avec un esp32 car le wemos a seulement une entrée analogique qui est déjà prise par le pluviometre

Il est déjà en place

Bonjour

Sacré projet et surtout très propre

Pour info l’ads1115 est un quadruple CAN qui est branché en I²C
L’avantage de la bête c’est qui peut être utilisé en différentiel, et surtout il a un gain variable et surtout il est géré pas ESPHOME

cordialement

température, humidité et pression : BME280
luminosité : BH1750
particules fines : SDS011
CO2 : MHZ19
Geiger : je ne me rappel plus du modèle exact mais c’était dans ce style : Vente Geekcreit Assembled Compteur Geiger Module Miller Tube GM Tube Nuclear Radiation Geekcreit for Arduino - produits compatibles avec les cartes officielles Arduino - Banggood Français

pour le geiger,
voir la video de beardedthinker

merci pour les infos et l’ads1115, c’est magique, on peux gagner jusqu’à 16 entrées analog.

l’ADS1115 peut-il servir pour faire du pulse counter ? car cela permettrai d’avoir seulement 4 fil pour tous les capteurs sur mat avec l’i2c

Bonjour
L’ads 1115 n’est « qu"un ADC »
en Faisant une recherche pulse counter et i2c je n’ai trouvé que des watchdog.
mais il me semble que les ESP32 en ont 8 des entree timers

sinon un cable reseau ou telecom ferait l’affaire non ?

Salut @Greg-au-riz

J’avais raté ce sujet… De quoi recycler les capteurs de ma station météo misol

Merci à toi

J’ai eu pas mal des soucis avec le Ads1115 sous esphome qui dépend de l’ArduinoPortExpander.

J’ai même ouvert un ticket dans ce github >> glmnet/esphome_devices/issues/4

Par contre effectivement très intéressant d’avoir la possibilité de plusieurs entrées analogiques.

le pulse counter avec un ads1115 est impossible car le pulse counter est fait pour compter des impulsions analogiques et l’ads1115 envoie du numérique.
par contre l’ArduinoPortExpander permet de connecter un arduino nano en i2c et je doit étudier la question

Je suis à la recherche de capteurs pluviométrie, anemometre, et direction du vent, personne n’aurait un bon plan pour pas y mettre trop cher ?
Ils faudrait qu’ils puissent être intégrables dans HA facilement via un ESP32 sans trop d’électronique :wink:

Les capteurs que j’utilise sont dispo sur aliexpress. Ils sont entre 20 et 30€ pièce.

Le code est largement simpliable pour tes besoins.

Au besoin contacte moi par MP.

Salut, super station, bravo !

Pourrais-tu nous poster les liens pour l’anemomètre, le pluviomètre ainsi que la girouette ? :slight_smile:

Merci

salut, merci, je vais bientôt me remettre a la tache pour l’améliorer et régler quelques problèmes.

Jai trouvé les capteurs en déchetterie mais j’ai racheté un anémomètre et un abri stevenson voici les liens.

Anémomètre, Instrument de mesure de la vitesse du vent, capteur de vitesse du vent, Instrument météorologique, accessoires pour anémomètre Misol, WH SP WS01 | AliExpress

TFA-Dostmann Housse de Protection pour émetteur extérieur, 98.1114.02, Facile à Monter, Blanc, protège l’émetteur du Soleil et de la Pluie 10,2 x 9,5 x 17,5 cm : Amazon.fr: Bricolage tu peux le trouver moins cher en avril il était à environ 17€