more esphome devices and fixes
This commit is contained in:
@@ -1,31 +1,86 @@
|
||||
##########################################################################################
|
||||
##########################################################################################
|
||||
# LOUNGE ENVIRONMENT SENSOR
|
||||
#
|
||||
# ESP32-C3 SuperMini + BME280 (I2C)
|
||||
#
|
||||
#:########################################################################################:#
|
||||
# TITLE: LOUNGE ENVIRONMENT SENSOR
|
||||
#:########################################################################################:#
|
||||
# REPO:
|
||||
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungeenvironment.yaml
|
||||
#:########################################################################################:#
|
||||
# VERSIONS:
|
||||
# V1.5 2026-03-22 Updated yaml to zorruno layout V1.1; fixed units to °C; added
|
||||
# device_class/state_class; retained MQTT publishing and all existing logic
|
||||
# V1.4 2026-03-22 Updated yaml to zorruno layout V1.1; added MQTT publishing for
|
||||
# temperature, humidity and pressure; retained all existing sensor logic
|
||||
# V1.3 2026-03-22 Added MQTT publishing for temperature, humidity and pressure readings
|
||||
# V1.2 2026-02-16 Pressure tendency now 5-state over 3 hours + rate/hour, 1h removed
|
||||
# V1.1 2026-02-16 Added derived min/max sensors and pressure trend text sensors
|
||||
# V1.0 2026-02-16 Initial Version
|
||||
##########################################################################################
|
||||
##########################################################################################
|
||||
#:########################################################################################:#
|
||||
# HARDWARE:
|
||||
# - ESP32-C3 SuperMini
|
||||
# - BME280 (I2C)
|
||||
# - SDA = GPIO1
|
||||
# - SCL = GPIO3
|
||||
# - I2C address = 0x76
|
||||
#:########################################################################################:#
|
||||
# OPERATION NOTES:
|
||||
# - Reads temperature, humidity and pressure from the BME280 every 20 seconds
|
||||
# - Publishes each fresh reading to local MQTT status topics:
|
||||
# - ${mqtt_local_status_topic}/temperature
|
||||
# - ${mqtt_local_status_topic}/humidity
|
||||
# - ${mqtt_local_status_topic}/pressure
|
||||
# - Tracks:
|
||||
# - Lowest Temp Overnight
|
||||
# - Highest Temp Today (Daytime)
|
||||
# - Highest/Lowest Temp This Month
|
||||
# - Highest/Lowest Temp Last Month
|
||||
# - Highest/Lowest Temp Last 24 Hours
|
||||
# - Lowest Humidity Overnight
|
||||
# - Highest Humidity Today (Daytime)
|
||||
# - Highest/Lowest Humidity This Month
|
||||
# - Highest/Lowest Humidity Last Month
|
||||
# - Highest/Lowest Humidity Last 24 Hours
|
||||
# - Pressure direction uses a 3-hour tendency:
|
||||
# - rising rapidly
|
||||
# - rising
|
||||
# - steady
|
||||
# - falling
|
||||
# - falling rapidly
|
||||
# - Pressure rate per hour is calculated from the 3-hour pressure delta
|
||||
#:########################################################################################:#
|
||||
# OFFLINE NOTES:
|
||||
# a) HA offline (network + MQTT online)
|
||||
# - Device continues reading sensors and publishing local MQTT status topics.
|
||||
# b) MQTT offline (or HA/MQTT offline)
|
||||
# - Device continues reading sensors and updating local derived values internally.
|
||||
# c) Entire WiFi/Network offline
|
||||
# - Accurate time is needed for daily/monthly min/max periods and pressure trend timing.
|
||||
# - If SNTP is unavailable, the fallback clock can drift and can be reset by power
|
||||
# cycling at 12pm (midday).
|
||||
#:########################################################################################:#
|
||||
|
||||
substitutions:
|
||||
# Device Naming
|
||||
device_name: "esp-loungeenvironment"
|
||||
friendly_name: "Lounge Environment"
|
||||
description_comment: "Lounge Environment :: ESP32-C3 SuperMini + BME280"
|
||||
description_comment: "Lounge Environment :: ESP32-C3 SuperMini + BME280 (Layout V1.1)"
|
||||
device_area: "Lounge"
|
||||
|
||||
# Project Naming
|
||||
project_name: "ESP32-C3 SuperMini.BME280"
|
||||
project_version: "v1.2"
|
||||
project_version: "v1.5"
|
||||
|
||||
# Passwords
|
||||
api_key: !secret esp-api_key
|
||||
ota_pass: !secret esp-ota_pass
|
||||
static_ip_address: !secret esp-loungeenvironment_ip
|
||||
|
||||
# Layout V1.1 Required
|
||||
current_ip_address: ${static_ip_address}
|
||||
|
||||
# MQTT Local Status
|
||||
mqtt_local_status_main_topic: !secret mqtt_status_main_topic
|
||||
mqtt_device_name: "lounge-environment"
|
||||
mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}"
|
||||
|
||||
# General Settings
|
||||
log_level: "WARN"
|
||||
update_interval: "60s"
|
||||
@@ -54,6 +109,7 @@ packages:
|
||||
vars:
|
||||
local_device_name: "${device_name}"
|
||||
local_static_ip_address: "${static_ip_address}"
|
||||
local_current_ip_address: "${current_ip_address}"
|
||||
local_ota_pass: "${ota_pass}"
|
||||
|
||||
common_api: !include
|
||||
@@ -73,10 +129,10 @@ packages:
|
||||
common_sntp: !include common/sntp_common.yaml
|
||||
|
||||
diag_basic: !include common/include_basic_diag_sensors.yaml
|
||||
diag_more: !include common/include_more_diag_sensors.yaml
|
||||
diag_more: !include common/include_more_diag_sensors.yaml
|
||||
|
||||
##########################################################################################
|
||||
# ESPHome
|
||||
# ESPHOME
|
||||
##########################################################################################
|
||||
esphome:
|
||||
name: "${device_name}"
|
||||
@@ -292,17 +348,26 @@ sensor:
|
||||
name: "${friendly_name} Temperature"
|
||||
id: lounge_temperature
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
on_value:
|
||||
then:
|
||||
# Publish current temperature to local MQTT status topic
|
||||
- mqtt.publish:
|
||||
topic: "${mqtt_local_status_topic}/temperature"
|
||||
payload: !lambda |-
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.2f", x);
|
||||
return std::string(buffer);
|
||||
|
||||
- lambda: |-
|
||||
auto now = id(sntp_time).now();
|
||||
// We only need hour buckets and month stats if we have valid SNTP.
|
||||
if (!now.is_valid()) return;
|
||||
|
||||
const int hour = now.hour;
|
||||
const uint32_t now_ts = now.timestamp;
|
||||
|
||||
// Update hourly bucket (rolling 24h)
|
||||
{
|
||||
int idx = hour;
|
||||
if (idx < 0) idx = 0;
|
||||
@@ -314,9 +379,6 @@ sensor:
|
||||
if (isnan(id(g_temp_hour_max)[idx]) || v > id(g_temp_hour_max)[idx]) id(g_temp_hour_max)[idx] = v;
|
||||
}
|
||||
|
||||
// Daily window tracking uses current_mins so it still works during fallback.
|
||||
// Overnight: 23:00 -> 07:00
|
||||
// Daytime: 07:00 -> 23:00
|
||||
const int mins = id(current_mins);
|
||||
const bool in_overnight = (mins >= 1380) || (mins < 420);
|
||||
|
||||
@@ -330,19 +392,43 @@ sensor:
|
||||
}
|
||||
}
|
||||
|
||||
// Month stats
|
||||
if (isnan(id(g_min_temp_this_month)) || x < id(g_min_temp_this_month)) id(g_min_temp_this_month) = x;
|
||||
if (isnan(id(g_max_temp_this_month)) || x > id(g_max_temp_this_month)) id(g_max_temp_this_month) = x;
|
||||
|
||||
pressure:
|
||||
name: "${friendly_name} Pressure"
|
||||
id: lounge_pressure
|
||||
unit_of_measurement: "hPa"
|
||||
device_class: pressure
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
on_value:
|
||||
then:
|
||||
# Publish current pressure to local MQTT status topic
|
||||
- mqtt.publish:
|
||||
topic: "${mqtt_local_status_topic}/pressure"
|
||||
payload: !lambda |-
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.2f", x);
|
||||
return std::string(buffer);
|
||||
|
||||
humidity:
|
||||
name: "${friendly_name} Humidity"
|
||||
id: lounge_humidity
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
on_value:
|
||||
then:
|
||||
# Publish current humidity to local MQTT status topic
|
||||
- mqtt.publish:
|
||||
topic: "${mqtt_local_status_topic}/humidity"
|
||||
payload: !lambda |-
|
||||
char buffer[32];
|
||||
snprintf(buffer, sizeof(buffer), "%.1f", x);
|
||||
return std::string(buffer);
|
||||
|
||||
- lambda: |-
|
||||
auto now = id(sntp_time).now();
|
||||
if (!now.is_valid()) return;
|
||||
@@ -350,7 +436,6 @@ sensor:
|
||||
const int hour = now.hour;
|
||||
const uint32_t now_ts = now.timestamp;
|
||||
|
||||
// Update hourly bucket (rolling 24h)
|
||||
{
|
||||
int idx = hour;
|
||||
if (idx < 0) idx = 0;
|
||||
@@ -362,7 +447,6 @@ sensor:
|
||||
if (isnan(id(g_hum_hour_max)[idx]) || v > id(g_hum_hour_max)[idx]) id(g_hum_hour_max)[idx] = v;
|
||||
}
|
||||
|
||||
// Daily window tracking uses current_mins so it still works during fallback.
|
||||
const int mins = id(current_mins);
|
||||
const bool in_overnight = (mins >= 1380) || (mins < 420);
|
||||
|
||||
@@ -376,7 +460,6 @@ sensor:
|
||||
}
|
||||
}
|
||||
|
||||
// Month stats
|
||||
if (isnan(id(g_min_humidity_this_month)) || x < id(g_min_humidity_this_month)) id(g_min_humidity_this_month) = x;
|
||||
if (isnan(id(g_max_humidity_this_month)) || x > id(g_max_humidity_this_month)) id(g_max_humidity_this_month) = x;
|
||||
|
||||
@@ -385,6 +468,9 @@ sensor:
|
||||
name: "Lowest Temp Overnight"
|
||||
id: min_temp_today_overnight
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_min_temp_today_overnight);
|
||||
@@ -394,6 +480,9 @@ sensor:
|
||||
name: "Highest Temp Today (Daytime)"
|
||||
id: max_temp_today_daytime
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_max_temp_today_daytime);
|
||||
@@ -403,6 +492,9 @@ sensor:
|
||||
name: "Highest Temp This Month"
|
||||
id: max_temp_this_month
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_max_temp_this_month);
|
||||
@@ -412,6 +504,9 @@ sensor:
|
||||
name: "Highest Temp Last Month"
|
||||
id: max_temp_last_month
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_max_temp_last_month);
|
||||
@@ -421,6 +516,9 @@ sensor:
|
||||
name: "Lowest Temp This Month"
|
||||
id: min_temp_this_month
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_min_temp_this_month);
|
||||
@@ -430,6 +528,9 @@ sensor:
|
||||
name: "Lowest Temp Last Month"
|
||||
id: min_temp_last_month
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_min_temp_last_month);
|
||||
@@ -439,6 +540,9 @@ sensor:
|
||||
name: "Lowest Temp Last 24 Hours"
|
||||
id: min_temp_today
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
auto now = id(sntp_time).now();
|
||||
@@ -460,6 +564,9 @@ sensor:
|
||||
name: "Highest Temp Last 24 Hours"
|
||||
id: max_temp_today
|
||||
unit_of_measurement: "°C"
|
||||
device_class: temperature
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
auto now = id(sntp_time).now();
|
||||
@@ -481,6 +588,9 @@ sensor:
|
||||
name: "Lowest Humidity Overnight"
|
||||
id: min_humidity_today_overnight
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_min_humidity_today_overnight);
|
||||
@@ -490,6 +600,9 @@ sensor:
|
||||
name: "Highest Humidity Today (Daytime)"
|
||||
id: max_humidity_today_daytime
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_max_humidity_today_daytime);
|
||||
@@ -499,6 +612,9 @@ sensor:
|
||||
name: "Highest Humidity This Month"
|
||||
id: max_humidity_this_month
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_max_humidity_this_month);
|
||||
@@ -508,6 +624,9 @@ sensor:
|
||||
name: "Highest Humidity Last Month"
|
||||
id: max_humidity_last_month
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_max_humidity_last_month);
|
||||
@@ -517,6 +636,9 @@ sensor:
|
||||
name: "Lowest Humidity This Month"
|
||||
id: min_humidity_this_month
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_min_humidity_this_month);
|
||||
@@ -526,6 +648,9 @@ sensor:
|
||||
name: "Lowest Humidity Last Month"
|
||||
id: min_humidity_last_month
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
return id(g_min_humidity_last_month);
|
||||
@@ -535,6 +660,9 @@ sensor:
|
||||
name: "Lowest Humidity Last 24 Hours"
|
||||
id: min_humidity_today
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
auto now = id(sntp_time).now();
|
||||
@@ -556,6 +684,9 @@ sensor:
|
||||
name: "Highest Humidity Last 24 Hours"
|
||||
id: max_humidity_today
|
||||
unit_of_measurement: "%"
|
||||
device_class: humidity
|
||||
state_class: measurement
|
||||
accuracy_decimals: 1
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
auto now = id(sntp_time).now();
|
||||
@@ -577,6 +708,7 @@ sensor:
|
||||
name: "Pressure Rate Per Hour (3h)"
|
||||
id: pressure_rate_per_hour_3h
|
||||
unit_of_measurement: "hPa/h"
|
||||
state_class: measurement
|
||||
accuracy_decimals: 2
|
||||
update_interval: 60s
|
||||
lambda: |-
|
||||
@@ -584,7 +716,7 @@ sensor:
|
||||
if (!now.is_valid()) return NAN;
|
||||
|
||||
const uint32_t now_ts = now.timestamp;
|
||||
const uint32_t target_ts = now_ts - 10800; // 3h
|
||||
const uint32_t target_ts = now_ts - 10800;
|
||||
|
||||
float past = NAN;
|
||||
uint32_t best_dt = 0xFFFFFFFF;
|
||||
@@ -610,12 +742,6 @@ sensor:
|
||||
##########################################################################################
|
||||
text_sensor:
|
||||
# Pressure Direction, Last 3 Hours (5-state tendency over the last ~3 hours)
|
||||
# Outputs exactly one of:
|
||||
# - rising rapidly
|
||||
# - rising
|
||||
# - steady
|
||||
# - falling
|
||||
# - falling rapidly
|
||||
- platform: template
|
||||
name: "Pressure Direction, Last 3 Hours"
|
||||
id: pressure_rising_or_falling_3_hours
|
||||
@@ -625,7 +751,7 @@ text_sensor:
|
||||
if (!now.is_valid()) return std::string("unknown");
|
||||
|
||||
const uint32_t now_ts = now.timestamp;
|
||||
const uint32_t target_ts = now_ts - 10800; // 3h
|
||||
const uint32_t target_ts = now_ts - 10800;
|
||||
|
||||
float past = NAN;
|
||||
uint32_t best_dt = 0xFFFFFFFF;
|
||||
@@ -689,7 +815,6 @@ interval:
|
||||
const bool at_0700 = (mins == 420);
|
||||
const bool at_2300 = (mins == 1380);
|
||||
|
||||
// Roll overnight window at 07:00
|
||||
if (at_0700) {
|
||||
id(g_min_temp_today_overnight) = id(g_work_min_temp_overnight);
|
||||
id(g_work_min_temp_overnight) = NAN;
|
||||
@@ -698,7 +823,6 @@ interval:
|
||||
id(g_work_min_humidity_overnight) = NAN;
|
||||
}
|
||||
|
||||
// Roll daytime window at 23:00
|
||||
if (at_2300) {
|
||||
id(g_max_temp_today_daytime) = id(g_work_max_temp_daytime);
|
||||
id(g_work_max_temp_daytime) = NAN;
|
||||
@@ -707,7 +831,6 @@ interval:
|
||||
id(g_work_max_humidity_daytime) = NAN;
|
||||
}
|
||||
|
||||
// Month rollover requires real date/time (SNTP valid)
|
||||
auto now = id(sntp_time).now();
|
||||
if (!now.is_valid()) return;
|
||||
|
||||
@@ -720,13 +843,11 @@ interval:
|
||||
}
|
||||
|
||||
if (mon != id(g_current_month) || yr != id(g_current_year)) {
|
||||
// Copy current month stats to last month
|
||||
id(g_max_temp_last_month) = id(g_max_temp_this_month);
|
||||
id(g_min_temp_last_month) = id(g_min_temp_this_month);
|
||||
id(g_max_humidity_last_month) = id(g_max_humidity_this_month);
|
||||
id(g_min_humidity_last_month) = id(g_min_humidity_this_month);
|
||||
|
||||
// Reset current month stats
|
||||
id(g_max_temp_this_month) = NAN;
|
||||
id(g_min_temp_this_month) = NAN;
|
||||
id(g_max_humidity_this_month) = NAN;
|
||||
|
||||
Reference in New Issue
Block a user