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.
This commit is contained in:
Joshua Boniface 2024-06-11 01:12:29 -04:00
parent c324689b19
commit 3088a6393b
2 changed files with 58 additions and 19 deletions

View File

@ -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

View File

@ -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