From 0dd83cb688ca87c66597bf0a4ea2ab9681bf8acc Mon Sep 17 00:00:00 2001 From: Joshua Boniface Date: Wed, 12 Jun 2024 01:54:04 -0400 Subject: [PATCH] Bump version to 1.1 and include detailed AQ docs --- README.md | 164 +++++++++++++++++++++++++++++++++++++++++------ supersensor.yaml | 2 +- 2 files changed, 146 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index ea18911..bf156d9 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,12 @@ For more details, please [see my blog post on the SuperSensor project](https://w * 1x ESP32 devkit (V4 38-pin, slim) [AliExpress (HW-395)](https://www.aliexpress.com/item/1005006019875837.html) * 1x INMP441 MEMS microphone [Amazon search](https://www.amazon.ca/s?k=INMP441) -* 1x BME680 temperature/humidity/pressure/gase sensor (3.3v models); BME280 or BMP280 can be subsistuted but with reduced fuctionality (comment/uncomment the appropriate blocks as needed) [AliExpress](https://www.aliexpress.com/item/4000818429803.html) +* 1x BME680 temperature/humidity/pressure/gas sensor (3.3v models); BME280 or BMP280 can be substituted but with reduced functionality (comment/uncomment the appropriate blocks as needed) [AliExpress](https://www.aliexpress.com/item/4000818429803.html) * 1x TSL2591 light sensor [AliExpress](https://www.aliexpress.com/item/1005005514391429.html) -* 1x HLK-LD2410C-P mmWave radar sensor [AliExpress (LD2410C-P)](https://www.aliexpress.com/item/1005006000579211.html) +* 1x HLK-LD2410C-P mm-Wave radar sensor [AliExpress (LD2410C-P)](https://www.aliexpress.com/item/1005006000579211.html) * 1x SR602 PIR sensor [AliExpress](https://www.aliexpress.com/item/1005001572550300.html) -* 2x Common-cathod RGB LEDs [Amazon search](https://www.amazon.ca/s?k=5mm+RGB+LED+common+cathode) -* 1x Resistor for the common-cathod RGB LED @ 3.3v input (~33-1000Ω, depending on desired brightness and LEDs) +* 2x Common-cathode RGB LEDs [Amazon search](https://www.amazon.ca/s?k=5mm+RGB+LED+common+cathode) +* 1x Resistor for the common-cathode RGB LED @ 3.3v input (~33-1000Ω, depending on desired brightness and LEDs) * 1x SuperSensor PCB board (see "board/supersensor.dxf" or "board/supersensor.easyeda.json") * 1x 3D Printed case [Optional] * 1x 3D Printed diffuser cover [Optional] @@ -51,7 +51,7 @@ For more details, please [see my blog post on the SuperSensor project](https://w ## Configurable Options There are several UI-configurable options with the SuperSensor to help you -get the most out of the sensor for your particular usecase. +get the most out of the sensor for your particular use-case. ### Voice Control @@ -64,18 +64,8 @@ but can be done if desired. 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 kΩ to provide an initial baseline, but -should be calibrated manually after setup as each sensor is different: - -1. Turn on the Supersensor in a known-clean environment (e.g. a sealed clean - container in fresh air). -2. Leave the sensor on for 4-6 hours to burn in. -3. Look at the historical graphs for the Gas Resistance sensor and find the - maximum value over the burn-in period. -4. Round the maximum Gas Resistance value **up** to the nearest 1000. -4. Divide the rounded maximum Gas Resistance value by 1000 to get the kΩ value. - -This value will then define what "100% air quality" represents, and the -Supersensor can then be moved to its normal operating location. +should be calibrated manually after setup as each sensor is different. See +the section "Calibrating AQ" below for more details. ### Light Threshold Control @@ -115,7 +105,7 @@ handled separately: #### PIR + Radar + Light Occupancy is detected when all 3 sensors report detected, and occupancy is -cleared when any of the sensors report clearered. +cleared when any of the sensors report cleared. For detect, this provides the most "safety" against misfires, but requires a normally-dark room with a non-automated light source and clear PIR @@ -154,7 +144,7 @@ Occupancy is detected when both sensors report detected, and occupancy is cleared when either of the sensors report cleared. For detect, this allows for radar detection while suppressing occupancy -without light, for insance in a hallway where one might not want a late +without light, for instance in a hallway where one might not want a late night bathroom visit to turn on the lights, or something to that effect. For clear, this option can provide a useful option to clear presence @@ -188,3 +178,139 @@ For detect, no occupancy will ever fire. For clear, no states will clear occupancy; with any detect option, this means that occupancy will be detected only once and never clear, which is likely not useful. + +## Calibrating AQ + +The Supersensor uses the Bosch BME680 combination temperature, humidity, +pressure, and gas sensor to provide a wide range of useful information about +the environmental conditions the sensor is placed in. However, this sensor +can be tricky to work with. + +While it's normally recommended to use the Bosch BSEC library with this +sensor, in my ~6 month experience I found this library to be far more trouble +than it was worth. Specifically, it's IAQ measurement is nearly useless, with +a strong tendency to get stuck in an upward trend constantly "calibrating" +itself to higher and higher baselines, to the point where nonsensical values +were being read. After much research into this, I decided to abandon the +library in version 1.1 and went with a more custom solution. + +Instead of the BSEC, we use the stock BME680 ESPHome library, along with +some calculations by thstielow on GitHub in their [IAQ project](https://github.com/thstielow/raspi-bme680-iaq). +This provided some useful example code and formulae to calculate a useful +Air Quality (AQ) value instead of the useless Bosch value. + +However using this method requires some manual calibration of the sensor +after putting it together but before final use, in order to get a somewhat +accurate value out of the AQ component. If you don't care about the AQ value, +you can skip this, but it is recommended to take full advantage of the sensor. + +As a quick explainer, the code leverages a combination of the "Gas Resistance" +value provided by the sensor, along with an absolute humidity calculated from +the temperature and relative humidity of the sensor (included ESPHome sensor), +along with two values (one configurable, one hard-coded) and several formulae +to arrive at the resulting AQ value. For full details of the calculation, +see the repository linked above, which was re-implemented faithfully here. + +The first thing to note is that each BME680 sensor is wildly different in +terms of gas resistance values. In the same air, I had sensors reading values +that differed by nearly 200,000Ω, which necessitates a human-configurable +baseline value. Further, the IAQ project recommends determining a linear +slope value for this, but instead of trying to explain how to calculate this, +I just went with the default slope value of 0.03 for this first iteration. + +Thus, the main difficulty in getting a useful AQ score is finding the +"Gas Resistance Ceiling" value. This value is configurable in the +SuperSensor interface (Web or HomeAssistant), and should be calibrated as +follows during the initial setup of the supersensor. + +1. Find a known-clean room, for instance a well-ventilated, well-cleaned +room in your house or similar. It should have fresh air (no stray VOCs) but +also minimal drafts or outside exposure especially if there is a poor external +AQ level. This will be your calibration reference room. Ideally, this room +should be somewhere between 16C and 26C for optimal performance, so air +conditioning (or a nice spring/fall day) is best. + +2. Turn on the SuperSensor in this environment, and connect it to your +HomeAssistant instance; this will be critical for viewing historical graphs +during the following steps. + +3. Let the SuperSensor run to "burn in" the gas sensor for at least 3-6 hours, +or until the value for the Gas Resistance stabilizes. It is best to avoid much +movement or activity in the selected calibration room to avoid disrupting +the sensor during this time. It is also best to ensure that the ambient +temperature changes as little as possible during this time. + +4. Review the resulting graph of Gas Resistance over the burn-in period. You +can usually ignore the first hour or two as the sensor was burning in, and +focus instead on the last hour or so. + +5. Make note of the highest mean value reached by the sensor during this time. +This will be your baseline value for calibrating the Gas Resistance Ceiling. + +6. Round the value up to the nearest 1000. For example, if the maximum value +was 195732.1, round this to 196000.0. + +7. Find the difference in the temperature of the BME680 temperature sensor +from 20C, called ΔT below. I found this part by trial-and-error, so this is +not precise, but as an example if the calibration room is reporting 26C, your +ΔT value in the next step is 6. If your temperature was below 20C, use 0. + +8. Use one of the following formulae to come up with your offset value, which +depends on the maximum value range found in step 6. + + * `<100,000`: 200 * ΔT = 0-1200 + * `100,000-200,000`: 500 * ΔT = 0-3000 + * `>200,000`: 1000 * ΔT = 0-6000 + +Again this value is rough, and might not even really be needed, but helps +avoid weird issues with AQ values dropping suddenly later as temperature +and humidity changes. + +9. Add your offset value from step 8 to the rounded maximum from step 6. +For example, 196000.0 with a ΔT of 5C (25C ambient) yields 201000.0 + +10. Divide the result from 9 by 1000 to give a number from 1-500. This +is the value to enter as the "Gas Resistance Ceiling (kΩ)" for this +sensor. This value will be saved in the NV-RAM of the ESP32 and preserved +on reboots. + +At this point, you should have a value that results in the "BME680 AQ" +sensor reporting 100% AQ, i.e. clean air. You can now test to ensure +that the value will correctly drop as VOCs are added. + +1. Take a Sharpie permanent marker, Acetone nail polish remover, or some +other VOC that the BME680 gas sensor can detect, and place it near the +sensor. For example with a sharpie, remove the cap and place the tip +about 1-2cm from the sensor, or place a small capful of nail polish +remover about 3-5cm from the sensor. + +2. Wait about 30 seconds. + +3. You should see the AQ value drop precipitously, into the order of 50% +or lower, and ideally closer to 0-20%. If the value remains higher than +50% with this test, your calculated Gas Resistance Ceiling might be +too low, and should be increased in increments of 1000. + +4. Remove the VOC source (replace the cap, remove the capful of remover, +etc.) and wait about 30-60 minutes. + +5. You should see the AQ value and gas resistance return to their original +values. If it is significantly lower than before, even after waiting 60+ +minutes, restart the calculation from step 5 in the previous section +using this new value as the baseline. + +At this point, the sensor should be calibrated enough for day-to-day +casual home use, and will tell you if there is any significant +VOC contamination in the air by dropping the AQ value from 100% to some +lower value representing the approximate decrease in air quality. Since +the sensor also factors in the absolute humidity (and via that, the +ambient temperature) into the AQ calculation, high humidity will also +drop the value, as this too impacts the air quality. Hopefully this +is useful for your purposes. + +If you find that the AQ value still doesn't represent known reality, +you can also tweak the in-code value for `ph_slope` on line 522, as +it's possible your sensor differs significantly here. As mentioned +above this is still a work in progress to determine for myself, so +future versions may alter this or include calibration of this value +automatically, depending on how things go in my testing. diff --git a/supersensor.yaml b/supersensor.yaml index d95e689..09338f6 100644 --- a/supersensor.yaml +++ b/supersensor.yaml @@ -26,7 +26,7 @@ esphome: friendly_name: "Supersensor" project: name: joshuaboniface.supersensor - version: "1.0" + version: "1.1" on_boot: - priority: 600 then: