ESP Home AirCan mesure de la qualité de l'air

Bonjour à tous,

Du temps ou j’étais sur domoticz, j’avais fait un AirCan (mesure de la qualité de l’air ) qui fonctionnait à merveille sous ESP Easy mis au point par StephDes. https://easydomoticz.com/forum/viewtopic.php?t=5520
les mesures concernaient CO2-température-hygrométrie-poussière PM10 - PM 2,5 et comportait un affichage sur 3 lignes des valeurs.
Enfin, un ruban de 3 LED WS2812 permettait un visuel rapide de la qualité de l’air:
Très bon : bleu foncé
Bon : bleuté
Moyen : vert
Médiocre : jaune
Mauvais : orange
Très mauvais : rouge

Depuis, j’ai migré avec bonheur sur HA et je commence a bidouiller mes premier modules sous ESP home.

J’aurais souhaité migrer aussi mon AirCan sous HA avec ESP Home mais je crains d’avoir vu un peu grand pour mon niveau.

Je galère avec mon code montré ci dessous:

esphome:
  name: aircan3
  friendly_name:  AirCan3

esp32:
  board: esp32dev
  framework:
    type: arduino

# Enable logging
logger:

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

ota:
  password: "**************************************"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Aircan3 Fallback Hotspot"
    password: "HEOldXfPtXCd"

uart: #*********** premiers tests pour l'afficheur avant que je lise https://esphome.io/components/display/ssd1306
  - id: sensor_1
    rx_pin: GPIO0
    baud_rate: 9600
  - id: sensor_2 
    rx_pin: GPIO14
    tx_pin: GPIO12
    baud_rate: 9600      

captive_portal:

i2c:
  sda: D1
  scl: D2

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
    reset_pin: D0
    address: 0x3C
    lambda: |-
      it.print(0, 0, id(font), "Hello World!"); # que marquer pour récupérer valeurs ?

sensor:
  - platform: mhz19
    co2:
      name: "CO2"
    temperature:
      name: "CO2 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false  

  - platform: dht
    pin: GPIO16
    temperature:
      name: "Temp AirCan"
    humidity:
      name: "Humidité AirCan"
    update_interval: 60s        

  - platform: sds011
    pm_2_5:
      name: "Particules <2.5µm Concentration"
    pm_10_0:
      name: "Particules <10.0µm Concentration"
    update_interval: 5min
  

#light:****** là, je ne sais pas encore; ce sera le dernier truc auquel je m'attaquerai !
#  - platform: neopixelbus
#    type: RGB
#    variant: WS2811
#    pin: GPIO15
#    num_leds: 3
#    name: "AirCan LED"
#  - platform: binary
#    name: "SenseNode D4Led"
#    output: D4led
#    id: aircanled   

ci dessous les erreurs générées:

INFO ESPHome 2023.11.6
INFO Reading configuration /config/esphome/aircan3.yaml...
Failed config

display.ssd1306_i2c: [source /config/esphome/aircan3.yaml:45]
  platform: ssd1306_i2c
  model: SSD1306_64X48
  reset_pin: 
    number: 16
    mode: 
      output: True
      analog: False
      input: False
      open_drain: False
      pullup: False
      pulldown: False
    inverted: False
  address: 0x3C
  
  Couldn't find ID 'font'. Please check you have defined an ID with that name in your configuration.
  lambda: !lambda |-
    it.print(0, 0, id(font), "Hello World!"); # que marquer pour récupérer valeurs ?
  auto_clear_enabled: True
  brightness: 1.0
  contrast: 1.0
  flip_x: True
  flip_y: True
  offset_x: 0
  offset_y: 0
  invert: False
  update_interval: 1s
sensor.mhz19: [source /config/esphome/aircan3.yaml:53]
  
  Too many candidates found for 'uart_id' type 'uart::UARTComponent' Some are 'sensor_1', 'sensor_2'.
  platform: mhz19
  co2: 
    name: CO2
    disabled_by_default: False
    force_update: False
    unit_of_measurement: ppm
    icon: mdi:molecule-co2
    accuracy_decimals: 0
    device_class: carbon_dioxide
    state_class: measurement
  temperature: 
    name: CO2 Temperature
    disabled_by_default: False
    force_update: False
    unit_of_measurement: °C
    accuracy_decimals: 0
    device_class: temperature
    state_class: measurement
  update_interval: 60s
  automatic_baseline_calibration: False
sensor.sds011: [source /config/esphome/aircan3.yaml:69]
  
  Too many candidates found for 'uart_id' type 'uart::UARTComponent' Some are 'sensor_1', 'sensor_2'.
  platform: sds011
  pm_2_5: 
    name: Particules <2.5µm Concentration
    disabled_by_default: False
    force_update: False
    unit_of_measurement: µg/m³
    icon: mdi:chemical-weapon
    accuracy_decimals: 1
    device_class: pm25
    state_class: measurement
  pm_10_0: 
    name: Particules <10.0µm Concentration
    disabled_by_default: False
    force_update: False
    unit_of_measurement: µg/m³
    icon: mdi:chemical-weapon
    accuracy_decimals: 1
    device_class: pm10
    state_class: measurement
  update_interval: 5min
  rx_only: False

J’ai été voir comment paramétrer l’UART (Custom UART Device — ESPHome) mais comme j’en ai deux (UART on est d’accord hein ? :upside_down_face:) … je manque d’exemples et je reste bloqué là…

Je crois avoir lu quelque part qu’il fallait que je précise quelle police je devais utiliser

Si quelqu’un n’est pas rebuté par ce texte trop long et veut bien me donner un coup de main ce ne serait pas de refus ! :pray:

En bonus si quelqu’un veut se lancer, la liste du matos:
1x WEMOS D1 mini (ou ESP8266)
1 x DHT 22
1 x module CO2 MH-Z19 de 0 à 2000 PPM ou de 0 à 5000 PPM
1 x module mesure poussière laser SDS011
1 x Shield OLED 0,48" WEMOS
3 x LED WS2812

et le plan de câblage:

Bj

la tu as un souci avec font qui est pas défini

le souci est ici

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
    reset_pin: D0
    address: 0x3C
    lambda: |-
      it.print(0, 0, id(font), "Hello World!"); # que marquer pour récupérer valeurs ?

remplace par

      it.print(0, 0, font_value, "Hello World!")

et tu dois mettre un code comme ceci , si je dis pas de betise

font:
  - file: "Comic Sans MS.ttf"
    id: my_font
    size: 20

Merci Nothing ! :+1:
J’ai donc modifié avec les lignes de code que tu m’as proposé (avec la police Nirmala.ttf) et effectivement, côté afficheur je n’ai plus de problèmes, ça semble réglé !
Ouf ça avance !

En ce qui concerne l’UART j’ai réalisé qu’il manquait l’ID UART à la fin de chaque sensors pour qu’il puisse « trier les patates ».
Donc ça aussi c’est réglé !

Je finis donc avec l’allumage des LED et en parallèle je commence l’interprétation des données qui permettront d’allumer les LED en fonction de la qualité de l’air intérieur.

Si mes neurones ramollies par les années me permettent d’aller au bout, je me propose de faire un tuto et de le poster sur le forum, qui sait ? Ca pourrait peut être intéresser quelqu’un ?

Le code fonctionnel en l’état (sans allumage des LED):

esphome:
  name: aircan3
  friendly_name:  AirCan3

esp8266:
  board: d1_mini


# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "zIx4aibcI+oHWqtYgbyvzmYwCr+qrULGqFYeQ5vvwKs="

ota:
  password: "d680a850938f9ad0cf052188768f9d35"

wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Aircan3 Fallback Hotspot"
    password: "HEOldXfPtXCd"

uart:
  - id: CO2
    rx_pin: GPIO0
    baud_rate: 9600
  - id: pm
    rx_pin: GPIO14
    tx_pin: GPIO12
    baud_rate: 9600      

captive_portal:

i2c:
  sda: D1
  scl: D2

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
    reset_pin: D0
    address: 0x3C
    lambda: |-
      it.print(0, 0, font_value, "Hello World!")

font:
  - file: "Nirmala.ttf"
    id: my_font
    size: 20      

sensor:
  - platform: mhz19
    co2:
      name: "CO2"
    temperature:
      name: "CO2 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false  
    uart_id: CO2

  - platform: dht
    pin: GPIO16
    temperature:
      name: "Temp AirCan"
    humidity:
      name: "Humidité AirCan"
    update_interval: 60s        

  - platform: sds011
    pm_2_5:
      name: "Particules <2.5µm Concentration"
    pm_10_0:
      name: "Particules <10.0µm Concentration"
    update_interval: 5min  
    uart_id: pm 

  

#light:
#  - platform: neopixelbus
#    type: RGB
#    variant: WS2811
#    pin: GPIO15
#    num_leds: 3
#    name: "AirCan LED"
#  - platform: binary
#    name: "SenseNode D4Led"
#    output: D4led
#    id: aircanled

[EDIT] Ci dessous la logique d’allumage et d’affichage des LED:

# valeur_PM10 vers coefpm10

if (val_10 < 13) then coefpm10 = 1
elseif ( 12 < val_10) and (val_10 < 27) then coefpm10 = 2
elseif ( 26 < val_10) and (val_10 < 34) then coefpm10 = 3
elseif ( 33 < val_10) and (val_10 < 49) then coefpm10 = 4
elseif ( 48 < val_10) and (val_10 < 79) then coefpm10 = 5
elseif ( val_10 > 78) then coefpm10 = 6
end

# valeur_PM25 vers coefpm25

if (val_25 < 23) then coefpm25 = 1
elseif ( 22 < val_25) and (val_25 < 41) then coefpm25 = 2
elseif ( 40 < val_25) and (val_25 < 47) then coefpm25 = 3
elseif ( 46 < val_25) and (val_25 < 58) then coefpm25 = 4
elseif ( 57 < val_25) and (val_25 < 69) then coefpm25 = 5
elseif ( val_10 > 68) then coefpm25 = 6
end

# valeur val_iqa retenue (qui de coefpm10 ou de coefpm25 a la valeur la plus haute)

if (coefpm10 > coefpm25) then val_iqa = coefpm10
elseif (coefpm10 < coefpm25) then val_iqa = coefpm25
else val_iqa = coefpm10
end

# attribution d'une note en fonction de la valeur CO2

if (val_co2 > 900) and (val_co2 < 1000) then val_iqa = 3
elseif (val_co2 <= 4) and (val_co2 > 999) and (val_co2 < 1100) then val_iqa = 4
elseif (val_co2 <= 5) and (val_co2 > 1099) and (val_co2 < 1500) then val_iqa = 5
elseif (val_co2 <= 6) and (val_co2 > 1499) then val_iqa = 6   
end

# Interprétation pour un afficher le contenu dans une carte du dashboard

if val_iqa == 1 then texte = 'TRES BON'
elseif val_iqa == 2 then texte = 'BON'
elseif val_iqa == 3 then texte = 'MOYEN'
elseif val_iqa == 4 then texte = 'MEDIOCRE'
elseif val_iqa == 5 then texte = 'MAUVAIS'
elseif val_iqa == 6 then texte = 'TRES MAUVAIS'
end

# Allumage des LED en fonction de la note

if val_iqa == 1 then commandArray[3]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,0,0,255' }
elseif val_iqa == 2 then commandArray[4]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,0,127,255' }
elseif val_iqa == 3 then commandArray[5]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,0,125,0' }
elseif val_iqa == 4 then commandArray[6]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,180,120,0' }
elseif val_iqa == 5 then commandArray[7]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,231,62,1' }
elseif val_iqa == 6 then commandArray[8]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,255,0,0' }
end 
 

C’est du LUA, si un dompteur de YAML passait dans le coin, ce serait sympa qu’il me mette sur la voie !

J’imagine que vu les capacités limitées du wemos, le calcul doit être fait par HA et c’est lui qui donne l’ordre au wemos d’allumer les LED avec une certaine couleur ? :thinking:

Allez, après pause COVID je m’y remets et j’en profite pour faire un petit up … au cas où…
J’ai un souci récurrent avec l’afficheur mais ce n’est pas la priorité alors je l’ai désactivé ainsi que la police.
Il faut que je règle mon problème d’UART d’abord: [EDIT] problème réglé mais ne dites à personne que je suis une buse!
2023-12-19_113735
Toutes les valeurs sont là!
Je me recolle a l’afficheur
Si quelqu’un pouvait me mettre sur la voie :sweat:

Je poursuis :yum:: dernière étape l’allumage des LEDs et la rédaction du tuto !

Ci dessous le code fonctionnel. Tous les capteurs sont pris en compte et les infos sont affichées sur le petit LCD:
Page 1 Titre-heure-temp-humidité
Page 2 Titre-CO2
Page 3 Titre-Particules 2.5-Particules 10

Le code si ça intéresse quelqu’un :

Résumé
# AIRCAN fonctionnel avec écran et rotation info sur 3 pages
esphome:
  name: esphome-web-19013f
  friendly_name: AirCan3 DEV

esp8266:
  board: d1_mini

# Enable logging
logger:

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

ota:


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esphome-Web-19013F"
    password: "***************"

uart:
  - id: CO2
    rx_pin: GPIO14
    tx_pin: GPIO12
    baud_rate: 9600
  - id: pm
    tx_pin: GPIO2
    rx_pin: GPIO0
    
    baud_rate: 9600      

captive_portal:

i2c:
  sda: D2
  scl: D1

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
#    reset_pin: D0
    address: 0x3C
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "Air Can 3");
          it.strftime(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "%H:%M:%S", id(esptime).now());
          if (id(temp).has_state()) {
           it.printf(0, 33, id(my_font), TextAlign::BASELINE_LEFT, "Temp %.1f ", id(temp).state);
          }
           if (id(temp).has_state()) {
          it.printf(0, 44, id(my_font), TextAlign::BASELINE_LEFT, "Hum %.1f ", id(hum).state);
          }

          
      - id: page2
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "CO 2");
          if (id(temp).has_state()) {
            it.printf(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "%.1f ppm", id(co2).state);
          }

      - id: page3
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "Poussieres");
          if (id(temp).has_state()) {
            it.printf(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "2,5- %.1f ppm", id(pm25).state);
          }
          if (id(temp).has_state()) {
            it.printf(0, 33, id(my_font), TextAlign::BASELINE_LEFT, "10- %.1f ppm", id(pm10).state);
          }
    


# For example cycle through pages on a timer
interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display



font:
  - file: 'Nirmala.ttf'
    id: my_font
    size: 12   

time:
  - platform: homeassistant
    id: esptime

sensor:
  - platform: mhz19
    co2:
      name: "CO2"
      id: co2
    temperature:
      name: "CO2 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false  
    uart_id: CO2

  - platform: dht
    pin: GPIO16
    temperature:
      name: "Temp AirCan"
      id: temp
    humidity:
      name: "Humidité AirCan"
      id: hum
    update_interval: 60s        

  - platform: sds011
    pm_2_5:
      name: "Particules <2.5µm Concentration"
      id: pm25
    pm_10_0:
      name: "Particules <10.0µm Concentration"
      id: pm10
    uart_id: pm 
    rx_only: True
   
  

light:
  - platform: neopixelbus
    type: GRB
    variant: WS2812
    pin: GPIO15
    num_leds: 3
    name: "LED"      
    effects:
      - pulse:
          name: "Slow Pulse"
          # transition_length: 1s      # defaults to 1s
          update_interval: 2s

web_server: # creates a web server where you can access all this stuff without home assistant (good for debugging or working headless (no HA))
  port: 80
  include_internal: true
  ota: true

binary_sensor: # exposes online status
  - platform: status
    name: "Sensor Status"

text_sensor:
  - platform: wifi_info
    ip_address: # exposes the IP Address when connected
      internal: true
      id: wifi_ip_addr
      name: "IP Address"
    ssid: # exposes the SSID when connected
      internal: true
      id: wifi_ssid

Il me reste plus qu’ a faire une automation qui allume les LED en fonction du niveau de pollution.

Au passage, un dieu du code pour me filer un coup de main ?

Je ne suis pas un dieu du code mais regarde la

https://forum.hacf.fr/t/pms5003-dans-boitier-ikea-vindriktning/23407

Wow c’est super ce que tu as fait !
Mais je ne sais pas trop si le wemos sera à même de gérer ce script ou si ce sera trop pour lui ?

Cae je voudrais essayer de me baser sur la pire valeur pour allumer les LED en conséquence.
Un truc de ce genre :

Résumé
# valeur_PM10 vers coefpm10

if (val_10 < 13) then coefpm10 = 1
elseif ( 12 < val_10) and (val_10 < 27) then coefpm10 = 2
elseif ( 26 < val_10) and (val_10 < 34) then coefpm10 = 3
elseif ( 33 < val_10) and (val_10 < 49) then coefpm10 = 4
elseif ( 48 < val_10) and (val_10 < 79) then coefpm10 = 5
elseif ( val_10 > 78) then coefpm10 = 6
end

# valeur_PM25 vers coefpm25

if (val_25 < 23) then coefpm25 = 1
elseif ( 22 < val_25) and (val_25 < 41) then coefpm25 = 2
elseif ( 40 < val_25) and (val_25 < 47) then coefpm25 = 3
elseif ( 46 < val_25) and (val_25 < 58) then coefpm25 = 4
elseif ( 57 < val_25) and (val_25 < 69) then coefpm25 = 5
elseif ( val_10 > 68) then coefpm25 = 6
end

# valeur val_iqa retenue (qui de coefpm10 ou de coefpm25 a la valeur la plus haute)

if (coefpm10 > coefpm25) then val_iqa = coefpm10
elseif (coefpm10 < coefpm25) then val_iqa = coefpm25
else val_iqa = coefpm10
end

# attribution d'une note en fonction de la valeur CO2

if (val_co2 > 900) and (val_co2 < 1000) then val_iqa = 3
elseif (val_co2 <= 4) and (val_co2 > 999) and (val_co2 < 1100) then val_iqa = 4
elseif (val_co2 <= 5) and (val_co2 > 1099) and (val_co2 < 1500) then val_iqa = 5
elseif (val_co2 <= 6) and (val_co2 > 1499) then val_iqa = 6   
end

# Interprétation pour un afficher le contenu dans une carte du dashboard

if val_iqa == 1 then texte = 'TRES BON'
elseif val_iqa == 2 then texte = 'BON'
elseif val_iqa == 3 then texte = 'MOYEN'
elseif val_iqa == 4 then texte = 'MEDIOCRE'
elseif val_iqa == 5 then texte = 'MAUVAIS'
elseif val_iqa == 6 then texte = 'TRES MAUVAIS'
end

# Allumage des LED en fonction de la note

if val_iqa == 1 then commandArray[3]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,0,0,255' }
elseif val_iqa == 2 then commandArray[4]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,0,127,255' }
elseif val_iqa == 3 then commandArray[5]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,0,125,0' }
elseif val_iqa == 4 then commandArray[6]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,180,120,0' }
elseif val_iqa == 5 then commandArray[7]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,231,62,1' }
elseif val_iqa == 6 then commandArray[8]={['OpenURL'] = ip_sens..'/control?cmd=NeoPixelAll,255,0,0' }
end

Crois-tu que ce soit faisable avec un wemos D1 Mini ?

J’ai une ESP8266 donc je pense que oui.

Pour le code je ne sais pas te répondre. il faut tester

Merci @Sweepy !
Effectivement, le Wemos D1 encaisse tout ça, bien vu et surtout merci, tu m’as débloqué quelques cases ! (comme quoi, il ne faut jamais désespérer !) :yum:

Ci dessous le code ESPhome avec
l’afficheur
l’allumage autonome des LED en fonction des valeurs CO2-Particules 2.5 et 10.

Code
# AIRCAN fonctionnel avec écran et LED
esphome:
  name: esphome-web-19013f
  friendly_name: AirCan3 DEV
  on_boot:
    priority: 60
    # ...
    then:
      - script.execute: update_aqi

esp8266:
  board: d1_mini

# Enable logging
logger:

# Enable Home Assistant API
api:
  encryption:
    key: "8HLf1XWjvDCwTMGMKhoIBzvu0WP8WnzYhEMEEVNL9Wk="

ota:


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esphome-Web-19013F"
    password: "x8AVa0lk4hDn"

uart:
  - id: CO2
    rx_pin: GPIO14
    tx_pin: GPIO12
    baud_rate: 9600
  - id: pm
    tx_pin: GPIO2
    rx_pin: GPIO0
    
    baud_rate: 9600      

captive_portal:

i2c:
  sda: D2
  scl: D1

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
#    reset_pin: D0
    address: 0x3C
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "Air Can 3");
          it.strftime(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "%H:%M:%S", id(esptime).now());
          if (id(temp).has_state()) {
           it.printf(0, 33, id(my_font), TextAlign::BASELINE_LEFT, "Temp %.1f ", id(temp).state);
          }
           if (id(temp).has_state()) {
          it.printf(0, 44, id(my_font), TextAlign::BASELINE_LEFT, "Hum %.1f ", id(hum).state);
          }

          
      - id: page2
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "CO 2");
          if (id(temp).has_state()) {
            it.printf(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "%.1f ppm", id(co2).state);
          }

      - id: page3
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "Poussieres");
          if (id(temp).has_state()) {
            it.printf(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "2,5- %.1f ppm", id(pm25).state);
          }
          if (id(temp).has_state()) {
            it.printf(0, 33, id(my_font), TextAlign::BASELINE_LEFT, "10- %.1f ppm", id(pm10).state);
          }
    


# For example cycle through pages on a timer
interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display



font:
  - file: 'Nirmala.ttf'
    id: my_font
    size: 12   

time:
  - platform: homeassistant
    id: esptime

sensor:
  - platform: mhz19
    co2:
      name: "CO2"
      id: co2
    temperature:
      name: "CO2 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false  
    uart_id: CO2

  - platform: dht
    pin: GPIO16
    temperature:
      name: "Temp AirCan"
      id: temp
    humidity:
      name: "Humidité AirCan"
      id: hum
    update_interval: 60s        

  - platform: sds011
    pm_2_5:
      name: "Particules <2.5µm Concentration"
      id: pm25
    pm_10_0:
      name: "Particules <10.0µm Concentration"
      id: pm10
    uart_id: pm 
    rx_only: True
   
  

light:
  - platform: neopixelbus
    type: GRB
    variant: WS2812
    pin: GPIO15
    num_leds: 3
    name: "LED" 
    id: LED     
    effects:
      - pulse:
          name: "Slow Pulse"
          # transition_length: 1s      # defaults to 1s
          update_interval: 2s

web_server: # creates a web server where you can access all this stuff without home assistant (good for debugging or working headless (no HA))
  port: 80
  include_internal: true
  ota: true

binary_sensor: # exposes online status
  - platform: status
    name: "Sensor Status"

text_sensor:
  - platform: wifi_info
    ip_address: # exposes the IP Address when connected
      internal: true
      id: wifi_ip_addr
      name: "IP Address"
    ssid: # exposes the SSID when connected
      internal: true
      id: wifi_ssid
  - platform: template
    name: "Airgradient Air Quality Index"
    id: aqi
    icon: mdi:air-filter


script:
  
  - id: update_aqi
    mode: restart
    then:
      - if:
          condition:
            or:
              - sensor.in_range:
                  id: pm25
                  above: 25
              - sensor.in_range:
                  id: pm10
                  above: 50
              - sensor.in_range:
                  id: co2
                  above: 1499
          then:
            - text_sensor.template.publish:
                id: aqi
                state: Tres Mauvais
            - script.execute: show_tr_bad
          else:
            - if:
                condition:
                  or:
                    - sensor.in_range:
                        id: pm25
                        above: 20
                    - sensor.in_range:
                        id: pm10
                        above: 40
                    - sensor.in_range:
                        id: co2
                        above: 800    

                then:
                  - text_sensor.template.publish:
                      id: aqi
                      state: Mauvais
                  - script.execute: show_bad
                else:
                  - if:
                      condition:
                        or:
                          - sensor.in_range:
                              id: pm25
                              above: 10
                          - sensor.in_range:
                              id: pm10
                              above: 20
                          - sensor.in_range:
                              id: co2
                              above: 500    
                      then:
                        - text_sensor.template.publish:
                            id: aqi
                            state: Mediocre
                        - script.execute: show_acceptable
                      else:
                        - text_sensor.template.publish:
                            id: aqi
                            state: Bon
                        - script.execute: show_good
  # Configuration for showing AQI status with the RGB LED
  - id: show_tr_bad
    then:
      - light.turn_on:
          id: LED
          brightness: 100%
          red: 80%
          green: 0%
          blue: 20%
  - id: show_bad
    then:
      - light.turn_on:
          id: LED
          brightness: 100%
          red: 100%
          green: 60%
          blue: 20%
  - id: show_acceptable
    then:
      - light.turn_on:
          id: LED
          brightness: 90%
          red: 100%
          green: 87%
          blue: 20%          
  - id: show_good
    then:
      - light.turn_on:
          id: LED
          brightness: 90%
          red: 0%
          green: 60%
          blue: 40%

A voir si je prévois un dimmer la nuit pour réduire l’intensité des LED… soit lié à l’heure soit par un switch de HA.

Bonjour et merci bcp pour ton partage, j’ai aussi un aircan rangé dans mon placard… Mais qui va revivre grâce à toi. J’ai les vacances scolaire pour le faire fonctionner !
Je mets ton post dans mes favoris

1 « J'aime »

Tu as cette condition qui permet un allumage des leds de 8h à 22h.

- id: show_tr_bad
    then:
      - if:
          condition:
            - lambda: 'return id(ha_time).now().hour < 22 && id(ha_time).now().hour > 8 ;'
          then:
            - light.turn_on:
                id: rgb_led
                brightness: 20%
                red: 80%
                green: 0%
                blue: 20%
          else:
            - light.turn_off:
                id: rgb_led

@Sweepy Oui, c’est bien vu merci ! Je vais mettre ça en, place: soit led eteintes soit brightness a 10 ou 20%.

Correction du code (il se lançait une fois au boot puis dodo !) :face_with_diagonal_mouth:

Le code
# AIRCAN fonctionnel avec écran, script et LED 
esphome:
  name: esphome-web-19013f
  friendly_name: AirCan3 DEV

esp8266:
  board: d1_mini

# Enable logging
logger:

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

ota:


wifi:
  ssid: !secret wifi_ssid
  password: !secret wifi_password

  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Esphome-Web**************"
    password: "*****************"

uart:
  - id: CO2
    rx_pin: GPIO14
    tx_pin: GPIO12
    baud_rate: 9600
  - id: pm
    tx_pin: GPIO2
    rx_pin: GPIO0
    
    baud_rate: 9600      

captive_portal:

i2c:
  sda: D2
  scl: D1

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
#    reset_pin: D0 # Pin déjà utilisé
    address: 0x3C
    id: my_display
    pages:
      - id: page1
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "Air Can 3");
          it.strftime(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "%H:%M:%S", id(esptime).now());
          if (id(temp).has_state()) {
           it.printf(0, 33, id(my_font), TextAlign::BASELINE_LEFT, "Temp %.1f ²", id(temp).state);
          }
           if (id(temp).has_state()) {
          it.printf(0, 44, id(my_font), TextAlign::BASELINE_LEFT, "Hum %.1f ", id(hum).state);
          }

          
      - id: page2
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "CO 2");
          if (id(temp).has_state()) {
            it.printf(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "%.1f ppm", id(co2).state);
          }

      - id: page3
        lambda: |-
          it.printf(0, 11, id(my_font), TextAlign::BASELINE_LEFT, "Poussieres");
          if (id(temp).has_state()) {
            it.printf(0, 22, id(my_font), TextAlign::BASELINE_LEFT, "2,5- %.1f ppm", id(pm25).state);
          }
          if (id(temp).has_state()) {
            it.printf(0, 33, id(my_font), TextAlign::BASELINE_LEFT, "10- %.1f ppm", id(pm10).state);
          }
    


# For example cycle through pages on a timer
interval:
  - interval: 5s
    then:
      - display.page.show_next: my_display
      - component.update: my_display



font:
  - file: 'Nirmala.ttf'
    id: my_font
    size: 12   

time:
  - platform: homeassistant
    id: esptime

  - platform: sntp
    # ...
    on_time:
      # Every 5 minutes
      - seconds: 0
        minutes: /5
        then:
          - script.execute: update_aqi

sensor:
  - platform: mhz19
    co2:
      name: "CO2"
      id: co2
    temperature:
      name: "CO2 Temperature"
    update_interval: 60s
    automatic_baseline_calibration: false  
    uart_id: CO2

  - platform: dht
    pin: GPIO16
    temperature:
      name: "Temp AirCan"
      id: temp
    humidity:
      name: "Humidité AirCan"
      id: hum
    update_interval: 60s        

  - platform: sds011
    pm_2_5:
      name: "Particules <2.5µm Concentration"
      id: pm25
    pm_10_0:
      name: "Particules <10.0µm Concentration"
      id: pm10
    uart_id: pm 
    rx_only: True
   
  

light:
  - platform: neopixelbus
    type: GRB
    variant: WS2812
    pin: GPIO15
    num_leds: 3
    name: "LED" 
    id: LED     
    effects:
      - pulse:
          name: "Slow Pulse"
          # transition_length: 1s      # defaults to 1s
          update_interval: 2s

web_server: # creates a web server where you can access all this stuff without home assistant (good for debugging or working headless (no HA))
  port: 80
  include_internal: true
  ota: true

binary_sensor: # exposes online status
  - platform: status
    name: "Sensor Status"

text_sensor:
  - platform: wifi_info
    ip_address: # exposes the IP Address when connected
      internal: true
      id: wifi_ip_addr
      name: "IP Address"
    ssid: # exposes the SSID when connected
      internal: true
      id: wifi_ssid
  - platform: template
    name: "Airgradient Air Quality Index"
    id: aqi
    icon: mdi:air-filter


script:
  
  - id: update_aqi
    mode: restart
    then:
      - if:
          condition:
            or:
              - sensor.in_range:
                  id: pm25
                  above: 25
              - sensor.in_range:
                  id: pm10
                  above: 50
              - sensor.in_range:
                  id: co2
                  above: 1499
          then:
            - text_sensor.template.publish:
                id: aqi
                state: Tres Mauvais
            - script.execute: show_tr_bad
          else:
            - if:
                condition:
                  or:
                    - sensor.in_range:
                        id: pm25
                        above: 20
                    - sensor.in_range:
                        id: pm10
                        above: 40
                    - sensor.in_range:
                        id: co2
                        above: 800    

                then:
                  - text_sensor.template.publish:
                      id: aqi
                      state: Mauvais
                  - script.execute: show_bad
                else:
                  - if:
                      condition:
                        or:
                          - sensor.in_range:
                              id: pm25
                              above: 10
                          - sensor.in_range:
                              id: pm10
                              above: 20
                          - sensor.in_range:
                              id: co2
                              above: 500    
                      then:
                        - text_sensor.template.publish:
                            id: aqi
                            state: Mediocre
                        - script.execute: show_acceptable
                      else:
                        - text_sensor.template.publish:
                            id: aqi
                            state: Bon
                        - script.execute: show_good
  # Configuration for showing AQI status with the RGB LED
  - id: show_tr_bad
    then:
      - light.turn_on:
          id: LED
          brightness: 100%
          red: 80%
          green: 0%
          blue: 20%
  - id: show_bad
    then:
      - light.turn_on:
          id: LED
          brightness: 100%
          red: 100%
          green: 60%
          blue: 20%
  - id: show_acceptable
    then:
      - light.turn_on:
          id: LED
          brightness: 90%
          red: 100%
          green: 87%
          blue: 20%          
  - id: show_good
    then:
      - light.turn_on:
          id: LED
          brightness: 90%
          red: 0%
          green: 60%
          blue: 40%
switch:
  - platform: restart
    name: "AirCan Restart"