Dear community,
yesterday, I have implemented a ESP32 with a BME680 to measure the air quality in our living room.
The sensor is providing data: temperature and humidity seem to be in an expected range, but the VOCs are just way off.
I do have to old Airthings Wave Plus devices: one in the basement, one in the second floor.
I can see the radon coming from the basement to the second floor. there is a correlation between values in the basement and in the second floor. So there is an airflow going upward through the houseâŠ
VOCs in the basement are very low, VOCs in the second floor jump up and down. (50 - 1100 ppb)
The newly BME680 is running for almost 12h and VOC values are way to high. If this was true, the sensor in the second floor (screenshot red) would be much higher.
Question: who has experience with this sensor? Is this expected behaviour? How long does the calibration period take? (BME680 Numeric IAQ Accuracy is switching between 2 and 3.)
Any help is very much appreciated.
ESPHome yaml
# sources:
# https://esphome.io/components/sensor/airthings_ble
# https://esphome.io/components/sensor/bme680_bsec.html
# Variablen
substitutions:
device_name: "esphome-wohnzimmer2"
friendly_name: "Wohnzimmer2"
node_name: "esphome_wohnzimmer2"
device_description: "Sensor liest den Airthings Wave Plus Sensor im Keller via Bluetooth aus und liefert Daten ĂŒber den BME680"
# ESPHome Core Configuration
esphome:
name: '${device_name}'
friendly_name: '${friendly_name}'
comment: '${device_description}'
# Loop, der nach erfolgreicher WLAN-Verbindung und Zeitabfrage ausgefĂŒhrt wird
on_boot:
priority: -100 # Setze die PrioritĂ€t niedriger als die WLAN-Verbindung (standardmĂ€Ăig -10)
then:
- while:
condition:
not:
lambda: 'return id(homeassistant_time).now().is_valid();'
then:
- delay: 1s # Warte eine Sekunde, bevor erneut ĂŒberprĂŒft wird
- lambda: |-
// Sobald die Zeit verfĂŒgbar ist, berechne den Boot-Zeitpunkt
id(${node_name}_last_boot_time).publish_state(
id(homeassistant_time).now().timestamp - (int) id(${node_name}_uptime_seconds).state
);
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
level: DEBUG
# Airthings Wave Plus finden
esp32_ble_tracker:
# airthings_ble:
# Enable Home Assistant API
api:
encryption:
key: "j...x"
ota:
- platform: esphome
password: "e7....1c"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
manual_ip:
# Set this to the IP of the ESP
static_ip: 192.168.30.26
# Set this to the IP address of the router. Often ends with .1
gateway: 192.168.30.1
# The subnet of the network. 255.255.255.0 works for most home networks.
subnet: 255.255.255.0
use_address: ${node_name}.internal
domain: .internal
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: '${device_name}'
password: "Bf...6"
captive_portal:
# Zeit von HomeAssistant abfragen -> fĂŒr Last Boot nötig
time:
- platform: homeassistant
id: homeassistant_time
switch:
- platform: restart
name: "ESPHome '${friendly_name}' neu starten"
# Airthings Wave Plus einbinden
ble_client:
- mac_address: A4:DA:32:B9:5A:A5
id: awp_Keller
# i2c-config fĂŒr BME680-Sensor
i2c:
sda: GPIO21
scl: GPIO22
scan: false
id: bus_a
bme680_bsec:
id: bme680_internal
address: 0x77
temperature_offset: 0
iaq_mode: static
supply_voltage: 3.3V
sample_rate: ulp
state_save_interval: 6h
sensor:
# Airthings Wave Plus Keller
- platform: airthings_wave_plus
name: '${friendly_name} Keller'
ble_client_id: awp_Keller
update_interval: 5min # default
battery_update_interval: 24h # default
temperature:
name: "Keller Temperatur"
id: awp_Keller_temp
radon:
name: "Keller Radon"
id: awp_Keller_Radon
radon_long_term:
name: "Keller Radon Long Term"
id: awp_Keller_Radon_long
pressure:
name: "Keller Luftdruck"
id: awp_Keller_pressure
humidity:
name: "Keller Feuchtigkeit"
id: awp_Keller_humidity
co2:
name: "Keller CO2"
id: awp_Keller_co2
tvoc:
name: "Keller VOC"
id: awp_Keller_voc
illuminance:
name: "Keller ambient light"
id: awp_Keller_light
battery_voltage:
name: "Keller Batterie Spannung"
id: awp_Keller_volt
# Airthings Wave Plus Keller: Batterieanzeige in %
- platform: copy
source_id: awp_Keller_volt
name: 'Keller Battery Level'
id: awp_Keller_battery
unit_of_measurement: "%"
device_class: battery
accuracy_decimals: 0
filters:
- calibrate_linear:
- 2.2 -> 0
- 3.1 -> 100
# Airthings Wave Plus Keller: Taupunkt berechnen
- platform: template
name: "Keller Taupunkt"
lambda: |-
return (243.5*(log(id(awp_Keller_humidity).state/100)+((17.67*id(awp_Keller_temp).state)/
(243.5+id(awp_Keller_temp).state)))/(17.67-log(id(awp_Keller_humidity).state/100)-
((17.67*id(awp_Keller_temp).state)/(243.5+id(awp_Keller_temp).state))));
device_class: temperature
state_class: measurement
unit_of_measurement: °C
update_interval: 5min
icon: 'mdi:thermometer-water'
# Example configuration entry for BME680
# - platform: bme680
# temperature:
# name: "BME680 Temperature"
# pressure:
# name: "BME680 Pressure"
# humidity:
# id: "humidity"
# name: "BME680 Humidity"
# gas_resistance:
# id: "gas_resistance"
# name: "BME680 Gas Resistance"
# i2c_id: bus_a
# address: 0x77
# update_interval: 60s
# - platform: template
# name: "BME680 Indoor Air Quality"
# id: iaq
# icon: "mdi:gauge"
# # calculation: comp_gas = log(R_gas[ohm]) + 0.04 log(Ohm)/%rh * hum[%rh]
# lambda: |-
# return log(id(gas_resistance).state) + 0.04 * id(humidity).state;
# state_class: "measurement"
- platform: bme680_bsec
# ID of the bme680_bsec component to use for the next sensors.
# Useful when working with multiple devices
bme680_bsec_id: bme680_internal
temperature:
# Temperature in °C
name: "BME680 Temperature"
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
pressure:
# Pressure in hPa
name: "BME680 Pressure"
sample_rate: ulp
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
accuracy_decimals: 0
humidity:
# Relative humidity %
name: "BME680 Humidity"
sample_rate: ulp
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
accuracy_decimals: 0
gas_resistance:
# Gas resistance in Ω
name: "BME680 Gas Resistance"
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
iaq:
# Indoor air quality value
name: "BME680 IAQ"
id: iaq
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
iaq_accuracy:
# IAQ accuracy as a numeric value of 0, 1, 2, 3
name: "BME680 Numeric IAQ Accuracy"
co2_equivalent:
# CO2 equivalent estimate in ppm
name: "BME680 CO2 Equivalent"
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
accuracy_decimals: 0
breath_voc_equivalent:
# Volatile organic compounds equivalent estimate in ppm
name: "BME680 Breath VOC Equivalent Source"
id: voc_source
internal: true
filters:
- median:
window_size: 5
send_every: 1
send_first_at: 1
- platform: template
name: "BME680 Breath VOC Equivalent"
id: BME680_voc_calc
lambda: |-
return ( (id(voc_source).state) * 1000) ;
device_class: volatile_organic_compounds_parts
state_class: measurement
unit_of_measurement: ppb
accuracy_decimals: 0
update_interval: 5min
icon: 'mdi:molecule'
# Last Boot Sensor definieren (Berechnung findet einmalig beim Boot statt)
- platform: uptime
id: ${node_name}_uptime_seconds
name: "Uptime Sekunden"
internal: true
- platform: template
name: "Last Boot"
id: ${node_name}_last_boot_time
device_class: timestamp
entity_category: diagnostic
accuracy_decimals: 0
update_interval: never # Kein regelmĂ€Ăiges Update nötig
text_sensor:
# Air Quality-Angaben
- platform: template
name: "BME680 IAQ Classification"
icon: "mdi:checkbox-marked-circle-outline"
lambda: |-
if (int(id(iaq).state) <= 50) {
return {"Excellent"};
}
else if (int(id(iaq).state) <= 100) {
return {"Good"};
}
else if (int(id(iaq).state) <= 150) {
return {"Lightly polluted"};
}
else if (int(id(iaq).state) <= 200) {
return {"Moderately polluted"};
}
else if (int(id(iaq).state) <= 250) {
return {"Heavily polluted"};
}
else if (int(id(iaq).state) <= 350) {
return {"Severely polluted"};
}
else if (int(id(iaq).state) <= 500) {
return {"Extremely polluted"};
}
else {
return {"unknown"};
}
# Send IP Address of ESP-device
- platform: wifi_info
ip_address:
name: IP Address
- platform: bme680_bsec
iaq_accuracy:
# IAQ accuracy as a text value of Stabilizing, Uncertain, Calibrating, Calibrated
name: "BME680 IAQ Accuracy"
EDIT
I have put the sensor in a freshly printed case (PLA). I have read that PLA emits VOCs during printing, but I found no information about emiting VOCs afterwards as well?
EDIT2
AFAIK, there should be a correlation between gas resistance and VOC-values?



