ESP Home bme680 led control

Hi, I need a bit of help. I have a bmc680 connected on the ESP8266, and it works great, There is a platform: template with the code bellow, that takes the iaq_range values and display different messages depends on its values, this is all great.

text_sensor:

  - platform: template
    name: "Air quality ${name}"
    icon: "mdi:air-filter"
    lambda: |-
   
      ESP_LOGD("main", "Current value %d", id(iaq_range));
      
      if ((id(iaq_range).state <= 50.0 )) {
        return {"Very good"};    
      }
      else if ((id(iaq_range).state > 50.00)  && (id(iaq_range).state <= 100.0)) {
        return {"Good"};
      }
      else if ((id(iaq_range).state > 100.0) && (id(iaq_range).state <= 150.0)) {
        return {"A little dirty"};
      }
      else if ((id(iaq_range).state > 150.0) && (id(iaq_range).state <= 200.0)) {
        return {"Moderately dirty"};
      }
      else if ((id(iaq_range).state > 200.0) && (id(iaq_range).state <= 250.0)) {
        return {"Very dirty"};
      }
      else if ((id(iaq_range).state > 250.0) && (id(iaq_range).state <= 350.0)) {
        return {"Extremely dirty"};
      }
      else if ((id(iaq_range).state > 350.00)) {
        return {"Dangerously polluted"};
      }
      return {};
    update_interval: 30s

I have created a led that I want to turn it on different colours depending on the value of the iaq_range.
The code for the led is bellow.

light:

  - platform: neopixelbus
    type: GRB
    variant: WS2812x
    pin: D8
    num_leds: 1
    name: "Air Quality"
    id: quality

I tried to chage the code to something like bellow but if fails. How can I do this.

  if ((id(iaq_range).state <= 50.0 )) {
        return {"Very good"};
        - light.turn_on:
            id: led_presence
            brightness: 20%
            red: 100%
            green: 0%
            blue: 0%    
      }

I would create a script or a new template sensor, instead of stuffing the functionality into the text_sensor.

Anyway, you could convert the light.turn_on action to lambda code.

You have to put it in before the return command though.

if ( id(iaq_range).state <= 50.0 )
{
    auto call = id(led_presence).turn_on();
    call.set_brightness(0.2);
    call.set_rgb(1.0, 0, 0);
    call.perform();
    return {"Very good"};
}

Notice that it’s using floats (0 to 1) instead of percentages.

Edit: I’ve created a script that you can try out. I haven’t tested it a lot but it seems to work. It sets the color of the LED from Green to Purple according to the IAQ level. It’s using HSV instead of RGB to get those fluent gradients. I’m using a version of the script in my Power Meter config to indicate current power level using a single WS2818 LED :wink:

You could try it out to see if it works for you.

light:
  - platform: neopixelbus
    type: GRB
    variant: WS2812x
    pin: D8
    num_leds: 1
    name: "Air Quality"
    id: quality

sensor:
  - platform: bme680_bsec
    temperature:
      name: "BME680 Temperature"
    pressure:
      name: "BME680 Pressure"
    humidity:
      name: "BME680 Humidity"
    iaq:
      name: "BME680 IAQ"
      id: iaq_range
      on_value:
        then:
          - lambda: |-
              id(set_iaq_led)->execute( x * 100 / 500);
    co2_equivalent:
      name: "BME680 CO2 Equivalent"
    breath_voc_equivalent:
      name: "BME680 Breath VOC Equivalent"

script:
  - id: set_iaq_led
    parameters:
      pct: float
    mode: restart
    then:
      lambda: |-
        const float s = 1.0;    // saturation (purity). [0-1]
        const float v = 0.5;    // brightness. [0-1]
        int i;
        float r, g, b, f, h, p, q, t;
        f = pct;      
        if (f < 100) {
          h = 130 - f;    // orange to green
        } else {
          f -= 100;
          if (f == 0) {
            h = 0;        // red
          } else if (f > 120) {
            h = 300;      // purple
          } else {
            h = 360 - ceil(f / 2.0);  // red to purple
          }
        }
        h /= 60;   // sector 0 to 5
        i = floor(h);
        f = h - i;
        p = v * ( 1 - s );
        q = v * ( 1 - s * f );
        t = v * ( 1 - s * ( 1 - f ) );
        switch( i ) {
          case 0:
            r = v;
            g = t;
            b = p;
            break;
          case 1:
            r = q;
            g = v;
            b = p;
            break;
          case 2:
            r = p;
            g = v;
            b = t;
            break;
          case 3:
            r = p;
            g = q;
            b = v;
            break;
          case 4:
            r = t;
            g = p;
            b = v;
            break;
          default:
            r = v;
            g = p;
            b = q;
            break;
        }
        auto call = id(quality).turn_on();
        call.set_rgb(r, g, b);
        call.perform();

Hi zenzay42, first of all, thank you for taking the time, to write all that. Do I use one or another?

anyway I tried the script first, I get no error compiling the code, but the led is always white, then I tried the other code still white.

The first script basically just uses the set_rgb function to set the light to red. If it shows up white, I suspect there could something with the wiring or maybe try another pin?

From the NeoPixelBus Light page:

On ESP8266 it’s highly recommended to connect the light strip to pin GPIO3 to reduce flickering.

What happens if you play around with the LED in Home Assistant? Are you able to get the colors going there?

If yes, you could try to make a simple button that just sets the color of the led when pressed.

button:
  - platform: template
    name: LED Test
    on_press:
      - light.turn_on:
          id: led_presence
          brightness: 20%
          red: 100%
          green: 0%
          blue: 0%   

Yes with the code bellow, it create a switch, and I can change the colours manually by clicking on it and choosing a colour.

light:

  - platform: neopixelbus
    type: GRB
    variant: WS2812x
    pin: D8
    num_leds: 1
    name: "Air Quality"
    id: quality

wait
your first script work beautifully. The problem was that I changed it only to the return {“Very good”}, and the sensor was now on Good. Perfect what I wanted. 1000000 thanks… a question, how do I set the colour? I seen that 1.0,0,0 is red, 0,1.0,0 is green and 0,0,1.0 is blue, can I get more colours?

Cool! Glad you got it working.

Yes, you can get more colors. You mix the red, green and blue colors by indicating their intensity.

Fx. Yellow: Red = 1, Green = 1, Blue = 0

It’s called Additive Color Mixing.

I´ll give it a go. I got it green, darker green, orange, red and on Dangerously polluted, maybe red blinking. Still, your code is spot on.

1 Like

I found this page to help me combine the colours. So 1.0,0.5,0 is orange, I got it. the numbers for RGB is from 0 to 9?

https://www.physics-chemistry-interactive-flash-animation.com/optics_interactive/additive_color_model_mixing_synthesis_flash.htm

No, in this case, the numbers goes from zero to one.

You can think of it as percentages. Just divide the percentage by 100 to get the value you should use.

Examples:

10% = 0.1
25% = 0.25
50% = 0.5
75% = 0.75
100% = 1.0

Edit: I’ve edited the second script in the post above. You should be able to use it like shown. This will make it easier to get the whole range of colours.

With the colours I got it, is basically the combination like on the page I found that show 0 to 100% but decided by 100.

I will try the script, I the first method works fine, but I don’t know what is the best value to use for the light is the AQI or is the 2.5 ppm value. Because I noticed that sometime the 2.5 ppm is low say 2 that would be a green but the AQI is 150 that is already yellow or orange.

I seen most of the comercia air quality meter show the 2.5 ppm. For example the Ikea one nd most use the same values have:

Green: 0-35 ppm Good/Low
Amber: 36-85 ppm Ok/Medium
Red: 86/- ppm Not Good/High

So what you think 2,5 or AQI.

Thank you

Not quite sure what you mean with 2.5 ppm value. Do you mean CO2 or VOC?
The BME680 is not a PM2.5 sensor - those type of sensors measure dust particles in the air, usually with a laser.

Found this that might help decipher the values:

yes the voc.


Here is my sensors, thanks to you. It has a mini d1, a mmwave sen0395, a iluminance sensor and the bme680. And the led its in the base.

That looks really neat. Nice job! When are they going into production? :wink:

It was hardly thanks to me, but I’m happy I was able to give some pointers :slight_smile:

PS. I just bought myself a PM2.5 sensor. Will be interesting to play around with.