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:
		
							
								
								
									
										17
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										17
									
								
								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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user