From 3088a6393b5c62376a41c14bb4fb8356193bf917 Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Tue, 11 Jun 2024 01:12:29 -0400 Subject: [PATCH] Implement improved AQ calculation Implements an AQ calculation from [1], which should hopefully provide a more stable, sensible value for the air quality. This also adds a configurable gas ceiling level, needed for full calibration and explained in the README. [1] https://github.com/thstielow/raspi-bme680-iaq The human text ratings are still a work-in-progress. --- README.md | 17 +++++++++++++- supersensor.yaml | 60 +++++++++++++++++++++++++++++++++--------------- 2 files changed, 58 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index b4e7f19..7871d57 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ Note: Once programmed, the output LED will flash continuously until connected to HomeAssistant, and a bit longer to establish if the wake word functionality is enabled. This is by design, so you know if your sensors are connected or not. If you do not want this, comment out the - `light.turn_on` block starting on line 54 of the ESPHome configuration + `light.turn_on` block starting on line 38 of the ESPHome configuration to disable this functionality. For more details, please [see my blog post on the SuperSensor project](https://www.boniface.me/the-supersensor/). @@ -59,6 +59,21 @@ The SuperSensor's voice functionality can be completely disabled if voice support is not desired. This defeats most of the point of the SuperSensor, but can be done if desired. +### Gas Ceiling + +The AQ (air quality) calculation from the BME680 requires a "maximum"/ceiling +threshold for the gas resistance value in clean air after some operation +time. The value defaults to 200,000 to provide an initial baseline, but +should be calibrated manually by: + +1. Turning on the Supersensor in a known-clean environment (e.g. a sealed + container in fresh air). +2. Leave the sensor on for 4-6 hours to burn in the sensor. +3. Setting this to the maximum value of the Gas Resistance sensor. + +This value will then define what "100% air quality" represents, and the +Supersensor can then be moved to its normal operating location. + ### Light Threshold Control The SuperSensor features a "light presence" binary sensor based on the light diff --git a/supersensor.yaml b/supersensor.yaml index 2860553..30d59d2 100644 --- a/supersensor.yaml +++ b/supersensor.yaml @@ -57,6 +57,11 @@ esp32: board: esp32dev globals: + - id: gas_ceiling + type: int + restore_value: yes + initial_value: "200000" + - id: pir_hold_time type: int restore_value: yes @@ -499,18 +504,26 @@ sensor: filters: - median - - platform: template - name: "BME680 IAQ" - id: bme680_iaq - icon: "mdi:gauge" - # caulculation: comp_gas = log(R_gas[ohm]) + 0.04 log(Ohm)/%rh * hum[%rh] - lambda: |- - return log(id(bme680_gas_resistance).state) + 0.04 * id(bme680_humidity).state; - - platform: absolute_humidity name: "BME680 Absolute Humidity" temperature: bme680_temperature humidity: bme680_humidity + id: bme680_absolute_humidity + + - platform: template + name: "BME680 AQ" + id: bme680_aq + icon: "mdi:gauge" + # Calculation from https://github.com/thstielow/raspi-bme680-iaq + lambda: |- + float ph_slope = 0.03; + float comp_gas = id(bme680_gas_resistance).state * pow(2.718281, (ph_slope * id(bme680_absolute_humidity).state)); + float gas_ratio = pow((comp_gas / id(gas_ceiling)), 2); + if (gas_ratio > 1) { + gas_ratio = 1.0; + } + float air_quality = gas_ratio * 100; + return (int)air_quality; - platform: tsl2591 address: 0x29 @@ -598,29 +611,26 @@ sensor: text_sensor: - platform: template - name: "BME680 IAQ Classification" + name: "BME680 AQ Classification" icon: "mdi:air-filter" update_interval: 15s lambda: |- - int iaq = int(id(bme680_iaq).state); - if (iaq <= 50) { + int aq = int(id(bme680_aq).state); + if (aq >= 90) { return {"Excellent"}; } - else if (iaq <= 100) { + else if (aq >= 80) { return {"Good"}; } - else if (iaq <= 150) { + else if (aq >= 70) { return {"Fair"}; } - else if (iaq <= 200) { + else if (aq >= 60) { return {"Moderate"}; } - else if (iaq <= 250) { + else if (aq >= 50) { return {"Bad"}; } - else if (iaq <= 350) { - return {"Very Bad"}; - } else { return {"Terrible"}; } @@ -698,6 +708,20 @@ switch: entity_category: diagnostic number: + - platform: template + name: "Gas Ceiling" + id: gas_ceiling_setter + min_value: 25000 + max_value: 350000 + step: 1000 + lambda: |- + return id(gas_ceiling); + set_action: + then: + - globals.set: + id: gas_ceiling + value: !lambda 'return int(x);' + # PIR Hold Time: # The number of seconds after motion detection for the PIR sensor to remain held on - platform: template