Send a sensor's status on a neopixelbus with a single led

I made an air sensor based on a ESP8266mod-12F with a MH-Z19b, a sth21, an aht10 and a bme280 for CO², humidity, temperature and athmospheric pressure.

sensor:
  - platform: mhz19
    co2:
      name: "Valeur CO² $long_devicename"
      on_value_range:
        - below: 400
          then:
            - switch.turn_off: red
            - switch.turn_off: yellow
            - switch.turn_off: green
        - above: 399
          below: 900
          then:
            - switch.turn_on: green
        - above: 899
          below: 2200
          then:
            - switch.turn_on: yellow
        - above: 2199
          then:
            - switch.turn_on: red
    temperature:
      name: "Temperature MH-Z19 $long_devicename"
    automatic_baseline_calibration: false
    uart_id: uart_mhz19
    id: mhz19_calibration
    update_interval: 30s
  - platform: htu21d
    temperature:
      name: "Temperature SHT21 $long_devicename"
    humidity:
      name: "Humidite SHT21 $long_devicename"
    address: 0x38
    update_interval: 30s
  - platform: bmp085
    temperature:
      name: "Temperature BMP11 $long_devicename"
    pressure:
      name: "Pression BMP11 $long_devicename"
    address: 0x77
    update_interval: 30s

switch:
  # Bouton de redémarrage
  - platform: restart
    name: "Redémarrage $long_devicename"
  # switch configuration to turn calibration on/off
  - platform: template
    name: "Calibration $long_devicename"
    optimistic: true
    on_turn_on:
      mhz19.abc_enable: mhz19_calibration
    on_turn_off:
      mhz19.abc_disable: mhz19_calibration
  # Gestion des LED
  - platform: gpio    
    pin: GPIO14        #d5
    name: "Light green"
    id: green
    icon: "mdi:led-on"
    interlock: [yellow, red]

  - platform: gpio
    pin: GPIO12        #d6
    name: "Light yellow"
    id: yellow
    icon: "mdi:led-on"
    interlock: [green, red]

  - platform: gpio
    pin: GPIO13        #d7
    name: "Light red"
    id: red
    icon: "mdi:led-on"
    interlock: [yellow, green]

uart:
  - rx_pin: GPIO05     #d1
    tx_pin: GPIO04     #d2
    baud_rate: 9600
    id: uart_mhz19
    
i2c:
  - sda: GPIO13     #d7
    scl: GPIO15     #d8
    scan: false
    id: bus_i2c

I know, this is not very nice but it was (roughly) working.

I had some trouble while booting, sometimes, it hangs, sometimes it starts in « no error mode » and nothing was working.
Removing some leds, mainly the red was helpful.
Then I installed a display on the I2C bus and added this part:

font:
  - file: "arial.ttf"
    id: my_font2
    size: 9
  - file: "arial.ttf"
    id: my_font3
    size: 16

display:
  - platform: ssd1306_i2c
    model: "SSD1306 128x64"
    reset_pin: D0
    address: 0x3C
    lambda: |-
      it.printf(0,  4, id(my_font2), "CO2");
      it.printf(32, 0, id(my_font3), "%.1f ppm", id(mhz19_co2).state);
      
      it.printf(0, 20, id(my_font2), "Temp");
      it.printf(32, 16, id(my_font3), "%.1f °C", id(bme280_temp).state);

      it.printf(0, 36, id(my_font2), "Hygr");
      it.printf(32, 32, id(my_font3), "%.1f %%", id(aht10_hyg).state);
      
      it.printf(0, 52, id(my_font2), "Press");
      it.printf(32, 48, id(my_font3), "%.1f hPa", id(bme280_pr).state);

it has been working fine for two months.
But I still want my status leds.
I replaced my 3 leds with a single addressable led, a PL9823 (compatible WS2812).
If I am able to lit it in red (or any color I want from the web side of the ESP) I cannot find how to lit it automatically, based on the percentage of data read by the “co2”captor.
This must be running locally in the ESP, the lights must works even if the connection with HA is down. (for instance, I want to keep this device with me during my holydays).
As the command for the neopixelbus is not trivial, I found this that was working:

light:
  - platform: neopixelbus
    name: "$long_devicename Light"
    pin: GPIO12        #d6
    variant: WS2812
    id: light_1
    num_leds: 1
    effects:
      - automation:
          name: "Custom Green"
          sequence:
            - light.addressable_set:
                id: light_1
                red: 100%
                green: 0%
                blue: 0%
      - automation:
          name: "Custom Orange"
          sequence:
            - light.addressable_set:
                id: light_1
                red: 100%
                green: 100%
                blue: 0%
      - automation:
          name: "Custom Red"
          sequence:
            - light.addressable_set:
                id: light_1
                red: 100%
                green: 0%
                blue: 0%

I know this IS ugly. I am definitely NOT a programmer; and by the way I am too old now.
With this code I can light my status led. A big step for me, but nothing for the humanity.

How would you write this code ???

I may add a particle sensor and one or two status led on the neopixel bus for the other sensors, but it won’t change anything.

thanks,
Benoit.

Ok, I could go further.

to change a color, you must use light.addressable_set
and to switch it on you must use light.turn_on

I changed the way to switch on the light at the boot:

esphome:
  name: $devicename
  platform: ESP8266
  board: nodemcuv2
  comment: $long_devicename
  on_boot:
    # switch on the led
    priority: -100.0
    then:
      - light.addressable_set:
          id: voyant_led
          red: 50%
          green: 0%
          blue: 100%
          color_brightness: 50%
          #this purple color is not used elsewhere, so I can see that is the boot is finished.
      - light.turn_on:
          id: voyant_led

the Light definition is the same, I just removed the name to avoid HA modification or a forgotted automation.

light:
  - platform: neopixelbus
#    name: "Status Light $long_devicename"
    pin: GPIO12   # pin d6
    variant: WS2812
    id: voyant_led
    num_leds: 1
    type: rgb

Here is the changing color function with the CO2 value, 4 levels: green, yellow, orange and red.

sensor:
  - platform: mhz19
    co2:
      name: "Valeur CO² $long_devicename"
      id: mhz19_co2
      on_value_range:

        - below: 899
          then:
          - light.addressable_set:
              id: voyant_led # Green
              red: 0%
              green: 100%
              blue: 0%

        - above: 900
          below: 1499
          then:
          - light.addressable_set:
              id: voyant_led # Yellow
              red: 100%
              green: 100%
              blue: 0%

        - above: 1500
          below: 2199
          then:
          - light.addressable_set:
              id: voyant_led # Orange
              red: 100%
              green: 50%
              blue: 0%

        - above: 2200
          then:
          - light.addressable_set:
              id: voyant_led # Red
              red: 100%
              green: 0%
              blue: 0% 

That is definitly cleaner.

but I still have a trouble:

at the boot, the light lit in purple and then switch to white.
It can stay in white for hours and days !!!

The only way I found is to blow my breath on the sensor to reach the condition following green:yellow, (above 900ppm) in the on_value_range. then the led will take the rights colors until next reboot…

It s normal you have to specify between each to go to 0 then to set the value example from my code:

  • light.addressable_set:

          - light.addressable_set:
              id: Strip_Press
              range_from: 0
              range_to: 1
              red: 0%
              green: 0%
              blue: 0%
          - delay : 100ms
          - light.addressable_set:
              id: Strip_Press
              range_from: 0
              range_to: 1
              red: 0%
              green: 50%
              blue: 25%

Hi,

I have the same problem right now.
Have you found a solution?