How to change WS2812B led colour based on sensor values

Hi everyone. I have just started using eshome and have setup a CO2 sensor scd41 with an addressable WS2812B LED. What I want to do is based on the value of the co2 in the air is to change the colour of the LED. below 800ppm green, between 800ppm and 1100ppm yellow and above 1100ppm red. My CO2 sensor samples the data every 60 seconds and I would like that to be the trigger. I searched and tried all sorts of things/code with no success, I would really appreciate some assistance on this. My current code below:

  esphome:
  name: co2-office
  friendly_name: CO2_Office

esp32:
  board: esp32dev

# Configuration entry for ESP32
i2c:
  sda: 21
  scl: 22
  scan: true
  frequency: 400kHz

# Configuration for scd41 CO2 Sensor
sensor:
  - platform: scd4x
    co2:
      name: "Office CO2"
      id: office_co2
    temperature:
      name: "Office Temperature"
      id: office_temperature
    temperature_offset: 3.5
    humidity:
      name: "Office Humidity"
      id: office_humidity

# Configuration for CO2 Status LED
light:
  - platform: fastled_clockless
    chipset: WS2812B
    pin: GPIO13
    num_leds: 1
    rgb_order: GRB
    name: "CO2 Status LED"
    id: co2_status_led

Thank you

Using single WS2812B with neopixel platform:

light:
- platform: neopixelbus
  variant: WS2812
  pin: GPIO13
  num_leds: 1
  type: GRB
  id: co2_status_led
  name: "CO2 Status LED"
  restore_mode: ALWAYS_OFF
  default_transition_length: 0s

To flash with red for half a second using

  - light.turn_on:
      id: co2_status_led
      brightness: 100%
      red:   1
      green: 0
      blue:  0
      flash_length: 500ms

To turn it on instantly remove flash_length: 500ms.
To turn it off:

  - light.turn_off:
      id: co2_status_led
1 Like

As described here - brightness etc. are templatable, so can mix colors in run-time.

Hi,

thanks for the control code. How would I link this to an event of CO2 sensor being updated and then checking it’s values to set the colour?

F.e by sensor automation on_value_range:

Define ranges and actions to perform then value is in range.

1 Like

Made something like this last weekend. using a single WS2812B LED and a SGP30 sensor. i use on_value_ range for the sensor to show the led, the red light is also a 100% brightness:

light:
# verlichting aan de achterkant van de kast
  - platform: neopixelbus
    variant: WS2812
    pin: 16
    num_leds: 1
    type: GRB
    name: statusLED27
    id: statusLED27

# luchtkwaliteit sensor
  - platform: sgp30
    eco2:
      name: "eCO2_27"
      id: eco27
      accuracy_decimals: 1
      on_value_range:
        - above: 0
          below: 1000
          then:
            - light.turn_on:
                id: statusLED27
                brightness: 20%
                red: 0%
                green: 100%
                blue: 0%
        - above: 1001
          below: 1600
          then:
            - light.turn_on:
                id: statusLED27
                brightness: 40%
                red: 100%
                green: 100%
                blue: 0%
        - above: 1601
          then:
            - light.turn_on:
                id: statusLED27
                brightness: 75%
                red: 100%
                green: 0%
                blue: 0%          

Eric

@Masterzz and @DieOuweGek thank you both very much, I was able to get it working now with you help :slight_smile: I really appreciate it. Just in case this is my working code below now:

esphome:
  name: co2-office
  friendly_name: CO2_Office

esp32:
  board: esp32dev

# Configuration entry for ESP32
i2c:
  sda: 21
  scl: 22
  scan: true
  frequency: 400kHz

# Configuration for scd41 CO2 Sensor
sensor:
  - platform: scd4x
    co2:
      name: "Office CO2"
      id: office_co2
      on_value_range:
        - below: 800
          then:
            - light.turn_on:
                id: co2_status_led
                brightness: 20%
                red:   0
                green: 1
                blue:  0
        - above: 800
          below: 1200
          then:
            - light.turn_on:
                id: co2_status_led
                brightness: 20%
                red:   1
                green: 1
                blue:  0
        - above: 1200
          then:
            - light.turn_on:
                id: co2_status_led
                brightness: 20%
                red:   1
                green: 0
                blue:  0
    temperature:
      name: "Office Temperature"
      id: office_temperature
    temperature_offset: 3.5
    humidity:
      name: "Office Humidity"
      id: office_humidity

# Configuration for CO2 Status LED
light:
  - platform: neopixelbus
    variant: WS2812
    pin: GPIO13
    num_leds: 1
    type: GRB
    id: co2_status_led
    name: "CO2 Status LED"
    restore_mode: ALWAYS_OFF
    default_transition_length: 0s

font:
  - file: "gfonts://Roboto"
    id: roboto12
    size: 12

  - file: "gfonts://Roboto"
    id: roboto14
    size: 14

  - file: "gfonts://Roboto"
    id: roboto16
    size: 16

display:
  - platform: ssd1306_i2c
    model: "SSD1306 64x48"
    #reset_pin: D0
    address: 0x3C
    contrast: 0.1
    update_interval: 10s
    lambda: |-
      float co2 = id(office_co2).state;
      String co2_string = String(co2, 0);
      it.print(0, 0, id(roboto16), "CO2:");
      it.print(0, 16, id(roboto14), co2_string.c_str());
      it.print(2 + co2_string.length() * 8, 16, id(roboto12), "ppm");

Btw is there a way to turn off the built in status led on the esp32?

Did you try GPIO2 for de status LED? I know that some ESP’s have a power LED that cannot turn of. But to make sure, check the pin layout for your ESP
eric

Your configuration have no status LED configured.
So, most probably this is power indicator - red one.
Status indicator (usually blue) will blink while connecting and then only if configured.
IMHO.

1 Like

You can mark a solution to help others to see if discussion is still in progress or some solution found.

I have noticed something weird. If the device boots up and the CO2 is high the LED will not get switched on. But if I boot it up in a room with low CO2 the LED will get turned on and work fine. Looking at the logs after deployment shows this as well, since the moment it goes below 800 LED colour gets changed. Any idea what could be causing this?


[07:06:18][C][api:139]: API Server:
[07:06:18][C][api:140]:   Address: co2-office.local:6053
[07:06:19][C][api:142]:   Using noise encryption: YES
[07:06:51][D][sensor:094]: 'Office CO2': Sending state 1675.00000 ppm with 0 decimals of accuracy
[07:06:51][D][sensor:094]: 'Office Temperature': Sending state 21.67976 °C with 2 decimals of accuracy
[07:06:51][D][sensor:094]: 'Office Humidity': Sending state 57.09076 % with 2 decimals of accuracy
[07:06:53][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:06:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:07:51][D][sensor:094]: 'Office CO2': Sending state 1672.00000 ppm with 0 decimals of accuracy
[07:07:51][D][sensor:094]: 'Office Temperature': Sending state 19.03084 °C with 2 decimals of accuracy
[07:07:51][D][sensor:094]: 'Office Humidity': Sending state 66.39557 % with 2 decimals of accuracy
[07:07:53][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:07:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:08:51][D][sensor:094]: 'Office CO2': Sending state 1739.00000 ppm with 0 decimals of accuracy
[07:08:51][D][sensor:094]: 'Office Temperature': Sending state 18.07220 °C with 2 decimals of accuracy
[07:08:51][D][sensor:094]: 'Office Humidity': Sending state 71.22040 % with 2 decimals of accuracy
[07:08:53][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:08:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:09:51][D][sensor:094]: 'Office CO2': Sending state 1752.00000 ppm with 0 decimals of accuracy
[07:09:51][D][sensor:094]: 'Office Temperature': Sending state 17.82387 °C with 2 decimals of accuracy
[07:09:51][D][sensor:094]: 'Office Humidity': Sending state 72.18170 % with 2 decimals of accuracy
[07:09:53][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:09:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:10:51][D][sensor:094]: 'Office CO2': Sending state 1239.00000 ppm with 0 decimals of accuracy
[07:10:51][D][sensor:094]: 'Office Temperature': Sending state 17.59422 °C with 2 decimals of accuracy
[07:10:51][D][sensor:094]: 'Office Humidity': Sending state 64.23035 % with 2 decimals of accuracy
[07:10:53][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:10:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:11:10][I][ota:117]: Boot seems successful, resetting boot loop counter.
[07:11:10][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:11:10][D][esp32.preferences:143]: Saving 1 preferences to flash: 0 cached, 1 written, 0 failed
[07:11:51][D][sensor:094]: 'Office CO2': Sending state 688.00000 ppm with 0 decimals of accuracy
[07:11:51][D][light:036]: 'CO2 Status LED' Setting:
[07:11:51][D][light:047]:   State: ON
[07:11:51][D][light:051]:   Brightness: 20%
[07:11:51][D][light:059]:   Red: 0%, Green: 100%, Blue: 0%
[07:11:51][D][sensor:094]: 'Office Temperature': Sending state 17.10823 °C with 2 decimals of accuracy
[07:11:51][D][sensor:094]: 'Office Humidity': Sending state 58.26263 % with 2 decimals of accuracy
[07:11:51][W][component:214]: Component scd4x.sensor took a long time for an operation (0.05 s).
[07:11:51][W][component:215]: Components should block for at most 20-30ms.
[07:11:53][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:11:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 0 cached, 1 written, 0 failed

Booting up in low CO2:

[07:13:53][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
WARNING co2-office @ 192.168.11.244: Connection error occurred: [Errno 104] Connection reset by peer
INFO Processing unexpected disconnect from ESPHome API for co2-office @ 192.168.11.244
WARNING Disconnected from API
INFO Successfully connected to co2-office @ 192.168.11.244 in 0.011s
INFO Successful handshake with co2-office @ 192.168.11.244 in 0.126s
[07:15:07][D][sensor:094]: 'Office CO2': Sending state 632.00000 ppm with 0 decimals of accuracy
[07:15:07][D][light:036]: 'CO2 Status LED' Setting:
[07:15:07][D][light:047]:   State: ON
[07:15:07][D][light:051]:   Brightness: 20%
[07:15:07][D][light:059]:   Red: 0%, Green: 100%, Blue: 0%
[07:15:07][D][sensor:094]: 'Office Temperature': Sending state 19.81056 °C with 2 decimals of accuracy

Booting up in high CO2:

WARNING co2-office @ 192.168.11.244: Connection error occurred: [Errno 104] Connection reset by peer
INFO Processing unexpected disconnect from ESPHome API for co2-office @ 192.168.11.244
WARNING Disconnected from API
INFO Successfully connected to co2-office @ 192.168.11.244 in 0.007s
INFO Successful handshake with co2-office @ 192.168.11.244 in 0.109s
[07:22:33][D][api:102]: Accepted 192.168.20.21
[07:22:33][D][api.connection:1121]: Home Assistant 2024.3.0 (192.168.20.21): Connected successfully
[07:22:46][D][sensor:094]: 'Office CO2': Sending state 1866.00000 ppm with 0 decimals of accuracy
[07:22:46][D][sensor:094]: 'Office Temperature': Sending state 21.42075 °C with 2 decimals of accuracy
[07:22:46][D][sensor:094]: 'Office Humidity': Sending state 56.79474 % with 2 decimals of accuracy
[07:22:56][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:22:56][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:23:46][D][sensor:094]: 'Office CO2': Sending state 1770.00000 ppm with 0 decimals of accuracy
[07:23:46][D][sensor:094]: 'Office Temperature': Sending state 18.33122 °C with 2 decimals of accuracy
[07:23:46][D][sensor:094]: 'Office Humidity': Sending state 68.45093 % with 2 decimals of accuracy
[07:23:56][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:23:56][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:24:46][D][sensor:094]: 'Office CO2': Sending state 1735.00000 ppm with 0 decimals of accuracy
[07:24:46][D][sensor:094]: 'Office Temperature': Sending state 17.35924 °C with 2 decimals of accuracy
[07:24:46][D][sensor:094]: 'Office Humidity': Sending state 73.24219 % with 2 decimals of accuracy
[07:24:56][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:24:56][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:25:46][D][sensor:094]: 'Office CO2': Sending state 1743.00000 ppm with 0 decimals of accuracy
[07:25:46][D][sensor:094]: 'Office Temperature': Sending state 17.06818 °C with 2 decimals of accuracy
[07:25:46][D][sensor:094]: 'Office Humidity': Sending state 75.24872 % with 2 decimals of accuracy
[07:25:56][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:25:56][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:26:46][D][sensor:094]: 'Office CO2': Sending state 1749.00000 ppm with 0 decimals of accuracy
[07:26:46][D][sensor:094]: 'Office Temperature': Sending state 17.01210 °C with 2 decimals of accuracy
[07:26:46][D][sensor:094]: 'Office Humidity': Sending state 75.52795 % with 2 decimals of accuracy
[07:26:56][D][esp32.preferences:114]: Saving 1 preferences to flash...
[07:26:56][D][esp32.preferences:143]: Saving 1 preferences to flash: 1 cached, 0 written, 0 failed
[07:27:16][I][ota:117]: Boot seems successful, resetting boot loop counter.

Hey,
I don’t see this problem with my setup and the SGP30. But the SGP30 needs a few hours to self calibrate. After an esphome update sometimes it takes a while for the led to turn on. Then i blow over the sensor to trigger the values and everything is normal again.
But i leave the setup running uninterrupted as long a possible
eric

Probably it is because of this:
This trigger will only trigger when the new value is inside the range and the previous value was outside the range. On startup, the last state before reboot is restored and if the value crossed the boundary during the boot process, the trigger is also executed.

To be indepent from sensor filter on_value_range logic You can use on_value and call a script:

sensor
  - platform: sgp30
...
    on_value:
      - script.execute: LED_control

script:
  - id: LED_control
    mode: single
    then:
      - if:
          condition:
            - lambda: return id(office_co2).state < 800;
          then:
            - light.turn_on:
                id: co2_status_led
                brightness: 20%
                red:   0
                green: 1
                blue:  0
      - if:
          condition:
            - lambda: return id(office_co2).state >= 800 & id(office_co2).state < 1200;
          then:
            - light.turn_on:
                id: co2_status_led
                brightness: 20%
                red:   1
                green: 1
                blue:  0
      - if:
          condition:
            - lambda: return id(office_co2).state >= 1200;
          then:
            - light.turn_on:
                id: co2_status_led
                brightness: 20%
                red:   1
                green: 0
                blue:  0
1 Like

Thank you @Masterzz this worked perfectly :slight_smile: