Working in a basement office for many years may result in long term dangers to one's health, with regards to Radon, Carbon Monoxide, etc.... With that in mind I set up some sensors and a dashboard:
(Actually I do not understand why the VOC jumped up as it was very low until today!....)
...and clicking on the "Explanation" rollup exposes:
And FYI, about 15 minutes ago I moved the AIR-1 sensor maybe a big mistake as you can see in the next screen shot below if you want to continuously measure readings as a baseline...! (I looked at those sensors a few minutes later and they are all back to their same previous levels, so it must have taken a measurement while I was moving it...)
Therefore it is best to put it in one p[lace and not move it again! Ideally it shoujld be about 4 to 6 feet above the floor, and the top of the unit should be not near any obstructions, away from HVAC supply vents, away from dehumidifier exhaust, away from exterior doors, away from windows, not directly under a ceiling fan, not in a corner... Think "head height while sitting" rather than "highest shelf available." Do NOT put it next to a furnace, water heater, sump pit, beside stairs, near a dehumidifier, on the ceiling or on the floor. Also it should not be near any computer monitors, heat sources or electronics and should be somewhere as close to where people breathe as possible.
Hardware:
Yolink Smoke/CO Detector (I use this for the CO detection)
Apollo AIR-1 Sensor with CO2 sensor option (WiFi based on ESPHome)
Airthings Wave2 Radon Sensor (Bluetooth)
Software:
I have a bunch of Shelly relays which can act at Bluetooth Proxies all over the house, but they do not work with the Wave2, as it is an active communicator needing a more robust proxy. However, the Apollo Air 1 since it is ESP32 ESPHome based, can act as a Bluetooth Proxy - but only if you burn a specific firmware they give you (that functionality is not avaliable by default). Also, do not add Apollo to your ESPHome HA integration when you first get it, because then the HA ESPHome Builder integration (which is easiest to use to burn the correct firmare) will not be able to see the AIR-1. First, add it the Air-1 into the ESPHome Builder integration - and then add it into the HA ESPHome integration later after updating the firmware. Then, as soon as you add the AIR-1 to the HA ESPHome integration, almost immediately you will see the Wave2 appears as a discovered device which you can then add to HA with the Airthings integration. (FYI the NYC Area AQI comes from the AirNow integration.)
Here is the source code for the above dashboard:
views:
- title: Basement Air Quality
path: overview
icon: mdi:molecule-co2
cards:
- type: markdown
content: |
{% set green = '#00c853' %}
{% set orange = '#ff9800' %}
{% set red = '#ff1744' %}
{% set co = states('binary_sensor.bsmt_steps_smoke_co_alarm_co_detected') | lower %}
{% set co_color = green if co == 'off' else red if co == 'on' else '' %}
{% set radon1 = states('sensor.basement_airthings_wave2_radon_sensor_radon_1_day_average') | float(0) %}
{% set radon1_color = green if radon1 < 2 else orange if radon1 < 4 else red %}
{% set radonlt = states('sensor.basement_airthings_wave2_radon_sensor_radon_longterm_average') | float(0) %}
{% set radonlt_color = green if radonlt < 2 else orange if radonlt < 4 else red %}
{% set radon_level = states('sensor.basement_airthings_wave2_radon_sensor_radon_1_day_level') | lower %}
{% set radon_level_color = green if radon_level in ['excellent','normal','good','off','ideal'] else orange if radon_level in ['moderate','watch'] else red if radon_level in ['high','very high','abnormal','very abnormal','extremely abnormal','extermely anormal','poor','unhealthy','extremely unhealthy'] else '' %}
{% set co2 = states('sensor.basement_apollo_air_1_air_sensor_co2') | float(0) %}
{% set co2_color = green if co2 < 800 else orange if co2 <= 1200 else red %}
{% set aqi_bsmt = states('sensor.basement_apollo_air_1_air_sensor_nowcast_aqi') | float(0) %}
{% set aqi_bsmt_color = green if aqi_bsmt <= 50 else orange if aqi_bsmt <= 100 else red %}
{% set aqi_nyc = states('sensor.airnow_aqi') | float(0) %}
{% set aqi_nyc_color = green if aqi_nyc <= 50 else orange if aqi_nyc <= 100 else red %}
{% set voc_quality = states('sensor.basement_apollo_air_1_air_sensor_voc_quality') | lower %}
{% set voc_quality_color = green if voc_quality in ['excellent','normal','good','off','ideal'] else orange if voc_quality in ['moderate','watch'] else red if voc_quality in ['high','very high','abnormal','very abnormal','extremely abnormal','extermely anormal','poor','unhealthy','extremely unhealthy'] else '' %}
{% set humidity = states('sensor.basement_airthings_wave2_radon_sensor_humidity') | float(0) %}
{% set humidity_color = orange if humidity < 30 else green if humidity < 50 else orange if humidity <= 60 else red %}
{% set pm25 = states('sensor.basement_apollo_air_1_air_sensor_pm_2_5mm_weight_concentration') | float(0) %}
{% set pm25_color = green if pm25 <= 9 else orange if pm25 <= 35.4 else red %}
{% set pm10 = states('sensor.basement_apollo_air_1_air_sensor_pm_10mm_weight_concentration') | float(0) %}
{% set pm10_color = green if pm10 < 50 else orange if pm10 <= 100 else red %}
{% set voc_index = states('sensor.basement_apollo_air_1_air_sensor_sen55_voc') | float(0) %}
{% set voc_index_color = green if voc_index <= 150 else orange if voc_index <= 250 else red %}
### Sensor Levels
<table>
<tr>
<td>
<table>
<tr><th>Reading</th><th>Currently</th></tr>
<tr><td><font color="{{ co_color }}">CO Alarm</font></td><td><font color="{{ co_color }}">{{ states('binary_sensor.bsmt_steps_smoke_co_alarm_co_detected') }}</font></td></tr>
<tr><td><font color="{{ radon_level_color }}">Radon Level</font></td><td><font color="{{ radon_level_color }}">{{ states('sensor.basement_airthings_wave2_radon_sensor_radon_1_day_level') }}</font></td></tr>
<tr><td><font color="{{ radon1_color }}">Radon 1-Day</font></td><td><font color="{{ radon1_color }}">{{ radon1 | round(2) }} pCi/L</font></td></tr>
<tr><td><font color="{{ radonlt_color }}">Radon Long Term</font></td><td><font color="{{ radonlt_color }}">{{ radonlt | round(2) }} pCi/L</font></td></tr>
<tr><td><font color="{{ co2_color }}">CO₂</font></td><td><font color="{{ co2_color }}">{{ co2 | round(0) }} ppm</font></td></tr>
<tr><td>PM1</td><td>{{ states('sensor.basement_apollo_air_1_air_sensor_pm_1mm_weight_concentration') | float(0) | round(1) }} µg/m³</td></tr>
<tr><td><font color="{{ pm25_color }}">PM2.5</font></td><td><font color="{{ pm25_color }}">{{ pm25 | round(1) }} µg/m³</font></td></tr>
<tr><td><font color="{{ pm10_color }}">PM10</font></td><td><font color="{{ pm10_color }}">{{ pm10 | round(1) }} µg/m³</font></td></tr>
</table>
</td>
<td>
<table>
<tr><th>Reading</th><th>Currently</th></tr>
<tr><td><font color="{{ voc_index_color }}">VOC Index</font></td><td><font color="{{ voc_index_color }}">{{ voc_index | round(0) }}</font></td></tr>
<tr><td><font color="{{ voc_quality_color }}">VOC Quality</font></td><td><font color="{{ voc_quality_color }}">{{ states('sensor.basement_apollo_air_1_air_sensor_voc_quality') }}</font></td></tr>
<tr><td>Temperature</td><td>{{ states('sensor.basement_airthings_wave2_radon_sensor_temperature') | float(0) | round(1) }} °F</td></tr>
<tr><td><font color="{{ humidity_color }}">Humidity</font></td><td><font color="{{ humidity_color }}">{{ humidity | round(1) }}%</font></td></tr>
<tr><td>Barometric Pressure</td><td>{{ states('sensor.basement_apollo_air_1_air_sensor_dps310_pressure') | float(0) | round(2) }} psi</td></tr>
<tr><td><font color="{{ aqi_bsmt_color }}">AQI Bsmt</font></td><td><font color="{{ aqi_bsmt_color }}">{{ aqi_bsmt | round(0) }}</font></td></tr>
<tr><td><font color="{{ aqi_nyc_color }}">AQI NYC</font></td><td><font color="{{ aqi_nyc_color }}">{{ aqi_nyc | round(0) }}</font></td></tr>
<tr><td>Light Level</td><td>{{ states('sensor.basement_airthings_wave2_radon_sensor_illuminance') | float(0) | round(0) }}%</td></tr>
</table>
</td>
</tr>
</table>
### Particulate Matter Quantity by Size
<table style="margin-top:6px;">
<tr>
<td>
<table>
<tr><th>µm Band</th><th>Currently</th></tr>
<tr><td>PM 0.3 to 1.0</td><td>{{ states('sensor.apollo_air_1_2b9738_pm_0_3_to_1_mm') | float(0) | round(1) }} µg/m³</td></tr>
<tr><td>PM 1.1 to 2.5</td><td>{{ states('sensor.apollo_air_1_2b9738_pm_1_to_2_5_mm') | float(0) | round(1) }} µg/m³</td></tr>
</table>
</td>
<td>
<table>
<tr><th>µm Band</th><th>Currently</th></tr>
<tr><td>PM 2.5 to 4.0</td><td>{{ states('sensor.apollo_air_1_2b9738_pm_2_5_to_4_mm') | float(0) | round(1) }} µg/m³</td></tr>
<tr><td>PM 4.1 to 10</td><td>{{ states('sensor.apollo_air_1_2b9738_pm_4_to_10_mm') | float(0) | round(1) }} µg/m³</td></tr>
</table>
</td>
</tr>
</table>
card_mod:
style: |
ha-card { font-size: 12px; line-height: 1.2; }
ha-markdown h3 { font-size: 14px; margin: 8px 0 6px 0; }
ha-markdown table { width: 100% !important; border-collapse: collapse; table-layout: fixed; }
ha-markdown > table > tbody > tr > td { width: 50% !important; vertical-align: top; padding: 0 8px 0 0; border: none !important; }
ha-markdown th:first-child, ha-markdown td:first-child { width: 70%; white-space: normal; }
ha-markdown th:last-child, ha-markdown td:last-child { width: 30%; text-align: right; white-space: nowrap; }
ha-markdown td, ha-markdown th { padding: 2px 4px; }
- type: markdown
content: |
<details>
<summary><b>Explanation</b></summary>
- **CO Alarm:** Carbon monoxide alarm from the smoke/CO detector.
- <font color="#00c853"><b>Off:</b> normal.</font>
- <font color="#ff1744"><b>On:</b> dangerous carbon monoxide may be present.</font>
- **Radon:** Radioactive gas from the ground. Long-term average matters most.
- <font color="#00c853"><b>Good:</b> less than 2 pCi/L.</font>
- <font color="#ff9800"><b>Watch:</b> 2 pCi/L or higher, but less than 4 pCi/L.</font>
- <font color="#ff1744"><b>Action:</b> 4 pCi/L or higher.</font>
- **CO₂:** Carbon dioxide. A ventilation and stale-air indicator.
- <font color="#00c853"><b>Good:</b> less than 800 ppm.</font>
- <font color="#ff9800"><b>Watch:</b> 800 ppm through 1200 ppm.</font>
- <font color="#ff1744"><b>High:</b> more than 1200 ppm.</font>
- **AQI:** Basement is local Apollo AQI. NYC is regional AirNow AQI.
- <font color="#00c853"><b>Good:</b> 0 through 50.</font>
- <font color="#ff9800"><b>Moderate:</b> 51 through 100.</font>
- <font color="#ff1744"><b>Unhealthy:</b> 101 or higher.</font>
- **VOC:** Volatile Organic Compounds.
- <font color="#00c853"><b>Normal:</b> fine.</font>
- <font color="#ff1744"><b>Abnormal / Very abnormal / Poor:</b> investigate.</font>
- **Humidity:** Moisture level in the air.
- <font color="#ff9800"><b>Dry / Watch:</b> less than 30%.</font>
- <font color="#00c853"><b>Ideal:</b> 30% or higher, but less than 50%.</font>
- <font color="#ff9800"><b>Watch:</b> 50% through 60%.</font>
- <font color="#ff1744"><b>Mold risk:</b> more than 60%.</font>
- **Pressure:** Barometric pressure.
- <font color="#00c853"><b>Rising pressure:</b> usually points toward clearing or stable weather.</font>
- <font color="#ff9800"><b>Falling pressure:</b> usually points toward unsettled weather or storms.</font>
- **Light Level:** Relative ambient light around the Airthings sensor.
- ~0% = dark.
- ~20% = dim or low room lighting.
- ~50% or higher = brighter lighting.
- **PM:** Particulate Matter (tiny particles suspended in the air).
- µg/m³ = Micrograms per Cubic Meter
- **PM1:** Ultra-fine particles ≤ 1.0 µm
- Smoke, candle soot, diesel exhaust, wildfire smoke, cooking fumes
- Lower values are generally better.
- **PM2.5:** Fine particles ≤ 2.5 microns (includes PM1):
- Smoke, combustion particles, aerosols, fine dust, some mold spores
- <font color="#00c853"><b>Good:</b> 0 through 9 µg/m³.</font>
- <font color="#ff9800"><b>Moderate:</b> more than 9 through 35.4 µg/m³.</font>
- <font color="#ff1744"><b>Unhealthy:</b> more than 35.4 µg/m³.</font>
- **PM10:** Larger particles ≤ 10 microns (includes PM1, PM5)
- Dust, pollen, pet dander, construction dust, textile fibers
- <font color="#00c853"><b>Excellent / Good:</b> less than 50 µg/m³.</font>
- <font color="#ff9800"><b>Watch:</b> 50 through 100 µg/m³.</font>
- <font color="#ff1744"><b>Poor:</b> more than 100 µg/m³.</font>
</details>
card_mod:
style: |
ha-card { font-size: 12px; line-height: 1.2; }
ha-markdown li { margin-bottom: 1px; }
- type: history-graph
title: Radon - Last 7 Days
hours_to_show: 168
entities:
- sensor.basement_airthings_wave2_radon_sensor_radon_1_day_average
- sensor.basement_airthings_wave2_radon_sensor_radon_longterm_average
card_mod:
style: |
.card-header {
font-size: 18px !important;
font-weight: 400 !important;
}
- type: history-graph
title: PM Particles 24 Hr Wt Concentration
hours_to_show: 24
entities:
- sensor.basement_apollo_air_1_air_sensor_pm_2_5mm_weight_concentration
- sensor.basement_apollo_air_1_air_sensor_pm_10mm_weight_concentration
- sensor.apollo_air_1_2b9738_pm_0_3_to_1_mm
- sensor.apollo_air_1_2b9738_pm_1_to_2_5_mm
- sensor.apollo_air_1_2b9738_pm_2_5_to_4_mm
- sensor.apollo_air_1_2b9738_pm_4_to_10_mm
card_mod:
style: |
.card-header {
font-size: 18px !important;
font-weight: 400 !important;
}
- type: history-graph
title: CO₂ - Last 24 Hours
hours_to_show: 24
entities:
- sensor.basement_apollo_air_1_air_sensor_co2
card_mod:
style: |
.card-header {
font-size: 18px !important;
font-weight: 400 !important;
}
- type: history-graph
title: AQI and VOC - 24 Hours
hours_to_show: 24
entities:
- sensor.basement_apollo_air_1_air_sensor_nowcast_aqi
- sensor.airnow_aqi
- sensor.basement_apollo_air_1_air_sensor_sen55_voc
card_mod:
style: |
.card-header {
font-size: 18px !important;
font-weight: 400 !important;
}
- type: history-graph
title: Temp & Humidity last 24 Hrs
hours_to_show: 24
entities:
- sensor.basement_airthings_wave2_radon_sensor_temperature
- sensor.basement_airthings_wave2_radon_sensor_humidity
card_mod:
style: |
.card-header {
font-size: 18px !important;
font-weight: 400 !important;
}
- type: history-graph
title: Barometer (Rising->Clearing, Falling->Storms)
hours_to_show: 168
entities:
- sensor.basement_apollo_air_1_air_sensor_dps310_pressure
card_mod:
style: |
.card-header {
font-size: 18px !important;
font-weight: 400 !important;
}
Obviously it makes little sense to have another Radon sensor unless that is in a different part of a basement, but I may in the future use some of this as a template for setting up other Apollo AIR-1's in other rooms where we spend alot of time.
Enjoy!






