yaml layout updates to v1.x

This commit is contained in:
root
2026-02-25 21:05:21 +13:00
parent 61b0c64a1e
commit a8d2927274
44 changed files with 6521 additions and 4689 deletions
+227 -62
View File
@@ -1,15 +1,30 @@
##########################################################################################
##########################################################################################
# MAIN HOUSE 3 PHASE POWER MONITOR
# Power Monitor using 3x PZEM004 for 3 phase monitoring plus energy monitoring for 32A EV Charger
#:########################################################################################:#
# TITLE: MAIN HOUSE 3 PHASE POWER MONITOR
# zorruno.com layout v1.1 2026
#:########################################################################################:#
# REPO:
# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-mainpowermonitor.yaml
#:########################################################################################:#
# VERSIONS:
# v1.3 2026-02-25 Updated yaml to zorruno layout V1.1
# v1.2 2026-02-25 Updated yaml to zorruno layout V1.1. Added EV charging binary sensor
# and EV power rolling average (default 5 min). Clarified EV pulse notes.
# v1.1 2026-02-21 Fix globals array init compile error, reduce flash writes (globals update_interval)
# v1.0 2026-02-21 Initial Version
#:########################################################################################:#
# HARDWARE:
# - Wemos D1 mini (ESP8266)
# - 3x PZEM-004T V3 (Modbus, 9600 baud)
# - DHT11 (GPIO2)
# - EV pulse input (GPIO14)
#:########################################################################################:#
# OPERATION NOTES:
# - Power Monitor using 3x PZEM-004T V3 (Modbus) for 3-phase monitoring
# - Pulse input energy monitoring for 32A EV Charger (2 Wh per pulse)
# - Adds a 5 minute rolling average for EV power to avoid spiky readings at low loads
# - Adds a binary sensor to indicate when the EV charger is operating (threshold configurable)
#
# Hardware: Wemos D1 mini (ESP8266) + 3x PZEM-004T V3 (Modbus) + DHT11 + EV Pulse Input
#
# V1.1 2026-02-21 Fix globals array init compile error, reduce flash writes (globals update_interval)
# V1.0 2026-02-21 Initial Version
#
# NOTES
# - PZEM-004T V3 uses Modbus over UART at 9600 baud.
# NOTES:
# - UART is on GPIO1 (TX) and GPIO3 (RX). Logger UART is disabled (baud_rate: 0).
# - You will usually need to disconnect PZEM UART wires while flashing via USB.
# - DHT11 is on GPIO2 (boot-strap pin and D1 mini onboard LED pin). Usually OK, but if you ever
@@ -17,23 +32,35 @@
# - PZEM "energy" from ESPHome pzemac is in Wh, converted to kWh in this YAML.
# - Phase mapping requested: Red=0, Yellow=1, Blue=2 (Tasmota-style). In ESPHome pzemac Modbus
# addresses must be 0x01..0xF7, so this YAML maps to Red=0x01, Yellow=0x02, Blue=0x03.
# - 365-day history array is RAM-only (not restored) to avoid ESP8266 restore limits and flash wear.
##########################################################################################
##########################################################################################
# - EV pulse power at very low load is inherently "chunky" due to 2 Wh pulses. Energy totals
# remain accurate. Rolling average reduces spikes but can still read 0 W between infrequent pulses.
#:########################################################################################:#
# OFFLINE NOTES:
# a) Home Assistant OFFLINE, WiFi OK
# - Device continues measuring power, energy, and pulses locally.
# - MQTT/API publishing will fail until HA is back.
# b) WiFi OFFLINE (LAN down), Device powered
# - No SNTP updates, so time may become invalid or drift (depending on last sync).
# - Power and energy totals continue accumulating, but period rollovers (today/month/year)
# will not update unless time is valid.
# c) Entire WiFi/Network OFFLINE
# - Accurate time IS needed for daily/monthly/year rollovers (SNTP required for correct period boundaries).
# - Loss of network will drift the timeclocks; time of day can be reset by powering off then on again at 12pm (midday)
#:########################################################################################:#
##########################################################################################
# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS
##########################################################################################
#:########################################################################################:#
# SUBSTITUTIONS: Specific device variable substitutions
#:########################################################################################:#
substitutions:
# Device Naming
device_name: "esp-mainpowermonitor"
friendly_name: "Main House 3 Phase Power Monitor"
description_comment: "Power Monitor using 3x PZEM004 for 3 phase monitoring plus energy monitoring for 32A EV Charger"
description_comment: "Power Monitor using 3x PZEM004 for 3 phase monitoring plus energy monitoring for 32A EV Charger (Layout V1.1)"
device_area: "Data Cupboard"
# Project Naming
project_name: "Wemos.D1Mini PZEM-004T V3 3-Phase Power Monitor"
project_version: "v1.1"
project_version: "v1.3"
# Passwords
api_key: !secret esp-api_key
@@ -45,10 +72,6 @@ substitutions:
# Don't forget to switch it back when changed.
current_ip_address: ${static_ip_address}
# MQTT Controls
#mqtt_device_name: "main-house-3phase-power"
#mqtt_main_topic: "${mqtt_command_main_topic}/${mqtt_device_name}"
# Device Settings
log_level: "ERROR"
pzem_update_interval: "10s"
@@ -70,6 +93,20 @@ substitutions:
ev_pulse_filter_ms: "50ms" # Debounce / filter
ev_pulse_pin_mode: "INPUT_PULLUP"
# EV Charging Detection (Averaged power + binary sensor)
# Minimum EV charging power threshold (W) for binary sensor
# NOTE: Pick a value comfortably above idle (idle can be ~0.2 kWh/day = very infrequent pulses).
ev_charging_min_power_w: "300"
# Rolling average window - configuration notes:
# - Substitutions are string replacements, so window samples must be updated manually if you change times.
# - window_samples = (avg_minutes * 60) / sample_interval_seconds
ev_power_avg_window_minutes: "5" # informational
ev_power_avg_sample_interval: "10s"
ev_power_avg_sample_interval_seconds: "10" # must match the value above
ev_power_avg_window_samples: "30" # 5 min @ 10s = 30 samples
ev_power_avg_buffer_size: "180" # ring buffer >= window_samples (180 @ 10s = 30 minutes)
# Names - PZEM (per phase)
pzem_red_v_name: "Main Power Red Voltage"
pzem_red_i_name: "Main Power Red Current"
@@ -109,6 +146,7 @@ substitutions:
# Names - EV Wallcharger
ev_power_name: "EV Wallcharger Power"
ev_charging_name: "EV Wallcharger Charging"
ev_total_energy_name: "EV Wallcharger Total Energy"
ev_today_name: "EV Wallcharger Energy Today"
ev_yesterday_name: "EV Wallcharger Energy Yesterday"
@@ -122,9 +160,9 @@ substitutions:
hum_name: "Main Power Monitor Humidity"
dew_name: "Main Power Monitor Dew Point"
##########################################################################################
#:########################################################################################:#
# PACKAGES: Included Common Packages
##########################################################################################
#:########################################################################################:#
packages:
#### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode ####
common_wifi: !include
@@ -154,9 +192,10 @@ packages:
diag_basic: !include common/include_basic_diag_sensors.yaml
diag_more: !include common/include_more_diag_sensors.yaml
##########################################################################################
# ESPHome
##########################################################################################
#:########################################################################################:#
# ESPHOME:
# https://esphome.io/components/esphome.html
#:########################################################################################:#
esphome:
name: "${device_name}"
friendly_name: "${friendly_name}"
@@ -172,9 +211,10 @@ esphome:
- delay: 3s
- script.execute: rollover_check
##########################################################################################
# ESP Platform and Framework
##########################################################################################
#:########################################################################################:#
# ESP PLATFORM AND FRAMEWORK:
# https://esphome.io/components/esp8266/
#:########################################################################################:#
esp8266:
board: d1_mini
restore_from_flash: true
@@ -185,16 +225,17 @@ preferences:
mdns:
disabled: false
##########################################################################################
# LOGGING
##########################################################################################
#:########################################################################################:#
# LOGGING:
# https://esphome.io/components/logger.html
#:########################################################################################:#
logger:
level: "${log_level}"
baud_rate: 0
##########################################################################################
# UART + MODBUS (PZEM-004T V3)
##########################################################################################
#:########################################################################################:#
# UART + MODBUS (PZEM-004T V3):
#:########################################################################################:#
uart:
id: uart_pzem_bus
tx_pin: GPIO1
@@ -205,9 +246,9 @@ modbus:
id: modbus_pzem_bus
send_wait_time: 200ms
##########################################################################################
# GLOBALS (Energy rollovers + 365-day history + temp min/max)
##########################################################################################
#:########################################################################################:#
# GLOBALS (Energy rollovers + 365-day history + temp min/max):
#:########################################################################################:#
globals:
# Date tracking for rollovers (restored)
- id: g_last_day
@@ -320,6 +361,25 @@ globals:
update_interval: ${globals_save_interval_pulses}
initial_value: "0"
# EV rolling average power (RAM only)
- id: g_ev_power_avg_w
type: float
restore_value: no
initial_value: "0.0"
# EV pulse history ring buffer for rolling average (RAM only)
- id: g_ev_pulses_hist
type: uint32_t[${ev_power_avg_buffer_size}]
restore_value: no
- id: g_ev_pulses_hist_index
type: int
restore_value: no
initial_value: "0"
- id: g_ev_pulses_hist_count
type: int
restore_value: no
initial_value: "0"
# Temperature min/max tracking (RAM ONLY - not restored, gentler on flash)
- id: g_temp_today_min
type: float
@@ -357,18 +417,35 @@ globals:
restore_value: no
initial_value: "-9999.0"
##########################################################################################
# INTERVAL (periodic rollover checks)
# NOTE: common_sntp may define its own interval. That is OK.
##########################################################################################
#:########################################################################################:#
# INTERVAL (periodic rollover checks + EV rolling average updates):
#:########################################################################################:#
interval:
- interval: "${rollover_check_interval}"
then:
- script.execute: rollover_check
##########################################################################################
# SENSORS
##########################################################################################
- interval: "${ev_power_avg_sample_interval}"
then:
- script.execute: ev_power_avg_update
#:########################################################################################:#
# BINARY SENSORS:
#:########################################################################################:#
binary_sensor:
- platform: template
name: "${ev_charging_name}"
id: ev_wallcharger_charging
device_class: power
icon: "mdi:ev-station"
lambda: |-
const float p = id(ev_power_avg_w).state;
if (isnan(p)) return false;
return (p >= ${ev_charging_min_power_w});
#:########################################################################################:#
# SENSORS:
#:########################################################################################:#
sensor:
########################################################################################
# PZEM-004T V3 - RED PHASE
@@ -851,23 +928,16 @@ sensor:
########################################################################################
# EV WALLCHARGER PULSE ENERGY (GPIO14)
# - pulse_counter reports pulses/minute
# - Power (W) = pulses_per_min * (Wh_per_pulse) * 60
########################################################################################
- platform: pulse_counter
id: ev_pulse_rate_ppm
internal: true
pin:
number: GPIO14
mode: ${ev_pulse_pin_mode}
inverted: false
update_interval: 10s
internal_filter: ${ev_pulse_filter_ms}
name: "${ev_power_name}"
unit_of_measurement: "W"
accuracy_decimals: 0
filters:
- lambda: |-
return x * (${ev_pulse_wh} * 60.0f);
total:
id: ev_pulses_raw_total
internal: true
@@ -882,6 +952,15 @@ sensor:
id(g_ev_pulses_total_abs) += (raw - last);
id(g_ev_pulses_raw_last) = raw;
- platform: template
name: "${ev_power_name}"
id: ev_power_avg_w
unit_of_measurement: "W"
accuracy_decimals: 0
update_interval: "${ev_power_avg_sample_interval}"
lambda: |-
return id(g_ev_power_avg_w);
- platform: template
name: "${ev_total_energy_name}"
id: ev_total_energy_kwh
@@ -957,9 +1036,9 @@ sensor:
lambda: |-
return id(g_ev_last_year_kwh);
##########################################################################################
# SCRIPTS
##########################################################################################
#:########################################################################################:#
# SCRIPTS:
#:########################################################################################:#
script:
# Initialize RAM-only history arrays and counters
- id: init_history_arrays
@@ -972,6 +1051,59 @@ script:
id(g_mains_daily_hist_index) = 0;
id(g_mains_daily_hist_count) = 0;
// Init EV pulse history buffer so rolling average starts stable after boot
const int ev_buf = ${ev_power_avg_buffer_size};
const uint32_t p0 = id(g_ev_pulses_total_abs);
for (int i = 0; i < ev_buf; i++) {
id(g_ev_pulses_hist)[i] = p0;
}
id(g_ev_pulses_hist_index) = 0;
id(g_ev_pulses_hist_count) = ev_buf;
id(g_ev_power_avg_w) = 0.0f;
# EV rolling average update (based on absolute pulse total)
- id: ev_power_avg_update
mode: queued
then:
- lambda: |-
const int buf = ${ev_power_avg_buffer_size};
int idx = id(g_ev_pulses_hist_index);
if (idx < 0 || idx >= buf) idx = 0;
const uint32_t p_now = id(g_ev_pulses_total_abs);
id(g_ev_pulses_hist)[idx] = p_now;
idx = (idx + 1) % buf;
id(g_ev_pulses_hist_index) = idx;
if (id(g_ev_pulses_hist_count) < buf) id(g_ev_pulses_hist_count)++;
int win = ${ev_power_avg_window_samples};
if (win < 1) win = 1;
if (win > buf) win = buf;
if (id(g_ev_pulses_hist_count) < win) {
return;
}
int old_idx = idx - win;
if (old_idx < 0) old_idx += buf;
const uint32_t p_old = id(g_ev_pulses_hist)[old_idx];
const uint32_t dp = (p_now >= p_old) ? (p_now - p_old) : 0;
const float wh = ((float) dp) * (${ev_pulse_wh});
const float seconds = ((float) win) * (${ev_power_avg_sample_interval_seconds});
if (seconds <= 0.0f) {
id(g_ev_power_avg_w) = 0.0f;
return;
}
// W = Wh * 3600 / seconds
id(g_ev_power_avg_w) = wh * 3600.0f / seconds;
# Period rollover check (day/month/year) for:
# - Main total energy (sum of 3 PZEM channels)
# - EV total energy (pulse derived)
@@ -1117,9 +1249,42 @@ script:
if (t < id(g_temp_month_min)) id(g_temp_month_min) = t;
if (t > id(g_temp_month_max)) id(g_temp_month_max) = t;
##########################################################################################
# SWITCHES
##########################################################################################
#:########################################################################################:#
# SWITCHES:
#:########################################################################################:#
switch:
- platform: restart
name: "Main Power Monitor Restart"
name: "Main Power Monitor Restart"
#:########################################################################################:#
# ROLLBACK COPY (v1.1) - EV POWER SECTION (for quick revert)
# NOTE: This is commented out. Remove the new EV blocks and uncomment to restore old behavior.
#:########################################################################################:#
#sensor:
# - platform: pulse_counter
# id: ev_pulse_rate_ppm
# pin:
# number: GPIO14
# mode: ${ev_pulse_pin_mode}
# inverted: false
# update_interval: 10s
# internal_filter: ${ev_pulse_filter_ms}
# name: "${ev_power_name}"
# unit_of_measurement: "W"
# accuracy_decimals: 0
# filters:
# - lambda: |-
# return x * (${ev_pulse_wh} * 60.0f);
# total:
# id: ev_pulses_raw_total
# internal: true
# on_value:
# then:
# - lambda: |-
# uint32_t raw = (uint32_t) x;
# uint32_t last = id(g_ev_pulses_raw_last);
# if (raw < last) {
# last = 0;
# }
# id(g_ev_pulses_total_abs) += (raw - last);
# id(g_ev_pulses_raw_last) = raw;