How to turn leds on or off according to the air quality state

Hi all, I have air quality sensors attached to a esp32 and I’m using it with esphome.
I also have three leds (red, yellow and green) attached to it.
I would like to show the air quality status with the leds, but I’m struggling with my code to get it working. I have tried the code first with one led but esphome doesn’t like it at all. What’s wrong?
Could you please help me?

output:
  - platform: ledc
    pin: GPIO25
    id: red_led

light:
  - platform: monochromatic
    output: red_led
    id: red_onoff
    name: "Red Led"
    internal: false
    restore_mode: ALWAYS_ON
    on_state:
      then:
        - if:
            condition:
              lambda: 'return id(iaq).state >= 351;'
            then:
              - light.turn_on: red_onoff
            else:
        - light.turn_off: red_onoff

That on_state defined for your light is only triggered if the light changes, but I guess you want that the other way round, i.e. if the air quality sensor changes then you want to chage the light?

Sensors can define on_value to trigger an action whenever the sensor value changes.

1 Like

Hi @exxamalte, yes exactly like you described.

I have the following code to show the quality. Can I implement the on_value there and how?

sensor:
  - platform: wifi_signal
    name: "Kitchen Sensor WiFi Signal"
    update_interval: 60s
  - platform: uptime
    name: "Kitchen Sensor Uptime"
  - platform: bme680_bsec
    bme680_bsec_id: "bme680_internal"
    temperature:
      # Temperature in °C
      name: "Kitchen Sensor BME680 Temperature"
      id: bme680_temperature
      sample_rate: lp
      filters:
        - median
    pressure:
      # Pressure in hPa
      name: "Kitchen Sensor BME680 Pressure"
      sample_rate: lp
      filters:
        - median
    humidity:
      # Relative humidity %
      name: "Kitchen Sensor BME680 Humidity"
      id: bme680_humidity
      sample_rate: lp
      filters:
        - median
    gas_resistance:
      # Gas resistance in Ω
      name: "Kitchen Sensor BME680 Gas Resistance"
      filters:
        - median
    iaq:
      # Indoor air quality value
      name: "Kitchen Sensor BME680 IAQ"
      id: iaq
      filters:
        - median

  - platform: template
    name: "Kitchen Sensor BME680 IAQ Classification"
    id: bme680_class
    icon: "mdi:checkbox-marked-circle-outline"
    lambda: |-
      if ( int(id(iaq).state) <= 50) {
        return {"Excellent"};
      }
      else if (int(id(iaq).state) >= 51 && int(id(iaq).state) <= 100) {
        return {"Good"};
      }
      else if (int(id(iaq).state) >= 101 && int(id(iaq).state) <= 150) {
        return {"Lightly polluted"};
      }
      else if (int(id(iaq).state) >= 151 && int(id(iaq).state) <= 200) {
        return {"Moderately polluted"};
      }
      else if (int(id(iaq).state) >= 201 && int(id(iaq).state) <= 250) {
        return {"Heavily polluted"};
      }
      else if (int(id(iaq).state) >= 251 && int(id(iaq).state) <= 350) {
        return {"Severely polluted"};
      }
      else if (int(id(iaq).state) >= 351) {
        return {"Extremely polluted"};
      }
      else {
        return {"error"};
      }

According to the documentation you should be able to add the on_value bit to each of the sensors, so in your particular case:

sensor:
  ...
  - platform: bme680_bsec
    bme680_bsec_id: "bme680_internal"
    ...
    iaq:
      # Indoor air quality value
      name: "Kitchen Sensor BME680 IAQ"
      id: iaq
      filters:
        - median
      on_value:
        then:
          - if:
              condition:
                lambda: 'return x >= 351;'
              then:
                - light.turn_on: red_onoff
              else:
          - light.turn_off: red_onoff

(I haven’t actually tested this myself, just stitched together from your code.)

Yes, it worked after minor change to the code. Thank you!
Please find the code below. Any optimization suggestions?

    iaq:
      # Indoor air quality value
      name: "Kitchen Sensor BME680 IAQ"
      id: iaq
      filters:
        - median
      on_value:
        then:
          - if:
              condition:
                lambda: 'return x >= 201;'
              then:
                - light.turn_on: red_onoff
              else:
                - light.turn_off: red_onoff
          - if:
              condition:
                lambda: 'return x <= 200;'
              then:
                - light.turn_on: yellow_onoff
              else:
                - light.turn_off: yellow_onoff
          - if:
              condition:
                lambda: 'return x >= 101;'
              then:
                - light.turn_on: yellow_onoff
              else:
                - light.turn_off: yellow_onoff
          - if:
              condition:
                lambda: 'return x <= 100;'
              then:
                - light.turn_on: green_onoff
              else:
                - light.turn_off: green_onoff
1 Like

How can combine these two? Now red and also yellow lights are on if value is over 200.

          - if:
              condition:
                lambda: 'return x <= 200;'
              then:
                - light.turn_on: yellow_onoff
              else:
                - light.turn_off: yellow_onoff
          - if:
              condition:
                lambda: 'return x >= 101;'
              then:
                - light.turn_on: yellow_onoff
              else:
                - light.turn_off: yellow_onoff

I believe I solved it myself:

      on_value:
        then:
          - if:
              condition:
                lambda: 'return x >= 201;'
              then:
                - light.turn_on: red_onoff
              else:
                - light.turn_off: red_onoff
          - if:
              condition:
                lambda: 'return x <= 200; return x >= 101;'
              then:
                - light.turn_on: yellow_onoff
              else:
                - light.turn_off: yellow_onoff
          - if:
              condition:
                lambda: 'return x <= 100;'
              then:
                - light.turn_on: green_onoff
              else:
                - light.turn_off: green_onoff
 lambda: 'return x <= 200; return x >= 101;'

Isn’t the last return just dead code? When the first return returns, the second should never be reached.
I think, it should be:

 lambda: 'return x <= 200 && x >= 101;'
1 Like

Yes, you are right, it didn’t work.
I changed it to the below after I noticed I didn’t work. Yours is even better, I will use that, thank you!

lambda: 'return (int(id(iaq).state) >= 101 && int(id(iaq).state) <= 200);'

So here’s (hopefully) the final code:

    iaq:
      # Indoor air quality value
      name: "Kitchen Sensor BME680 IAQ"
      id: iaq
      filters:
        - median
      on_value:
        then:
          - if:
              condition:
                lambda: 'return x >= 201;'
              then:
                - light.turn_on: red_onoff
              else:
                - light.turn_off: red_onoff
          - if:
              condition:
                lambda: 'return x <= 200 && x >= 101;'
              then:
                - light.turn_on: yellow_onoff
              else:
                - light.turn_off: yellow_onoff
          - if:
              condition:
                lambda: 'return x <= 100;'
              then:
                - light.turn_on: green_onoff
              else:
                - light.turn_off: green_onoff