--- ############################################################################### # SuperSensor v2.0 ESPHome configuration ############################################################################### # # Copyright (C) 2025 Joshua M. Boniface # # 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 . # ############################################################################### 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: sgp30 address: 0x58 eco2: name: "SGP30 eCO2" id: sgp30_eco2 accuracy_decimals: 1 icon: mdi:molecule-co2 filters: - sliding_window_moving_average: window_size: 20 send_every: 1 tvoc: name: "SGP30 TVOC" id: sgp30_tvoc accuracy_decimals: 1 icon: mdi:molecule filters: - sliding_window_moving_average: window_size: 20 send_every: 1 eco2_baseline: name: "SGP30 Baseline eCO2" id: sgp30_baseline_ec02 tvoc_baseline: name: "SGP30 Baseline TVOC" id: sgp30_baseline_tvoc compensation: temperature_source: sht45_temperature humidity_source: sht45_humidity store_baseline: yes update_interval: 15s - 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: 20 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: 20 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 # IAQ Index (1-5, 5=Great)) - platform: template name: "IAQ Index" icon: mdi:air-purifier id: iaq_index lambda: |- int tvoc = id(sgp30_tvoc).state; int eco2 = id(sgp30_eco2).state; if (tvoc > 2200 || eco2 > 2000) return 1; // Bad if (tvoc > 660 || eco2 > 1200) return 2; // Poor if (tvoc > 220 || eco2 > 800) return 3; // Fair if (tvoc > 65 || eco2 > 500) return 4; // Good return 5; // Great update_interval: 15s # Room Health Score (1-4, 4=Optimal) - platform: template name: "Room Health Score" icon: mdi:home-thermometer id: room_health lambda: |- float temp = id(sht45_temperature).state; float rh = id(sht45_humidity).state; int iaq = id(iaq_index).state; bool temp_ok = (temp >= 18 && temp <= 24); bool hum_ok = (rh >= 30 && rh <= 70); bool iaq_ok = (iaq >= 4); int conditions_met = 0; if (temp_ok) conditions_met++; if (hum_ok) conditions_met++; if (iaq_ok) conditions_met++; if (iaq_ok && temp_ok && hum_ok) { return 4; // Optimal: All conditions met and IAQ is excellent/good } else if (iaq >= 3 && conditions_met >= 2) { return 3; // Fair: IAQ is moderate and at least 2 conditions met } else if (iaq >= 2 && conditions_met >= 1) { return 2; // Poor: IAQ is poor and at least 1 condition met } else { return 1; // Bad: All conditions failed or IAQ is unhealthy } - 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" # VOC Level - platform: template name: "VOC Level" icon: mdi:molecule lambda: |- int tvoc = id(sgp30_tvoc).state; if (tvoc < 65) return {"Great"}; if (tvoc < 220) return {"Good"}; if (tvoc < 660) return {"Fair"}; if (tvoc < 2200) return {"Poor"}; return {"Bad"}; update_interval: 15s # CO2 Level - platform: template name: "CO2 Level" icon: mdi:molecule-co2 lambda: |- int eco2 = id(sgp30_eco2).state; if (eco2 < 500) return {"Great"}; if (eco2 < 800) return {"Good"}; if (eco2 < 1200) return {"Fair"}; if (eco2 < 2000) return {"Poor"}; return {"Bad"}; update_interval: 15s # IAQ Classification - platform: template name: "IAQ Classification" icon: mdi:air-purifier lambda: |- int iaq = id(iaq_index).state; if (iaq == 5) return {"Great"}; if (iaq == 4) return {"Good"}; if (iaq == 3) return {"Fair"}; if (iaq == 2) return {"Poor"}; return {"Bad"}; update_interval: 15s # Room Health - platform: template name: "Room Health" icon: mdi:home-thermometer lambda: |- int score = id(room_health).state; if (score == 4) return {"Optimal"}; if (score == 3) return {"Fair"}; if (score == 2) return {"Poor"}; return {"Bad"}; update_interval: 15s 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);'