SGP30's were too unreliable, so swap to the SGP41 and its adjusted configurations. We leverage the same algorithm and values as the AirGradient One to ensure consistency.
256 lines
6.3 KiB
YAML
256 lines
6.3 KiB
YAML
---
|
|
|
|
###############################################################################
|
|
# MicroEnv v1.0 ESPHome configuration
|
|
###############################################################################
|
|
#
|
|
# Copyright (C) 2025 Joshua M. Boniface <joshua@boniface.me>
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, version 3.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
#
|
|
###############################################################################
|
|
|
|
esphome:
|
|
name: microenv
|
|
name_add_mac_suffix: true
|
|
friendly_name: "MicroEnv Sensor"
|
|
project:
|
|
name: "Joshua Boniface.microenv"
|
|
version: "1.0"
|
|
min_version: 2025.5.0
|
|
|
|
dashboard_import:
|
|
package_import_url: github://joshuaboniface/microenv/microenv.yaml
|
|
|
|
esp32:
|
|
board: esp32-c3-devkitm-1
|
|
variant: esp32c3
|
|
framework:
|
|
type: esp-idf
|
|
|
|
preferences:
|
|
flash_write_interval: 15sec
|
|
|
|
globals:
|
|
# Defaults to -5 due to heating from the ESP
|
|
- id: temperature_offset
|
|
type: float
|
|
restore_value: true
|
|
initial_value: "-5.0"
|
|
|
|
- id: humidity_offset
|
|
type: float
|
|
restore_value: true
|
|
initial_value: "0.0"
|
|
|
|
logger:
|
|
level: INFO
|
|
baud_rate: 115200
|
|
|
|
api:
|
|
reboot_timeout: 15min
|
|
|
|
ota:
|
|
platform: esphome
|
|
|
|
web_server:
|
|
port: 80
|
|
|
|
captive_portal:
|
|
|
|
mdns:
|
|
disabled: false
|
|
|
|
wifi:
|
|
ap: {}
|
|
domain: ""
|
|
output_power: 8.5dB
|
|
reboot_timeout: 15min
|
|
power_save_mode: none
|
|
|
|
i2c:
|
|
- id: i2c_bus
|
|
sda: GPIO21
|
|
scl: GPIO20
|
|
scan: true
|
|
|
|
sensor:
|
|
- platform: sgp4x
|
|
voc:
|
|
name: "SGP41 VOC Index"
|
|
id: sgp41_voc_index
|
|
accuracy_decimals: 0
|
|
icon: mdi:molecule
|
|
filters:
|
|
- sliding_window_moving_average: # We take a reading every 15 seconds, but calculate the sliding
|
|
window_size: 12 # average over 12 readings i.e. 60 seconds/1 minute to normalize
|
|
send_every: 3 # brief spikes while still sending a value every 15 seconds.
|
|
nox:
|
|
name: "SGP41 NOx Index"
|
|
id: sgp41_nox_index
|
|
accuracy_decimals: 0
|
|
icon: mdi:molecule
|
|
filters:
|
|
- sliding_window_moving_average:
|
|
window_size: 12
|
|
send_every: 3
|
|
compensation:
|
|
temperature_source: sht45_temperature
|
|
humidity_source: sht45_humidity
|
|
store_baseline: true
|
|
update_interval: 5s
|
|
|
|
- platform: template
|
|
name: "SGP41 TVOC (µg/m³)"
|
|
id: sgp41_tvoc_ugm3
|
|
lambda: |-
|
|
float i = id(sgp41_voc_index).state;
|
|
if (i < 1) return NAN;
|
|
float tvoc = (log(501.0 - i) - 6.24) * -878.53;
|
|
return tvoc;
|
|
unit_of_measurement: "µg/m³"
|
|
accuracy_decimals: 0
|
|
|
|
- platform: template
|
|
name: "SGP41 TVOC (ppb)"
|
|
id: sgp41_tvoc_ppb
|
|
lambda: |-
|
|
float tvoc_ugm3 = id(sgp41_tvoc_ugm3).state;
|
|
float tvoc_ppm = tvoc_ugm3 * 0.436; // ppb estimated using isobutylene MW (56.1 g/mol)
|
|
return tvoc_ppm;
|
|
unit_of_measurement: "ppb"
|
|
accuracy_decimals: 0
|
|
|
|
- platform: template
|
|
name: "SGP41 eCO2 (approx ppm)"
|
|
id: sgp41_eco2_ppm
|
|
lambda: |-
|
|
float tvoc_ppb = id(sgp41_tvoc_ppb).state;
|
|
float eco2_ppm = 400.0 + 1.5 * tvoc_ppb;
|
|
if (eco2_ppm > 2000) eco2_ppm = 2000;
|
|
return eco2_ppm;
|
|
unit_of_measurement: "ppm"
|
|
accuracy_decimals: 0
|
|
|
|
- platform: sht4x
|
|
temperature:
|
|
name: "SHT45 Temperature"
|
|
id: sht45_temperature
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- offset: !lambda return id(temperature_offset);
|
|
- sliding_window_moving_average:
|
|
window_size: 4
|
|
send_every: 1
|
|
humidity:
|
|
name: "SHT45 Relative Humidity"
|
|
id: sht45_humidity
|
|
accuracy_decimals: 1
|
|
filters:
|
|
- offset: !lambda return id(humidity_offset);
|
|
- sliding_window_moving_average:
|
|
window_size: 4
|
|
send_every: 1
|
|
heater_max_duty: 0.0
|
|
update_interval: 15s
|
|
|
|
- platform: absolute_humidity
|
|
name: "SHT45 Absolute Humidity"
|
|
temperature: sht45_temperature
|
|
humidity: sht45_humidity
|
|
id: sht45_absolute_humidity
|
|
|
|
- platform: template
|
|
name: "SHT45 Dew Point"
|
|
icon: mdi:thermometer-water
|
|
id: sht45_dew_point
|
|
unit_of_measurement: "°C"
|
|
lambda: |-
|
|
float temp = id(sht45_temperature).state;
|
|
float rh = id(sht45_humidity).state;
|
|
if (isnan(temp) || isnan(rh)) return NAN;
|
|
float a = 17.27, b = 237.7;
|
|
float alpha = ((a * temp) / (b + temp)) + log(rh / 100.0);
|
|
return (b * alpha) / (a - alpha);
|
|
update_interval: 15s
|
|
|
|
- platform: wifi_signal
|
|
name: "WiFi Signal"
|
|
update_interval: 60s
|
|
entity_category: diagnostic
|
|
|
|
- platform: uptime
|
|
name: "Uptime"
|
|
update_interval: 60s
|
|
entity_category: diagnostic
|
|
|
|
text_sensor:
|
|
- platform: version
|
|
name: "ESPHome Version"
|
|
entity_category: diagnostic
|
|
|
|
- platform: wifi_info
|
|
ip_address:
|
|
name: "WiFi IP Address"
|
|
ssid:
|
|
name: "WiFi SSID"
|
|
bssid:
|
|
name: "WiFi BSSID"
|
|
mac_address:
|
|
name: "WiFi MAC Address"
|
|
|
|
button:
|
|
- platform: restart
|
|
name: "ESP32 Restart"
|
|
icon: mdi:power-cycle
|
|
entity_category: diagnostic
|
|
|
|
- platform: factory_reset
|
|
name: "ESP32 Factory Reset"
|
|
icon: mdi:restart-alert
|
|
entity_category: diagnostic
|
|
|
|
number:
|
|
# Temperature offset:
|
|
# A calibration from -30 to +5 for the temperature sensor
|
|
- platform: template
|
|
name: "Temperature Offset"
|
|
id: temperature_offset_setter
|
|
min_value: -30
|
|
max_value: 10
|
|
step: 0.1
|
|
lambda: |-
|
|
return id(temperature_offset);
|
|
set_action:
|
|
then:
|
|
- globals.set:
|
|
id: temperature_offset
|
|
value: !lambda 'return float(x);'
|
|
|
|
# Humidity offset:
|
|
# A calibration from -20 to +20 for the humidity sensor
|
|
- platform: template
|
|
name: "Humidity Offset"
|
|
id: humidity_offset_setter
|
|
min_value: -20
|
|
max_value: 20
|
|
step: 0.1
|
|
lambda: |-
|
|
return id(humidity_offset);
|
|
set_action:
|
|
then:
|
|
- globals.set:
|
|
id: humidity_offset
|
|
value: !lambda 'return float(x);'
|
|
|