diff --git a/.cache/brands/integrations/3_day_blinds/dark_icon.png b/.cache/brands/integrations/3_day_blinds/dark_icon.png new file mode 100644 index 0000000..d465b40 Binary files /dev/null and b/.cache/brands/integrations/3_day_blinds/dark_icon.png differ diff --git a/.cache/brands/integrations/abode/dark_icon.png b/.cache/brands/integrations/abode/dark_icon.png new file mode 100644 index 0000000..ad08a47 Binary files /dev/null and b/.cache/brands/integrations/abode/dark_icon.png differ diff --git a/.cache/brands/integrations/acaia/dark_icon.png b/.cache/brands/integrations/acaia/dark_icon.png new file mode 100644 index 0000000..6f74cfa Binary files /dev/null and b/.cache/brands/integrations/acaia/dark_icon.png differ diff --git a/.cache/brands/integrations/accuweather/dark_icon.png b/.cache/brands/integrations/accuweather/dark_icon.png new file mode 100644 index 0000000..a3c7dc1 Binary files /dev/null and b/.cache/brands/integrations/accuweather/dark_icon.png differ diff --git a/.cache/brands/integrations/acomax/dark_icon.png b/.cache/brands/integrations/acomax/dark_icon.png new file mode 100644 index 0000000..7482ab8 Binary files /dev/null and b/.cache/brands/integrations/acomax/dark_icon.png differ diff --git a/.cache/brands/integrations/actron_air/dark_icon.png b/.cache/brands/integrations/actron_air/dark_icon.png new file mode 100644 index 0000000..6c4ff72 Binary files /dev/null and b/.cache/brands/integrations/actron_air/dark_icon.png differ diff --git a/.cache/brands/integrations/adax/dark_icon.png b/.cache/brands/integrations/adax/dark_icon.png new file mode 100644 index 0000000..f013ea6 Binary files /dev/null and b/.cache/brands/integrations/adax/dark_icon.png differ diff --git a/.cache/brands/integrations/adguard/dark_icon.png b/.cache/brands/integrations/adguard/dark_icon.png new file mode 100644 index 0000000..0fed052 Binary files /dev/null and b/.cache/brands/integrations/adguard/dark_icon.png differ diff --git a/.cache/brands/integrations/advantage_air/dark_icon.png b/.cache/brands/integrations/advantage_air/dark_icon.png new file mode 100644 index 0000000..ac2f2c9 Binary files /dev/null and b/.cache/brands/integrations/advantage_air/dark_icon.png differ diff --git a/.cache/brands/integrations/aemet/dark_icon.png b/.cache/brands/integrations/aemet/dark_icon.png new file mode 100644 index 0000000..c73f97c Binary files /dev/null and b/.cache/brands/integrations/aemet/dark_icon.png differ diff --git a/.cache/brands/integrations/aep_ohio/dark_icon.png b/.cache/brands/integrations/aep_ohio/dark_icon.png new file mode 100644 index 0000000..82f8ec2 Binary files /dev/null and b/.cache/brands/integrations/aep_ohio/dark_icon.png differ diff --git a/.cache/brands/integrations/aep_texas/dark_icon.png b/.cache/brands/integrations/aep_texas/dark_icon.png new file mode 100644 index 0000000..424eca4 Binary files /dev/null and b/.cache/brands/integrations/aep_texas/dark_icon.png differ diff --git a/.cache/brands/integrations/aftership/dark_icon.png b/.cache/brands/integrations/aftership/dark_icon.png new file mode 100644 index 0000000..8d26467 Binary files /dev/null and b/.cache/brands/integrations/aftership/dark_icon.png differ diff --git a/.cache/brands/integrations/agent_dvr/dark_icon.png b/.cache/brands/integrations/agent_dvr/dark_icon.png new file mode 100644 index 0000000..481b927 Binary files /dev/null and b/.cache/brands/integrations/agent_dvr/dark_icon.png differ diff --git a/.cache/brands/integrations/airgradient/dark_icon.png b/.cache/brands/integrations/airgradient/dark_icon.png new file mode 100644 index 0000000..175998b Binary files /dev/null and b/.cache/brands/integrations/airgradient/dark_icon.png differ diff --git a/.cache/brands/integrations/airly/dark_icon.png b/.cache/brands/integrations/airly/dark_icon.png new file mode 100644 index 0000000..9ead38d Binary files /dev/null and b/.cache/brands/integrations/airly/dark_icon.png differ diff --git a/.cache/brands/integrations/airnow/dark_icon.png b/.cache/brands/integrations/airnow/dark_icon.png new file mode 100644 index 0000000..2e9cb47 Binary files /dev/null and b/.cache/brands/integrations/airnow/dark_icon.png differ diff --git a/.cache/brands/integrations/airobot/dark_icon.png b/.cache/brands/integrations/airobot/dark_icon.png new file mode 100644 index 0000000..ef57240 Binary files /dev/null and b/.cache/brands/integrations/airobot/dark_icon.png differ diff --git a/.cache/brands/integrations/airpatrol/dark_icon.png b/.cache/brands/integrations/airpatrol/dark_icon.png new file mode 100644 index 0000000..c21ed50 Binary files /dev/null and b/.cache/brands/integrations/airpatrol/dark_icon.png differ diff --git a/.cache/brands/integrations/airq/dark_icon.png b/.cache/brands/integrations/airq/dark_icon.png new file mode 100644 index 0000000..45e6e4c Binary files /dev/null and b/.cache/brands/integrations/airq/dark_icon.png differ diff --git a/.cache/brands/integrations/airthings/dark_icon.png b/.cache/brands/integrations/airthings/dark_icon.png new file mode 100644 index 0000000..678a93c Binary files /dev/null and b/.cache/brands/integrations/airthings/dark_icon.png differ diff --git a/.cache/brands/integrations/androidtv_remote/dark_icon@2x.png b/.cache/brands/integrations/androidtv_remote/dark_icon@2x.png new file mode 100644 index 0000000..05c22be Binary files /dev/null and b/.cache/brands/integrations/androidtv_remote/dark_icon@2x.png differ diff --git a/.cache/brands/integrations/androidtv_remote/dark_logo.png b/.cache/brands/integrations/androidtv_remote/dark_logo.png new file mode 100644 index 0000000..983ce1b Binary files /dev/null and b/.cache/brands/integrations/androidtv_remote/dark_logo.png differ diff --git a/.cache/brands/integrations/aosmith/dark_icon.png b/.cache/brands/integrations/aosmith/dark_icon.png new file mode 100644 index 0000000..30920c2 Binary files /dev/null and b/.cache/brands/integrations/aosmith/dark_icon.png differ diff --git a/.cache/brands/integrations/brel_home/dark_icon.png b/.cache/brands/integrations/brel_home/dark_icon.png new file mode 100644 index 0000000..df2639f Binary files /dev/null and b/.cache/brands/integrations/brel_home/dark_icon.png differ diff --git a/.cache/brands/integrations/directv/dark_icon.png b/.cache/brands/integrations/directv/dark_icon.png new file mode 100644 index 0000000..5431d9b Binary files /dev/null and b/.cache/brands/integrations/directv/dark_icon.png differ diff --git a/.cache/brands/integrations/esphome/icon@2x.png b/.cache/brands/integrations/esphome/icon@2x.png new file mode 100644 index 0000000..94a787e Binary files /dev/null and b/.cache/brands/integrations/esphome/icon@2x.png differ diff --git a/.cache/brands/integrations/fireservicerota/dark_icon.png b/.cache/brands/integrations/fireservicerota/dark_icon.png new file mode 100644 index 0000000..2fd0479 Binary files /dev/null and b/.cache/brands/integrations/fireservicerota/dark_icon.png differ diff --git a/.cache/brands/integrations/forecast_solar/dark_icon.png b/.cache/brands/integrations/forecast_solar/dark_icon.png new file mode 100644 index 0000000..ef2d279 Binary files /dev/null and b/.cache/brands/integrations/forecast_solar/dark_icon.png differ diff --git a/.cache/brands/integrations/freebox/dark_icon.png b/.cache/brands/integrations/freebox/dark_icon.png new file mode 100644 index 0000000..330ec05 Binary files /dev/null and b/.cache/brands/integrations/freebox/dark_icon.png differ diff --git a/.cache/brands/integrations/freedompro/dark_icon.png b/.cache/brands/integrations/freedompro/dark_icon.png new file mode 100644 index 0000000..49111ac Binary files /dev/null and b/.cache/brands/integrations/freedompro/dark_icon.png differ diff --git a/.cache/brands/integrations/fressnapf_tracker/dark_icon.png b/.cache/brands/integrations/fressnapf_tracker/dark_icon.png new file mode 100644 index 0000000..5729a7e Binary files /dev/null and b/.cache/brands/integrations/fressnapf_tracker/dark_icon.png differ diff --git a/.cache/brands/integrations/gree/dark_icon.png b/.cache/brands/integrations/gree/dark_icon.png new file mode 100644 index 0000000..88c4f5d Binary files /dev/null and b/.cache/brands/integrations/gree/dark_icon.png differ diff --git a/.cache/brands/integrations/microsoft/dark_icon.png b/.cache/brands/integrations/microsoft/dark_icon.png new file mode 100644 index 0000000..29b9b62 Binary files /dev/null and b/.cache/brands/integrations/microsoft/dark_icon.png differ diff --git a/.cache/brands/integrations/onewire/dark_icon.png b/.cache/brands/integrations/onewire/dark_icon.png new file mode 100644 index 0000000..d5b7b7d Binary files /dev/null and b/.cache/brands/integrations/onewire/dark_icon.png differ diff --git a/.cache/brands/integrations/rachio/dark_icon.png b/.cache/brands/integrations/rachio/dark_icon.png new file mode 100644 index 0000000..620296a Binary files /dev/null and b/.cache/brands/integrations/rachio/dark_icon.png differ diff --git a/.cache/brands/integrations/radarr/dark_icon.png b/.cache/brands/integrations/radarr/dark_icon.png new file mode 100644 index 0000000..7555ebc Binary files /dev/null and b/.cache/brands/integrations/radarr/dark_icon.png differ diff --git a/.cache/brands/integrations/rainforest_automation/dark_icon.png b/.cache/brands/integrations/rainforest_automation/dark_icon.png new file mode 100644 index 0000000..214ec9a Binary files /dev/null and b/.cache/brands/integrations/rainforest_automation/dark_icon.png differ diff --git a/.cache/brands/integrations/rainmachine/dark_icon.png b/.cache/brands/integrations/rainmachine/dark_icon.png new file mode 100644 index 0000000..f9bef4c Binary files /dev/null and b/.cache/brands/integrations/rainmachine/dark_icon.png differ diff --git a/.cache/brands/integrations/raspberry_pi/dark_icon.png b/.cache/brands/integrations/raspberry_pi/dark_icon.png new file mode 100644 index 0000000..2d8d010 Binary files /dev/null and b/.cache/brands/integrations/raspberry_pi/dark_icon.png differ diff --git a/.cache/brands/integrations/rdw/dark_icon.png b/.cache/brands/integrations/rdw/dark_icon.png new file mode 100644 index 0000000..3c7c355 Binary files /dev/null and b/.cache/brands/integrations/rdw/dark_icon.png differ diff --git a/.cache/brands/integrations/recollect_waste/dark_icon.png b/.cache/brands/integrations/recollect_waste/dark_icon.png new file mode 100644 index 0000000..fd477ef Binary files /dev/null and b/.cache/brands/integrations/recollect_waste/dark_icon.png differ diff --git a/.cache/brands/integrations/redgtech/dark_icon.png b/.cache/brands/integrations/redgtech/dark_icon.png new file mode 100644 index 0000000..f01dfca Binary files /dev/null and b/.cache/brands/integrations/redgtech/dark_icon.png differ diff --git a/.cache/brands/integrations/refoss/dark_icon.png b/.cache/brands/integrations/refoss/dark_icon.png new file mode 100644 index 0000000..8a1caf3 Binary files /dev/null and b/.cache/brands/integrations/refoss/dark_icon.png differ diff --git a/.cache/brands/integrations/rehlko/dark_icon.png b/.cache/brands/integrations/rehlko/dark_icon.png new file mode 100644 index 0000000..c586a1f Binary files /dev/null and b/.cache/brands/integrations/rehlko/dark_icon.png differ diff --git a/.cache/brands/integrations/remote_calendar/dark_icon.png b/.cache/brands/integrations/remote_calendar/dark_icon.png new file mode 100644 index 0000000..9003aca Binary files /dev/null and b/.cache/brands/integrations/remote_calendar/dark_icon.png differ diff --git a/.cache/brands/integrations/renault/dark_icon.png b/.cache/brands/integrations/renault/dark_icon.png new file mode 100644 index 0000000..788ea0b Binary files /dev/null and b/.cache/brands/integrations/renault/dark_icon.png differ diff --git a/.cache/brands/integrations/renson/dark_icon.png b/.cache/brands/integrations/renson/dark_icon.png new file mode 100644 index 0000000..86920a4 Binary files /dev/null and b/.cache/brands/integrations/renson/dark_icon.png differ diff --git a/.cache/brands/integrations/reolink/dark_logo.png b/.cache/brands/integrations/reolink/dark_logo.png new file mode 100644 index 0000000..9da7d81 Binary files /dev/null and b/.cache/brands/integrations/reolink/dark_logo.png differ diff --git a/.cache/brands/integrations/reolink/icon.png b/.cache/brands/integrations/reolink/icon.png new file mode 100644 index 0000000..0c9ac17 Binary files /dev/null and b/.cache/brands/integrations/reolink/icon.png differ diff --git a/.cache/brands/integrations/rexel/dark_icon.png b/.cache/brands/integrations/rexel/dark_icon.png new file mode 100644 index 0000000..da2aca7 Binary files /dev/null and b/.cache/brands/integrations/rexel/dark_icon.png differ diff --git a/.cache/brands/integrations/rhasspy/dark_icon.png b/.cache/brands/integrations/rhasspy/dark_icon.png new file mode 100644 index 0000000..e1c5a2f Binary files /dev/null and b/.cache/brands/integrations/rhasspy/dark_icon.png differ diff --git a/.cache/brands/integrations/roth/dark_icon.png b/.cache/brands/integrations/roth/dark_icon.png new file mode 100644 index 0000000..37fa7b4 Binary files /dev/null and b/.cache/brands/integrations/roth/dark_icon.png differ diff --git a/.cache/brands/integrations/russound/dark_icon.png b/.cache/brands/integrations/russound/dark_icon.png new file mode 100644 index 0000000..5178775 Binary files /dev/null and b/.cache/brands/integrations/russound/dark_icon.png differ diff --git a/.cache/brands/integrations/ruuvi/dark_icon.png b/.cache/brands/integrations/ruuvi/dark_icon.png new file mode 100644 index 0000000..a040987 Binary files /dev/null and b/.cache/brands/integrations/ruuvi/dark_icon.png differ diff --git a/.cache/brands/integrations/script/dark_icon.png b/.cache/brands/integrations/script/dark_icon.png new file mode 100644 index 0000000..50b4e38 Binary files /dev/null and b/.cache/brands/integrations/script/dark_icon.png differ diff --git a/.cache/brands/integrations/script/icon.png b/.cache/brands/integrations/script/icon.png new file mode 100644 index 0000000..50b4e38 Binary files /dev/null and b/.cache/brands/integrations/script/icon.png differ diff --git a/.cache/brands/integrations/seventeentrack/dark_icon.png b/.cache/brands/integrations/seventeentrack/dark_icon.png new file mode 100644 index 0000000..b6754a2 Binary files /dev/null and b/.cache/brands/integrations/seventeentrack/dark_icon.png differ diff --git a/.cache/brands/integrations/solaredge/dark_icon.png b/.cache/brands/integrations/solaredge/dark_icon.png new file mode 100644 index 0000000..8a902cd Binary files /dev/null and b/.cache/brands/integrations/solaredge/dark_icon.png differ diff --git a/.cache/brands/integrations/tasmota/logo.png b/.cache/brands/integrations/tasmota/logo.png new file mode 100644 index 0000000..cdcb1a3 Binary files /dev/null and b/.cache/brands/integrations/tasmota/logo.png differ diff --git a/.cache/brands/integrations/trafikverket/dark_icon.png b/.cache/brands/integrations/trafikverket/dark_icon.png new file mode 100644 index 0000000..618e177 Binary files /dev/null and b/.cache/brands/integrations/trafikverket/dark_icon.png differ diff --git a/.cache/brands/integrations/waste_collection_schedule/dark_icon.png b/.cache/brands/integrations/waste_collection_schedule/dark_icon.png new file mode 100644 index 0000000..4db5580 Binary files /dev/null and b/.cache/brands/integrations/waste_collection_schedule/dark_icon.png differ diff --git a/.ha_run.lock b/.ha_run.lock index fcb9b23..3a45f89 100644 --- a/.ha_run.lock +++ b/.ha_run.lock @@ -1 +1 @@ -{"pid": 67, "version": 1, "ha_version": "2026.3.1", "start_ts": 1772875766.7594833} \ No newline at end of file +{"pid": 67, "version": 1, "ha_version": "2026.4.0", "start_ts": 1775105928.9191253} \ No newline at end of file diff --git a/esphome/esp-entrancebathrmlights.yaml b/esphome/esp-entrancebathrmlights.yaml index 0d470e1..196200a 100644 --- a/esphome/esp-entrancebathrmlights.yaml +++ b/esphome/esp-entrancebathrmlights.yaml @@ -6,9 +6,10 @@ # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-entrancebathrmlights.yaml #:########################################################################################:# # VERSIONS: -# v3.8 2026-02-25 Updated yaml to zorruno layout V1.1 -# v3.7 2025-09-34 Upload to this bathroom (as noted in original header) -# v3.5 2025-07-24 YAML tidyups +# V3.9 2026-03-11 Updated yaml to zorruno layout V1.1 +# V3.8 2026-02-25 Updated yaml to zorruno layout V1.1 +# V3.7 2025-09-34 Upload to this bathroom (as noted in original header) +# V3.5 2025-07-24 YAML tidyups #:########################################################################################:# # HARDWARE: # - Zemismart KS-811 Double push button (ESP8266) @@ -33,7 +34,6 @@ # - Accurate time is NOT needed (SNTP not needed). #:########################################################################################:# - #:########################################################################################:# # SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) @@ -47,7 +47,7 @@ substitutions: # Project Naming project_name: "Zemismart Technologies.KS-811 Double" - project_version: "v3.8" + project_version: "v3.9" # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names @@ -144,7 +144,7 @@ logger: status_led: pin: number: GPIO2 - inverted: yes + inverted: true #:########################################################################################:# # BINARY SENSORS @@ -155,7 +155,7 @@ binary_sensor: pin: number: GPIO16 mode: INPUT - inverted: True + inverted: true use_interrupt: false # GPIO16 pin doesn't support interrupts so use polling. Only suppresses a warning. name: "Button 1: ${switch_1_name}" on_press: @@ -163,9 +163,9 @@ binary_sensor: - platform: gpio pin: - number: GPIO05 + number: GPIO5 mode: INPUT - inverted: True + inverted: true name: "Button 2: ${switch_2_name}" on_press: - switch.toggle: Relay_2 diff --git a/esphome/esp-entranceoutsideledlights.yaml b/esphome/esp-entranceoutsideledlights.yaml index 7f9f48f..0ae5233 100644 --- a/esphome/esp-entranceoutsideledlights.yaml +++ b/esphome/esp-entranceoutsideledlights.yaml @@ -1,14 +1,19 @@ -########################################################################################## -########################################################################################## -# FRONT ENTRANCEWAY LED LIGHT CONTROLS -# File: esp-entranceoutsideledlights.yaml -# -# v1.0 - 2026-02-23 Initial version (converted from Tasmota) -# -# Hardware: H801 (ESP8266EX) 5-channel PWM MOSFET LED controller -# -########################################################################################### -# NOTES +#:########################################################################################:# +# TITLE: FRONT ENTRANCEWAY LED LIGHT CONTROLS +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-entranceoutsideledlights.yaml +#:########################################################################################:# +# VERSIONS: +# V1.2 2026-03-10 Added per-channel maximum ON timers with auto-dim-to-off, restart-on-ON, and moved defaults into substitutions +# V1.1 2026-03-10 Updated yaml to zorruno layout V1.1 +# V1.0 2026-02-23 Initial version (converted from Tasmota) +#:########################################################################################:# +# HARDWARE: +# - H801 (ESP8266EX) 5-channel PWM MOSFET LED controller +#:########################################################################################:# +# OPERATION NOTES: # - H801 PWM outputs (typical / ESPHome Devices): # PWM1 / R -> GPIO15 # PWM2 / G -> GPIO13 @@ -23,43 +28,56 @@ # * Brightness slider 0-100% normalized to the per-channel hard limit # * Ramp time (seconds) for a full 0 -> hard limit transition # * Hard limit (percent) absolute cap for that channel +# * Maximum ON time (minutes) after which the channel dims to OFF +# +# - A fresh ON command restarts the countdown timer for that channel. +# - Setting channel brightness above 0 also restarts that channel timer. # # - Underlying PWM light entities are INTERNAL so HA cannot bypass the hard limit. -# -########################################################################################## -########################################################################################## +#:########################################################################################:# +# MQTT COMMANDS: +# - None (no device-specific MQTT commands in this YAML; common_mqtt is included for standardisation) +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant OFFLINE, but Network and MQTT ONLINE +# - Local PWM control continues via HA entities if HA is offline (entities unavailable until HA returns) +# - Device continues running with last commanded PWM states +# - Any already-running max ON timer continues locally on the device +# b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) +# - No impact unless you rely on MQTT for diagnostics; local control via HA/API continues +# - Any already-running max ON timer continues locally on the device +# c) Entire WiFi/Network OFFLINE +# - No HA API and no MQTT connectivity +# - Outputs remain in their last driven state (until power loss/reboot) +# - Any already-running max ON timer continues locally on the device +# - Accurate time is NOT needed (SNTP not required for operation) +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-entranceoutsideledlights" friendly_name: "Front Entranceway LED Light controls" - description_comment: "H801 ESP8266 5-channel PWM LED controller (Entranceway)" + description_comment: "H801 ESP8266 5-channel PWM LED controller (Entranceway) (Layout V1.1)" device_area: "Entranceway" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "H801.5CH PWM LED Controller" - project_version: "v1.0" + project_version: "v1.2" # Passwords & Secrets api_key: !secret esp-api_key ota_pass: !secret esp-ota_pass static_ip_address: !secret esp-entranceoutsideledlights_ip # unfortunately you can't use substitutions inside secrets names - #mqtt_command_main_topic: !secret mqtt_command_main_topic - #mqtt_status_main_topic: !secret mqtt_status_main_topic # If we are changing IP addresses, you must update the current IP address here, otherwise it remains # Don't forget to switch it back when changed. current_ip_address: ${static_ip_address} - # MQTT LOCAL Controls (optional, kept for consistency with your templates) - #mqtt_local_device_name: "entranceoutsideledlights" - #mqtt_local_command_topic: "${mqtt_command_main_topic}/${mqtt_local_device_name}" - #mqtt_local_status_topic: "${mqtt_status_main_topic}/${mqtt_local_device_name}" - # Device Settings log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG, VERBOSE, VERY_VERBOSE update_interval: "60s" @@ -68,9 +86,28 @@ substitutions: out1_name: "Main Entrance Outside LED Lights" out2_name: "Number 16 LED Light" out3_name: "Spare 3" - out4_name: "Spare 4" + out4_name: "Doorbell Illumination" out5_name: "Spare 5" + # OUTPUT DEFAULT SETTINGS + out1_ramp_default_s: "2.0" + out2_ramp_default_s: "2.0" + out3_ramp_default_s: "2.0" + out4_ramp_default_s: "2.0" + out5_ramp_default_s: "2.0" + + out1_max_limit_default_pct: "100" + out2_max_limit_default_pct: "100" + out3_max_limit_default_pct: "100" + out4_max_limit_default_pct: "100" + out5_max_limit_default_pct: "100" + + out1_max_on_time_default_mins: "240" + out2_max_on_time_default_mins: "240" + out3_max_on_time_default_mins: "10" + out4_max_on_time_default_mins: "4" + out5_max_on_time_default_mins: "10" + # H801 PWM PINS (easy swap here if needed) out1_pwm_pin: "GPIO15" out2_pwm_pin: "GPIO13" @@ -79,10 +116,11 @@ substitutions: out5_pwm_pin: "GPIO4" pwm_frequency: "1000 Hz" -########################################################################################## + +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -115,38 +153,43 @@ packages: diag_debug: !include common/include_debug_diag_sensors.yaml #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -############################################# -# ESPHome -# https://esphome.io/components/esphome.html -############################################# -esphome: - name: ${device_name} - friendly_name: ${friendly_name} - comment: ${description_comment} # appears on the esphome page in HA - min_version: 2025.11.0 - area: ${device_area} - project: - name: ${project_name} - version: ${project_version} -############################################# -# ESP Platform and Framework +#:########################################################################################:# +# ESPHOME: +# https://esphome.io/components/esphome.html +#:########################################################################################:# +esphome: + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" # appears on the esphome page in HA + min_version: 2025.11.0 + area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" + + +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: # https://esphome.io/components/esp8266.html -############################################# +#:########################################################################################:# esp8266: board: esp01_1m -############################################# -# ESPHome Logging Enable + +#:########################################################################################:# +# LOGGING: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: ${log_level} + level: "${log_level}" baud_rate: 0 # set to 0 for no logging via UART -########################################################################################## -# OUTPUTS (H801 PWM MOSFET CHANNELS) -########################################################################################## + +#:########################################################################################:# +# OUTPUTS: H801 PWM MOSFET CHANNELS +# https://esphome.io/components/output/esp8266_pwm.html +#:########################################################################################:# output: - platform: esp8266_pwm id: out1_pwm @@ -173,9 +216,11 @@ output: pin: ${out5_pwm_pin} frequency: ${pwm_frequency} -########################################################################################## -# INTERNAL LIGHTS (do not expose to HA; use helper entities below) -########################################################################################## + +#:########################################################################################:# +# LIGHTS: Internal raw PWM lights (not exposed to HA) +# https://esphome.io/components/light/monochromatic.html +#:########################################################################################:# light: - platform: monochromatic id: out1_light_raw @@ -212,9 +257,11 @@ light: internal: true restore_mode: RESTORE_DEFAULT_OFF -########################################################################################## -# GLOBALS (store "last non-zero" brightness per channel) -########################################################################################## + +#:########################################################################################:# +# GLOBALS: Store "last non-zero" brightness per channel +# https://esphome.io/components/globals.html +#:########################################################################################:# globals: - id: out1_last_nonzero_pct type: float @@ -241,9 +288,11 @@ globals: restore_value: true initial_value: "100.0" -########################################################################################## -# SCRIPTS (apply normalized brightness + proportional ramping) -########################################################################################## + +#:########################################################################################:# +# SCRIPTS: Apply normalized brightness + proportional ramping + per-channel auto-off timers +# https://esphome.io/components/script.html +#:########################################################################################:# script: ############################################# # OUT1 @@ -319,6 +368,14 @@ script: call.set_transition_length(trans_ms); call.perform(); + - id: out1_auto_off_timer + mode: restart + parameters: + delay_ms: int + then: + - delay: !lambda "return delay_ms;" + - script.execute: out1_turn_off + ############################################# # OUT2 ############################################# @@ -393,6 +450,14 @@ script: call.set_transition_length(trans_ms); call.perform(); + - id: out2_auto_off_timer + mode: restart + parameters: + delay_ms: int + then: + - delay: !lambda "return delay_ms;" + - script.execute: out2_turn_off + ############################################# # OUT3 ############################################# @@ -467,6 +532,14 @@ script: call.set_transition_length(trans_ms); call.perform(); + - id: out3_auto_off_timer + mode: restart + parameters: + delay_ms: int + then: + - delay: !lambda "return delay_ms;" + - script.execute: out3_turn_off + ############################################# # OUT4 ############################################# @@ -541,6 +614,14 @@ script: call.set_transition_length(trans_ms); call.perform(); + - id: out4_auto_off_timer + mode: restart + parameters: + delay_ms: int + then: + - delay: !lambda "return delay_ms;" + - script.execute: out4_turn_off + ############################################# # OUT5 ############################################# @@ -615,9 +696,19 @@ script: call.set_transition_length(trans_ms); call.perform(); -########################################################################################## -# NUMBERS (brightness normalized to limit, plus per-channel ramp and hard limit) -########################################################################################## + - id: out5_auto_off_timer + mode: restart + parameters: + delay_ms: int + then: + - delay: !lambda "return delay_ms;" + - script.execute: out5_turn_off + + +#:########################################################################################:# +# NUMBER: Brightness normalized to limit, plus per-channel ramp, hard limit, and max ON time +# https://esphome.io/components/number/template.html +#:########################################################################################:# number: ############################################# # OUT1 @@ -632,7 +723,7 @@ number: max_value: 30.0 step: 0.1 restore_value: true - initial_value: 2.0 + initial_value: ${out1_ramp_default_s} optimistic: true set_action: - script.execute: out1_apply_target @@ -647,11 +738,24 @@ number: max_value: 100 step: 1 restore_value: true - initial_value: 100 + initial_value: ${out1_max_limit_default_pct} optimistic: true set_action: - script.execute: out1_apply_target + - platform: template + id: out1_auto_off_mins + name: "${out1_name} Max ON Time" + icon: mdi:timer-lock-outline + entity_category: config + unit_of_measurement: "min" + min_value: 1 + max_value: 720 + step: 1 + restore_value: true + initial_value: ${out1_max_on_time_default_mins} + optimistic: true + - platform: template id: out1_brightness_pct name: "${out1_name} Brightness" @@ -667,6 +771,16 @@ number: - lambda: |- if (x > 0.0f) id(out1_last_nonzero_pct) = x; - script.execute: out1_apply_target + - if: + condition: + lambda: |- + return x > 0.0f; + then: + - script.execute: + id: out1_auto_off_timer + delay_ms: !lambda "return (int) (id(out1_auto_off_mins).state * 60000.0f);" + else: + - script.stop: out1_auto_off_timer ############################################# # OUT2 @@ -681,7 +795,7 @@ number: max_value: 30.0 step: 0.1 restore_value: true - initial_value: 2.0 + initial_value: ${out2_ramp_default_s} optimistic: true set_action: - script.execute: out2_apply_target @@ -696,11 +810,24 @@ number: max_value: 100 step: 1 restore_value: true - initial_value: 100 + initial_value: ${out2_max_limit_default_pct} optimistic: true set_action: - script.execute: out2_apply_target + - platform: template + id: out2_auto_off_mins + name: "${out2_name} Max ON Time" + icon: mdi:timer-lock-outline + entity_category: config + unit_of_measurement: "min" + min_value: 1 + max_value: 720 + step: 1 + restore_value: true + initial_value: ${out2_max_on_time_default_mins} + optimistic: true + - platform: template id: out2_brightness_pct name: "${out2_name} Brightness" @@ -716,6 +843,16 @@ number: - lambda: |- if (x > 0.0f) id(out2_last_nonzero_pct) = x; - script.execute: out2_apply_target + - if: + condition: + lambda: |- + return x > 0.0f; + then: + - script.execute: + id: out2_auto_off_timer + delay_ms: !lambda "return (int) (id(out2_auto_off_mins).state * 60000.0f);" + else: + - script.stop: out2_auto_off_timer ############################################# # OUT3 @@ -730,7 +867,7 @@ number: max_value: 30.0 step: 0.1 restore_value: true - initial_value: 2.0 + initial_value: ${out3_ramp_default_s} optimistic: true set_action: - script.execute: out3_apply_target @@ -745,11 +882,24 @@ number: max_value: 100 step: 1 restore_value: true - initial_value: 100 + initial_value: ${out3_max_limit_default_pct} optimistic: true set_action: - script.execute: out3_apply_target + - platform: template + id: out3_auto_off_mins + name: "${out3_name} Max ON Time" + icon: mdi:timer-lock-outline + entity_category: config + unit_of_measurement: "min" + min_value: 1 + max_value: 720 + step: 1 + restore_value: true + initial_value: ${out3_max_on_time_default_mins} + optimistic: true + - platform: template id: out3_brightness_pct name: "${out3_name} Brightness" @@ -765,6 +915,16 @@ number: - lambda: |- if (x > 0.0f) id(out3_last_nonzero_pct) = x; - script.execute: out3_apply_target + - if: + condition: + lambda: |- + return x > 0.0f; + then: + - script.execute: + id: out3_auto_off_timer + delay_ms: !lambda "return (int) (id(out3_auto_off_mins).state * 60000.0f);" + else: + - script.stop: out3_auto_off_timer ############################################# # OUT4 @@ -779,7 +939,7 @@ number: max_value: 30.0 step: 0.1 restore_value: true - initial_value: 2.0 + initial_value: ${out4_ramp_default_s} optimistic: true set_action: - script.execute: out4_apply_target @@ -794,11 +954,24 @@ number: max_value: 100 step: 1 restore_value: true - initial_value: 100 + initial_value: ${out4_max_limit_default_pct} optimistic: true set_action: - script.execute: out4_apply_target + - platform: template + id: out4_auto_off_mins + name: "${out4_name} Max ON Time" + icon: mdi:timer-lock-outline + entity_category: config + unit_of_measurement: "min" + min_value: 1 + max_value: 720 + step: 1 + restore_value: true + initial_value: ${out4_max_on_time_default_mins} + optimistic: true + - platform: template id: out4_brightness_pct name: "${out4_name} Brightness" @@ -814,6 +987,16 @@ number: - lambda: |- if (x > 0.0f) id(out4_last_nonzero_pct) = x; - script.execute: out4_apply_target + - if: + condition: + lambda: |- + return x > 0.0f; + then: + - script.execute: + id: out4_auto_off_timer + delay_ms: !lambda "return (int) (id(out4_auto_off_mins).state * 60000.0f);" + else: + - script.stop: out4_auto_off_timer ############################################# # OUT5 @@ -828,7 +1011,7 @@ number: max_value: 30.0 step: 0.1 restore_value: true - initial_value: 2.0 + initial_value: ${out5_ramp_default_s} optimistic: true set_action: - script.execute: out5_apply_target @@ -843,11 +1026,24 @@ number: max_value: 100 step: 1 restore_value: true - initial_value: 100 + initial_value: ${out5_max_limit_default_pct} optimistic: true set_action: - script.execute: out5_apply_target + - platform: template + id: out5_auto_off_mins + name: "${out5_name} Max ON Time" + icon: mdi:timer-lock-outline + entity_category: config + unit_of_measurement: "min" + min_value: 1 + max_value: 720 + step: 1 + restore_value: true + initial_value: ${out5_max_on_time_default_mins} + optimistic: true + - platform: template id: out5_brightness_pct name: "${out5_name} Brightness" @@ -863,14 +1059,26 @@ number: - lambda: |- if (x > 0.0f) id(out5_last_nonzero_pct) = x; - script.execute: out5_apply_target + - if: + condition: + lambda: |- + return x > 0.0f; + then: + - script.execute: + id: out5_auto_off_timer + delay_ms: !lambda "return (int) (id(out5_auto_off_mins).state * 60000.0f);" + else: + - script.stop: out5_auto_off_timer -########################################################################################## -# SWITCHES (On/Off that respects ramping; brightness slider remains unchanged when off) -########################################################################################## + +#:########################################################################################:# +# SWITCH: On/Off that respects ramping; brightness slider remains unchanged when off +# https://esphome.io/components/switch/template.html +#:########################################################################################:# switch: - platform: template id: out1_switch - name: ${out1_name} + name: "${out1_name}" icon: mdi:lightbulb lambda: |- return id(out1_light_raw).current_values.is_on(); @@ -885,12 +1093,16 @@ switch: value: !lambda "return id(out1_last_nonzero_pct);" else: - script.execute: out1_apply_target + - script.execute: + id: out1_auto_off_timer + delay_ms: !lambda "return (int) (id(out1_auto_off_mins).state * 60000.0f);" turn_off_action: + - script.stop: out1_auto_off_timer - script.execute: out1_turn_off - platform: template id: out2_switch - name: ${out2_name} + name: "${out2_name}" icon: mdi:lightbulb lambda: |- return id(out2_light_raw).current_values.is_on(); @@ -905,12 +1117,16 @@ switch: value: !lambda "return id(out2_last_nonzero_pct);" else: - script.execute: out2_apply_target + - script.execute: + id: out2_auto_off_timer + delay_ms: !lambda "return (int) (id(out2_auto_off_mins).state * 60000.0f);" turn_off_action: + - script.stop: out2_auto_off_timer - script.execute: out2_turn_off - platform: template id: out3_switch - name: ${out3_name} + name: "${out3_name}" icon: mdi:lightbulb lambda: |- return id(out3_light_raw).current_values.is_on(); @@ -925,12 +1141,16 @@ switch: value: !lambda "return id(out3_last_nonzero_pct);" else: - script.execute: out3_apply_target + - script.execute: + id: out3_auto_off_timer + delay_ms: !lambda "return (int) (id(out3_auto_off_mins).state * 60000.0f);" turn_off_action: + - script.stop: out3_auto_off_timer - script.execute: out3_turn_off - platform: template id: out4_switch - name: ${out4_name} + name: "${out4_name}" icon: mdi:lightbulb lambda: |- return id(out4_light_raw).current_values.is_on(); @@ -945,12 +1165,16 @@ switch: value: !lambda "return id(out4_last_nonzero_pct);" else: - script.execute: out4_apply_target + - script.execute: + id: out4_auto_off_timer + delay_ms: !lambda "return (int) (id(out4_auto_off_mins).state * 60000.0f);" turn_off_action: + - script.stop: out4_auto_off_timer - script.execute: out4_turn_off - platform: template id: out5_switch - name: ${out5_name} + name: "${out5_name}" icon: mdi:lightbulb lambda: |- return id(out5_light_raw).current_values.is_on(); @@ -965,5 +1189,9 @@ switch: value: !lambda "return id(out5_last_nonzero_pct);" else: - script.execute: out5_apply_target + - script.execute: + id: out5_auto_off_timer + delay_ms: !lambda "return (int) (id(out5_auto_off_mins).state * 60000.0f);" turn_off_action: + - script.stop: out5_auto_off_timer - script.execute: out5_turn_off \ No newline at end of file diff --git a/esphome/esp-garagebtproxy.yaml b/esphome/esp-garagebtproxy.yaml index f16efed..e38a723 100644 --- a/esphome/esp-garagebtproxy.yaml +++ b/esphome/esp-garagebtproxy.yaml @@ -1,49 +1,66 @@ -############################################# -############################################# -# ESP32 - Garage -# Bluetooth Proxy -############################################# -############################################# +#:########################################################################################:# +# TITLE: GARAGE ENTRANCE BLUETOOTH PROXY +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-garagebtproxy.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-11 Updated yaml to zorruno layout V1.1 +# V1.0 2025-06-14 Initial Version +#:########################################################################################:# +# HARDWARE: +# - ESP32-WROOM (esp32dev) +# - Bluetooth Proxy (ESPHome bluetooth_proxy + esp32_ble_tracker) +#:########################################################################################:# +# OPERATION NOTES: +# - Provides Bluetooth Proxy coverage at the garage entrance for Home Assistant +# - Uses ESP-IDF framework for BLE stability/performance +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant OFFLINE, but Network and MQTT ONLINE +# - BLE proxy is unavailable to Home Assistant until HA returns +# b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) +# - BLE proxy still works via Home Assistant API +# c) Entire WiFi/Network OFFLINE +# - BLE proxy unavailable until network returns +# - Accurate time is not needed (SNTP not required) +#:########################################################################################:# -############################################# -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -############################################# +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-garagebtproxy" friendly_name: "Garage Entrance Bluetooth Proxy" - description_comment: "ESP32-WROOM garage entrance with BT Proxy" - device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - + description_comment: "ESP32-WROOM garage entrance with BT Proxy (Layout V1.1)" + device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + # Project Naming - project_name: "Zemismart Technologies.KS-811-3 (Triple)" # Project Details - project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - - #entity_prefix: "Main Bathroom" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + project_name: "ESPHome.Bluetooth Proxy" + project_version: "v1.1" + + # Passwords & Secrets + api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names + static_ip_address: !secret esp-garagebtproxy_ip # unfortunately you can't use substitutions inside secrets names + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} - # Passwords - api_key: !secret esp-api_key #unfortunately you can't use substitutions in secrets names - ota_pass: !secret esp-ota_pass #unfortunately you can't use substitutions in secrets names - static_ip_address: !secret esp-garagebtproxy_ip - #mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic - #mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic - # Device Settings - #relay_icon: "mdi:heating-coil" - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for general sensors etc - ############################################# - # SPECIFIC PROJECT VARIABLE SUBSTITUTIONS - ############################################# - # - # -########################################################################################## +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -52,6 +69,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -65,69 +83,62 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - - #### WEB PORTAL #### - #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - common_sntp: !include common/sntp_common.yaml + common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml - -############################################# -# ESPHome + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + + +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -############################################# +#:########################################################################################:# esphome: name: ${device_name} friendly_name: ${friendly_name} - comment: ${description_comment} #appears on the esphome page in HA - min_version: 2024.6.0 # + comment: ${description_comment} # appears on the esphome page in HA area: ${device_area} + min_version: 2024.6.0 + project: + name: ${project_name} + version: ${project_version} -############################################# -# ESP Platform and Framework + +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: # https://esphome.io/components/esp32.html -############################################# +#:########################################################################################:# esp32: board: esp32dev framework: #type: arduino - type: esp-idf #Suggested Use ESP-IDF Framework, or Plug Out the UART Cable Might Cause ESP32 Hang. - version: recommended #recommended, latest or dev + type: esp-idf + version: recommended advanced: - minimum_chip_revision: "3.1" # This makes the binary slightly smaller + minimum_chip_revision: "3.1" -############################################# -# ESPHome Logging Enable + +#:########################################################################################:# +# LOGGING: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: ${log_level} #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 + level: ${log_level} -############################################# -# Bluetooth + +#:########################################################################################:# +# BLUETOOTH: # https://esphome.io/components/bluetooth_proxy.html # https://esphome.io/components/esp32_ble_tracker.html -# Remember that this takes a LOT of processing. On the -# ESP32, enable the IDF framework, and disable the -# Web server component. Changing to the IDF framework -# needs to be via cable not OTA to change the -# partition setup. -############################################# +#:########################################################################################:# bluetooth_proxy: active: true esp32_ble_tracker: scan_parameters: - # We currently use the defaults to ensure Bluetooth - # can co-exist with WiFi In the future we may be able to - # enable the built-in coexistence logic in ESP-IDF - active: true - + active: true \ No newline at end of file diff --git a/esphome/esp-garageentrylights.yaml b/esphome/esp-garageentrylights.yaml index 2069b77..9057211 100644 --- a/esphome/esp-garageentrylights.yaml +++ b/esphome/esp-garageentrylights.yaml @@ -1,54 +1,91 @@ -############################################# -############################################# -# GARAGE ENTRY LIGHTSWITCH (OBK Converted, BK7231N) +#:########################################################################################:# +# TITLE: GARAGE ENTRY LIGHTSWITCH (OBK CONVERTED, BK7231N) +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-garageentrylights.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V1.0 2025-11-23 Initial -############################################# -# Zemismart KS-811 Triple push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ -# -# NOTES -# - -# -############################################# -############################################# +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Triple push button (OBK converted, BK7231N) +# - ESPHome bk72xx: generic-bk7231n-qfn32-tuya +# - Status LED: P22 +# - Buttons: P17 (Btn1), P26 (Btn2), P24 (Btn3) +# - Relays: P14 (Relay1), P16 (Relay2), P15 (Relay3) +# - Pinout/schematic: https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# OPERATION NOTES: +# - 3 button / 3 relay wall switch +# - Button 1 toggles Relay 1 (Corridor Lights) +# - Button 2 toggles Relay 2 (Patio Lights) +# - Button 3 toggles Relay 3 (Garage Lights) +# - Default relay restore mode is controlled via substitution: relay_restore_mode +# - WiFi package overrides: +# - min_auth_mode removed (WPA2-only not supported on bk72xx) +# - reboot_timeout overridden to 15min +# - fast_connect forced false +# - MQTT keepalive overridden to 15s +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant OFFLINE, but Network and MQTT ONLINE +# - Physical buttons still toggle relays locally +# - MQTT (from common package) continues if broker is reachable +# b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) +# - Physical buttons still toggle relays locally +# - HA/API control remains available (switch entities) +# - MQTT diagnostics/publishes (common_mqtt) will fail while MQTT is down +# c) Entire WiFi/Network OFFLINE +# - Physical buttons still toggle relays locally (standalone operation) +# - No HA API and no MQTT connectivity until network returns +# - Accurate time is not needed (SNTP not required) +#:########################################################################################:# -############################################# -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -############################################# +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-garageentrylights" friendly_name: "Garage Entry Lightswitch (3)" - description_comment: "BK7231N - Garage Entry Lightswitch using a Zemismart KS-811 Triple Push Button. Corridor Light (1), Patio Lights (2), Garage Lights (3)" - device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - - # Project Naming - project_name: "Zemismart Technologies.KS-811 Triple BK7231N" # Project Details - project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + description_comment: "BK7231N - Garage Entry Lightswitch using a Zemismart KS-811 Triple Push Button. Corridor Light (1), Patio Lights (2), Garage Lights (3) (Layout V1.1)" + device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - # Passwords + # Project Naming + project_name: "Zemismart Technologies.KS-811 Triple BK7231N" + project_version: "v1.1" + + # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-garageentrylights_ip + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + # Device Settings - log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + log_level: "NONE" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for general sensors etc # Default relay restore mode # Options: RESTORE_DEFAULT_OFF, RESTORE_DEFAULT_ON, ALWAYS_ON, ALWAYS_OFF relay_restore_mode: "RESTORE_DEFAULT_OFF" - - # Switch Naming - switch_1_name: "Corridor Lights" # Only one light (Garage Side) actually connected to this relay - switch_2_name: "Patio Lights" # Output for pario string hanging lights - switch_3_name: "Garage Lights" # This is virtual only, no power connected to 3rd relay -########################################################################################## + # Switch Naming + switch_1_name: "Corridor Lights" # Only one light (Garage Side) actually connected to this relay + switch_2_name: "Patio Lights" # Output for patio string hanging lights + switch_3_name: "Garage Lights" # This is virtual only, no power connected to 3rd relay + + +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -57,6 +94,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -70,86 +108,75 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - - #### WEB PORTAL #### - #common_webportal: !include common/webportal_common.yaml - #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - #diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + #diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -# Package item removals + +#:########################################################################################:# +# PACKAGE OVERRIDES: +# These override or remove items from included packages above +#:########################################################################################:# wifi: - min_auth_mode: !remove # The WPA2 only works on esp32/8266 - reboot_timeout: 15min # override the selection from from the common package - fast_connect: false # (optional) force off, in case package vars change + min_auth_mode: !remove # The WPA2-only mode works on esp32/esp8266, not bk72xx + reboot_timeout: 15min # override selection from common package + fast_connect: false # force off, in case package vars change mqtt: - keepalive: 15s # overriding the value from the common package + keepalive: 15s # override value from common package -############################################# -# ESPHome + +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -############################################# +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" # Appears on the ESPHome page in HA area: "${device_area}" project: name: "${project_name}" version: "${project_version}" -# on_boot: -# priority: 200 -# then: -# - switch.turn_on: Relay_3 mdns: disabled: true -############################################# -# BUILD FOR BK CHIPSET -# bk72xx + +#:########################################################################################:# +# BK72XX: # https://devices.esphome.io/board/bk72xx/ -############################################# +#:########################################################################################:# bk72xx: board: generic-bk7231n-qfn32-tuya -############################################# -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -############################################# -#esp8266: -# board: esp01_1m -# early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. -# board_flash_mode: dout # Default is dout -############################################# -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGING: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + level: "${log_level}" id: logger_id -############################################# -# STATUS LED + +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -############################################# +#:########################################################################################:# status_led: pin: - number: P22 #GPIO22 + number: P22 inverted: true -############################################# -# BINARY SENSORS + +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -############################################# +#:########################################################################################:# binary_sensor: - platform: gpio pin: @@ -172,8 +199,8 @@ binary_sensor: inverted: true name: "Button 2: ${switch_2_name}" on_press: - - delay: 50ms - - switch.toggle: Relay_2 + - delay: 50ms + - switch.toggle: Relay_2 - platform: gpio pin: @@ -184,26 +211,29 @@ binary_sensor: inverted: true name: "Button 3: ${switch_3_name}" on_press: - - delay: 50ms - - switch.toggle: Relay_3 + - delay: 50ms + - switch.toggle: Relay_3 -############################################# -# SWITCH COMPONENT + +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -############################################# +#:########################################################################################:# switch: - platform: gpio name: "Relay 1: ${switch_1_name}" - pin: P14 #GPIO14 + pin: P14 id: Relay_1 restore_mode: ${relay_restore_mode} + - platform: gpio name: "Relay 2: ${switch_2_name}" - pin: P16 #GPIO16 + pin: P16 id: Relay_2 restore_mode: ${relay_restore_mode} + - platform: gpio name: "Relay 3: ${switch_3_name}" - pin: P15 #GPIO15 + pin: P15 id: Relay_3 restore_mode: ${relay_restore_mode} \ No newline at end of file diff --git a/esphome/esp-garageextcornerlight.yaml b/esphome/esp-garageextcornerlight.yaml index f90950c..fb96233 100644 --- a/esphome/esp-garageextcornerlight.yaml +++ b/esphome/esp-garageextcornerlight.yaml @@ -1,54 +1,90 @@ -############################################# -############################################# -# GARAGE LIGHTS -# Controlled by a Sonoff Basic R1 -# +#:########################################################################################:# +# TITLE: GARAGE EXTERNAL CORNER LIGHT +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-garageextcornerlight.yaml +#:########################################################################################:# +# VERSIONS: +# V2.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V2.0 2025-10-22 Latest layout with home MQTT code # V1.0 2025-10-22 Initial Version -# -########################################################################################## -########################################################################################## +#:########################################################################################:# +# HARDWARE: +# - Sonoff Basic R1 (ESP8266) +# - Relay: GPIO12 +# - Button: GPIO03 +# - Status LED: GPIO13 (inverted) +#:########################################################################################:# +# OPERATION NOTES: +# - Local button toggles the relay output +# - MQTT control: +# - Command topic: ${mqtt_command_topic} +# Payload: "ON" / "OFF" +# - Status topic: ${mqtt_status_topic} +# Payload: "ON" / "OFF" +# - On MQTT connect, publishes current relay state to the status topic +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant OFFLINE, but Network and MQTT ONLINE +# - Local button still works +# - MQTT commands still work +# b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) +# - Local button still works +# - HA/API control still works +# - MQTT commands will not work while broker is down +# c) Entire WiFi/Network OFFLINE +# - Local button still works +# - No HA/API and no MQTT control until network returns +# - Accurate time is not needed (SNTP not required) +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Custom Naming device_name: "esp-garageextcornerlight" friendly_name: "Garage External Corner Light" - description_comment: "Garage External Corner Light :: Sonoff Basic" + description_comment: "Garage External Corner Light :: Sonoff Basic (Layout V1.1)" device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. static_ip_address: !secret esp-garageextcornerlight_ip mqtt_device_name: "garage-externalcorner-light" # Project Naming - project_name: "Sonoff Technologies.Sonoff Basic V1" # Project Details - project_version: "v2.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - - # Passwords + project_name: "Sonoff Technologies.Sonoff Basic V1" # Project Details + project_version: "v2.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names mqtt_command_main_topic: !secret mqtt_command_main_topic mqtt_status_main_topic: !secret mqtt_status_main_topic + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + # Device Settings relay_icon: "mdi:lightbulb" - log_level: "ERROR" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + log_level: "ERROR" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for for general sensors etc - # Device Naming + # I/O Naming relay_1_name: "Garage External Light" button_1_name: "Power Button" # MQTT Controls - mqtt_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" + mqtt_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" mqtt_status_topic: "${mqtt_status_main_topic}/${mqtt_device_name}" -########################################################################################## + +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -57,6 +93,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -70,80 +107,85 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -########################################################################################## -# ESPHome + +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" # Appears on the ESPHome page in HA area: "${device_area}" -# platformio_options: -# build_flags: -# - "-Os" # optimize for size -# - "-Wl,--gc-sections" # drop unused code/data -# - "-fno-exceptions" # strip C++ exceptions -# - "-fno-rtti" # strip C++ RTTI -########################################################################################## -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -########################################################################################## + +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: - board: esp01_1m # The original sonoff basic - restore_from_flash: True # restore some values on reboot + board: esp01_1m # The original Sonoff Basic + restore_from_flash: true # restore some values on reboot + +#:########################################################################################:# +# PREFERENCES: +# https://esphome.io/components/preferences.html +#:########################################################################################:# preferences: flash_write_interval: 5min + +#:########################################################################################:# +# MDNS: +# https://esphome.io/components/mdns.html +#:########################################################################################:# mdns: - disabled: False + disabled: false -########################################################################################## -# ESPHome Logging Enable + +#:########################################################################################:# +# LOGGING: # https://esphome.io/components/logger.html -########################################################################################## +#:########################################################################################:# logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing + level: "${log_level}" baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 -########################################################################################## -# SWITCH COMPONENT + +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -########################################################################################## -# Sonoff Basic R1 Relay Switch is GPIO12 -############################################# +# Sonoff Basic R1 relay is GPIO12 +#:########################################################################################:# switch: - platform: gpio name: "${relay_1_name}" pin: GPIO12 id: relay1 restore_mode: RESTORE_DEFAULT_OFF - icon: "${relay_icon}" + icon: "${relay_icon}" -########################################################################################## -# BINARY SENSORS + +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -########################################################################################## -# Sonoff Basic R1 Button is GPIO03 -############################################# +# Sonoff Basic R1 button is GPIO03 +#:########################################################################################:# binary_sensor: - # Actual button input - platform: gpio pin: @@ -166,8 +208,8 @@ binary_sensor: // Relay is OFF: turn it ON id(relay1).turn_on(); } - - # Mimics actual relay status + + # Mimics actual relay status (publishes MQTT state) - platform: template name: "${relay_1_name} Status" lambda: |- @@ -175,34 +217,30 @@ binary_sensor: on_press: - mqtt.publish: topic: "${mqtt_status_topic}" - payload: "ON" + payload: "ON" on_release: - mqtt.publish: topic: "${mqtt_status_topic}" - payload: "OFF" - -########################################################################################## -# STATUS LED + payload: "OFF" + + +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -########################################################################################## -# Sonoff Basic R1 LED is GPIO13 -########################################################################################## +# Sonoff Basic R1 LED is GPIO13 +#:########################################################################################:# status_led: pin: number: GPIO13 - inverted: yes + inverted: true -########################################################################################## -# MQTT COMMANDS -# This adds device-specific MQTT command triggers to the common MQTT configuration. -# Requires you to define: -# substitutions: -# mqtt_command_topic: "" -# mqtt_state_topic: "" -########################################################################################## + +#:########################################################################################:# +# MQTT: Device-specific command triggers +#:########################################################################################:# mqtt: on_message: - # Relay 1 control (only act and publish if a change is needed) + # Relay control (only act and publish if a change is needed) - topic: "${mqtt_command_topic}" payload: "ON" then: @@ -215,7 +253,6 @@ mqtt: - mqtt.publish: topic: "${mqtt_status_topic}" payload: "ON" - #retain: true - topic: "${mqtt_command_topic}" payload: "OFF" @@ -229,7 +266,6 @@ mqtt: - mqtt.publish: topic: "${mqtt_status_topic}" payload: "OFF" - #retain: true # Announce current state whenever MQTT (re)connects on_connect: @@ -237,4 +273,3 @@ mqtt: - mqtt.publish: topic: "${mqtt_status_topic}" payload: !lambda 'return id(relay1).state ? "ON" : "OFF";' - #retain: true diff --git a/esphome/esp-gasheater.yaml b/esphome/esp-gasheater.yaml index 48ec717..61ee0e3 100644 --- a/esphome/esp-gasheater.yaml +++ b/esphome/esp-gasheater.yaml @@ -1,116 +1,160 @@ -########################################################################################## -########################################################################################## -# RINNAI NEO - GAS HEATER CONTROLLER (BUTTON PRESS VIA RELAYS) +#:########################################################################################:# +# TITLE: +# RINNAI NEO GAS HEATER CONTROLLER +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-gasheater.yaml +#:########################################################################################:# +# VERSIONS: +# V1.7 2026-03-26 Added Heater Operation switch; MQTT status now mirrors the Status Text +# entity; preserved Test Mode AUTO test temperature and visible 6-step calibration +# V1.6 2026-03-22 Added richer status text: At Temperature, Operating (Level X), +# Calibrating, and Fault (Room Temperature Lost) +# V1.5 2026-03-22 Added Test Temperature Value slider for Test Mode AUTO; status text +# shows Test Mode state; temperature units set to °C +# V1.4 2026-03-22 Updated yaml to zorruno layout V1.1; boot into BYPASS (Remote Only); +# renamed remote-only mode; refined Test Mode to click real power relay; +# added setpoint text and setpoint up/down buttons +# V1.3 2026-03-22 Refined Test Mode so power relay still clicks; added setpoint text plus +# setpoint up/down buttons; Test Mode can now be used for MANUAL or AUTO testing +# V1.2 2026-03-22 Added Test Mode bench testing override +# V1.1 2026-03-22 Updated yaml to zorruno layout V1.1; forced AUTO on reboot; initialized +# stale-temp timer at boot; cleared Remote Control Only self-power flag +# V1.0 2025-07-21 First setup (replacement of Tasmota) +#:########################################################################################:# +# HARDWARE: +# - Sonoff DEV (ESP8266) +# - 3-relay daughterboard +# - Rinnai Neo gas heater +# - Relay outputs: +# - GPIO12 = ON/OFF button press +# - GPIO13 = Flame UP button press +# - GPIO14 = Flame DOWN button press +# - LED inputs: +# - GPIO4 = Red standby LED +# - GPIO5 = Blue operating LED +#:########################################################################################:# +# OPERATION NOTES: +# - Replaces the RF remote by pressing the heater panel buttons via relays. +# - Heater manages its own ignition, flame safety, and fan control. +# - AUTO mode uses: +# - Local HA setpoint number entity +# - External room temperature via MQTT +# - In Test Mode, AUTO uses the local Test Temperature Value slider instead of MQTT room +# temperature. +# - Setpoint is locally adjustable and also supports two-way MQTT sync. +# - Manual flame control is available via: +# - Flame Level select (1..7) +# - Flame Up step button +# - Flame Down step button +# - Setpoint helper entities are available via: +# - Setpoint Text +# - Setpoint Up (+0.5 °C) +# - Setpoint Down (-0.5 °C) +# - Test Mode is for bench testing before connection to the heater: +# - Forces Mode to MANUAL when enabled +# - Uses an internal powered flag instead of LED monitoring +# - Still clicks the real power relay when Power is turned ON or OFF +# - AUTO may still be selected manually later for testing +# - Heater Operation is a high-level thermostat enable helper: +# - ON = turn Test Mode OFF (if needed) and set Mode to AUTO +# - OFF = turn heater Power OFF and set Mode to BYPASS (Remote Only) +# - On normal ESPHome startup, Mode defaults to BYPASS (Remote Only). +# - On power ON in AUTO, the controller: +# - Applies a warmup lockout +# - Calibrates to level 1 using 6x DOWN +# - Begins auto level adjustment +# - If the heater is turned on externally while in AUTO, the controller will re-baseline +# after warmup and resume automatic control. +# - Fast-ramp mode allows faster flame stepping for a short period after turn-on. +#:########################################################################################:# +# MQTT COMMANDS: +# - Room temperature input: +# viewroad-status/lounge-environment/temperature +# - Setpoint input/output: +# viewroad-status/lounge-environment/temp-setpoint +# - Heater operating status output: +# viewroad-status/lounge-gasheater +#:########################################################################################:# +# OFFLINE NOTES: +# a) HA offline, WiFi/MQTT online: +# - Device continues to operate normally. +# - AUTO control still works if room temperature MQTT is still being published. +# - Setpoint can still be changed via MQTT. # -# Device: Sonoff DEV (ESP8266) + 3-Relay daughterboard -# Project: esp-gasheater Friendly Name: "Rinnai Neo Gas Heater" +# b) MQTT offline (or HA and MQTT offline): +# - No fresh room temperature or setpoint updates are received. +# - Device retains the last local setpoint. +# - If AUTO is active and temperature data becomes stale, the heater will turn OFF after +# temp_stale_timeout_min as a fail-safe. +# - Manual mode and flame tracking still work locally inside the ESP device logic. # -# Purpose: -# - Replace RF remote. Press panel buttons with relays: -# ON/OFF = GPIO12 Flame UP = GPIO13 Flame DOWN = GPIO14 -# - Sense panel LEDs as inputs: -# RED Standby = GPIO4 BLUE Operating = GPIO5 -# - AUTO thermostat uses local setpoint entity (adjustable in HA) and room temp via MQTT. -# Setpoint also listens to MQTT and will adopt an external value when published. -# - MANUAL override with level select and step UP/DOWN buttons. -# - On power ON or boot (if already powered), wait warmup then force level 1 (7x DOWN). -# - Publish status text to /viewroad-status/gasfire -> "Operating" | "Standby" | "Off" -# -# Notes: -# - Heater manages safety, ignition and fan. We only press buttons and watch LEDs. -# - LEDs pull to 0V when ON. Inputs default to inverted=true. Flip if your Tasmota shows -# opposite logic. Pull-ups enabled on inputs. -# - To reduce click noise: press pulses are short and spaced; optional min on/off timers. -########################################################################################## -########################################################################################## -# V1.0 - 2025-07-21 First Setup (and replacement of Tasmota) -# -# NOTES: -# Command the fan with MQTT -# ${mqtt_local_command_full_topic}/speed/set 1,2,3,0,+,- -# ${mqtt_local_command_full_topic}/light/set ON,OFF -# Status of the fan is in MQTT -# ${mqtt_local_command_full_topic}/speed/state 1,2,3,0 -# ${mqtt_local_command_full_topic}/light/state ON,OFF -# -########################################################################################## -########################################################################################## +# c) Entire WiFi/Network offline: +# - No MQTT temperature or setpoint updates are available. +# - Accurate time is not needed. SNTP is not required for this device. +# - If AUTO is active and the heater is ON, stale temperature fail-safe will turn it OFF +# after the configured timeout. +# - Existing heater safety systems still operate normally. +#:########################################################################################:# ########################################################################################## # SPECIFIC DEVICE VARIABLE SUBSTITUTIONS -# If NOT using a secrets file, just replace these with the passwords etc (in quotes) ########################################################################################## substitutions: # Device Naming device_name: "esp-gasheater" friendly_name: "Rinnai Neo Gas Heater" description_comment: "7 Setting controller for Rinnai Neo Gas heater :: Sonoff DEV + Relay Board" - device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + device_area: "Lounge" # Project Naming - project_name: "Sonoff Technologies.Sonoff DEV" # Project Details - project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - - # Passwords & Secrets (unfortunately you can't use substitutions inside secrets names) + project_name: "Sonoff Technologies.Sonoff DEV" + project_version: "v1.7" + + # Passwords & Secrets api_key: !secret esp-api_key - ota_pass: !secret esp-ota_pass + ota_pass: !secret esp-ota_pass static_ip_address: !secret esp-gasheater_ip - mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic - mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic - + current_ip_address: ${static_ip_address} + mqtt_local_command_main_topic: !secret mqtt_command_main_topic + mqtt_local_status_main_topic: !secret mqtt_status_main_topic + # Device Settings - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc - - # MQTT LOCAL Controls - #mqtt_device_name: "bedroom3-ceilingfan" - #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA - #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA - - # MQTT REMOTE Controls - - # Button Naming & Icons - - # Switch/Relay Naming & Icons - #relay_icon: "mdi:lightbulb-group" - #light_1_name: "Fan Light" - #switch_2_name: "Fan 2 Relay" - #switch_3_name: "Fan 3 Relay" - #switch_4_name: "Fan 4 Relay" + log_level: "INFO" + update_interval: "60s" ######################################################################################## - # TIMING TUNABLES (string values as required by substitutions) + # TIMING TUNABLES ######################################################################################## - relay_pulse_ms: "250" # length of each "button press" - min_click_gap_ms: "1200" # minimum gap between any two clicks - warmup_seconds: "60" # wait after ON before calibration/stepping - control_interval_s: "30" # AUTO control loop cadence - adjust_step_interval_s: "30" # gap between level steps in AUTO - recalibrate_interval_min: "180" # while at level 1, re-baseline every X min - temp_stale_timeout_min: "20" # turn OFF if no valid temp for this long (AUTO only) - fast_ramp_seconds: "180" # fast stepping window after turn-on - fast_ramp_step_s: "8" # step every 8s during fast-ramp - + relay_pulse_ms: "250" + min_click_gap_ms: "1200" + warmup_seconds: "30" + control_interval_s: "10" + adjust_step_interval_s: "10" + recalibrate_interval_min: "180" + temp_stale_timeout_min: "20" + fast_ramp_seconds: "240" + fast_ramp_step_s: "4" # Optional anti short-cycle (set to "0" to disable either one) - min_on_minutes: "5" - min_off_minutes: "5" + min_on_minutes: "1" + min_off_minutes: "0.5" ######################################################################################## # ELECTRICAL POLARITY ######################################################################################## - relay_inverted: "true" # many relay boards are active-low - red_led_inverted: "true" # LEDs pull to 0V when ON -> invert input + relay_inverted: "true" + red_led_inverted: "true" blue_led_inverted: "true" ######################################################################################## - # THERMOSTAT HYSTERESIS (in C) + # THERMOSTAT HYSTERESIS (°C) ######################################################################################## - on_below_c: "0.5" # turn ON when temp <= setpoint - on_below_c - off_above_c: "0.3" # turn OFF when temp >= setpoint + off_above_c + on_below_c: "0.2" + off_above_c: "0.3" ######################################################################################## - # SETPOINT LIMITS FOR HA NUMBER (in C) + # SETPOINT LIMITS FOR HA NUMBER (°C) ######################################################################################## setpoint_min_c: "6.0" setpoint_max_c: "32.0" @@ -118,7 +162,6 @@ substitutions: ########################################################################################## # PACKAGES: Included Common Packages -# https://esphome.io/components/packages.html ########################################################################################## packages: common_wifi: !include @@ -126,19 +169,22 @@ 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 file: common/api_common.yaml vars: local_api_key: "${api_key}" - #common_webportal: !include - # file: common/webportal_common.yaml + common_mqtt: !include file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" + common_sntp: !include file: common/sntp_common.yaml + common_general_sensors: !include file: common/sensors_common.yaml vars: @@ -146,28 +192,26 @@ packages: local_update_interval: "${update_interval}" ########################################################################################## -# ESPHome -# https://esphome.io/components/esphome.html +# ESPHOME ########################################################################################## esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" area: "${device_area}" - # On boot: if heater is already powered, warm up then calibrate to level 1. - # This protects against unknown state after power outages. + on_boot: priority: -100 then: - script.execute: recompute_powered_state - lambda: |- - // Initialize min on/off timers according to current state if (id(powered_state).state) { if (id(last_on_ms) == 0) id(last_on_ms) = millis(); } else { if (id(last_off_ms) == 0) id(last_off_ms) = millis(); } - // Suppress level adjustments during boot warmup window + + id(last_temp_ms) = millis(); id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); - delay: ${warmup_seconds}s - if: @@ -176,149 +220,133 @@ esphome: then: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - logger.log: "Boot: heater already powered. Calibrating to level 1." - script.execute: calibrate_to_min else: - - logger.log: "Boot: heater already powered. Remote Control Only -> skipping calibration." - -# platformio_options: -# build_flags: -# - "-Os" -# - "-Wl,--gc-sections" -# - "-fno-exceptions" -# - "-fno-rtti" - - + - logger.log: "Boot: heater already powered. BYPASS (Remote Only) -> skipping calibration." ########################################################################################## -# ESP Platform and Framework -# https://esphome.io/components/esp32.html +# ESP PLATFORM ########################################################################################## esp8266: - board: esp01_1m # The original sonoff basic - restore_from_flash: true # restore some values on reboot + board: esp01_1m + restore_from_flash: true preferences: flash_write_interval: 5min mdns: - disabled: false # Disabling will make the build file smaller (and it is still available via static IP) + disabled: false ########################################################################################## -# Global Variables for use in automations etc -# https://esphome.io/guides/automations.html?highlight=globals#global-variables +# GLOBAL VARIABLES ########################################################################################## globals: - # Current flame level we believe the heater is at (1..7). Kept across reboots. - id: current_level type: int restore_value: yes initial_value: "1" - # Target flame level we want to reach (set by AUTO or manual selection). Not persisted. - id: desired_level type: int restore_value: no initial_value: "1" - # Timestamp (ms since boot) of the last level step (up/down). Used for rate limiting. - id: last_adjust_ms type: uint32_t restore_value: no initial_value: "0" - # Timestamp (ms) of the last calibration-to-min action. Used for periodic re-baseline. - id: last_recal_ms type: uint32_t restore_value: no initial_value: "0" - # Timestamp (ms) when powered_state last went ON. Used to enforce min_on_minutes. - id: last_on_ms type: uint32_t restore_value: no initial_value: "0" - # Timestamp (ms) when powered_state last went OFF. Used to enforce min_off_minutes. - id: last_off_ms type: uint32_t restore_value: no initial_value: "0" - # Local thermostat setpoint (°C). This is the authority; mirrored to MQTT with guard. - id: setpoint_c type: float restore_value: yes initial_value: "21.0" - # Guard to avoid MQTT echo: true while applying a setpoint that came from MQTT. - id: sp_suppress_mqtt type: bool restore_value: no initial_value: "false" - # Timestamp (ms) of last received room temperature via MQTT. Detects stale sensor. - id: last_temp_ms type: uint32_t restore_value: no initial_value: "0" - # Until this ms timestamp we suppress any level changes (post-ON warmup window). - id: warmup_until_ms type: uint32_t restore_value: no initial_value: "0" - # The level chosen on the previous AUTO tick. Used to confirm stable targets. - id: last_level_target type: int restore_value: no initial_value: "1" - # True if desired_level matched last_level_target on consecutive ticks. - id: target_confirmed type: bool restore_value: no initial_value: "true" - # End of the fast-ramp window (ms since boot). Allows faster stepping right after ON. - id: ramp_until_ms type: uint32_t restore_value: no initial_value: "0" - # True when we initiated power ON ourselves (not RF/panel). Helps skip duplicate actions. - id: self_power_on type: bool restore_value: no initial_value: "false" -########################################################################################## -# ESPHome Logging Enable -# https://esphome.io/components/logger.html + # Bench-test logical power state used only when Test Mode is enabled + - id: test_powered + type: bool + restore_value: no + initial_value: "false" + + # Bench-test room temperature used only when Test Mode is enabled + - id: test_temp_c + type: float + restore_value: yes + initial_value: "20.0" + + # True while a calibration sequence is actively stepping down to level 1 + - id: calibrating + type: bool + restore_value: no + initial_value: "false" + + # True when remote MQTT room temperature has gone stale in normal (non-test) mode + - id: room_temp_lost_fault + type: bool + restore_value: no + initial_value: "false" + +########################################################################################## +# ESPHOME LOGGING ENABLE ########################################################################################## logger: - level: "${log_level}" # INFO Level suggested, or DEBUG for testing - baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM, Serial control) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 + level: "${log_level}" + baud_rate: 0 ########################################################################################## # BINARY SENSORS -# https://esphome.io/components/binary_sensor/ -########################################################################################## -# GPIO MAP (PHYSICAL) -# -# INPUTS: -# GPIO4 -> RED Standby LED (binary_sensor.led_standby_red) -# GPIO5 -> BLUE Operating LED (binary_sensor.led_operating_blue) -# -# OUTPUTS (RELAY COILS - INTERNAL): -# GPIO12 -> ON/OFF button (switch.sw_power_raw) -# GPIO13 -> Flame UP button (switch.sw_up_raw) -# GPIO14 -> Flame DOWN button (switch.sw_down_raw) ########################################################################################## binary_sensor: - platform: gpio @@ -334,7 +362,6 @@ binary_sensor: - delayed_on_off: 50ms entity_category: diagnostic on_state: - - script.execute: publish_status - script.execute: recompute_powered_state - platform: gpio @@ -350,46 +377,37 @@ binary_sensor: - delayed_on_off: 50ms entity_category: diagnostic on_state: - - script.execute: publish_status - script.execute: recompute_powered_state - # Derived powered state (any LED on). Internal helper for min on/off timing. - # NOTE: No lambda or update_interval here — state is pushed by a script. - platform: template id: powered_state internal: true on_press: - lambda: |- id(last_on_ms) = millis(); - // If AUTO, enforce warmup lockout on RF/panel ON too - if (id(mode_select).state == "AUTO") { + if (!id(test_mode_enabled).state && id(mode_select).state == "AUTO") { id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); } - # If heater was powered ON externally (RF/panel) while in AUTO, baseline after warmup - if: condition: - lambda: 'return (id(mode_select).state == "AUTO") && (!id(self_power_on));' + lambda: 'return !id(test_mode_enabled).state && (id(mode_select).state == "AUTO") && (!id(self_power_on));' then: - lambda: |- - // Start fast-ramp window as well id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); - delay: ${warmup_seconds}s - script.execute: calibrate_to_min - script.execute: auto_control_tick - script.execute: adjust_to_desired + on_release: - lambda: |- id(last_off_ms) = millis(); - // Clear self-power flag on any OFF edge so the next RF ON is recognized id(self_power_on) = false; - ########################################################################################## # SWITCH COMPONENT -# https://esphome.io/components/switch/ ########################################################################################## switch: - # Raw coils (do not expose these) - platform: gpio id: sw_power_raw internal: true @@ -414,66 +432,129 @@ switch: number: GPIO14 inverted: ${relay_inverted} - # Power as a logical switch (we press ON/OFF only if a change is needed). + - platform: template + id: test_mode_enabled + name: "${friendly_name} Test Mode" + icon: mdi:test-tube + optimistic: true + restore_mode: ALWAYS_OFF + turn_on_action: + - lambda: |- + // Preserve current logical power state when entering Test Mode + id(test_powered) = id(powered_state).state; + id(room_temp_lost_fault) = false; + - select.set: + id: mode_select + option: "MANUAL" + - script.execute: recompute_powered_state + turn_off_action: + - lambda: |- + id(test_powered) = false; + - script.execute: recompute_powered_state + + # High-level thermostat enable helper. + # ON = thermostat logic active in AUTO + # OFF = force BYPASS and turn heater power OFF + - platform: template + id: heater_operation_switch + name: "Heater Operation" + icon: mdi:radiator + lambda: |- + return id(mode_select).state == "AUTO"; + + turn_on_action: + - select.set: + id: mode_select + option: "AUTO" + + turn_off_action: + - switch.turn_off: power_switch + - select.set: + id: mode_select + option: "BYPASS (Remote Only)" + - platform: template id: power_switch name: "${friendly_name} Power" icon: mdi:power lambda: |- - return (id(led_operating_blue).state || id(led_standby_red).state); + return id(powered_state).state; turn_on_action: - if: condition: - lambda: |- - return !(id(led_operating_blue).state || id(led_standby_red).state); + lambda: 'return id(mode_select).state == "BYPASS (Remote Only)" && !id(test_mode_enabled).state;' then: - - script.execute: press_power - - script.execute: after_power_on_reset_to_auto + - logger.log: "BYPASS (Remote Only): ignoring Power ON." + else: + - if: + condition: + lambda: |- + return !id(powered_state).state; + then: + - script.execute: press_power + - if: + condition: + lambda: 'return id(test_mode_enabled).state;' + then: + - lambda: |- + id(test_powered) = true; + - script.execute: recompute_powered_state + - script.execute: after_power_on_reset_to_auto + turn_off_action: - if: condition: - lambda: |- - return (id(led_operating_blue).state || id(led_standby_red).state); + lambda: 'return id(mode_select).state == "BYPASS (Remote Only)" && !id(test_mode_enabled).state;' then: - - script.execute: press_power + - logger.log: "BYPASS (Remote Only): ignoring Power OFF." + else: + - if: + condition: + lambda: |- + return id(powered_state).state; + then: + - script.execute: press_power + - if: + condition: + lambda: 'return id(test_mode_enabled).state;' + then: + - lambda: |- + id(test_powered) = false; + - script.execute: recompute_powered_state ########################################################################################## -# Sensors -# https://esphome.io/components/sensor/index.html +# SENSORS ########################################################################################## -# MQTT I/O (ROOM TEMP IN, SETPOINT IN/OUT, STATUS TEXT OUT) sensor: - platform: mqtt_subscribe id: room_temp name: "${friendly_name} Room Temperature (MQTT)" - topic: /viewroad-status/lounge-environment/temperature - unit_of_measurement: "C" + topic: "viewroad-status/lounge-environment/temperature" + unit_of_measurement: "°C" accuracy_decimals: 1 on_value: - lambda: |- id(last_temp_ms) = millis(); + id(room_temp_lost_fault) = false; float v = x; if (v < -10.0f) v = -10.0f; if (v > 50.0f) v = 50.0f; if (v != id(room_temp).state) id(room_temp).publish_state(v); - # Setpoint mirror from MQTT -> adopt into local number without echoing back - platform: mqtt_subscribe id: setpoint_from_mqtt internal: true - topic: /viewroad-status/lounge-environment/temp-setpoint - unit_of_measurement: "C" + topic: "viewroad-command/lounge-gasheater/setpoint" + unit_of_measurement: "°C" accuracy_decimals: 1 on_value: - lambda: |- - // Clamp to substitution-defined range float v = x; const float vmin = ${setpoint_min_c}; const float vmax = ${setpoint_max_c}; if (v < vmin) v = vmin; if (v > vmax) v = vmax; - // Guard: applying an MQTT-driven update -> do not re-publish id(sp_suppress_mqtt) = true; id(setpoint_c) = v; - number.set: @@ -482,10 +563,8 @@ sensor: - lambda: |- id(sp_suppress_mqtt) = false; - ########################################################################################## # TEXT SENSOR COMPONENT -# https://esphome.io/components/text_sensor/index.html ########################################################################################## text_sensor: - platform: template @@ -493,25 +572,103 @@ text_sensor: name: "${friendly_name} Status Text" update_interval: 1s lambda: |- - if (id(led_operating_blue).state) return std::string("Operating"); - if (id(led_standby_red).state) return std::string("Standby"); + const bool use_test_temp = id(test_mode_enabled).state; + const float effective_t = use_test_temp ? id(test_temp_c) : id(room_temp).state; + const float at_temp_threshold = id(setpoint_c) + ${off_above_c}; + const std::string mode = id(mode_select).state; + + if (!use_test_temp && id(room_temp_lost_fault)) { + return std::string("Fault (Room Temperature Lost)"); + } + + if (id(calibrating)) { + if (use_test_temp) return std::string("Calibrating (Test)"); + return std::string("Calibrating"); + } + + if (use_test_temp) { + if (mode == "MANUAL") { + if (id(powered_state).state) { + char buf[48]; + snprintf(buf, sizeof(buf), "Manual (Level %d) (Test)", id(current_level)); + return std::string(buf); + } + if (id(led_standby_red).state) return std::string("Manual (Standby) (Test)"); + return std::string("Manual (Off) (Test)"); + } + + if (id(powered_state).state) { + char buf[40]; + snprintf(buf, sizeof(buf), "Operating (Level %d) (Test)", id(current_level)); + return std::string(buf); + } + if (mode == "AUTO" && !isnan(effective_t) && effective_t >= at_temp_threshold) { + return std::string("At Temperature (Test)"); + } + return std::string("Off (Test)"); + } + + if (mode == "BYPASS (Remote Only)") { + if (id(led_operating_blue).state) return std::string("Remote Only (Operating)"); + if (id(led_standby_red).state) return std::string("Remote Only (Standby)"); + return std::string("Remote Only (Off)"); + } + + if (mode == "MANUAL") { + if (id(led_operating_blue).state) { + char buf[32]; + snprintf(buf, sizeof(buf), "Manual (Level %d)", id(current_level)); + return std::string(buf); + } + if (id(led_standby_red).state) return std::string("Manual (Standby)"); + return std::string("Manual (Off)"); + } + + if (id(led_operating_blue).state) { + char buf[32]; + snprintf(buf, sizeof(buf), "Operating (Level %d)", id(current_level)); + return std::string(buf); + } + if (!isnan(effective_t) && effective_t >= at_temp_threshold) { + return std::string("At Temperature"); + } + if (id(led_standby_red).state) return std::string("Standby"); return std::string("Off"); + on_value: + - script.execute: publish_status + + - platform: template + id: setpoint_text + name: "Setpoint Text" + icon: mdi:thermometer + update_interval: 1s + lambda: |- + char buf[16]; + snprintf(buf, sizeof(buf), "%.1f °C", id(setpoint_c)); + return std::string(buf); + + - platform: template + id: test_temperature_text + name: "${friendly_name} Test Mode Temp" + icon: mdi:thermometer-chevron-up + update_interval: 1s + lambda: |- + char buf[20]; + snprintf(buf, sizeof(buf), "%.1f °C", id(test_temp_c)); + return std::string(buf); ########################################################################################## # SELECT COMPONENT -# https://esphome.io/components/select/index.html ########################################################################################## select: - # AUTO or MANUAL (MANUAL is sticky until next power ON) - platform: template id: mode_select - name: "${friendly_name} Mode" - options: ["AUTO","MANUAL","Remote Control Only"] + name: "Mode" + options: ["AUTO","MANUAL","BYPASS (Remote Only)"] optimistic: true - initial_option: "AUTO" - restore_value: true + initial_option: "BYPASS (Remote Only)" + restore_value: false - # Flame level (1..7). Selecting forces MANUAL and adjusts to the chosen level. - platform: template id: flame_level_select name: "${friendly_name} Flame Level" @@ -519,7 +676,6 @@ select: optimistic: true restore_value: true set_action: - # If selection equals our known current level, ignore to avoid loops. - if: condition: lambda: |- @@ -530,9 +686,11 @@ select: else: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - - select.set: { id: mode_select, option: "MANUAL" } + - select.set: + id: mode_select + option: "MANUAL" - lambda: |- int target = atoi(x.c_str()); if (target < 1) target = 1; @@ -542,72 +700,112 @@ select: condition: lambda: 'return !id(powered_state).state;' then: - # Power on, respect warmup, calibrate to level 1, then adjust toward desired (still MANUAL) - script.execute: press_power - - lambda: |- - id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); - id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); // fast ramp window - - delay: ${warmup_seconds}s - - script.execute: calibrate_to_min - - script.execute: adjust_to_desired + - if: + condition: + lambda: 'return id(test_mode_enabled).state;' + then: + - lambda: |- + id(test_powered) = true; + - script.execute: recompute_powered_state + - if: + condition: + lambda: 'return !id(test_mode_enabled).state;' + then: + - lambda: |- + id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); + id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); + - delay: ${warmup_seconds}s + - script.execute: calibrate_to_min + - script.execute: adjust_to_desired + else: + - logger.log: "Test Mode active: logical power now ON." + - script.execute: adjust_to_desired else: - script.execute: adjust_to_desired else: - - logger.log: "Remote Control Only: ignoring Flame Level selection." + - logger.log: "BYPASS (Remote Only): ignoring Flame Level selection." - -################################################################################################# +########################################################################################## # BUTTON COMPONENT -# https://esphome.io/components/button/index.html -################################################################################################# +########################################################################################## button: - # Manual step buttons (each press forces MANUAL) - button up - platform: template id: btn_flame_up name: "${friendly_name} Flame Up (step)" on_press: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - - select.set: { id: mode_select, option: "MANUAL" } + - select.set: + id: mode_select + option: "MANUAL" - script.execute: step_up_once else: - - logger.log: "Remote Control Only: ignoring Flame Up (step)." + - logger.log: "BYPASS (Remote Only): ignoring Flame Up (step)." - # Manual step buttons (each press forces MANUAL) - button down - platform: template id: btn_flame_down name: "${friendly_name} Flame Down (step)" on_press: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - - select.set: { id: mode_select, option: "MANUAL" } + - select.set: + id: mode_select + option: "MANUAL" - script.execute: step_down_once else: - - logger.log: "Remote Control Only: ignoring Flame Down (step)." + - logger.log: "BYPASS (Remote Only): ignoring Flame Down (step)." - # Calibrate - platform: template id: btn_calibrate_min - name: "${friendly_name} Calibrate: Force Level 1 (7x down)" + name: "${friendly_name} Calibrate: Force Level 1 (6x down)" entity_category: config on_press: - script.execute: calibrate_to_min + - platform: template + id: btn_setpoint_up + name: "${friendly_name} Setpoint Up" + icon: mdi:plus + on_press: + - lambda: |- + const float step = ${setpoint_step_c}; + float v = id(setpoint_c) + step; + const float vmax = ${setpoint_max_c}; + if (v > vmax) v = vmax; + id(setpoint_c) = v; + - number.set: + id: setpoint_number + value: !lambda 'return id(setpoint_c);' -################################################################################################# + - platform: template + id: btn_setpoint_down + name: "${friendly_name} Setpoint Down" + icon: mdi:minus + on_press: + - lambda: |- + const float step = ${setpoint_step_c}; + float v = id(setpoint_c) - step; + const float vmin = ${setpoint_min_c}; + if (v < vmin) v = vmin; + id(setpoint_c) = v; + - number.set: + id: setpoint_number + value: !lambda 'return id(setpoint_c);' + +########################################################################################## # NUMBER COMPONENT -# https://esphome.io/components/number/ -################################################################################################# +########################################################################################## number: - # Setpoint number (primary authority). Two-way MQTT sync with loop guard. - platform: template id: setpoint_number name: "${friendly_name} Setpoint" icon: mdi:thermometer + unit_of_measurement: "°C" min_value: ${setpoint_min_c} max_value: ${setpoint_max_c} step: ${setpoint_step_c} @@ -615,29 +813,41 @@ number: lambda: |- return id(setpoint_c); set_action: - # 1) adopt the new value locally - lambda: |- id(setpoint_c) = x; - # 2) unless we are processing an incoming MQTT update, publish out - if: condition: lambda: |- return !id(sp_suppress_mqtt); then: - mqtt.publish: - topic: /viewroad-status/lounge-environment/temp-setpoint + topic: "viewroad-status/lounge-gasheater/setpoint" retain: true payload: !lambda |- char buf[16]; snprintf(buf, sizeof(buf), "%.1f", x); return std::string(buf); + # Bench-test room temperature slider used by AUTO whenever Test Mode is ON. + - platform: template + id: test_temperature_value + name: "${friendly_name} Test Temperature Value" + icon: mdi:thermometer-chevron-up + unit_of_measurement: "°C" + min_value: -10.0 + max_value: 40.0 + step: 0.1 + mode: slider + lambda: |- + return id(test_temp_c); + set_action: + - lambda: |- + id(test_temp_c) = x; + ########################################################################################## # INTERVAL COMPONENT -# https://esphome.io/components/interval/ ########################################################################################## interval: - # AUTO loop tick (only when AUTO is enabled) - interval: ${control_interval_s}s then: - if: @@ -646,30 +856,35 @@ interval: then: - script.execute: auto_control_tick - -################################################################################################# +########################################################################################## # SCRIPT COMPONENT -# https://esphome.io/components/script.html -################################################################################################# +########################################################################################## script: - # Publish textual status to MQTT + # Mirror the already-computed Status Text entity out to MQTT. + # This keeps the HA text entity and MQTT status using the same source of truth. - id: publish_status mode: restart then: - mqtt.publish: - topic: /viewroad-status/gasfire + topic: "viewroad-status/lounge-gasheater" payload: !lambda |- - if (id(led_operating_blue).state) return std::string("Operating"); - if (id(led_standby_red).state) return std::string("Standby"); - return std::string("Off"); + if (id(status_text).state.size() == 0) return std::string("Unknown"); + return id(status_text).state; - id: recompute_powered_state then: - lambda: |- - const bool new_state = id(led_operating_blue).state || id(led_standby_red).state; - id(powered_state).publish_state(new_state); + const bool led_powered = + id(led_operating_blue).state || id(led_standby_red).state; - # Low-level press with enforced pulse and gap + const bool new_state = + id(test_mode_enabled).state ? id(test_powered) : led_powered; + + id(powered_state).publish_state(new_state); + - script.execute: publish_status + + # Low-level relay click helper. + # Handles the button press pulse and enforces a minimum gap between clicks. - id: press_with_gap mode: queued parameters: @@ -696,44 +911,49 @@ script: - switch.turn_off: sw_down_raw - delay: ${min_click_gap_ms}ms - - id: press_power then: - lambda: |- id(self_power_on) = true; - - script.execute: { id: press_with_gap, which: "power" } - + - script.execute: + id: press_with_gap + which: "power" - id: press_up then: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - - script.execute: { id: press_with_gap, which: "up" } + - script.execute: + id: press_with_gap + which: "up" else: - - logger.log: "Remote Control Only: ignoring UP press." + - logger.log: "BYPASS (Remote Only): ignoring UP press." - id: press_down then: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - - script.execute: { id: press_with_gap, which: "down" } + - script.execute: + id: press_with_gap + which: "down" else: - - logger.log: "Remote Control Only: ignoring DOWN press." + - logger.log: "BYPASS (Remote Only): ignoring DOWN press." - # Single-step level adjusters (track current_level and update the select) + # Step one flame level UP and only update the visible level after the relay click finishes. - id: step_up_once then: - if: condition: lambda: 'return id(powered_state).state;' then: + - script.execute: press_up + - script.wait: press_with_gap - lambda: |- if (id(current_level) < 7) id(current_level)++; - - script.execute: press_up - select.set: id: flame_level_select option: !lambda 'return std::to_string(id(current_level));' @@ -742,15 +962,17 @@ script: else: - logger.log: "Heater is OFF; ignoring manual step up." + # Step one flame level DOWN and only update the visible level after the relay click finishes. - id: step_down_once then: - if: condition: lambda: 'return id(powered_state).state;' then: + - script.execute: press_down + - script.wait: press_with_gap - lambda: |- if (id(current_level) > 1) id(current_level)--; - - script.execute: press_down - select.set: id: flame_level_select option: !lambda 'return std::to_string(id(current_level));' @@ -759,34 +981,40 @@ script: else: - logger.log: "Heater is OFF; ignoring manual step down." - - # Force level 1 certainty (7x DOWN) - skipped in Remote Control Only and if OFF + # Force a visible re-baseline to flame level 1. + # Six DOWN clicks guarantee that even from level 7 we end at level 1. - id: calibrate_to_min then: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only" && id(powered_state).state;' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)" && id(powered_state).state;' then: - - repeat: - count: 7 - then: - - script.execute: press_down - lambda: |- - id(current_level) = 1; + id(calibrating) = true; + - script.execute: publish_status + - repeat: + count: 6 + then: + - script.execute: step_down_once + - script.wait: step_down_once + - lambda: |- id(last_recal_ms) = millis(); + id(calibrating) = false; - select.set: id: flame_level_select option: "1" + - script.execute: publish_status else: - - logger.log: "Skipping calibration (Remote Control Only or heater OFF)." + - logger.log: "Skipping calibration (BYPASS or heater OFF)." - # Move smoothly toward desired_level (rate-limited) + # Moves one step at a time toward desired_level. + # In Test Mode, target confirmation is bypassed so bench testing feels responsive. - id: adjust_to_desired mode: queued then: - if: condition: - lambda: 'return millis() < id(warmup_until_ms);' + lambda: 'return millis() < id(warmup_until_ms) && !id(test_mode_enabled).state;' then: - logger.log: format: "Warmup: suppressing level change." @@ -795,7 +1023,6 @@ script: - if: condition: lambda: |- - // Faster stepping during ramp window, normal otherwise const uint32_t step_ms = (millis() < id(ramp_until_ms)) ? (${fast_ramp_step_s} * 1000UL) : (${adjust_step_interval_s} * 1000UL); @@ -809,10 +1036,9 @@ script: format: "Heater is OFF; not adjusting level." level: DEBUG else: - # Proceed if target is confirmed OR we are still in the ramp window - if: condition: - lambda: 'return id(target_confirmed) || (millis() < id(ramp_until_ms));' + lambda: 'return id(test_mode_enabled).state || id(target_confirmed) || (millis() < id(ramp_until_ms));' then: - if: condition: @@ -826,51 +1052,78 @@ script: then: - script.execute: step_down_once - + # Called after a successful power ON request. + # Handles warmup, optional calibration, and initial AUTO control startup. - id: after_power_on_reset_to_auto then: - if: condition: - lambda: 'return id(mode_select).state != "Remote Control Only";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - - lambda: |- - // Suppress level adjustments during post-power-on warmup - id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); - // Enable a short fast-ramp window for quicker heat-up - id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); - - select.set: { id: mode_select, option: "AUTO" } - - delay: ${warmup_seconds}s - - script.execute: calibrate_to_min - # Immediately compute a level and move toward it (no extra 30s wait) - - script.execute: auto_control_tick - - script.execute: adjust_to_desired - - lambda: |- - // Done with our own ON sequence - id(self_power_on) = false; + - if: + condition: + lambda: 'return id(test_mode_enabled).state;' + then: + - if: + condition: + lambda: 'return id(mode_select).state == "AUTO";' + then: + - lambda: |- + id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); + id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); + - delay: ${warmup_seconds}s + - script.execute: calibrate_to_min + - script.execute: auto_control_tick + - script.execute: adjust_to_desired + - lambda: |- + id(self_power_on) = false; + else: + - lambda: |- + id(self_power_on) = false; + - logger.log: "Test Mode active: staying in MANUAL; no AUTO startup actions." + else: + - lambda: |- + id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); + id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); + - select.set: + id: mode_select + option: "AUTO" + - delay: ${warmup_seconds}s + - script.execute: calibrate_to_min + - script.execute: auto_control_tick + - script.execute: adjust_to_desired + - lambda: |- + id(self_power_on) = false; else: - - logger.log: "Remote Control Only: keeping mode; no auto-calibrate." + - lambda: |- + id(self_power_on) = false; + - logger.log: "BYPASS (Remote Only): keeping mode; no auto-calibrate." - - # AUTO thermostat logic (hysteresis + level mapping) + # Main thermostat logic. + # Uses test_temp_c whenever Test Mode is enabled, otherwise uses MQTT room_temp. - id: auto_control_tick mode: queued then: - lambda: |- - const float t = id(room_temp).state; + const bool use_test_temp = id(test_mode_enabled).state; + const float t = use_test_temp ? id(test_temp_c) : id(room_temp).state; const float sp = id(setpoint_c); const uint32_t now_ms = millis(); - // Fail-safe: if temperature is missing (NAN), optionally turn OFF after timeout. - if (isnan(t)) { - const bool powered = id(powered_state).state; - const bool stale = (id(last_temp_ms) > 0) && - ((now_ms - id(last_temp_ms)) >= (${temp_stale_timeout_min} * 60000UL)); - if (powered && stale) { - ESP_LOGW("gas", "AUTO: temperature stale -> turning OFF as fail-safe"); - id(press_power).execute(); - } else { - ESP_LOGW("gas", "AUTO: temperature missing; skipping control tick"); + if (!use_test_temp) { + const bool temp_lost = (id(last_temp_ms) > 0) && + ((now_ms - id(last_temp_ms)) >= (${temp_stale_timeout_min} * 60000UL)); + id(room_temp_lost_fault) = temp_lost; + if (temp_lost) { + ESP_LOGW("gas", "AUTO: room temperature lost; skipping control tick"); + return; } + } else { + id(room_temp_lost_fault) = false; + } + + if (isnan(t)) { + ESP_LOGW("gas", "AUTO: temperature missing; skipping control tick"); return; } @@ -883,34 +1136,42 @@ script: const float low = sp - ${on_below_c}; const float high = sp + ${off_above_c}; - // Honour minimum on/off durations const bool can_turn_on = (!powered) && ((${min_off_minutes} == 0) || ((now_ms - id(last_off_ms)) >= (${min_off_minutes} * 60000UL))); const bool can_turn_off = ( powered) && ((${min_on_minutes} == 0) || ((now_ms - id(last_on_ms)) >= (${min_on_minutes} * 60000UL))); - // Hysteresis-based ON/OFF if (t <= low && can_turn_on) { ESP_LOGI("gas", "AUTO: below setpoint -> ON"); id(press_power).execute(); + if (id(test_mode_enabled).state) { + id(test_powered) = true; + id(powered_state).publish_state(true); + id(publish_status).execute(); + } id(after_power_on_reset_to_auto).execute(); return; } + if (t >= high && can_turn_off) { ESP_LOGI("gas", "AUTO: above setpoint -> OFF"); id(press_power).execute(); + if (id(test_mode_enabled).state) { + id(test_powered) = false; + id(powered_state).publish_state(false); + id(publish_status).execute(); + } return; } - // Map error to desired flame level when powered. - // Always set desired_level; use target_confirmed to gate normal (non-ramp) steps. if (powered) { - float diff = sp - t; // positive => need more heat + float diff = sp - t; int target = 1; + if (diff > 3.0f) target = 7; - else if (diff > 2.0f) target = 6; - else if (diff > 1.5f) target = 5; - else if (diff > 1.0f) target = 4; - else if (diff > 0.6f) target = 3; - else if (diff > 0.2f) target = 2; + else if (diff > 2.5f) target = 6; + else if (diff > 2.0f) target = 5; + else if (diff > 1.5f) target = 4; + else if (diff > 1.0f) target = 3; + else if (diff > 0.5f) target = 2; else target = 1; id(desired_level) = target; @@ -918,7 +1179,6 @@ script: id(last_level_target) = target; } - - if: condition: lambda: 'return id(powered_state).state;' @@ -929,8 +1189,6 @@ script: return (id(desired_level) == 1) && ((millis() - id(last_recal_ms)) >= (${recalibrate_interval_min} * 60000UL)); then: - - logger.log: "Re-baseline at level 1 (7x DOWN)." + - logger.log: "Re-baseline at level 1 (6x DOWN)." - script.execute: calibrate_to_min - - script.execute: adjust_to_desired - - + - script.execute: adjust_to_desired \ No newline at end of file diff --git a/esphome/esp-laundrydrypow.yaml b/esphome/esp-laundrydrypow.yaml index 461dfbb..09dfe5f 100644 --- a/esphome/esp-laundrydrypow.yaml +++ b/esphome/esp-laundrydrypow.yaml @@ -1,39 +1,82 @@ -############################################# -############################################# -# LAUNDRY DRYER MACHINE POWER +#:########################################################################################:# +# TITLE: LAUNDRY DRYER MACHINE POWER +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-laundrydrypow.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V1.0 2025-05-28 Initial Version -############################################# -# Sonoff POW R1 -# https://devices.esphome.io/devices/Sonoff-POW-R1 +#:########################################################################################:# +# HARDWARE: +# - Sonoff POW R1 +# - ESP8266 based +# - HLW8012 power monitoring +# - Single relay output +# - Blue status LED on GPIO15 +# - Local push button on GPIO0 +# - Relay output on GPIO12 +# - Reference: https://devices.esphome.io/devices/Sonoff-POW-R1 +#:########################################################################################:# +# OPERATION NOTES: +# - Monitors dryer load current, voltage, and power +# - Provides a virtual relay switch that controls the physical relay and LED together +# - Local button toggles the virtual relay switch +# - On boot, the virtual relay is turned ON +# - "Load Running" turns ON when measured power is above 4 W +# - "Load Running" uses delayed_off: 15s to avoid rapid state changes +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Device continues running normally +# - Local button still works +# - MQTT remains available if your common MQTT package is enabled and broker is reachable # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - Device continues running locally +# - Local button, relay control, LED control, and power monitoring still work # -############################################# -############################################# +# c) Entire WiFi/Network offline: +# - Device continues running locally +# - Local button, relay control, LED control, and power monitoring still work +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -############################################# -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -############################################# +#:########################################################################################:# substitutions: - device_name: "esp-laundrydrypow" # Reference name for the device in the system. - project_name: "Sonoff Technologies.POW R1" # Project Details - project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - entity_prefix: "Load" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + # Device Naming + device_name: "esp-laundrydrypow" friendly_name: "Laundry Dryer Power" - description_comment: "Laundry Dryer Power using a Sonoff Pow R1." - device_area: "Laundry" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - api_key: !secret esp-laundrydrypow_api_key # unfortunately you can't use substitutions inside secrets names - ota_pass: !secret esp-laundrydrypow_ota_pass # unfortunately you can't use substitutions inside secrets names - static_ip_address: !secret esp-laundrydrypow_ip - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + description_comment: "Laundry Dryer Power using a Sonoff Pow R1. (Layout V1.1)" + device_area: "Laundry" -########################################################################################## -# PACKAGES: Included Common Packages + # Project Naming + project_name: "Sonoff Technologies.POW R1" + project_version: "v1.1" + + # Entity Naming + entity_prefix: "Load" + + # Passwords and Secrets + api_key: !secret esp-laundrydrypow_api_key + ota_pass: !secret esp-laundrydrypow_ota_pass + static_ip_address: !secret esp-laundrydrypow_ip + current_ip_address: ${static_ip_address} + + # Device Settings + log_level: "INFO" + update_interval: "60s" + +#:########################################################################################:# +# PACKAGES: +# Included common packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -41,12 +84,13 @@ 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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include file: common/api_common.yaml - #file: common/api_common_noencryption.yaml + # file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" @@ -55,137 +99,154 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### - #common_webportal: !include common/webportal_common.yaml + # common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + # common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + # diag_debug: !include common/include_debug_diag_sensors.yaml + # diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -############################################# -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -############################################# +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" area: "${device_area}" project: name: "${project_name}" version: "${project_version}" - on_boot: + on_boot: priority: 200 then: - - switch.turn_on: "virtual_button" + - switch.turn_on: virtual_button -############################################# -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -############################################# +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. - board_flash_mode: dout # Default is dout + early_pin_init: false + board_flash_mode: dout -############################################# -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: ${log_level} #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 + level: "${log_level}" + # baud_rate: 0 + # esp8266_store_log_strings_in_flash: false + # tx_buffer_size: 64 -############################################# -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -############################################# -#status_led: -# pin: -# number: GPIO2 -# inverted: yes +#:########################################################################################:# +# status_led: +# pin: +# number: GPIO2 +# inverted: true -############################################# -# SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -############################################# +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT_PULLUP - inverted: True - name: Button + inverted: true + name: "Button" on_press: - switch.toggle: virtual_button + - platform: template - name: ${entity_prefix} Running + name: "${entity_prefix} Running" filters: - delayed_off: 15s lambda: |- if (isnan(id(power).state)) { return {}; } else if (id(power).state > 4) { - // Running return true; } else { - // Not running return false; } +#:########################################################################################:# +# SENSORS: +# https://esphome.io/components/sensor/ +#:########################################################################################:# sensor: - platform: hlw8012 - sel_pin: 5 - cf_pin: 14 - cf1_pin: 13 + sel_pin: GPIO5 + cf_pin: GPIO14 + cf1_pin: GPIO13 update_interval: 2s current: - name: ${entity_prefix} Current + name: "${entity_prefix} Current" voltage: - name: ${entity_prefix} Voltage + name: "${entity_prefix} Voltage" power: - name: ${entity_prefix} Power + name: "${entity_prefix} Power" id: power - #on_value_range: - # - above: 4.0 - # then: - # - light.turn_on: led - # - below: 3.0 - # then: - # - light.turn_off: led + # on_value_range: + # - above: 4.0 + # then: + # - light.turn_on: led + # - below: 3.0 + # then: + # - light.turn_off: led +#:########################################################################################:# +# SWITCH: +# https://esphome.io/components/switch/ +#:########################################################################################:# switch: - platform: template name: "Relay" - optimistic: true id: virtual_button + optimistic: true turn_on_action: - switch.turn_on: relay - light.turn_on: led turn_off_action: - switch.turn_off: relay - light.turn_off: led + - platform: gpio id: relay pin: GPIO12 - #restore_mode: ALWAYS_ON # Or RESTORE_DEFAULT_ON/RESTORE_DEFAULT_OFF + # restore_mode: ALWAYS_ON +#:########################################################################################:# +# OUTPUT: +# https://esphome.io/components/output/ +#:########################################################################################:# output: - platform: esp8266_pwm id: pow_blue_led pin: number: GPIO15 - inverted: True + inverted: true +#:########################################################################################:# +# LIGHT: +# https://esphome.io/components/light/ +#:########################################################################################:# light: - platform: monochromatic - name: Status LED + name: "Status LED" output: pow_blue_led id: led \ No newline at end of file diff --git a/esphome/esp-laundryenv.yaml b/esphome/esp-laundryenv.yaml index b2c2045..47cc503 100644 --- a/esphome/esp-laundryenv.yaml +++ b/esphome/esp-laundryenv.yaml @@ -1,39 +1,78 @@ -############################################# -############################################# -# LAUNDRY ENVIRONMENT - SONOFF DEV +#:########################################################################################:# +# TITLE: LAUNDRY ENVIRONMENT - SONOFF DEV +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-laundryenv.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V1.0 2025-03-28 Initial Version -############################################# -# Sonoff Dev -# https://wiki.iteadstudio.com/Sonoff_DEV +#:########################################################################################:# +# HARDWARE: +# - Sonoff DEV +# - ESP8266 based +# - DHT temperature and humidity sensor on GPIO14 +# - PIR input on GPIO13 +# - Smoke detector input on GPIO5 +# - Reference: https://wiki.iteadstudio.com/Sonoff_DEV +#:########################################################################################:# +# OPERATION NOTES: +# - Provides laundry temperature and humidity monitoring +# - Provides a PIR motion binary sensor +# - Provides a smoke detector binary sensor +# - Designed as a simple environmental and safety monitoring node +# - No relay or timed control logic is used in this yaml +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Device continues to read and publish local sensor states +# - PIR, smoke, temperature, and humidity sensing continue locally # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - Device continues sampling sensors locally +# - No MQTT-based status publishing will be available # -############################################# -############################################# +# c) Entire WiFi/Network offline: +# - Device continues sampling sensors locally +# - No HA or MQTT connectivity will be available +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -############################################# -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -############################################# +#:########################################################################################:# substitutions: - device_name: "esp-laundryenv" # Reference name for the device in the system. - project_name: "Sonoff Technologies.Sonoff DEV" # Project Details - project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - entity_prefix: "Laundry" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + # Device Naming + device_name: "esp-laundryenv" friendly_name: "Laundry Environment" - description_comment: "Laundry Environment Sensor, PIR and Smoke Detector using Sonoff DEV" - device_area: "Laundry" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - api_key: !secret esp-laundryenv_api_key # unfortunately you can't use substitutions inside secrets names - ota_pass: !secret esp-laundryenv_ota_pass # unfortunately you can't use substitutions inside secrets names - static_ip_address: !secret esp-laundryenv_ip - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + description_comment: "Laundry Environment Sensor, PIR and Smoke Detector using Sonoff DEV (Layout V1.1)" + device_area: "Laundry" -########################################################################################## -# PACKAGES: Included Common Packages + # Project Naming + project_name: "Sonoff Technologies.Sonoff DEV" + project_version: "v1.1" + + # Entity Naming + entity_prefix: "Laundry" + + # Passwords and Secrets + api_key: !secret esp-laundryenv_api_key + ota_pass: !secret esp-laundryenv_ota_pass + static_ip_address: !secret esp-laundryenv_ip + current_ip_address: ${static_ip_address} + + # Device Settings + log_level: "INFO" + update_interval: "60s" + +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -41,6 +80,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -55,63 +95,68 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -############################################# -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -############################################# +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" area: "${device_area}" project: name: "${project_name}" version: "${project_version}" -############################################# -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -############################################# +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. - board_flash_mode: dout # Default is dout + early_pin_init: false + board_flash_mode: dout -############################################# -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: ${log_level} #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + level: "${log_level}" + #baud_rate: 0 #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -############################################# -# SENSORS -# https://esphome.io/components/binary_sensor/ -############################################# +#:########################################################################################:# +# SENSORS: +# https://esphome.io/components/sensor/ +#:########################################################################################:# sensor: - platform: dht pin: GPIO14 temperature: - name: ${entity_prefix} Temperature + name: "${entity_prefix} Temperature" humidity: - name: ${entity_prefix} Humidity - update_interval: ${update_interval} + name: "${entity_prefix} Humidity" + update_interval: "${update_interval}" +#:########################################################################################:# +# BINARY SENSORS: +# https://esphome.io/components/binary_sensor/ +#:########################################################################################:# binary_sensor: - platform: gpio pin: @@ -119,19 +164,16 @@ binary_sensor: mode: input: true pullup: false - name: ${entity_prefix} PIR + name: "${entity_prefix} PIR" device_class: motion #filters: - # - invert: + # - invert: - platform: gpio pin: - number: GPIO05 + number: GPIO5 mode: input: true pullup: true - inverted: True - name: ${entity_prefix} Smoke Detector - - - + inverted: true + name: "${entity_prefix} Smoke Detector" \ No newline at end of file diff --git a/esphome/esp-laundrylights.yaml b/esphome/esp-laundrylights.yaml index 39d332a..467247a 100644 --- a/esphome/esp-laundrylights.yaml +++ b/esphome/esp-laundrylights.yaml @@ -1,39 +1,90 @@ -########################################################################################## -########################################################################################## -# LAUNDRY MAIN LIGHTSWITCH +#:########################################################################################:# +# TITLE: LAUNDRY MAIN LIGHTSWITCH +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-laundrylights.yaml +#:########################################################################################:# +# VERSIONS: +# V3.6 2026-03-11 Updated yaml to zorruno layout V1.1 # V3.5 2025-07-24 YAML tidyups # V3.0 2025-06-05 YAML tidyups # V2.0 2025-06-01 Was initially a 3 button switch, now 2 # V1.0 2025-05-30 Initial Version -########################################################################################## -# Zemismart KS-811 Double push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Double push button +# - ESP8266 based +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# - Relay 1 output on GPIO13 +# - Relay 2 output on GPIO12 +# - Button 1 input on GPIO16 +# - Button 2 input on GPIO5 +# - Status LED on GPIO2 +#:########################################################################################:# +# OPERATION NOTES: +# - Button 1 toggles Relay 1 for the laundry lights +# - Button 2 supports two actions: +# - Single click toggles Relay 2 locally +# - Hold for 2 seconds or more sends MQTT ON/OFF to the remote device +# - Relay 2 is turned ON at boot +# - Remote MQTT status is subscribed to and normalised to ON/OFF/TRUE/FALSE/1/0 +# - If the remote state is unknown, a hold on Button 2 defaults to sending ON +# - This switch is used for: +# - Laundry Lights (1) +# - Laundry Power Enable (2) +#:########################################################################################:# +# MQTT COMMANDS: +# - Remote device command topic: +# - ${mqtt_remote1_command_topic} +# - Remote device status topic: +# - ${mqtt_remote1_status_topic} +# - Hold Button 2: +# - Sends OFF if remote state is known and currently ON +# - Sends ON otherwise +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Local buttons and local relays continue to work +# - Remote MQTT control/status for Button 2 hold still works if the MQTT broker is online # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - Local buttons and local relays continue to work +# - Button 2 single click still toggles Relay 2 locally +# - Button 2 hold cannot control the remote MQTT device # -########################################################################################## -########################################################################################## +# c) Entire WiFi/Network offline: +# - Local buttons and local relays continue to work +# - Remote MQTT control/status is unavailable +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-laundrylights" friendly_name: "Laundry Main Lightswitch (2)" - description_comment: "Laundry Main Lightswitch using a Zemismart KS-811 Double Push Button. Laundry Lights (1), Laundry Power Signal (2)" - device_area: "Laundry" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Laundry Main Lightswitch using a Zemismart KS-811 Double Push Button. Laundry Lights (1), Laundry Power Signal (2) (Layout V1.1)" + device_area: "Laundry" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Zemismart Technologies.KS-811 Double" # Project Details - project_version: "v3.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Zemismart Technologies.KS-811 Double" # Project Details + project_version: "v3.6" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-laundrylights_ip + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + mqtt_command_main_topic: !secret mqtt_command_main_topic mqtt_status_main_topic: !secret mqtt_status_main_topic @@ -49,14 +100,15 @@ substitutions: # Switch Naming switch_1_name: "Laundry Lights" - switch_2_name: "Laundry Power Enable" # This is virtual only, no power connected to 3rd relay - #switch_3_name: "Fan 3 Relay" - #switch_4_name: "Fan 4 Relay" + switch_2_name: "Laundry Power Enable" # This is virtual only, no power connected to 3rd relay + #switch_3_name: "Fan 3 Relay" + #switch_4_name: "Fan 4 Relay" -######################################################################################### -# PACKAGES: Included Common Packages +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -64,6 +116,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -78,22 +131,23 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -102,70 +156,70 @@ esphome: project: name: "${project_name}" version: "${project_version}" - on_boot: + on_boot: priority: 200 then: - switch.turn_on: Relay_2 -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: level: "${log_level}" #INFO Level suggested, or DEBUG for testing #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -######################################################################################### -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: number: GPIO2 - inverted: yes + inverted: true -######################################################################################### -# GLOBAL VARIABLES -# -######################################################################################### +#:########################################################################################:# +# GLOBAL VARIABLES: +#:########################################################################################:# globals: - id: remote1_state type: bool - restore_value: no - initial_value: 'false' + restore_value: false + initial_value: "false" + - id: remote1_known type: bool - restore_value: no - initial_value: 'false' + restore_value: false + initial_value: "false" -######################################################################################### -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO16 mode: INPUT - inverted: True + inverted: true name: "Button 1: ${switch_1_name}" on_press: - switch.toggle: Relay_1 - platform: gpio pin: - number: GPIO05 + number: GPIO5 mode: INPUT inverted: true name: "Button 2: ${switch_2_name}" @@ -177,18 +231,21 @@ binary_sensor: then: - if: condition: - lambda: 'return id(Relay_2).state;' + lambda: |- + return id(Relay_2).state; then: - switch.turn_off: Relay_2 else: - switch.turn_on: Relay_2 + # HOLD: pressed for 2s or more -> toggle remote; default to ON if unknown - timing: - ON for at least 2s then: - if: condition: - lambda: 'return id(remote1_known) && id(remote1_state);' # known AND currently ON + lambda: |- + return id(remote1_known) && id(remote1_state); // known AND currently ON then: - mqtt.publish: topic: "${mqtt_remote1_command_topic}" @@ -200,10 +257,9 @@ binary_sensor: payload: "ON" retain: false -######################################################################################### -# TEXT SENSORS -# -######################################################################################### +#:########################################################################################:# +# TEXT SENSORS: +#:########################################################################################:# text_sensor: - platform: mqtt_subscribe id: remote1_status @@ -214,11 +270,13 @@ text_sensor: - lambda: |- // copy, trim whitespace, uppercase std::string s = x; + // trim leading/trailing whitespace - auto notspace = [](int ch){ return !std::isspace(ch); }; + auto notspace = [](int ch) { return !std::isspace(ch); }; s.erase(s.begin(), std::find_if(s.begin(), s.end(), notspace)); s.erase(std::find_if(s.rbegin(), s.rend(), notspace).base(), s.end()); - for (auto &c : s) c = (char)toupper(c); + + for (auto &c : s) c = (char) toupper(c); bool recognized = false; if (s == "ON" || s == "1" || s == "TRUE") { @@ -233,15 +291,16 @@ text_sensor: // unknown payload (e.g. "ONLINE", "OFFLINE", JSON, etc.) id(remote1_known) = false; } + ESP_LOGI("remote1_status", "Parsed status='%s' -> known=%s state=%s", s.c_str(), id(remote1_known) ? "true" : "false", id(remote1_state) ? "ON" : "OFF"); -######################################################################################### -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: - platform: gpio name: "Relay 1: ${switch_1_name}" @@ -251,7 +310,4 @@ switch: - platform: gpio name: "Relay 2: ${switch_2_name}" pin: GPIO12 - id: Relay_2 - - - + id: Relay_2 \ No newline at end of file diff --git a/esphome/esp-laundryplugpow.yaml b/esphome/esp-laundryplugpow.yaml index d67304b..ad994fb 100644 --- a/esphome/esp-laundryplugpow.yaml +++ b/esphome/esp-laundryplugpow.yaml @@ -1,39 +1,82 @@ -############################################# -############################################# -# LAUNDRY BENCH PLUGS POWER AND SWITCH +#:########################################################################################:# +# TITLE: LAUNDRY BENCH PLUGS POWER AND SWITCH +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-laundryplugpow.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V1.0 2025-03-28 Initial Version -############################################# -# Sonoff POW R1 -# https://devices.esphome.io/devices/Sonoff-POW-R1 +#:########################################################################################:# +# HARDWARE: +# - Sonoff POW R1 +# - ESP8266 based +# - HLW8012 power monitoring +# - Single relay output +# - Blue status LED on GPIO15 +# - Local push button on GPIO0 +# - Relay output on GPIO12 +# - Reference: https://devices.esphome.io/devices/Sonoff-POW-R1 +#:########################################################################################:# +# OPERATION NOTES: +# - Monitors plug load current, voltage, and power +# - Provides a virtual relay switch that controls the physical relay and LED together +# - Local button toggles the virtual relay switch +# - On boot, the virtual relay is turned ON +# - "Load Running" turns ON when measured power is above 4 W +# - "Load Running" uses delayed_off: 15s to avoid rapid state changes +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Device continues running normally +# - Local button still works +# - MQTT remains available if your common MQTT package is enabled and broker is reachable # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - Device continues running locally +# - Local button, relay control, LED control, and power monitoring still work # -############################################# -############################################# +# c) Entire WiFi/Network offline: +# - Device continues running locally +# - Local button, relay control, LED control, and power monitoring still work +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -############################################# -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -############################################# +#:########################################################################################:# substitutions: - device_name: "esp-laundryplugpow" # Reference name for the device in the system. - project_name: "Sonoff Technologies.POW R1" # Project Details - project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - entity_prefix: "Load" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + # Device Naming + device_name: "esp-laundryplugpow" friendly_name: "Laundry Bench Plug Power" - description_comment: "Laundry Bench Plug Power and switch override using a Sonoff Pow R1." - device_area: "Laundry" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - api_key: !secret esp-laundryplugpow_api_key # unfortunately you can't use substitutions inside secrets names - ota_pass: !secret esp-laundryplugpow_ota_pass # unfortunately you can't use substitutions inside secrets names - static_ip_address: !secret esp-laundryplugpow_ip - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + description_comment: "Laundry Bench Plug Power and switch override using a Sonoff Pow R1. (Layout V1.1)" + device_area: "Laundry" -########################################################################################## -# PACKAGES: Included Common Packages + # Project Naming + project_name: "Sonoff Technologies.POW R1" + project_version: "v1.1" + + # Entity Naming + entity_prefix: "Load" + + # Passwords and Secrets + api_key: !secret esp-laundryplugpow_api_key + ota_pass: !secret esp-laundryplugpow_ota_pass + static_ip_address: !secret esp-laundryplugpow_ip + current_ip_address: ${static_ip_address} + + # Device Settings + log_level: "INFO" + update_interval: "60s" + +#:########################################################################################:# +# PACKAGES: +# Included common packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -41,12 +84,13 @@ 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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include file: common/api_common.yaml - #file: common/api_common_noencryption.yaml + # file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" @@ -55,137 +99,154 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### - #common_webportal: !include common/webportal_common.yaml + # common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + # common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + # diag_debug: !include common/include_debug_diag_sensors.yaml + # diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -############################################# -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -############################################# +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" area: "${device_area}" project: name: "${project_name}" version: "${project_version}" - on_boot: + on_boot: priority: 200 then: - - switch.turn_on: "virtual_button" + - switch.turn_on: virtual_button -############################################# -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -############################################# +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. - board_flash_mode: dout # Default is dout + early_pin_init: false + board_flash_mode: dout -############################################# -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: ${log_level} #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 + level: "${log_level}" + # baud_rate: 0 + # esp8266_store_log_strings_in_flash: false + # tx_buffer_size: 64 -############################################# -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -############################################# -#status_led: -# pin: -# number: GPIO2 -# inverted: yes +#:########################################################################################:# +# status_led: +# pin: +# number: GPIO2 +# inverted: true -############################################# -# SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -############################################# +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT_PULLUP - inverted: True - name: Button + inverted: true + name: "Button" on_press: - switch.toggle: virtual_button + - platform: template - name: ${entity_prefix} Running + name: "${entity_prefix} Running" filters: - delayed_off: 15s lambda: |- if (isnan(id(power).state)) { return {}; } else if (id(power).state > 4) { - // Running return true; } else { - // Not running return false; } +#:########################################################################################:# +# SENSORS: +# https://esphome.io/components/sensor/ +#:########################################################################################:# sensor: - platform: hlw8012 - sel_pin: 5 - cf_pin: 14 - cf1_pin: 13 + sel_pin: GPIO5 + cf_pin: GPIO14 + cf1_pin: GPIO13 update_interval: 2s current: - name: ${entity_prefix} Current + name: "${entity_prefix} Current" voltage: - name: ${entity_prefix} Voltage + name: "${entity_prefix} Voltage" power: - name: ${entity_prefix} Power + name: "${entity_prefix} Power" id: power - #on_value_range: - # - above: 4.0 - # then: - # - light.turn_on: led - # - below: 3.0 - # then: - # - light.turn_off: led + # on_value_range: + # - above: 4.0 + # then: + # - light.turn_on: led + # - below: 3.0 + # then: + # - light.turn_off: led +#:########################################################################################:# +# SWITCH: +# https://esphome.io/components/switch/ +#:########################################################################################:# switch: - platform: template name: "Relay" - optimistic: true id: virtual_button + optimistic: true turn_on_action: - switch.turn_on: relay - light.turn_on: led turn_off_action: - switch.turn_off: relay - light.turn_off: led + - platform: gpio id: relay pin: GPIO12 - #restore_mode: ALWAYS_ON # Or RESTORE_DEFAULT_ON/RESTORE_DEFAULT_OFF + # restore_mode: ALWAYS_ON +#:########################################################################################:# +# OUTPUT: +# https://esphome.io/components/output/ +#:########################################################################################:# output: - platform: esp8266_pwm id: pow_blue_led pin: number: GPIO15 - inverted: True + inverted: true +#:########################################################################################:# +# LIGHT: +# https://esphome.io/components/light/ +#:########################################################################################:# light: - platform: monochromatic - name: Status LED + name: "Status LED" output: pow_blue_led id: led \ No newline at end of file diff --git a/esphome/esp-laundrywashpow.yaml b/esphome/esp-laundrywashpow.yaml index 69642dc..225ea86 100644 --- a/esphome/esp-laundrywashpow.yaml +++ b/esphome/esp-laundrywashpow.yaml @@ -1,39 +1,82 @@ -############################################# -############################################# -# LAUNDRY WASHING MACHINE POWER +#:########################################################################################:# +# TITLE: LAUNDRY WASHING MACHINE POWER +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-laundrywashpow.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V1.0 2025-03-28 Initial Version -############################################# -# Sonoff POW R1 -# https://devices.esphome.io/devices/Sonoff-POW-R1 +#:########################################################################################:# +# HARDWARE: +# - Sonoff POW R1 +# - ESP8266 based +# - HLW8012 power monitoring +# - Single relay output +# - Blue status LED on GPIO15 +# - Local push button on GPIO0 +# - Relay output on GPIO12 +# - Reference: https://devices.esphome.io/devices/Sonoff-POW-R1 +#:########################################################################################:# +# OPERATION NOTES: +# - Monitors washing machine load current, voltage, and power +# - Provides a virtual relay switch that controls the physical relay and LED together +# - Local button toggles the virtual relay switch +# - On boot, the virtual relay is turned ON +# - "Load Running" turns ON when measured power is above 4 W +# - "Load Running" uses delayed_off: 15s to avoid rapid state changes +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Device continues running normally +# - Local button still works +# - MQTT remains available if your common MQTT package is enabled and broker is reachable # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - Device continues running locally +# - Local button, relay control, LED control, and power monitoring still work # -############################################# -############################################# +# c) Entire WiFi/Network offline: +# - Device continues running locally +# - Local button, relay control, LED control, and power monitoring still work +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -############################################# -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -############################################# +#:########################################################################################:# substitutions: - device_name: "esp-laundrywashpow" # Reference name for the device in the system. - project_name: "Sonoff Technologies.POW R1" # Project Details - project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - entity_prefix: "Load" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. - friendly_name: "Laundry Washing Machine Power" # Friendly name to show in Home Assistant. - description_comment: "Laundry Washing Machine Power using a Sonoff Pow R1." - device_area: "Laundry" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - api_key: !secret esp-laundrywashpow_api_key # unfortunately you can't use substitutions inside secrets names - ota_pass: !secret esp-laundrywashpow_ota_pass # unfortunately you can't use substitutions inside secrets names - static_ip_address: !secret esp-laundrywashpow_ip - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + # Device Naming + device_name: "esp-laundrywashpow" + friendly_name: "Laundry Washing Machine Power" + description_comment: "Laundry Washing Machine Power using a Sonoff Pow R1. (Layout V1.1)" + device_area: "Laundry" -########################################################################################## -# PACKAGES: Included Common Packages + # Project Naming + project_name: "Sonoff Technologies.POW R1" + project_version: "v1.1" + + # Entity Naming + entity_prefix: "Load" + + # Passwords and Secrets + api_key: !secret esp-laundrywashpow_api_key + ota_pass: !secret esp-laundrywashpow_ota_pass + static_ip_address: !secret esp-laundrywashpow_ip + current_ip_address: ${static_ip_address} + + # Device Settings + log_level: "INFO" + update_interval: "60s" + +#:########################################################################################:# +# PACKAGES: +# Included common packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -41,12 +84,13 @@ 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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include file: common/api_common.yaml - #file: common/api_common_noencryption.yaml + # file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" @@ -55,137 +99,154 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### - #common_webportal: !include common/webportal_common.yaml + # common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + # common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + # diag_debug: !include common/include_debug_diag_sensors.yaml + # diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -############################################# -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -############################################# +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" area: "${device_area}" project: name: "${project_name}" version: "${project_version}" - on_boot: + on_boot: priority: 200 then: - - switch.turn_on: "virtual_button" + - switch.turn_on: virtual_button -############################################# -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -############################################# +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. - board_flash_mode: dout # Default is dout + early_pin_init: false + board_flash_mode: dout -############################################# -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: - level: ${log_level} #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 + level: "${log_level}" + # baud_rate: 0 + # esp8266_store_log_strings_in_flash: false + # tx_buffer_size: 64 -############################################# -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -############################################# -#status_led: -# pin: -# number: GPIO2 -# inverted: yes +#:########################################################################################:# +# status_led: +# pin: +# number: GPIO2 +# inverted: true -############################################# -# SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -############################################# +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT_PULLUP - inverted: True - name: Button + inverted: true + name: "Button" on_press: - switch.toggle: virtual_button + - platform: template - name: ${entity_prefix} Running + name: "${entity_prefix} Running" filters: - delayed_off: 15s lambda: |- if (isnan(id(power).state)) { return {}; } else if (id(power).state > 4) { - // Running return true; } else { - // Not running return false; } +#:########################################################################################:# +# SENSORS: +# https://esphome.io/components/sensor/ +#:########################################################################################:# sensor: - platform: hlw8012 - sel_pin: 5 - cf_pin: 14 - cf1_pin: 13 + sel_pin: GPIO5 + cf_pin: GPIO14 + cf1_pin: GPIO13 update_interval: 2s current: - name: ${entity_prefix} Current + name: "${entity_prefix} Current" voltage: - name: ${entity_prefix} Voltage + name: "${entity_prefix} Voltage" power: - name: ${entity_prefix} Power + name: "${entity_prefix} Power" id: power - #on_value_range: - # - above: 4.0 - # then: - # - light.turn_on: led - # - below: 3.0 - # then: - # - light.turn_off: led + # on_value_range: + # - above: 4.0 + # then: + # - light.turn_on: led + # - below: 3.0 + # then: + # - light.turn_off: led +#:########################################################################################:# +# SWITCH: +# https://esphome.io/components/switch/ +#:########################################################################################:# switch: - platform: template name: "Relay" - optimistic: true id: virtual_button + optimistic: true turn_on_action: - switch.turn_on: relay - light.turn_on: led turn_off_action: - switch.turn_off: relay - light.turn_off: led + - platform: gpio id: relay pin: GPIO12 - #restore_mode: ALWAYS_ON # Or RESTORE_DEFAULT_ON/RESTORE_DEFAULT_OFF + # restore_mode: ALWAYS_ON +#:########################################################################################:# +# OUTPUT: +# https://esphome.io/components/output/ +#:########################################################################################:# output: - platform: esp8266_pwm id: pow_blue_led pin: number: GPIO15 - inverted: True + inverted: true +#:########################################################################################:# +# LIGHT: +# https://esphome.io/components/light/ +#:########################################################################################:# light: - platform: monochromatic - name: Status LED + name: "Status LED" output: pow_blue_led id: led \ No newline at end of file diff --git a/esphome/esp-leafbattery.yaml b/esphome/esp-leafbattery.yaml index 849bf14..7f1ab8d 100644 --- a/esphome/esp-leafbattery.yaml +++ b/esphome/esp-leafbattery.yaml @@ -1,29 +1,59 @@ -########################################################################################## -########################################################################################## -# Nissan Leaf 12V Battery Monitor -# Monitoring the status of a vehicle 12V battery with -# an esp8266 (D1 Mini). It will obviously only -# transmit when the vehicle is within wifi range. -# Voltage is measured with a resistor voltage divider -# into the analogue GPIO on the esp8266. -# https://zorruno.com/2022/vehicle-12v-battery-monitoring/ -########################################################################################## -########################################################################################## +#:########################################################################################:# +# TITLE: NISSAN LEAF 12V BATTERY MONITOR +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-leafbattery.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-03-22 Updated yaml to zorruno layout V1.1 +# V1.0 2025-??-?? Initial Version +#:########################################################################################:# +# HARDWARE: +# - Generic ESP8266 D1 Mini +# - Nissan Leaf 12V battery monitor +# - Voltage measured with a resistor divider into the ESP8266 analogue pin +# - Device only transmits when the vehicle is within WiFi range +# - Reference: +# https://zorruno.com/2022/vehicle-12v-battery-monitoring/ +#:########################################################################################:# +# OPERATION NOTES: +# - Monitors the Nissan Leaf 12V battery voltage. +# - Device wakes for a short period, publishes voltage, then deep sleeps. +# - Deep sleep is PREVENTED on boot by default. +# - Device waits up to 30 seconds for MQTT to connect. +# - If MQTT does not connect within 30 seconds, it enters a longer fallback sleep period. +# - If MQTT connects, deep sleep can be controlled by MQTT command topic. +# - Battery voltage is read from A0 and calibrated using a linear table. +# - Voltage is published immediately when it changes by 0.05 V or more. +# - Voltage is also republished every 60 seconds while awake. +# +# MQTT COMMANDS: +# - ${mqtt_command_topic}/deepsleep = ON +# - Allow deep sleep when run_duration expires +# - ${mqtt_command_topic}/deepsleep = OFF +# - Prevent deep sleep +# +# MQTT STATUS: +# - ${mqtt_status_topic}/availability = online/offline +# - ${mqtt_status_topic}/batteryvoltage = voltage value +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-leafbattery" friendly_name: "Nissan Leaf 12V Battery Monitor" - description_comment: "Nissan Leaf 12V Battery Monitor (when home)" - device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Nissan Leaf 12V Battery Monitor (when home) (Layout V1.1)" + device_area: "Garage" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Generic ESP8266.D1 Mini" # Project Details - project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Generic ESP8266.D1 Mini" # Project Details + project_version: "v1.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names @@ -32,26 +62,28 @@ substitutions: mqtt_command_main_topic: !secret mqtt_command_main_topic mqtt_status_main_topic: !secret mqtt_status_main_topic + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + # MQTT LOCAL Controls mqtt_device_name: "leaf-battery" mqtt_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA mqtt_status_topic: "${mqtt_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA # Device Settings - #relay_icon: "mdi:lightbulb-group" log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for for general sensors etc wake_interval: "20s" sleep_interval: "300s" - mqtt_fail_sleep: "1h" # If MQTT is unavailable after boot wait, sleep this long + mqtt_fail_sleep: "1h" # If MQTT is unavailable after boot wait, sleep this long -########################################################################################## -# PACKAGES: Included Common Packages +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## -# Comment some of these out where not needed, eg MQTT, Web portal, SNTP, General Sensors -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -60,6 +92,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -73,28 +106,32 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### common_webportal: !include common/webportal_common.yaml - + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -########################################################################################## -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: - name: ${device_name} - friendly_name: ${friendly_name} - comment: ${description_comment} #appears on the esphome page in HA + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" # appears on the esphome page in HA + area: "${device_area}" min_version: 2024.6.0 + project: + name: "${project_name}" + version: "${project_version}" on_boot: priority: 600 then: @@ -115,41 +152,41 @@ esphome: - logger.log: "MQTT unreachable after 30s -> entering FALLBACK sleep for ${mqtt_fail_sleep}." - deep_sleep.enter: id: deep_sleep_1 - sleep_duration: ${mqtt_fail_sleep} # override only this cycle + sleep_duration: ${mqtt_fail_sleep} # override only this cycle else: - logger.log: "MQTT connected; awaiting '${mqtt_command_topic}/deepsleep' command." -########################################################################################## -# ESP Platform and Framework +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: # https://esphome.io/components/esp8266.html # https://esphome.io/components/esp32.html -########################################################################################## +#:########################################################################################:# esp8266: board: d1_mini framework: - version: latest #recommended, latest or dev + version: latest # recommended, latest or dev -########################################################################################## -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -########################################################################################## +#:########################################################################################:# logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + level: "${log_level}" # INFO Level suggested, or DEBUG for testing + #baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -############################################# -# Enable Over the Air Update Capability -# https://esphome.io/components/ota.html?highlight=ota -############################################# +#:########################################################################################:# +# OTA: +# https://esphome.io/components/ota.html +#:########################################################################################:# ota: - platform: web_server # Uncomment if you want to be able to do OTA with the web interface -########################################################################################## -# MQTT COMMANDS +#:########################################################################################:# +# MQTT COMMANDS: # This adds device-specific MQTT command triggers to the common MQTT configuration. -########################################################################################## +#:########################################################################################:# mqtt: # Availability Topic birth_message: @@ -173,19 +210,19 @@ mqtt: - deep_sleep.prevent: deep_sleep_1 - logger.log: "Deep sleep PREVENTED via MQTT." -########################################################################################## -# Deep Sleep +#:########################################################################################:# +# DEEP SLEEP: # https://esphome.io/components/deep_sleep.html -########################################################################################## +#:########################################################################################:# deep_sleep: id: deep_sleep_1 - run_duration: ${wake_interval} - sleep_duration: ${sleep_interval} - -########################################################################################## -# SENSOR COMPONENT + run_duration: ${wake_interval} + sleep_duration: ${sleep_interval} + +#:########################################################################################:# +# SENSOR COMPONENT: # https://esphome.io/components/sensor/ -########################################################################################## +#:########################################################################################:# sensor: - platform: adc pin: A0 @@ -208,8 +245,8 @@ sensor: - 0.32 -> 07.00 - 0.28 -> 06.00 - 0.23 -> 05.00 - - delta: 0.05 # publish immediately if change >= 0.05 V - - throttle: 2s # avoid bursts if noisy + - delta: 0.05 # publish immediately if change >= 0.05 V + - throttle: 2s # avoid bursts if noisy on_value: then: - mqtt.publish: @@ -221,9 +258,10 @@ sensor: snprintf(buf, sizeof(buf), "%.2f", x); return std::string(buf); -########################################################################################## -# INTERVAL COMPONENT -########################################################################################## +#:########################################################################################:# +# INTERVAL COMPONENT: +# https://esphome.io/components/interval.html +#:########################################################################################:# interval: - interval: 60s then: @@ -237,6 +275,3 @@ interval: snprintf(buf, sizeof(buf), "%.2f", v); return std::string(buf); - - - diff --git a/esphome/esp-loungebookshelfleds.yaml b/esphome/esp-loungebookshelfleds.yaml index 4bf157c..9915535 100644 --- a/esphome/esp-loungebookshelfleds.yaml +++ b/esphome/esp-loungebookshelfleds.yaml @@ -1,72 +1,97 @@ -########################################################################################## -########################################################################################## -# Title: LOUNGE BOOKSHELF LEDS -# Repo: https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungebookshelfleds.yaml -# -# v2.0 - 2025-09-15 A bunch of fixes and made it more standard across my devices -# v1.0 - 2025-08-17 First setup (and replacement of Tasmota) +#:########################################################################################:# +# TITLE: LOUNGE BOOKSHELF LEDS +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungebookshelfleds.yaml +#:########################################################################################:# +# VERSIONS: +# V2.1 2026-03-11 Updated yaml to zorruno layout V1.1 +# V2.0 2025-09-15 A bunch of fixes and made it more standard across my devices +# V1.0 2025-08-17 First setup (and replacement of Tasmota) +#:########################################################################################:# +# HARDWARE: +# - Magichome LED controller single channel (ESP8266, NOT the later ones with BL602) +# - Reference: +# https://devices.esphome.io/devices/MagicHome-ZJ-WFMN-C-Single-Color +# - Device GPIO (Magichome ESP8266): +# - GPIO2 Blue LED (used for ESPHome status) +# - GPIO12 MOSFET output (0 V when switched) +#:########################################################################################:# +# OPERATION NOTES: +# - General-purpose LED controller. +# - Designed for the Sinilink XY-WFMS board with a MOSFET output (claimed 5A, 5-36 V DC), +# but will suit similar MOSFET boards. +# - In SUBSTITUTIONS there is a maximum output setting to extend LED life. +# - In SUBSTITUTIONS there is a minimum output setting; switches fully OFF at/below the minimum +# to avoid low-PWM flicker. +# - PWM frequency is set to 1 kHz by default. You can increase it, but higher values caused +# resets on the Sinilink device. On ESP32 you can run much higher. +# - Min/max output settings are not exposed in Home Assistant/MQTT by default, but could be. +# - Packages include common items: network settings, diagnostic entities, MQTT, and optional SNTP. +# - Default restart behaviours: +# - Fade up to full +# - Restore Brightness +# - Remain Off +# - The green LED flashes while fading (different patterns for up/down). The red LED follows the +# output (it shares the MOSFET GPIO). This depends on hardware. +# - Fade timing scales with configured values proportionally when starting mid-brightness. +# - Exposed in Home Assistant/MQTT: +# - Startup action (On, Off, Restore) +# - Fade Up / Fade Down / Fade Stop buttons +# - Fade Up/Down toggle switch +# - Normal On/Off switch using quick ramp up/down +# - Fade up/down times (0-60 s) +# - Output % (pre-gamma) and PWM % (post-gamma) +# - Output Set (1-100, respects min/max) +# - Many device diagnostics from the included diagnostics package +# - Maximum ON time before automatic fade-down (1-48 h, 0 = no limit) # -# ------------------------------------------ -# OPERATION (as of v2.0) -# ------------------------------------------ -# 1. General-purpose LED controller. -# 2. Designed for the Sinilink XY-WFMS board with a MOSFET output (claimed 5A, 5-36 V DC), but will suit similar mosfet boards. -# 3. (In SUBSTITUTIONS) setting for MAX % output to extend LED life (ie can ensure it is only ever 95%) -# 4. (In SUBSTITUTIONS) Minimum output setting; switches fully OFF at/below the minimum to avoid low-PWM flicker. -# 5. (In SUBSTITUTIONS) PWM frequency is set to 1kHz by default. You can increase it, but higher values caused -# resets on Sinilink device. On ESP32 you can run much higher (~40 kHz). -# 6. Min/Max output settings are not exposed in Home Assistant/MQTT by default, but could be. -# With a 1 MB flash, space is tight and only minimal optimisation has been done so far. -# 7. (PACKAGES) include common items: network settings, diagnostic entities, MQTT, and SNTP (optional). -# 8. Default behaviours, for recovery from lost power or reset: -# - "Fade up to full": fade from floor to max on boot. -# - "Restore Brightness": fade from floor to the last non-zero brightness on boot (should be no on/off blip/flash). -# - "Remain Off": stays off on boot. -# 9. The green LED flashes while fading (different patterns for up/down). The red LED follows the -# output (it shares the MOSFET GPIO). (Obviously this depends on hardware) -# 10. Fade timing scales with the configured values (proportionally when starting mid-brightness). -# 11. Exposed in Home Assistant/MQTT: -# - Startup action (On,Off,Restore) -# - Fade Up / Fade Down / Fade Stop buttons -# - Fade Up/Down toggle switch (keeps fading up to full, or down to off unless stopped) -# - Normal On/Off switch (quick ramp up/down, up to the level of previous brightness) -# - Fade up/down times (0-60s) -# - Output % (pre-gamma) and PWM % (post-gamma) -# - Output Set (1-100, respects min/max). This also changes with other output so reflects value. -# - Many device diagnostics (from the included 'diagnostics' package) -# - Maximum 'on' time before automatic fade-down (1-48 h, 0 = no limit) -########################################################################################## -########################################################################################## -# Hardware: Magishome LED controller single channel (ESP8266, NOT the later ones with BL602) -# https://devices.esphome.io/devices/MagicHome-ZJ-WFMN-C-Single-Color -# ------------------------------------------ -# DEVICE GPIO (Magichome ESP8266) -# ------------------------------------------ -# GPIO02 Blue LED (used for ESPHome status) - I think... can't see the board -# GPIO12 MOSFET output (0 V when switched) -########################################################################################## -########################################################################################## +# MQTT COMMANDS: +# - ${mqtt_local_command_topic}/light/set = ON +# - ${mqtt_local_command_topic}/light/set = OFF +# - State publishes to: +# - ${mqtt_local_status_topic}/light/state +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - LED control continues locally on the device +# - Direct local MQTT commands still work if the broker is available +# - Stored brightness/ramp settings and restart behaviour continue to work +# +# b) MQTT offline (or HA/MQTT offline): +# - LED control continues locally on the device +# - Physical button control and local ramp logic continue to work +# - No MQTT control/state publishing available +# +# c) Entire WiFi/Network offline: +# - LED control continues locally on the device +# - Physical button control and local ramp logic continue to work +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-loungebookshelfleds" # yaml file should be device_name.yaml friendly_name: "Lounge Bookshelf LEDs" - description_comment: "LED Strip around the bookshelf in the upstairs lounge :: Magichome ESP8266" + description_comment: "LED Strip around the bookshelf in the upstairs lounge :: Magichome ESP8266 (Layout V1.1)" device_area: "Lounge" # Allows the ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Magichome Single Colour V1.1 LED Controller.Generic ESP8266" # Project details. Manufacturer before the dot, device after the dot. - project_version: "v2.0" # Project version denotes release of the YAML file, allowing checking of deployed vs latest version - + project_name: "Magichome Single Colour V1.1 LED Controller.Generic ESP8266" # Project details. Manufacturer before the dot, device after the dot. + project_version: "v2.1" # Project version denotes release of the YAML file, allowing checking of deployed vs latest version + # Passwords & Secrets (Unfortunately, you can't use substitutions inside secret names) - api_key: !secret esp-api_key # If using HA API + api_key: !secret esp-api_key # If using HA API ota_pass: !secret esp-ota_pass # If passwording OTA updates static_ip_address: !secret esp-loungebookshelfleds_ip # CHANGE THIS - + current_ip_address: ${static_ip_address} + # MQTT LOCAL Controls (This is just my local method of controlling via MQTT, I also use the built in method) mqtt_local_device_name: "lounge-bookshelfleds" mqtt_local_command_main_topic: !secret mqtt_command_main_topic @@ -77,24 +102,25 @@ substitutions: mqtt_local_device_command_OFF: "OFF" # Device Specific Settings - log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (default), VERBOSE, VERY_VERBOSE - update_interval: "20s" # Update time for general sensors, etc. - led_gamma: "1.2" # Gamma from 1.2-3 is sensible to normalise the LED fading vs PWM - minimum_led_output: "1" # % If at this value or below, we'll switch it completely off - maximum_led_output: "90" # % Maximum output; it is sometimes nice to limit the output for longevity or aesthetics + log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (default), VERBOSE, VERY_VERBOSE + update_interval: "20s" # Update time for general sensors, etc. + led_gamma: "1.2" # Gamma from 1.2-3 is sensible to normalise the LED fading vs PWM + minimum_led_output: "1" # % If at this value or below, we will switch it completely off + maximum_led_output: "90" # % Maximum output; it is sometimes nice to limit the output for longevity or aesthetics max_on_default_hours: "24" # The maximum time the LEDs will be on, in case they get left on. 0 = no automatic turn-off - pwm_frequency: "1000" # PWM output Frequency in Hz. High enough to avoid audible/visible artifacts + pwm_frequency: "1000" # PWM output Frequency in Hz. High enough to avoid audible/visible artifacts # Device Specific GPIO (so we can easily update for other devices) - device_status_led: GPIO02 + device_status_led: GPIO2 device_mosfet_out: GPIO12 - device_usr_button: GPIO04 # if no button, this is just a fake/safeish choice so it compiles with the generic yaml + device_usr_button: GPIO4 # if no button, this is just a fake/safeish choice so it compiles with the generic yaml device_fading_led: GPIO13 # if no LED, this is just a fake/safeish choice so it compiles with the generic yaml -########################################################################################## -# PACKAGES: Included Common Packages +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -102,6 +128,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -116,22 +143,23 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -########################################################################################## -# ESPHome CORE CONFIGURATION +#:########################################################################################:# +# ESPHOME CORE CONFIGURATION # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -152,32 +180,32 @@ esphome: # Mode 0: Fade up to full (obeys fade settings; no on/off flicker) - if: condition: - lambda: 'return id(restart_mode) == 0;' + lambda: "return id(restart_mode) == 0;" then: - - lambda: 'id(ramp_switch_target_on) = true;' + - lambda: "id(ramp_switch_target_on) = true;" - script.execute: ramp_on_script # Mode 1: Restore Brightness (deferred to avoid races) - if: condition: - lambda: 'return id(restart_mode) == 1;' + lambda: "return id(restart_mode) == 1;" then: - script.execute: deferred_restore_brightness # Mode 2: Remain Off (no blip; stays off) - if: condition: - lambda: 'return id(restart_mode) == 2;' + lambda: "return id(restart_mode) == 2;" then: - script.stop: ramp_on_script - script.stop: ramp_off_script - - lambda: 'id(ramp_switch_target_on) = false;' + - lambda: "id(ramp_switch_target_on) = false;" - light.turn_off: id: mosfet_leds transition_length: 0s # Boot complete: allow OFF handlers again - - lambda: 'id(booting) = false;' + - lambda: "id(booting) = false;" # NEW: force indicator OFF after boot logic # (Removed: output.turn_off: green_led_out) @@ -193,11 +221,11 @@ esphome: # - -fdata-sections # - -DNDEBUG -########################################################################################## +#:########################################################################################:# # ESP PLATFORM AND FRAMEWORK # https://esphome.io/components/esp8266.html # https://esphome.io/components/esp32.html -########################################################################################## +#:########################################################################################:# esp8266: board: esp01_1m restore_from_flash: true # restore some values on reboot @@ -208,10 +236,10 @@ mdns: preferences: flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash -########################################################################################## +#:########################################################################################:# # GLOBAL VARIABLES # https://esphome.io/components/globals.html -########################################################################################## +#:########################################################################################:# globals: # Minimum Brightness % for LEDs (will switch off if <=) - id: min_brightness_pct @@ -223,7 +251,7 @@ globals: type: int restore_value: false initial_value: "${maximum_led_output}" # hard cap; never exceed this - # The maximum time the lights will stay on, in hours. Just in case they are left on. 0 = forever + # The maximum time the lights will stay on, in hours. Just in case they are left on. 0 = forever - id: max_on_hours type: int restore_value: true @@ -232,23 +260,23 @@ globals: - id: led_gamma_f type: float restore_value: false - initial_value: ${led_gamma} # <-- numeric at compile time + initial_value: ${led_gamma} # numeric at compile time # Default Fading Up Time (Selectable and will be retained) - id: ramp_up_ms # fade-in when turned ON type: int restore_value: true - initial_value: '5000' # 5 s + initial_value: "5000" # 5 s # Default Fading Down Time (Selectable and will be retained) - id: ramp_down_ms # fade-out when turned OFF type: int restore_value: true - initial_value: '10000' # 10 s + initial_value: "10000" # 10 s # Action on Restart. (0=Fade full, 1=Restore brightness, 2=Remain off) - - id: restart_mode + - id: restart_mode type: int restore_value: true - initial_value: '0' # default = Fade Up to Full (so can be deployed with no other setup) + initial_value: "0" # default = Fade Up to Full (so can be deployed with no other setup) # Determine last fade direction. # true when you asked the light to end up ON (Ramp Up) @@ -256,70 +284,70 @@ globals: - id: ramp_switch_target_on type: bool restore_value: true - initial_value: 'false' + initial_value: "false" # Prevent jitter when adjusting the slider - id: suppress_slider_sync type: bool restore_value: false - initial_value: 'false' - # actual 0..100 seen last time, for restart - - id: last_brightness_pct + initial_value: "false" + # actual 0..100 seen last time, for restart + - id: last_brightness_pct type: float restore_value: true - initial_value: '0.0' + initial_value: "0.0" # last published "Output Set (0-100)" integer - id: last_set_pos type: int restore_value: false - initial_value: '-1' - # helper to keep blink time == transition time + initial_value: "-1" + # helper to keep blink time == transition time - id: last_ramp_ms type: int restore_value: false - initial_value: '0' + initial_value: "0" # target for "Restore Brightness" scripted ramp - id: restore_target_pct type: float restore_value: false - initial_value: '0.0' + initial_value: "0.0" # true while a scripted ramp is in progress (to limit flash writes) - id: is_ramping type: bool restore_value: false - initial_value: 'false' + initial_value: "false" # guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF - id: booting type: bool restore_value: false - initial_value: 'true' + initial_value: "true" # true only while we are performing a ramp-down that briefly turns the light ON to hit the floor - id: ramping_for_off type: bool restore_value: false - initial_value: 'false' + initial_value: "false" -########################################################################################## +#:########################################################################################:# # LOGGER COMPONENT # https://esphome.io/components/logger.html # Logs all log messages through the serial port and through MQTT topics. -########################################################################################## +#:########################################################################################:# logger: level: "${log_level}" # INFO Level suggested, or DEBUG for testing baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM, Serial control) -######################################################################################### +#:########################################################################################:# # STATUS LED # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: number: ${device_status_led} inverted: true -########################################################################################## +#:########################################################################################:# # MQTT COMMANDS # This adds device-specific MQTT command triggers to the common MQTT configuration. -########################################################################################## +#:########################################################################################:# mqtt: on_message: # Light control to ramp up @@ -333,10 +361,10 @@ mqtt: then: - switch.turn_off: mosfet_ramp_switch -########################################################################################## +#:########################################################################################:# # SWITCH COMPONENT # https://esphome.io/components/switch/ -########################################################################################## +#:########################################################################################:# switch: # Ramp-aware ON/OFF for HA (asymmetric, eased; no bounce) - platform: template @@ -356,10 +384,10 @@ switch: - script.stop: ramp_on_script - script.execute: ramp_off_script -################################################################################################# +#:########################################################################################:# # BUTTON COMPONENT # https://esphome.io/components/button/index.html -################################################################################################# +#:########################################################################################:# button: # Start ramping UP (from current level) - platform: template @@ -399,7 +427,7 @@ button: id(ramping_for_off) = false; id(is_ramping) = false; - // Freeze the light at its *current* level by overwriting the transition + // Freeze the light at its current level by overwriting the transition const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { auto call = id(mosfet_leds).make_call(); @@ -415,12 +443,10 @@ button: id(last_brightness_pct) = pct; } - - -######################################################################################### +#:########################################################################################:# # SELECT COMPONENT # https://esphome.io/components/select/index.html -######################################################################################### +#:########################################################################################:# select: - platform: template id: restart_action @@ -442,10 +468,10 @@ select: id(restart_mode) = 2; } -######################################################################################### +#:########################################################################################:# # BINARY SENSORS # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio id: btn_gpio12 @@ -462,7 +488,7 @@ binary_sensor: on_press: - if: condition: - lambda: 'return id(ramp_switch_target_on);' + lambda: "return id(ramp_switch_target_on);" then: # Target is currently ON -> press should go OFF (start ramp-down) - lambda: |- @@ -478,10 +504,10 @@ binary_sensor: - script.stop: ramp_off_script - script.execute: ramp_on_script -########################################################################################## +#:########################################################################################:# # SENSOR COMPONENT # https://esphome.io/components/sensor/ -########################################################################################## +#:########################################################################################:# sensor: - platform: template id: mosfet_output_pct @@ -489,7 +515,7 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 2s # consider 200ms if you want fewer updates + update_interval: 2s lambda: |- const auto &cv = id(mosfet_leds).current_values; return cv.is_on() ? (float) (int)(cv.get_brightness() * 100.0f + 0.5f) : 0.0f; @@ -530,28 +556,29 @@ sensor: if (pwm > 1.0f) pwm = 1.0f; return pwm * 100.0f; -########################################################################################## +#:########################################################################################:# # OUTPUT COMPONENT # https://esphome.io/components/light/index.html -########################################################################################## +#:########################################################################################:# # An OUTPUT can be binary (0,1) or float, which is any value between 0 and 1. # PWM Outputs such as "ledc" are float. https://esphome.io/components/output/ledc.html -########################################################################################## +#:########################################################################################:# output: - platform: esp8266_pwm id: mosfet_pwm pin: ${device_mosfet_out} frequency: ${pwm_frequency} + - platform: gpio id: green_led_out # Green LED pin: number: ${device_fading_led} inverted: false -########################################################################################## +#:########################################################################################:# # LIGHT COMPONENT # https://esphome.io/components/light/ -########################################################################################## +#:########################################################################################:# light: - platform: monochromatic id: mosfet_leds @@ -570,14 +597,14 @@ light: payload: "${mqtt_local_device_command_ON}" retain: true - lambda: |- - // Do not flip "intent to ON" when we're inside an OFF ramp's floor-kick + // Do not flip "intent to ON" when we are inside an OFF ramp's floor-kick if (!id(ramping_for_off)) { id(ramp_switch_target_on) = true; } - script.stop: max_on_watchdog - if: condition: - lambda: 'return id(max_on_hours) > 0;' + lambda: "return id(max_on_hours) > 0;" then: - script.execute: max_on_watchdog @@ -587,13 +614,13 @@ light: - output.turn_off: green_led_out - if: condition: - lambda: 'return !id(booting);' + lambda: "return !id(booting);" then: - mqtt.publish: topic: "${mqtt_local_status_topic}/light/state" payload: "${mqtt_local_device_command_OFF}" retain: true - - lambda: 'id(ramp_switch_target_on) = false;' + - lambda: "id(ramp_switch_target_on) = false;" - script.stop: max_on_watchdog - lambda: |- id(last_brightness_pct) = 0.0f; @@ -614,11 +641,10 @@ light: call.set_transition_length(0); call.perform(); - -########################################################################################## +#:########################################################################################:# # NUMBER COMPONENT # https://esphome.io/components/number/ -########################################################################################## +#:########################################################################################:# number: - platform: template id: cfg_ramp_up_s @@ -683,10 +709,10 @@ number: set_action: - if: condition: - lambda: 'return x <= 0.0f;' + lambda: "return x <= 0.0f;" then: # 0 means OFF - - lambda: 'id(suppress_slider_sync) = true;' + - lambda: "id(suppress_slider_sync) = true;" - script.stop: ramp_on_script - script.stop: ramp_off_script - light.turn_off: @@ -698,7 +724,7 @@ number: id(last_brightness_pct) = 0.0f; // persist OFF immediately id(last_set_pos) = 0; - delay: 400ms - - lambda: 'id(suppress_slider_sync) = false;' + - lambda: "id(suppress_slider_sync) = false;" else: # Map 1..100 - [min..max] and set ON - lambda: |- @@ -730,7 +756,7 @@ number: if (out_pct > maxp) out_pct = maxp; id(last_brightness_pct) = out_pct; // persist exact target now - delay: 400ms - - lambda: 'id(suppress_slider_sync) = false;' + - lambda: "id(suppress_slider_sync) = false;" - platform: template id: cfg_max_on_hours @@ -753,27 +779,26 @@ number: id(cfg_max_on_hours).publish_state((float) hrs); - if: condition: - lambda: 'return id(mosfet_leds).current_values.is_on();' + lambda: "return id(mosfet_leds).current_values.is_on();" then: - script.stop: max_on_watchdog - if: condition: - lambda: 'return id(max_on_hours) > 0;' + lambda: "return id(max_on_hours) > 0;" then: - script.execute: max_on_watchdog -########################################################################################## +#:########################################################################################:# # SCRIPT COMPONENT # https://esphome.io/components/script.html # Scripts can be executed nearly anywhere in your device configuration with a single call. -########################################################################################## +#:########################################################################################:# script: - - # Script: ramp up from current level. Obey global max. (LED ON while ramping) + # Script: ramp up from current level. Obey global max. (LED ON while ramping) - id: ramp_on_script mode: restart then: - - lambda: 'id(is_ramping) = true;' + - lambda: "id(is_ramping) = true;" - script.stop: ramp_off_script # Ensure we start at at least the floor without a visible "pop". - if: @@ -785,12 +810,12 @@ script: then: - light.turn_on: id: mosfet_leds - brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' + brightness: !lambda "return id(min_brightness_pct) / 100.0f;" transition_length: 80ms # Ramp from current (>= floor) to cap over a fraction of ramp_up_ms. - light.turn_on: id: mosfet_leds - brightness: !lambda 'return id(max_brightness_pct) / 100.0f;' + brightness: !lambda "return id(max_brightness_pct) / 100.0f;" transition_length: !lambda |- const auto &cv = id(mosfet_leds).current_values; const float floor = id(min_brightness_pct) / 100.0f; @@ -810,7 +835,7 @@ script: if (frac > 1.0f) frac = 1.0f; id(last_ramp_ms) = (int) (id(ramp_up_ms) * frac); return (uint32_t) id(last_ramp_ms); - - delay: !lambda 'return (uint32_t) id(last_ramp_ms);' + - delay: !lambda "return (uint32_t) id(last_ramp_ms);" - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; @@ -823,7 +848,7 @@ script: - id: ramp_to_target_script mode: restart then: - - lambda: 'id(is_ramping) = true;' + - lambda: "id(is_ramping) = true;" - script.stop: ramp_off_script # Ensure we start at the floor cleanly. - if: @@ -835,7 +860,7 @@ script: then: - light.turn_on: id: mosfet_leds - brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' + brightness: !lambda "return id(min_brightness_pct) / 100.0f;" transition_length: 80ms # Ramp from current (>= floor) to restore_target_pct over a fraction of ramp_up_ms. - light.turn_on: @@ -866,7 +891,7 @@ script: if (frac > 1.0f) frac = 1.0f; id(last_ramp_ms) = (int) (id(ramp_up_ms) * frac); return (uint32_t) id(last_ramp_ms); - - delay: !lambda 'return (uint32_t) id(last_ramp_ms);' + - delay: !lambda "return (uint32_t) id(last_ramp_ms);" - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; @@ -875,7 +900,6 @@ script: id(last_brightness_pct) = pct; // persist final level } - # Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping) - id: ramp_off_script mode: restart @@ -886,7 +910,7 @@ script: - script.stop: ramp_on_script - light.turn_on: id: mosfet_leds - brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' + brightness: !lambda "return id(min_brightness_pct) / 100.0f;" transition_length: !lambda |- const auto &cv = id(mosfet_leds).current_values; const float floor = id(min_brightness_pct) / 100.0f; @@ -899,7 +923,7 @@ script: if (frac > 1.0f) frac = 1.0f; id(last_ramp_ms) = (int) (id(ramp_down_ms) * frac); return (uint32_t) id(last_ramp_ms); - - delay: !lambda 'return (uint32_t) id(last_ramp_ms);' + - delay: !lambda "return (uint32_t) id(last_ramp_ms);" - light.turn_off: id: mosfet_leds transition_length: 150ms @@ -916,12 +940,12 @@ script: then: - if: condition: - lambda: 'return id(max_on_hours) > 0;' + lambda: "return id(max_on_hours) > 0;" then: - - delay: !lambda 'return (uint32_t) (id(max_on_hours) * 3600000UL);' + - delay: !lambda "return (uint32_t) (id(max_on_hours) * 3600000UL);" - if: condition: - lambda: 'return id(mosfet_leds).current_values.is_on();' + lambda: "return id(mosfet_leds).current_values.is_on();" then: - lambda: |- id(ramp_switch_target_on) = false; @@ -948,18 +972,18 @@ script: - if: condition: - lambda: 'return id(restore_target_pct) > 0.5f;' + lambda: "return id(restore_target_pct) > 0.5f;" then: - lambda: |- id(ramp_switch_target_on) = true; // reflect our intent - id(suppress_slider_sync) = true; + id(suppress_slider_sync) = true; - script.stop: ramp_off_script - script.execute: ramp_to_target_script - - delay: !lambda 'return (uint32_t) id(last_ramp_ms);' - - lambda: 'id(suppress_slider_sync) = false;' + - delay: !lambda "return (uint32_t) id(last_ramp_ms);" + - lambda: "id(suppress_slider_sync) = false;" else: # Exact last was 0 -> remain OFF - - lambda: 'id(ramp_switch_target_on) = false;' + - lambda: "id(ramp_switch_target_on) = false;" - light.turn_off: id: mosfet_leds transition_length: 0s diff --git a/esphome/esp-loungecabinetleds2.yaml b/esphome/esp-loungecabinetleds.yaml similarity index 73% rename from esphome/esp-loungecabinetleds2.yaml rename to esphome/esp-loungecabinetleds.yaml index 02986bf..dc2bf12 100644 --- a/esphome/esp-loungecabinetleds2.yaml +++ b/esphome/esp-loungecabinetleds.yaml @@ -1,76 +1,95 @@ -########################################################################################## -########################################################################################## -# Title: LOUNGE CABINET LEDS -# Repo: https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungecabinetleds.yaml +#:########################################################################################:# +# TITLE: LOUNGE CABINET LEDS +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungecabinetleds.yaml +#:########################################################################################:# +# VERSIONS: +# V2.1 2026-03-11 Updated yaml to zorruno layout V1.1 +# V2.0 2025-09-15 A bunch of fixes, this is now the master for other similar mosfet controllers of mine +# V1.5 2025-09-11 First setup (copied from another template) +#:########################################################################################:# +# HARDWARE: +# - Sinilink MOSFET Board XY-WFMS (ESP8266) - sometimes listed as "XY-VFMS" +# - Reference: +# https://devices.esphome.io/devices/Sinilink-XY-WFMS +# - DEVICE GPIO (Sinilink XY-WFMS) +# - GPIO2 Blue LED, active-low (used for ESPHome status) +# - GPIO4 MOSFET output (0V when switched) and Red LED +# - GPIO12 Toggle button +# - GPIO13 Green LED (used to display fading status) +# - 3D-printed case for Sinilink XY-WFMS: +# https://cults3d.com/en/3d-model/tool/snapfit-enclosure-for-esp8266-sinilink-xy-wfms-5v-36v-mosfet-switch-module +#:########################################################################################:# +# OPERATION NOTES: +# - General-purpose LED controller. +# - Designed for the Sinilink XY-WFMS board with a MOSFET output (claimed 5A, 5-36 V DC), but will suit similar MOSFET boards. +# - In SUBSTITUTIONS there is a MAX % output setting to extend LED life. +# - In SUBSTITUTIONS there is a minimum output setting; switches fully OFF at/below the minimum to avoid low-PWM flicker. +# - In SUBSTITUTIONS PWM frequency is set to 1kHz by default. You can increase it, but higher values caused resets on Sinilink device. +# - On ESP32 you can run much higher PWM frequencies (about 40 kHz). +# - Min/Max output settings are not exposed in Home Assistant/MQTT by default, but could be. +# - With a 1 MB flash, space is tight and only minimal optimisation has been done so far. +# - Included packages provide network settings, diagnostic entities, MQTT, and optional SNTP. +# - Default restart behaviours: +# - Fade up to full +# - Restore Brightness +# - Remain Off +# - The green LED flashes while fading. The red LED follows the output because it shares the MOSFET GPIO. +# - Fade timing scales with the configured values proportionally when starting mid-brightness. +# - Exposed in Home Assistant/MQTT: +# - Startup action (On, Off, Restore) +# - Fade Up / Fade Down / Fade Stop buttons +# - Fade Up/Down toggle switch +# - Normal On/Off switch +# - Fade up/down times (0-60s) +# - Output % (pre-gamma) and PWM % (post-gamma) +# - Output Set (1-100, respects min/max) +# - Many device diagnostics from the included diagnostics package +# - Maximum ON time before automatic fade-down (1-48 h, 0 = no limit) # -# v2.0 - 2025-09-15 A bunch of fixes, this is now the master for other similar mosfet controllers of mine -# v1.5 - 2025-09-11 First setup (copied from another template) -# -# ------------------------------------------ -# OPERATION (as of v2.0) -# ------------------------------------------ -# 1. General-purpose LED controller. -# 2. Designed for the Sinilink XY-WFMS board with a MOSFET output (claimed 5A, 5-36 V DC), but will suit similar mosfet boards. -# 3. (In SUBSTITUTIONS) setting for MAX % output to extend LED life (ie can ensure it is only ever 95%) -# 4. (In SUBSTITUTIONS) Minimum output setting; switches fully OFF at/below the minimum to avoid low-PWM flicker. -# 5. (In SUBSTITUTIONS) PWM frequency is set to 1kHz by default. You can increase it, but higher values caused -# resets on Sinilink device. On ESP32 you can run much higher (~40 kHz). -# 6. Min/Max output settings are not exposed in Home Assistant/MQTT by default, but could be. -# With a 1 MB flash, space is tight and only minimal optimisation has been done so far. -# 7. (PACKAGES) include common items: network settings, diagnostic entities, MQTT, and SNTP (optional). -# 8. Default behaviours, for recovery from lost power or reset: -# - "Fade up to full": fade from floor to max on boot. -# - "Restore Brightness": fade from floor to the last non-zero brightness on boot (should be no on/off blip/flash). -# - "Remain Off": stays off on boot. -# 9. The green LED flashes while fading (different patterns for up/down). The red LED follows the -# output (it shares the MOSFET GPIO). (Obviously this depends on hardware) -# 10. Fade timing scales with the configured values (proportionally when starting mid-brightness). -# 11. Exposed in Home Assistant/MQTT: -# - Startup action (On,Off,Restore) -# - Fade Up / Fade Down / Fade Stop buttons -# - Fade Up/Down toggle switch (keeps fading up to full, or down to off unless stopped) -# - Normal On/Off switch (quick ramp up/down, up to the level of previous brightness) -# - Fade up/down times (0-60s) -# - Output % (pre-gamma) and PWM % (post-gamma) -# - Output Set (1-100, respects min/max). This also changes with other output so reflects value. -# - Many device diagnostics (from the included 'diagnostics' package) -# - Maximum 'on' time before automatic fade-down (1-48 h, 0 = no limit) -########################################################################################### -# Hardware: Sinilink MOSFET Board XY-WFMS (ESP8266) - sometimes listed as "XY-VFMS" -# https://devices.esphome.io/devices/Sinilink-XY-WFMS -# ------------------------------------------ -# DEVICE GPIO (Sinilink XY-WFMS) -# ------------------------------------------ -# GPIO02 Blue LED, active-low (used for ESPHome status) -# GPIO04 MOSFET output (0V when switched) and Red LED -# GPIO12 Toggle button -# GPIO13 Green LED (used to display fading status) -# -# 3D-printed case for Sinilink XY-WFMS -# https://cults3d.com/en/3d-model/tool/snapfit-enclosure-for-esp8266-sinilink-xy-wfms-5v-36v-mosfet-switch-module -# -########################################################################################## -########################################################################################## +# MQTT COMMANDS: +# - ${mqtt_local_command_topic}/light/set = ON +# - ${mqtt_local_command_topic}/light/set = OFF +# - State publishes to: +# - ${mqtt_local_status_topic}/light/state +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online) +# - Local light logic, fades, restart behaviour, and watchdog timing continue to operate. +# - Local MQTT control and status publishing continue if the MQTT broker is online. +# b) MQTT offline (or HA/MQTT offline) +# - Local light logic, fades, restart behaviour, and watchdog timing continue to operate. +# - MQTT control and MQTT state publishing are unavailable. +# c) Entire WiFi/Network offline +# - Local light logic, fades, restart behaviour, and watchdog timing continue to operate. +# - Accurate time is not needed (SNTP not needed). +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming - device_name: "esp-loungecabinetleds2" # yaml file should be device_name.yaml + device_name: "esp-loungecabinetleds" # yaml file should be device_name.yaml friendly_name: "Lounge Cabinet LEDs" - description_comment: "LED Strip inside the display cabinet upstairs lounge :: Sinilink XY-WFMS" + description_comment: "LED Strip inside the display cabinet upstairs lounge :: Sinilink XY-WFMS (Layout V1.1)" device_area: "Lounge" # Allows the ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Sinilink.XY-WFMS" # Project details. Manufacturer before the dot, device after the dot. - project_version: "v2.0" # Project version denotes release of the YAML file, allowing checking of deployed vs latest version - + project_name: "Sinilink.XY-WFMS" # Project details. Manufacturer before the dot, device after the dot. + project_version: "v2.1" # Project version denotes release of the YAML file, allowing checking of deployed vs latest version + # Passwords & Secrets (Unfortunately, you can't use substitutions inside secret names) - api_key: !secret esp-api_key # If using HA API + api_key: !secret esp-api_key # If using HA API ota_pass: !secret esp-ota_pass # If passwording OTA updates - static_ip_address: !secret esp-loungecabinetleds2_ip # CHANGE THIS + static_ip_address: !secret esp-loungecabinetleds_ip # CHANGE THIS + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} # MQTT LOCAL Controls (This is just my local method of controlling via MQTT, I also use the built in method) mqtt_local_device_name: "lounge-cabinetleds" @@ -82,24 +101,24 @@ substitutions: mqtt_local_device_command_OFF: "OFF" # Device Specific Settings - log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (default), VERBOSE, VERY_VERBOSE - update_interval: "30s" # Update time for general sensors, etc. - led_gamma: "1.2" # Gamma from 1.2-3 is sensible to normalise the LED fading vs PWM - minimum_led_output: "1" # % If at this value or below, we'll switch it completely off - maximum_led_output: "90" # % Maximum output; it is sometimes nice to limit the output for longevity or aesthetics - max_on_default_hours: "24" # The maximum time the LEDs will be on, in case they get left on. 0 = no automatic turn-off - pwm_frequency: "1000" # PWM output Frequency in Hz. High enough to avoid audible/visible artifacts + log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (default), VERBOSE, VERY_VERBOSE + update_interval: "30s" # Update time for general sensors, etc. + led_gamma: "1.2" # Gamma from 1.2-3 is sensible to normalise the LED fading vs PWM + minimum_led_output: "1" # % If at this value or below, we'll switch it completely off + maximum_led_output: "90" # % Maximum output; it is sometimes nice to limit the output for longevity or aesthetics + max_on_default_hours: "24" # The maximum time the LEDs will be on, in case they get left on. 0 = no automatic turn-off + pwm_frequency: "1000" # PWM output Frequency in Hz. High enough to avoid audible/visible artifacts # Device Specific GPIO (so we can easily update for other devices) - device_status_led: GPIO02 - device_mosfet_out: GPIO04 - device_usr_button: GPIO12 # if no button, this is just a fake/safeish choice so it compiles with the generic yaml - device_fading_led: GPIO13 # if no LED, this is just a fake/safeish choice so it compiles with the generic yaml + device_status_led: GPIO2 + device_mosfet_out: GPIO4 + device_usr_button: GPIO12 # if no button, this is just a fake/safeish choice so it compiles with the generic yaml + device_fading_led: GPIO13 # if no LED, this is just a fake/safeish choice so it compiles with the generic yaml -########################################################################################## +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -108,6 +127,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -121,27 +141,31 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - #diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + #diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -########################################################################################## -# ESPHome CORE CONFIGURATION +#:########################################################################################:# +# ESPHOME CORE CONFIGURATION # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" comment: "${description_comment}" area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" on_boot: # Run later so everything is initialised before we touch states. priority: 200 @@ -198,11 +222,11 @@ esphome: # - -fdata-sections # - -DNDEBUG -########################################################################################## +#:########################################################################################:# # ESP PLATFORM AND FRAMEWORK # https://esphome.io/components/esp8266.html # https://esphome.io/components/esp32.html -########################################################################################## +#:########################################################################################:# esp8266: board: esp01_1m restore_from_flash: true # restore some values on reboot @@ -213,47 +237,52 @@ mdns: preferences: flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash -########################################################################################## +#:########################################################################################:# # GLOBAL VARIABLES # https://esphome.io/components/globals.html -########################################################################################## +#:########################################################################################:# globals: # Minimum Brightness % for LEDs (will switch off if <=) - id: min_brightness_pct type: int restore_value: true - initial_value: "${minimum_led_output}" # start/finish at X% + initial_value: "${minimum_led_output}" # start/finish at X% + # Maximum Brightness % for LEDs (should never go beyond this) - id: max_brightness_pct type: int restore_value: false - initial_value: "${maximum_led_output}" # hard cap; never exceed this - # The maximum time the lights will stay on, in hours. Just in case they are left on. 0 = forever + initial_value: "${maximum_led_output}" # hard cap; never exceed this + + # The maximum time the lights will stay on, in hours. Just in case they are left on. 0 = forever - id: max_on_hours type: int restore_value: true initial_value: "${max_on_default_hours}" + # Compile time Gamma - id: led_gamma_f type: float restore_value: false - initial_value: ${led_gamma} # <-- numeric at compile time + initial_value: ${led_gamma} # numeric at compile time # Default Fading Up Time (Selectable and will be retained) - - id: ramp_up_ms # fade-in when turned ON + - id: ramp_up_ms # fade-in when turned ON type: int restore_value: true - initial_value: '5000' # 5 s + initial_value: "5000" # 5 s + # Default Fading Down Time (Selectable and will be retained) - - id: ramp_down_ms # fade-out when turned OFF + - id: ramp_down_ms # fade-out when turned OFF type: int restore_value: true - initial_value: '10000' # 10 s + initial_value: "10000" # 10 s + # Action on Restart. (0=Fade full, 1=Restore brightness, 2=Remain off) - - id: restart_mode + - id: restart_mode type: int restore_value: true - initial_value: '0' # default = Fade Up to Full (so can be deployed with no other setup) + initial_value: "0" # default = Fade Up to Full (so can be deployed with no other setup) # Determine last fade direction. # true when you asked the light to end up ON (Ramp Up) @@ -261,70 +290,78 @@ globals: - id: ramp_switch_target_on type: bool restore_value: true - initial_value: 'false' + initial_value: "false" + # Prevent jitter when adjusting the slider - id: suppress_slider_sync type: bool restore_value: false - initial_value: 'false' - # actual 0..100 seen last time, for restart - - id: last_brightness_pct + initial_value: "false" + + # actual 0..100 seen last time, for restart + - id: last_brightness_pct type: float restore_value: true - initial_value: '0.0' + initial_value: "0.0" + # last published "Output Set (0-100)" integer - id: last_set_pos type: int restore_value: false - initial_value: '-1' - # helper to keep blink time == transition time + initial_value: "-1" + + # helper to keep blink time == transition time - id: last_ramp_ms type: int restore_value: false - initial_value: '0' + initial_value: "0" + # target for "Restore Brightness" scripted ramp - id: restore_target_pct type: float restore_value: false - initial_value: '0.0' + initial_value: "0.0" + # true while a scripted ramp is in progress (to limit flash writes) - id: is_ramping type: bool restore_value: false - initial_value: 'false' + initial_value: "false" + # guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF - id: booting type: bool restore_value: false - initial_value: 'true' + initial_value: "true" + # true only while we are performing a ramp-down that briefly turns the light ON to hit the floor - id: ramping_for_off type: bool restore_value: false - initial_value: 'false' + initial_value: "false" -########################################################################################## +#:########################################################################################:# # LOGGER COMPONENT # https://esphome.io/components/logger.html # Logs all log messages through the serial port and through MQTT topics. -########################################################################################## +#:########################################################################################:# logger: - level: "${log_level}" # INFO Level suggested, or DEBUG for testing + level: "${log_level}" # INFO Level suggested, or DEBUG for testing baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM, Serial control) -######################################################################################### +#:########################################################################################:# # STATUS LED # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: number: ${device_status_led} inverted: true -########################################################################################## +#:########################################################################################:# # MQTT COMMANDS # This adds device-specific MQTT command triggers to the common MQTT configuration. -########################################################################################## +#:########################################################################################:# mqtt: on_message: # Light control to ramp up @@ -332,16 +369,17 @@ mqtt: payload: "${mqtt_local_device_command_ON}" then: - switch.turn_on: mosfet_ramp_switch + # Light control to ramp down - topic: "${mqtt_local_command_topic}/light/set" payload: "${mqtt_local_device_command_OFF}" then: - switch.turn_off: mosfet_ramp_switch -########################################################################################## +#:########################################################################################:# # SWITCH COMPONENT # https://esphome.io/components/switch/ -########################################################################################## +#:########################################################################################:# switch: # Ramp-aware ON/OFF for HA (asymmetric, eased; no bounce) - platform: template @@ -361,10 +399,10 @@ switch: - script.stop: ramp_on_script - script.execute: ramp_off_script -################################################################################################# +#:########################################################################################:# # BUTTON COMPONENT # https://esphome.io/components/button/index.html -################################################################################################# +#:########################################################################################:# button: # Start ramping UP (from current level) - platform: template @@ -404,7 +442,7 @@ button: id(ramping_for_off) = false; id(is_ramping) = false; - // Freeze the light at its *current* level by overwriting the transition + // Freeze the light at its current level by overwriting the transition const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { auto call = id(mosfet_leds).make_call(); @@ -420,12 +458,10 @@ button: id(last_brightness_pct) = pct; } - - -######################################################################################### +#:########################################################################################:# # SELECT COMPONENT # https://esphome.io/components/select/index.html -######################################################################################### +#:########################################################################################:# select: - platform: template id: restart_action @@ -447,10 +483,10 @@ select: id(restart_mode) = 2; } -######################################################################################### +#:########################################################################################:# # BINARY SENSORS # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio id: btn_gpio12 @@ -483,10 +519,10 @@ binary_sensor: - script.stop: ramp_off_script - script.execute: ramp_on_script -########################################################################################## +#:########################################################################################:# # SENSOR COMPONENT # https://esphome.io/components/sensor/ -########################################################################################## +#:########################################################################################:# sensor: - platform: template id: mosfet_output_pct @@ -494,7 +530,7 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 2s # consider 200ms if you want fewer updates + update_interval: 2s # consider 200ms if you want fewer updates lambda: |- const auto &cv = id(mosfet_leds).current_values; return cv.is_on() ? (float) (int)(cv.get_brightness() * 100.0f + 0.5f) : 0.0f; @@ -535,28 +571,29 @@ sensor: if (pwm > 1.0f) pwm = 1.0f; return pwm * 100.0f; -########################################################################################## +#:########################################################################################:# # OUTPUT COMPONENT -# https://esphome.io/components/light/index.html -########################################################################################## +# https://esphome.io/components/output/ +#:########################################################################################:# # An OUTPUT can be binary (0,1) or float, which is any value between 0 and 1. # PWM Outputs such as "ledc" are float. https://esphome.io/components/output/ledc.html -########################################################################################## +#:########################################################################################:# output: - platform: esp8266_pwm id: mosfet_pwm pin: ${device_mosfet_out} frequency: ${pwm_frequency} + - platform: gpio - id: green_led_out # Green LED + id: green_led_out # Green LED pin: number: ${device_fading_led} inverted: false -########################################################################################## +#:########################################################################################:# # LIGHT COMPONENT # https://esphome.io/components/light/ -########################################################################################## +#:########################################################################################:# light: - platform: monochromatic id: mosfet_leds @@ -619,11 +656,10 @@ light: call.set_transition_length(0); call.perform(); - -########################################################################################## +#:########################################################################################:# # NUMBER COMPONENT # https://esphome.io/components/number/ -########################################################################################## +#:########################################################################################:# number: - platform: template id: cfg_ramp_up_s @@ -767,14 +803,13 @@ number: then: - script.execute: max_on_watchdog -########################################################################################## +#:########################################################################################:# # SCRIPT COMPONENT # https://esphome.io/components/script.html # Scripts can be executed nearly anywhere in your device configuration with a single call. -########################################################################################## +#:########################################################################################:# script: - - # Script: ramp up from current level. Obey global max. (LED ON while ramping) + # Script: ramp up from current level. Obey global max. (LED ON while ramping) - id: ramp_on_script mode: restart then: @@ -880,7 +915,6 @@ script: id(last_brightness_pct) = pct; // persist final level } - # Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping) - id: ramp_off_script mode: restart @@ -938,7 +972,7 @@ script: - id: deferred_restore_brightness mode: restart then: - - delay: 5s # let preferences/globals load and light settle + - delay: 5s # let preferences/globals load and light settle - lambda: |- // Use ONLY the exact last saved brightness. float target = id(last_brightness_pct); @@ -968,4 +1002,4 @@ script: - light.turn_off: id: mosfet_leds transition_length: 0s - # (Removed: output.turn_off: green_led_out) # make sure LED is off if no ramp + # (Removed: output.turn_off: green_led_out) # make sure LED is off if no ramp \ No newline at end of file diff --git a/esphome/esp-loungeenvironment.yaml b/esphome/esp-loungeenvironment.yaml index 2d9b11c..4a54981 100644 --- a/esphome/esp-loungeenvironment.yaml +++ b/esphome/esp-loungeenvironment.yaml @@ -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; diff --git a/esphome/esp-loungemiddleswitch.yaml b/esphome/esp-loungemiddleswitch.yaml index d150cdb..20e30bf 100644 --- a/esphome/esp-loungemiddleswitch.yaml +++ b/esphome/esp-loungemiddleswitch.yaml @@ -1,38 +1,90 @@ -########################################################################################## -########################################################################################## -# LOUNGE MIDDLE LIGHTSwITCH +#:########################################################################################:# +# TITLE: LOUNGE MIDDLE LIGHTSWITCH +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungemiddleswitch.yaml +#:########################################################################################:# +# VERSIONS: +# V3.6 2026-03-11 Updated yaml to zorruno layout V1.1 # V3.5 2025-07-28 YAML tidyups -########################################################################################## -# Zemismart KS-811 Triple push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ -# -# NOTES -# - -# -########################################################################################## -########################################################################################## +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Triple push button +# - ESP8266 based +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# - Relay 1 output on GPIO13 +# - Relay 2 output on GPIO12 +# - Relay 3 output on GPIO14 +# - Button 1 input on GPIO16 +# - Button 2 input on GPIO5 +# - Button 3 input on GPIO4 +# - Status LED on GPIO2 +#:########################################################################################:# +# OPERATION NOTES: +# - Button 1: +# - Online with HA Loss manual override ON and HA Loss Test OFF: +# - Uses Home Assistant last-scene logic +# - If last scene is not "All Off", set "All Off" +# - If last scene is "All Off", set "Bright" +# - Offline/test with HA Loss manual override ON: +# - Toggles Relay_1 locally +# - Button 2: +# - Online with HA Loss manual override ON and HA Loss Test OFF: +# - Sets Home Assistant scene "Movie" +# - Offline/test with HA Loss manual override ON: +# - Toggles Relay_2 locally +# - Button 3: +# - Online with HA Loss manual override ON and HA Loss Test OFF: +# - Sets Home Assistant scene "Reading On/Off" +# - Offline/test with HA Loss manual override ON: +# - Toggles Relay_3 locally +# - On API connect: +# - If HA Loss Test is OFF, Relay_1 and Relay_2 follow HA Loss manual override state +# - If HA Loss Test is ON, relay override is not applied +# - HA Loss manual override defaults ON and persists across restarts +# - HA Loss Test defaults OFF and can force offline/test behaviour even when HA is connected +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network online): +# - Device switches to manual/offline behaviour +# - Buttons still operate local relays if HA Loss manual override is ON +# - Home Assistant scene calls are unavailable +# b) MQTT offline (or HA/MQTT offline): +# - This yaml does not depend on MQTT for its button logic +# - If Home Assistant/API is offline, device falls back to manual/offline behaviour +# - Buttons still operate local relays if HA Loss manual override is ON +# c) Entire WiFi/Network offline: +# - Device operates in local manual/offline behaviour only +# - Buttons still operate local relays if HA Loss manual override is ON +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-loungemiddleswitch" friendly_name: "Lounge Middle Lightswitch (3)" - description_comment: "Lounge Main Lightswitch using a Zemismart KS-811 Triple Push Button. Downlights South (1), Downlights Middle (2), Downlights North (3)" + description_comment: "Lounge Main Lightswitch using a Zemismart KS-811 Triple Push Button. Downlights South (1), Downlights Middle (2), Downlights North (3) (Layout V1.1)" device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "Zemismart Technologies.KS-811 Triple" # Project Details - project_version: "v3.5" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_version: "v3.6" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-loungemiddleswitch_ip - #mqtt_command_main_topic: !secret mqtt_local_command_main_topic - #mqtt_status_main_topic: !secret mqtt_local_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} # Device Settings log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE @@ -51,10 +103,11 @@ substitutions: switch_2_name: "Downlights Middle" # Lights are connected via DMX dimmer (another esphome controller) (6 Downlights) switch_3_name: "Downlights North" # Lights are directly connected (2 downlights) -######################################################################################### -# PACKAGES: Included Common Packages +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -62,6 +115,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -79,6 +133,7 @@ packages: #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### #common_sntp: !include common/sntp_common.yaml @@ -88,10 +143,10 @@ packages: #diag_debug: !include common/include_debug_diag_sensors.yaml #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -101,9 +156,9 @@ esphome: name: "${project_name}" version: "${project_version}" -######################################################################################### -# Home Assistant API -######################################################################################### +#:########################################################################################:# +# HOME ASSISTANT API: +#:########################################################################################:# api: on_client_connected: then: @@ -137,38 +192,38 @@ api: level: WARN format: "API disconnected: switching to manual/offline behavior" -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -######################################################################################### +#:########################################################################################:# logger: level: "${log_level}" # INFO Level suggested, or DEBUG for testing #baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -######################################################################################### -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: - number: GPIO02 - inverted: yes + number: GPIO2 + inverted: true -######################################################################################### -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: # GPIO16 for KS-811 first button UNLESS # it is a single button KS-811 in which case it is GPIO00 @@ -176,7 +231,7 @@ binary_sensor: pin: number: GPIO16 mode: INPUT - inverted: True + inverted: true use_interrupt: false # This pin doesn't support interrupts so use polling. Only suppresses a warning. name: "Button 1: ${switch_1_name}" on_multi_click: @@ -231,7 +286,8 @@ binary_sensor: then: - if: condition: - lambda: 'return id(Relay_1).state;' + lambda: |- + return id(Relay_1).state; then: - switch.turn_off: Relay_1 - logger.log: @@ -250,9 +306,9 @@ binary_sensor: # GPIO05 for second button (only for KS-811-2 Double or -3 Triple) - platform: gpio pin: - number: GPIO05 + number: GPIO5 mode: INPUT - inverted: True + inverted: true name: "Button 2: ${switch_2_name}" on_multi_click: # --- Single short click --- @@ -289,7 +345,8 @@ binary_sensor: then: - if: condition: - lambda: 'return id(Relay_2).state;' + lambda: |- + return id(Relay_2).state; then: - switch.turn_off: Relay_2 - logger.log: @@ -310,7 +367,7 @@ binary_sensor: pin: number: GPIO4 mode: INPUT - inverted: True + inverted: true name: "Button 3: ${switch_3_name}" on_multi_click: # --- Single short click --- @@ -347,7 +404,8 @@ binary_sensor: then: - if: condition: - lambda: 'return id(Relay_3).state;' + lambda: |- + return id(Relay_3).state; then: - switch.turn_off: Relay_3 - logger.log: @@ -363,9 +421,10 @@ binary_sensor: level: INFO format: "BTN3: Single click ignored (override OFF)" -######################################################################################### -# TEXT SENSOR COMPONENT -######################################################################################### +#:########################################################################################:# +# TEXT SENSOR COMPONENT: +# https://esphome.io/components/text_sensor/ +#:########################################################################################:# text_sensor: - platform: homeassistant id: ha_last_scene @@ -376,10 +435,10 @@ text_sensor: format: "HA last scene now: %s" args: ["x.c_str()"] -######################################################################################### -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: # GPIO13 for KS-811 first button UNLESS it is KS-811-1 then it is GPIO12 - platform: gpio @@ -436,7 +495,8 @@ switch: - homeassistant.service: service: script.lounge_set_scene data: - scene_name: !lambda 'return id(ha_last_scene).state;' + scene_name: !lambda |- + return id(ha_last_scene).state; - logger.log: level: INFO format: "HA Loss Test OFF: restored last scene: %s" @@ -444,5 +504,4 @@ switch: else: - logger.log: level: WARN - format: "HA Loss Test OFF: cannot restore scene (API not connected or last scene unknown)" - + format: "HA Loss Test OFF: cannot restore scene (API not connected or last scene unknown)" \ No newline at end of file diff --git a/esphome/esp-loungenorthswitch.yaml b/esphome/esp-loungenorthswitch.yaml index ea9b74b..3c2cde1 100644 --- a/esphome/esp-loungenorthswitch.yaml +++ b/esphome/esp-loungenorthswitch.yaml @@ -1,41 +1,86 @@ -########################################################################################## -########################################################################################## -# LOUNGE NORTH SWITCH (Single Switch into hallway) +#:########################################################################################:# +# TITLE: LOUNGE NORTH SWITCH (Single Switch into hallway) +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungenorthswitch.yaml +#:########################################################################################:# +# VERSIONS: +# V4.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V4.0 2025-10-01 Copy from other device -########################################################################################## -# Zemismart KS-811 Single push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Single push button +# - ESP8266 based +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# - Button input on GPIO0 +# - Relay output on GPIO12 +# - Status LED on GPIO2 +#:########################################################################################:# +# OPERATION NOTES: +# - Single wall switch used for Lounge North / hallway control +# - This device uses Home Assistant scene calls when API is connected +# - Single click: +# - Online and HA Loss manual override ON: +# - If last scene is not "All Off", call scene "All Off" +# - If last scene is "All Off", call scene "Bright" +# - Offline and HA Loss manual override ON: +# - Toggle physical Relay_1 +# - Double click: +# - Online only, calls Home Assistant script for scene "Night Light" +# - Long hold (4s+): +# - Online only, calls Home Assistant script for scene "All Off" +# - Also fires Home Assistant event esphome.lounge_switch_hold +# - On API client connect: +# - Applies override state to Relay_1 +# - HA Loss manual override switch defaults ON and is restored after reboot +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network online): +# - API will disconnect and device switches to manual/offline behavior +# - Single click can still toggle Relay_1 when HA Loss manual override is ON +# - Double click and long hold actions that require Home Assistant are ignored # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - This yaml does not currently depend on MQTT for its switch logic +# - If Home Assistant/API is offline, device falls back to manual/offline behavior +# - Single click can still toggle Relay_1 when HA Loss manual override is ON # -########################################################################################## -########################################################################################## +# c) Entire WiFi/Network offline: +# - Device operates in local manual/offline behavior only +# - Single click can still toggle Relay_1 when HA Loss manual override is ON +# - Double click and long hold Home Assistant scene/event actions are unavailable +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-loungenorthswitch" friendly_name: "Lounge North Single Switch (1)" - description_comment: "Main Lounge from hallway Lightswitch using a Zemismart KS-811 Single Push Button. Main Lights (1)" - device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Main Lounge from hallway Lightswitch using a Zemismart KS-811 Single Push Button. Main Lights (1) (Layout V1.1)" + device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Zemismart Technologies.KS-811 Single" # Project Details - project_version: "v4.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Zemismart Technologies.KS-811 Single" # Project Details + project_version: "v4.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-loungenorthswitch_ip - #mqtt_command_main_topic: !secret mqtt_local_command_main_topic - #mqtt_status_main_topic: !secret mqtt_local_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} # Device Settings - log_level: "DEBUG" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for for general sensors etc # MQTT LOCAL Controls @@ -49,14 +94,15 @@ substitutions: #mqtt_remote_status_topic: "${mqtt_status_main_topic}/${mqtt_remote_device_name}" # Topic we will use to view status locally without HA #mqtt_remote_device_command_on: "On" #mqtt_remote_device_command_off: "Off" - + # Switch/Relay/Button Naming & Icons switch_1_name: "Main Lights" # NOTE there is no physical connection to the lights on this switch, it is connected to the dimmer ESPhome for the pelmet lights - -######################################################################################### -# PACKAGES: Included Common Packages + +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -64,6 +110,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -78,23 +125,23 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml - + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -104,6 +151,9 @@ esphome: name: "${project_name}" version: "${project_version}" +#:########################################################################################:# +# HOME ASSISTANT API: +#:########################################################################################:# api: on_client_connected: then: @@ -125,44 +175,44 @@ api: level: WARN format: "API disconnected: switching to manual/offline behavior" -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: level: "${log_level}" #INFO Level suggested, or DEBUG for testing #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -######################################################################################### -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: - number: GPIO02 - inverted: yes + number: GPIO2 + inverted: true -######################################################################################### -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT - inverted: True + inverted: true name: "Button 1: ${switch_1_name}" on_multi_click: @@ -183,7 +233,7 @@ binary_sensor: scene_name: "Night Light" - logger.log: level: INFO - format: "BTN: Double click → Scene Night Light" + format: "BTN: Double click -> Scene Night Light" else: - logger.log: level: INFO @@ -191,8 +241,8 @@ binary_sensor: # --- Single short click --- # Online (and override ON): use HA's last scene to decide. - # If last != "All Off" → send "All Off" - # If last == "All Off" → send "Bright" + # If last != "All Off" -> send "All Off" + # If last == "All Off" -> send "Bright" # Offline (and override ON): toggle physical Relay_1 - timing: - ON for at most 0.5s @@ -218,7 +268,7 @@ binary_sensor: scene_name: "All Off" - logger.log: level: INFO - format: "BTN: Single click (online) → Last scene was not 'All Off' → Set 'All Off'" + format: "BTN: Single click (online) -> Last scene was not 'All Off' -> Set 'All Off'" else: - homeassistant.service: service: script.lounge_set_scene @@ -226,7 +276,7 @@ binary_sensor: scene_name: "Bright" - logger.log: level: INFO - format: "BTN: Single click (online) → Last scene was 'All Off' → Set 'Bright'" + format: "BTN: Single click (online) -> Last scene was 'All Off' -> Set 'Bright'" else: # OFFLINE path: only act if override ON; toggle physical relay - if: @@ -238,17 +288,18 @@ binary_sensor: then: - if: condition: - lambda: 'return id(Relay_1).state;' + lambda: |- + return id(Relay_1).state; then: - switch.turn_off: Relay_1 - logger.log: level: INFO - format: "BTN: Single click (offline) → Relay_1 OFF" + format: "BTN: Single click (offline) -> Relay_1 OFF" else: - switch.turn_on: Relay_1 - logger.log: level: INFO - format: "BTN: Single click (offline) → Relay_1 ON" + format: "BTN: Single click (offline) -> Relay_1 ON" else: - logger.log: level: INFO @@ -272,16 +323,16 @@ binary_sensor: action: "hold" - logger.log: level: INFO - format: "BTN: Long press → Scene All Off + HA event (hold)" + format: "BTN: Long press -> Scene All Off + HA event (hold)" else: - logger.log: level: INFO format: "BTN: Long press ignored (no HA connection)" -######################################################################################### -# TEXT SENSOR COMPONENT -# -######################################################################################### +#:########################################################################################:# +# TEXT SENSOR COMPONENT: +# https://esphome.io/components/text_sensor/ +#:########################################################################################:# text_sensor: - platform: homeassistant id: ha_last_scene @@ -292,13 +343,13 @@ text_sensor: level: DEBUG format: "HA last scene now: %s" args: ["x.c_str()"] - -######################################################################################### -# SWITCH COMPONENT + +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: -# GPIO13 for KS-811 first button UNLESS it is KS-811-1 then it is GPIO12 + # GPIO13 for KS-811 first button UNLESS it is KS-811-1 then it is GPIO12 - platform: gpio name: "Relay 1: ${switch_1_name}" pin: GPIO12 @@ -310,6 +361,4 @@ switch: name: "HA Loss manual override" id: ha_loss_override optimistic: true - restore_mode: RESTORE_DEFAULT_ON - - + restore_mode: RESTORE_DEFAULT_ON \ No newline at end of file diff --git a/esphome/esp-loungepelmetleds2.yaml b/esphome/esp-loungepelmetleds2.yaml index 2c11824..fdc3917 100644 --- a/esphome/esp-loungepelmetleds2.yaml +++ b/esphome/esp-loungepelmetleds2.yaml @@ -1,83 +1,95 @@ -########################################################################################## -########################################################################################## -# Title: LOUNGE - PELMET LEDS (H801, 2x Monochrome PWM) -# Repo: (new) +#:########################################################################################:# +# TITLE: LOUNGE - PELMET LEDS (H801, 2x Monochrome PWM) +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungepelmetleds2.yaml +#:########################################################################################:# +# VERSIONS: +# V2.8 2026-03-11 Updated yaml to zorruno layout V1.1 +# V2.7 2025-09-30 A bunch of fixes for final version +# V2.0 2025-09-30 Based on single MOSFET version; adapted to H801 dual-monochrome (A/B) +# V1.x History from single-channel base maintained in prior comments +#:########################################################################################:# +# HARDWARE: +# - H801 (ESP8266, 5 MOSFET outputs) +# - Used here as 2 independent monochrome PWM channels (A and B) +# - Reference hardware: +# https://devices.esphome.io/devices/Sinilink-XY-WFMS +# - Device GPIO as used here: +# - GPIO02 Blue status LED, active-low (ESPHome status) +# - GPIO15 MOSFET output A (PWM) +# - GPIO13 MOSFET output B (PWM) +# - GPIO05 Red LED (used to display status for Channel A) +# - GPIO01 Green LED (used to display status for Channel B) [UART TX, logger baud=0] +#:########################################################################################:# +# OPERATION NOTES: +# - General-purpose LED controller using an H801 board. +# - Designed for 2 independent monochrome outputs: +# - Channel A +# - Channel B +# - Minimum and maximum output limits are defined in SUBSTITUTIONS per channel. +# - Minimum output allows the light to switch fully OFF at or below the threshold to avoid low-PWM flicker. +# - PWM frequency is set in SUBSTITUTIONS. +# - Restart behaviours: +# - Fade up to full +# - Restore Brightness +# - Remain Off +# - Fade timing scales with the configured values. +# - Exposed in Home Assistant for both A and B: +# - Restart action +# - Fade Up-Down switch +# - Fade up/down times +# - Output percentage +# - Output Set slider +# - Shared maximum ON time +# - Fade Up-Down switch auto-syncs to brightness thresholds and does not itself trigger a ramp during sync. +# - This yaml currently uses Home Assistant API and diagnostics packages. +# - MQTT and SNTP packages are currently disabled in this file. +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network online): +# - Device continues to run its local light logic and stored restart behaviour. +# - Existing light states, watchdog timers, and fades continue locally. +# - No Home Assistant control is available until API connectivity returns. # -# v2.7 - a bunch of fixes for final version -# v2.0-dual - 2025-09-30 Based on single MOSFET version; adapted to H801 dual-monochrome (A/B). -# v1.x (history from single-channel base maintained in comments below) +# b) MQTT offline (or HA/MQTT offline): +# - MQTT is not enabled in this yaml, so MQTT offline has no direct effect on device logic. +# - If Home Assistant/API is also offline, control from HA is unavailable. # -# ------------------------------------------ -# OPERATION (as of v2.x) -# ------------------------------------------ -# 1. General-purpose LED controller. -# 2. Designed here for the H801 5-MOSFET board (ESP8266). Using 2 channels as independent -# monochrome outputs (A and B). The remaining 3 MOSFETs are ignored. -# 3. (In SUBSTITUTIONS) setting for MAX % output to extend LED life (ie can ensure it is only ever 95%) -# 4. (In SUBSTITUTIONS) Minimum output setting; switches fully OFF at/below the minimum to avoid low-PWM flicker. -# 5. (In SUBSTITUTIONS) PWM frequency is set to 1kHz by default. You can increase it, but higher values caused -# resets on some ESP8266 boards. On ESP32 you can run much higher (~40 kHz). -# 6. Min/Max output settings are not exposed in Home Assistant/MQTT by default, but could be. -# With a 1 MB flash, space is tight and only minimal optimisation has been done so far. -# 7. (PACKAGES) include common items: network settings, diagnostic entities, MQTT, and SNTP (optional). -# 8. Default behaviours, for recovery from lost power or reset: -# - "Fade up to full": fade from floor to max on boot. -# - "Restore Brightness": fade from floor to the last non-zero brightness on boot (no on/off blip/flash). -# - "Remain Off": stays off on boot. -# 9. The board LEDs show output on status. Channel A uses the **RED** LED on GPIO5. -# Channel B uses the **GREEN** LED on GPIO1 (UART TX; logger baud=0) -# 10. Fade timing scales with the configured values (proportionally when starting mid-brightness). -# 11. Exposed in Home Assistant/MQTT (duplicated for A and B): -# - Startup action (On,Off,Restore) -# - Fade Up/Down toggle switch -# - Normal On/Off switch (quick ramp up/down) -# - Fade up/down times (0-60s) -# - Output % (pre-gamma) -# - Output Set (1-100, respects min/max). This also changes with other output so reflects value. -# - Many device diagnostics (from the included 'diagnostics' package) -# - Maximum 'on' time before automatic fade-down (1-48 h, 0 = no limit) -# 12. The Fade Up/Down switch auto-syncs to brightness (no ramp is triggered by the sync itself): -# - Stops <33% of cap → switch shows OFF -# - Stops >66% of cap → switch shows ON -########################################################################################### -# Hardware: H801 (ESP8266, 5 MOSFET outputs) -# ------------------------------------------ -# DEVICE GPIO (H801, as used here) -# ------------------------------------------ -# GPIO02 Blue Status LED, active-low (ESPHOME status) -# GPIO12 MOSFET output A (PWM) -# GPIO13 MOSFET output B (PWM) -# GPIO05 Red LED (used to display status for Channel A) -# GPIO01 Green LED (used to display status for Channel B) [UART TX, logger baud=0] -# -########################################################################################## -########################################################################################## +# c) Entire WiFi/Network offline: +# - Device continues to run its local light logic and stored restart behaviour. +# - No HA or MQTT control is available. +# - Accurate time is not needed; SNTP is not required for operation. +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-loungepelmetleds2" # yaml file should be device_name.yaml friendly_name: "Lounge Pelmet LEDs" - description_comment: "Lounge Pelmet LEDs :: H801 dual-channel monochrome" + description_comment: "Lounge Pelmet LEDs :: H801 dual-channel monochrome (Layout V1.1)" device_area: "Lounge" # Allows the ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "H801.5xMOSFET" # Manufacturer before the dot, device after the dot. - project_version: "v2.7" # Project version denotes release of the YAML file + project_version: "v2.8" # Project version denotes release of the YAML file - # Passwords & Secrets (Unfortunately, you can't use substitutions inside secret names) + # Passwords & Secrets (Unfortunately, you can't use substitutions inside secret names) api_key: !secret esp-api_key - ota_pass: !secret esp-ota_pass - static_ip_address: !secret esp-loungepelmetleds2_ip # CHANGE THIS - + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-loungepelmetleds2_ip + current_ip_address: ${static_ip_address} + # Device Specific Settings (shared defaults applied per channel below) - log_level: "NONE" # Use INFO while testing; flip back to NONE later - update_interval: "60s" - led_gamma: "1.6" - pwm_frequency: "1000Hz" + log_level: "NONE" # Use INFO while testing; flip back to NONE later + update_interval: "60s" + led_gamma: "1.6" + pwm_frequency: "1000Hz" max_on_default_hours: "24" # Per-channel output caps (%), internal-only (no HA sliders) @@ -87,49 +99,64 @@ substitutions: maximum_led_output_B: "90" # Device Specific GPIO - #device_status_led: GPIO05 + #device_status_led: GPIO5 device_mosfet_out_A: GPIO15 device_mosfet_out_B: GPIO13 - device_fading_led_A: GPIO05 - device_fading_led_B: GPIO01 + device_fading_led_A: GPIO5 + device_fading_led_B: GPIO1 -########################################################################################## -# PACKAGES -########################################################################################## +#:########################################################################################:# +# PACKAGES: +# Included Common Packages +# https://esphome.io/components/packages.html +#:########################################################################################:# packages: + #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml 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}" + #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include + #file: common/api_common.yaml file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" + #### MQTT #### #common_mqtt: !include # file: common/mqtt_common.yaml # vars: # local_device_name: "${device_name}" - + + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml - #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_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### + #common_sntp: !include common/sntp_common.yaml -########################################################################################## -# ESPHome CORE CONFIGURATION -########################################################################################## + #### DIAGNOSTICS Sensors #### + diag_basic: !include common/include_basic_diag_sensors.yaml + #diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + +#:########################################################################################:# +# ESPHOME CORE CONFIGURATION: +# https://esphome.io/components/esphome.html +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" comment: "${description_comment}" area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" on_boot: priority: 200 then: @@ -171,9 +198,22 @@ esphome: transition_length: 0s - lambda: 'id(booting) = false;' -########################################################################################## -# ESP PLATFORM AND FRAMEWORK -########################################################################################## +# Only if you want to play with build flags... +# platformio_options: +# build_unflags: +# - -flto +# build_flags: +# - -fno-lto +# - -Wl,--gc-sections +# - -ffunction-sections +# - -fdata-sections +# - -DNDEBUG + +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +# https://esphome.io/components/esp32.html +#:########################################################################################:# esp8266: board: esp01_1m restore_from_flash: true @@ -182,25 +222,29 @@ mdns: disabled: true preferences: - flash_write_interval: 5min # reduce flash churn while testing + flash_write_interval: 5min -########################################################################################## -# GLOBAL VARIABLES -########################################################################################## +#:########################################################################################:# +# GLOBAL VARIABLES: +# https://esphome.io/components/globals.html +#:########################################################################################:# globals: # Per-channel brightness caps (internal; set via YAML substitutions) - id: min_brightness_pct_A type: int restore_value: true initial_value: "${minimum_led_output_A}" + - id: max_brightness_pct_A type: int restore_value: false initial_value: "${maximum_led_output_A}" + - id: min_brightness_pct_B type: int restore_value: true initial_value: "${minimum_led_output_B}" + - id: max_brightness_pct_B type: int restore_value: false @@ -216,123 +260,146 @@ globals: - id: ramp_up_ms_A type: int restore_value: true - initial_value: '5000' + initial_value: "5000" + - id: ramp_down_ms_A type: int restore_value: true - initial_value: '10000' + initial_value: "10000" + - id: ramp_up_ms_B type: int restore_value: true - initial_value: '5000' + initial_value: "5000" + - id: ramp_down_ms_B type: int restore_value: true - initial_value: '10000' + initial_value: "10000" # Restart Action. (0=Fade full, 1=Restore brightness, 2=Remain off) - id: restart_mode type: int restore_value: true - initial_value: '1' # align with select initial_option "Restore Brightness" + initial_value: "1" # align with select initial_option "Restore Brightness" # Per-channel runtime state (A) - id: ramp_switch_target_on_A type: bool restore_value: true - initial_value: 'false' + initial_value: "false" + - id: suppress_slider_sync_A type: bool restore_value: false - initial_value: 'false' - - id: suppress_quick_on_A # guard to prevent quick-to-cap on slider turn-on + initial_value: "false" + + - id: suppress_quick_on_A type: bool restore_value: false - initial_value: 'false' + initial_value: "false" + - id: last_brightness_pct_A type: float restore_value: true - initial_value: '0.0' + initial_value: "0.0" + - id: last_set_pos_A type: int restore_value: false - initial_value: '-1' + initial_value: "-1" + - id: last_ramp_ms_A type: uint32_t restore_value: false - initial_value: '0' + initial_value: "0" + - id: last_nonzero_brightness_pct_A type: float restore_value: true - initial_value: '0.0' + initial_value: "0.0" + - id: restore_target_pct_A type: float restore_value: false - initial_value: '0.0' + initial_value: "0.0" + - id: is_ramping_A type: bool restore_value: false - initial_value: 'false' + initial_value: "false" + - id: last_nonzero_tmp_A type: float restore_value: false - initial_value: '0.0' + initial_value: "0.0" + - id: ramping_for_off_A type: bool restore_value: false - initial_value: 'false' + initial_value: "false" # Per-channel runtime state (B) - id: ramp_switch_target_on_B type: bool restore_value: true - initial_value: 'false' + initial_value: "false" + - id: suppress_slider_sync_B type: bool restore_value: false - initial_value: 'false' - - id: suppress_quick_on_B # guard to prevent quick-to-cap on slider turn-on + initial_value: "false" + + - id: suppress_quick_on_B type: bool restore_value: false - initial_value: 'false' + initial_value: "false" + - id: last_brightness_pct_B type: float restore_value: true - initial_value: '0.0' + initial_value: "0.0" + - id: last_set_pos_B type: int restore_value: false - initial_value: '-1' + initial_value: "-1" + - id: last_ramp_ms_B type: uint32_t restore_value: false - initial_value: '0' + initial_value: "0" + - id: last_nonzero_brightness_pct_B type: float restore_value: true - initial_value: '0.0' + initial_value: "0.0" + - id: restore_target_pct_B type: float restore_value: false - initial_value: '0.0' + initial_value: "0.0" + - id: is_ramping_B type: bool restore_value: false - initial_value: 'false' + initial_value: "false" + - id: last_nonzero_tmp_B type: float restore_value: false - initial_value: '0.0' + initial_value: "0.0" + - id: ramping_for_off_B type: bool restore_value: false - initial_value: 'false' + initial_value: "false" # Guard for startup behaviour - id: booting type: bool restore_value: false - initial_value: 'true' + initial_value: "true" # Compile time Gamma (cached; currently unused since PWM% sensors were removed) - id: led_gamma_f @@ -340,48 +407,51 @@ globals: restore_value: false initial_value: ${led_gamma} -########################################################################################## -# LOGGER -########################################################################################## +#:########################################################################################:# +# LOGGER: +# https://esphome.io/components/logger.html +#:########################################################################################:# logger: level: "${log_level}" baud_rate: 0 -######################################################################################### -# STATUS LED -######################################################################################### +#:########################################################################################:# +# STATUS LED: +# https://esphome.io/components/status_led.html +#:########################################################################################:# #status_led: # pin: # number: ${device_status_led} # inverted: true -########################################################################################## -# MQTT COMMANDS -########################################################################################## +#:########################################################################################:# +# MQTT COMMANDS: +#:########################################################################################:# #mqtt: - # on_message handlers commented for efficiency (S8). Uncomment if you need local MQTT control again. - #on_message: - # - topic: "${mqtt_local_command_topic_A}/lightA/set" - # payload: "${mqtt_local_device_command_ON}" - # then: - # - switch.turn_on: mosfet_ramp_switch_a - # - topic: "${mqtt_local_command_topic_A}/lightA/set"} - # payload: "${mqtt_local_device_command_OFF}" - # then: - # - switch.turn_off: mosfet_ramp_switch_a - # - # - topic: "${mqtt_local_command_topic_B}/lightB/set" - # payload: "${mqtt_local_device_command_ON}" - # then: - # - switch.turn_on: mosfet_ramp_switch_b - # - topic: "${mqtt_local_command_topic_B}/lightB/set" - # payload: "${mqtt_local_device_command_OFF}" - # then: - # - switch.turn_off: mosfet_ramp_switch_b +# on_message handlers commented for efficiency. Uncomment if you need local MQTT control again. +# on_message: +# - topic: "${mqtt_local_command_topic_A}/lightA/set" +# payload: "${mqtt_local_device_command_ON}" +# then: +# - switch.turn_on: mosfet_ramp_switch_a +# - topic: "${mqtt_local_command_topic_A}/lightA/set" +# payload: "${mqtt_local_device_command_OFF}" +# then: +# - switch.turn_off: mosfet_ramp_switch_a +# +# - topic: "${mqtt_local_command_topic_B}/lightB/set" +# payload: "${mqtt_local_device_command_ON}" +# then: +# - switch.turn_on: mosfet_ramp_switch_b +# - topic: "${mqtt_local_command_topic_B}/lightB/set" +# payload: "${mqtt_local_device_command_OFF}" +# then: +# - switch.turn_off: mosfet_ramp_switch_b -########################################################################################## -# SWITCHES -########################################################################################## +#:########################################################################################:# +# SWITCH COMPONENT: +# https://esphome.io/components/switch/ +#:########################################################################################:# switch: - platform: template id: mosfet_ramp_switch_a @@ -417,13 +487,15 @@ switch: - script.stop: ramp_on_script_B - script.execute: ramp_off_script_B -################################################################################################# -# BUTTONS (none) -################################################################################################# +#:########################################################################################:# +# BUTTON COMPONENT: +# No standalone template button entities in this yaml +#:########################################################################################:# -######################################################################################### -# SELECTS -######################################################################################### +#:########################################################################################:# +# SELECT COMPONENT: +# https://esphome.io/components/select/index.html +#:########################################################################################:# select: - platform: template id: restart_action @@ -445,9 +517,10 @@ select: id(restart_mode) = 2; } -########################################################################################## -# SENSORS -########################################################################################## +#:########################################################################################:# +# SENSOR COMPONENT: +# https://esphome.io/components/sensor/ +#:########################################################################################:# sensor: # Channel A: Output % (pre-gamma) - platform: template @@ -456,7 +529,7 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 200ms # show real-time ramp + update_interval: 200ms disabled_by_default: true lambda: |- const auto &cv = id(mosfet_leds_A).current_values; @@ -488,22 +561,21 @@ sensor: id(led_output_set_pct_A).publish_state(pos_i); } } - // Auto-sync fade switch to brightness thresholds (no scripts) if (!id(booting) && !id(is_ramping_A)) { - float cap = (float) id(max_brightness_pct_A); // cap in % - float low_th = cap * 0.33f; + float cap = (float) id(max_brightness_pct_A); + float low_th = cap * 0.33f; float high_th = cap * 0.66f; if (cv_now.is_on()) { - float b = x; // current brightness in % - if (b < low_th - 0.25f) { // hysteresis margin + float b = x; + if (b < low_th - 0.25f) { if (id(ramp_switch_target_on_A)) { id(ramp_switch_target_on_A) = false; - id(mosfet_ramp_switch_a).publish_state(false); // UI-only; no ramp + id(mosfet_ramp_switch_a).publish_state(false); } } else if (b > high_th + 0.25f) { if (!id(ramp_switch_target_on_A)) { id(ramp_switch_target_on_A) = true; - id(mosfet_ramp_switch_a).publish_state(true); // UI-only; no ramp + id(mosfet_ramp_switch_a).publish_state(true); } } } @@ -548,10 +620,9 @@ sensor: id(led_output_set_pct_B).publish_state(pos_i); } } - // Auto-sync fade switch to brightness thresholds (no scripts) if (!id(booting) && !id(is_ramping_B)) { float cap = (float) id(max_brightness_pct_B); - float low_th = cap * 0.33f; + float low_th = cap * 0.33f; float high_th = cap * 0.66f; if (cv_now.is_on()) { float b = x; @@ -569,14 +640,16 @@ sensor: } } -########################################################################################## -# OUTPUTS -########################################################################################## +#:########################################################################################:# +# OUTPUT COMPONENT: +# https://esphome.io/components/output/ +#:########################################################################################:# output: - platform: esp8266_pwm id: mosfet_pwm_A pin: ${device_mosfet_out_A} frequency: ${pwm_frequency} + - platform: esp8266_pwm id: mosfet_pwm_B pin: ${device_mosfet_out_B} @@ -587,27 +660,28 @@ output: pin: number: ${device_fading_led_A} inverted: false + - platform: gpio id: fading_led_out_B pin: number: ${device_fading_led_B} inverted: false -########################################################################################## -# LIGHTS -########################################################################################## +#:########################################################################################:# +# LIGHT COMPONENT: +# https://esphome.io/components/light/ +#:########################################################################################:# light: - platform: monochromatic id: mosfet_leds_A name: "${friendly_name} A" output: mosfet_pwm_A restore_mode: RESTORE_DEFAULT_OFF - default_transition_length: 250ms # quick ramp for normal light toggle + default_transition_length: 250ms icon: mdi:led-strip-variant gamma_correct: "${led_gamma}" on_turn_on: - # Start/refresh Max-On watchdog quietly whenever light turns on - if: condition: lambda: 'return id(max_on_hours) > 0;' @@ -628,13 +702,11 @@ light: on_state: - lambda: |- - // Mirror board RED LED to this channel's on/off const auto &cv_s = id(mosfet_leds_A).current_values; const bool is_on = cv_s.is_on() && (cv_s.get_brightness() > 0.0005f); if (is_on) id(fading_led_out_A).turn_on(); else id(fading_led_out_A).turn_off(); - lambda: |- - // Enforce cap if anyone tries to exceed it const float cap = id(max_brightness_pct_A) / 100.0f; const auto &cv = id(mosfet_leds_A).current_values; if (!cv.is_on()) return; @@ -651,7 +723,7 @@ light: name: "${friendly_name} B" output: mosfet_pwm_B restore_mode: RESTORE_DEFAULT_OFF - default_transition_length: 250ms # quick ramp for normal light toggle + default_transition_length: 250ms icon: mdi:led-strip-variant gamma_correct: "${led_gamma}" @@ -676,7 +748,6 @@ light: on_state: - lambda: |- - // Mirror board GREEN LED to this channel's on/off const auto &cv_s = id(mosfet_leds_B).current_values; const bool is_on = cv_s.is_on() && (cv_s.get_brightness() > 0.0005f); if (is_on) id(fading_led_out_B).turn_on(); @@ -693,9 +764,10 @@ light: call.set_transition_length(0); call.perform(); -########################################################################################## -# NUMBERS -########################################################################################## +#:########################################################################################:# +# NUMBER COMPONENT: +# https://esphome.io/components/number/ +#:########################################################################################:# number: - platform: template id: cfg_ramp_up_s_A @@ -777,7 +849,6 @@ number: id(ramp_down_ms_B) = secs * 1000; id(cfg_ramp_down_s_B).publish_state((float) secs); - # Per-channel position slider (0..100 mapped into [min..max]) - platform: template id: led_output_set_pct_A name: "${friendly_name} A Output Set (0-100)" @@ -788,11 +859,11 @@ number: step: 1 lambda: |- const auto &cv = id(mosfet_leds_A).current_values; - float actual = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; // 0..100 actual + float actual = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; float minp = (float) id(min_brightness_pct_A); float maxp = (float) id(max_brightness_pct_A); - if (maxp <= minp) maxp = minp + 1.0f; // avoid div/0 - if (actual <= 0.0f) return 0.0f; // when OFF, show 0 + if (maxp <= minp) maxp = minp + 1.0f; + if (actual <= 0.0f) return 0.0f; float pos = (actual - minp) * 100.0f / (maxp - minp); if (pos < 0.0f) pos = 0.0f; if (pos > 100.0f) pos = 100.0f; @@ -817,22 +888,19 @@ number: else: - lambda: |- id(suppress_slider_sync_A) = true; - float pos = x; // 0..100 - if (pos < 1.0f) pos = 1.0f; // 0 is OFF + float pos = x; + if (pos < 1.0f) pos = 1.0f; if (pos > 100.0f) pos = 100.0f; id(led_output_set_pct_A).publish_state((int) floorf(pos + 0.5f)); - // Map slider position into absolute % within [min..max] float minp = (float) id(min_brightness_pct_A); float maxp = (float) id(max_brightness_pct_A); if (maxp <= minp) maxp = minp + 1.0f; float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; - // Stash target for the ramp script id(restore_target_pct_A) = out_pct; - // Choose duration by direction (up vs down) const auto &cv = id(mosfet_leds_A).current_values; float curr = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; id(last_ramp_ms_A) = (out_pct > curr) ? id(ramp_up_ms_A) : id(ramp_down_ms_A); @@ -852,11 +920,11 @@ number: step: 1 lambda: |- const auto &cv = id(mosfet_leds_B).current_values; - float actual = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; // 0..100 actual + float actual = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; float minp = (float) id(min_brightness_pct_B); float maxp = (float) id(max_brightness_pct_B); - if (maxp <= minp) maxp = minp + 1.0f; // avoid div/0 - if (actual <= 0.0f) return 0.0f; // when OFF, show 0 + if (maxp <= minp) maxp = minp + 1.0f; + if (actual <= 0.0f) return 0.0f; float pos = (actual - minp) * 100.0f / (maxp - minp); if (pos < 0.0f) pos = 0.0f; if (pos > 100.0f) pos = 100.0f; @@ -881,22 +949,19 @@ number: else: - lambda: |- id(suppress_slider_sync_B) = true; - float pos = x; // 0..100 - if (pos < 1.0f) pos = 1.0f; // 0 is OFF + float pos = x; + if (pos < 1.0f) pos = 1.0f; if (pos > 100.0f) pos = 100.0f; id(led_output_set_pct_B).publish_state((int) floorf(pos + 0.5f)); - // Map slider position into absolute % within [min..max] float minp = (float) id(min_brightness_pct_B); float maxp = (float) id(max_brightness_pct_B); if (maxp <= minp) maxp = minp + 1.0f; float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; - // Stash target for the ramp script id(restore_target_pct_B) = out_pct; - // Choose duration by direction (up vs down) const auto &cv = id(mosfet_leds_B).current_values; float curr = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; id(last_ramp_ms_B) = (out_pct > curr) ? id(ramp_up_ms_B) : id(ramp_down_ms_B); @@ -906,8 +971,6 @@ number: - delay: !lambda 'return (uint32_t) id(last_ramp_ms_B);' - lambda: 'id(suppress_slider_sync_B) = false;' - - # Shared "Max On" hours (0=disabled). When light is turned on, watchdog restarts. - platform: template id: cfg_max_on_hours name: "${friendly_name} Max On (h)" @@ -923,11 +986,10 @@ number: set_action: - lambda: |- int hrs = (int) x; - if (hrs < 0) hrs = 0; + if (hrs < 0) hrs = 0; if (hrs > 48) hrs = 48; id(max_on_hours) = hrs; id(cfg_max_on_hours).publish_state((float) hrs); - # Restart/stop watchdogs appropriately for both channels - if: condition: lambda: 'return id(mosfet_leds_A).current_values.is_on();' @@ -949,9 +1011,10 @@ number: then: - script.execute: max_on_watchdog_B -########################################################################################## -# SCRIPTS -########################################################################################## +#:########################################################################################:# +# SCRIPT COMPONENT: +# https://esphome.io/components/script.html +#:########################################################################################:# script: # Ramps: Channel A - id: ramp_on_script_A @@ -959,7 +1022,6 @@ script: then: - lambda: 'id(is_ramping_A) = true;' - script.stop: ramp_off_script_A - # Single transition to CAP for the full configured time - light.turn_on: id: mosfet_leds_A brightness: !lambda 'return id(max_brightness_pct_A) / 100.0f;' @@ -1000,7 +1062,6 @@ script: id(is_ramping_A) = true; id(ramping_for_off_A) = true; - script.stop: ramp_on_script_A - # Single transition directly to OFF for the full configured time - light.turn_off: id: mosfet_leds_A transition_length: !lambda 'return (uint32_t) id(ramp_down_ms_A);' @@ -1039,7 +1100,7 @@ script: float minp = (float) id(min_brightness_pct_A); float maxp = (float) id(max_brightness_pct_A); if (target > 0.0f && target < minp) target = minp; - if (target > maxp) target = maxp; + if (target > maxp) target = maxp; id(restore_target_pct_A) = target; id(last_ramp_ms_A) = id(ramp_up_ms_A); - if: @@ -1048,14 +1109,14 @@ script: then: - lambda: |- id(ramp_switch_target_on_A) = true; - id(suppress_slider_sync_A) = true; - id(suppress_quick_on_A) = true; + id(suppress_slider_sync_A) = true; + id(suppress_quick_on_A) = true; - script.stop: ramp_off_script_A - script.execute: ramp_to_target_script_A - delay: !lambda 'return (uint32_t) id(last_ramp_ms_A);' - lambda: |- - id(suppress_slider_sync_A) = false; - id(suppress_quick_on_A) = false; + id(suppress_slider_sync_A) = false; + id(suppress_quick_on_A) = false; else: - lambda: 'id(ramp_switch_target_on_A) = false;' - light.turn_off: @@ -1146,7 +1207,7 @@ script: float minp = (float) id(min_brightness_pct_B); float maxp = (float) id(max_brightness_pct_B); if (target > 0.0f && target < minp) target = minp; - if (target > maxp) target = maxp; + if (target > maxp) target = maxp; id(restore_target_pct_B) = target; id(last_ramp_ms_B) = id(ramp_up_ms_B); - if: @@ -1155,18 +1216,16 @@ script: then: - lambda: |- id(ramp_switch_target_on_B) = true; - id(suppress_slider_sync_B) = true; - id(suppress_quick_on_B) = true; + id(suppress_slider_sync_B) = true; + id(suppress_quick_on_B) = true; - script.stop: ramp_off_script_B - script.execute: ramp_to_target_script_B - delay: !lambda 'return (uint32_t) id(last_ramp_ms_B);' - lambda: |- - id(suppress_slider_sync_B) = false; - id(suppress_quick_on_B) = false; + id(suppress_slider_sync_B) = false; + id(suppress_quick_on_B) = false; else: - lambda: 'id(ramp_switch_target_on_B) = false;' - light.turn_off: id: mosfet_leds_B - transition_length: 0s -########################################################################################## -########################################################################################## + transition_length: 0s \ No newline at end of file diff --git a/esphome/esp-loungesouthleftswitch.yaml b/esphome/esp-loungesouthleftswitch.yaml index c7859f8..8764bf3 100644 --- a/esphome/esp-loungesouthleftswitch.yaml +++ b/esphome/esp-loungesouthleftswitch.yaml @@ -1,35 +1,86 @@ -########################################################################################## -########################################################################################## -# LOUNGE SOUTH LEFT LIGHTSWITCH +#:########################################################################################:# +# TITLE: LOUNGE SOUTH LEFT LIGHTSWITCH +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungesouthleftswitch.yaml +#:########################################################################################:# +# VERSIONS: +# V4.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V4.0 2025-10-04 Copied from other device -########################################################################################## -# Zemismart KS-811 Double push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Double push button +# - ESP8266 based +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# - Relay 1 output on GPIO13 +# - Relay 2 output on GPIO12 +# - Button 1 input on GPIO16 +# - Button 2 input on GPIO5 +# - Status LED on GPIO2 +#:########################################################################################:# +# OPERATION NOTES: +# - Lounge South Left switch with 2 outputs: +# 1) Wall Washer Left +# 2) Outside Light 1 +# - Button 1 toggles Relay_1 locally +# - Button 2 toggles Relay_2 locally +# - Relay_2 is synchronised with a remote MQTT device: +# - Remote device name: garage-corridor-lights +# - Remote ON/OFF commands are mirrored locally +# - Local Relay_2 ON/OFF changes are published back to the remote topic +# - A guard flag is used to prevent MQTT feedback loops when Relay_2 state changes originate remotely +#:########################################################################################:# +# MQTT COMMANDS: +# - Remote command topic: +# - ${mqtt_remote_command_topic} +# - Remote status topic: +# - ${mqtt_remote_status_topic} +# - Payloads used: +# - ON +# - OFF +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Local button control continues to operate both relays +# - Relay_2 MQTT sync with the remote device continues if MQTT broker is online # -# NOTES -# - -########################################################################################## -########################################################################################## +# b) MQTT offline (or HA/MQTT offline): +# - Local button control continues to operate both relays +# - Relay_2 sync to the remote MQTT device is unavailable +# +# c) Entire WiFi/Network offline: +# - Local button control continues to operate both relays +# - Relay_2 sync to the remote MQTT device is unavailable +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-loungesouthleftswitch" friendly_name: "Lounge South Left Lightswitch (2)" - description_comment: "Lounge South Left Lightswitch using a Zemismart KS-811 Double Push Button. Wall Washer Left (1), Outside Light 1 (2)" - device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Lounge South Left Lightswitch using a Zemismart KS-811 Double Push Button. Wall Washer Left (1), Outside Light 1 (2) (Layout V1.1)" + device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Zemismart Technologies.KS-811 Double" # Project Details - project_version: "v4.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Zemismart Technologies.KS-811 Double" # Project Details + project_version: "v4.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-loungesouthleftswitch_ip + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + mqtt_command_main_topic: !secret mqtt_command_main_topic mqtt_status_main_topic: !secret mqtt_status_main_topic @@ -41,19 +92,19 @@ substitutions: # MQTT REMOTE Controls mqtt_remote_device_name: "garage-corridor-lights" mqtt_remote_command_topic: "${mqtt_command_main_topic}/${mqtt_remote_device_name}" - mqtt_remote_status_topic: "${mqtt_status_main_topic}/${mqtt_remote_device_name}" + mqtt_remote_status_topic: "${mqtt_status_main_topic}/${mqtt_remote_device_name}" mqtt_remote_device_command_ON: "ON" mqtt_remote_device_command_OFF: "OFF" # Switch Naming switch_1_name: "Wall Washer Left" switch_2_name: "Outside Light 1" - #switch_3_name: "Nil" -######################################################################################### -# PACKAGES: Included Common Packages +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -62,6 +113,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -75,23 +127,23 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml - + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -101,64 +153,71 @@ esphome: name: "${project_name}" version: "${project_version}" -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: level: "${log_level}" #INFO Level suggested, or DEBUG for testing #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 +#:########################################################################################:# +# GLOBAL VARIABLES: +#:########################################################################################:# globals: - id: relay2_change_origin_remote type: bool - restore_value: no + restore_value: false initial_value: "false" -######################################################################################### -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: number: GPIO2 - inverted: yes + inverted: true -######################################################################################### -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO16 mode: INPUT - inverted: True - use_interrupt: false # This pin doesn't support interrupts so use polling. Only supresses a warning. + inverted: true + use_interrupt: false # This pin doesn't support interrupts so use polling. Only suppresses a warning. name: "Button 1: ${switch_1_name}" on_press: - switch.toggle: Relay_1 - platform: gpio pin: - number: GPIO05 + number: GPIO5 mode: INPUT - inverted: True + inverted: true name: "Button 2: ${switch_2_name}" on_press: - switch.toggle: Relay_2 +#:########################################################################################:# +# TEXT SENSOR COMPONENT: +# https://esphome.io/components/text_sensor/ +#:########################################################################################:# text_sensor: - platform: mqtt_subscribe id: remote2_status @@ -192,10 +251,10 @@ text_sensor: id(relay2_change_origin_remote) = true; - switch.turn_off: Relay_2 -######################################################################################### -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: - platform: gpio name: "Relay 1: ${switch_1_name}" @@ -223,7 +282,4 @@ switch: - mqtt.publish: topic: "${mqtt_remote_command_topic}" payload: "${mqtt_remote_device_command_OFF}" - - lambda: 'id(relay2_change_origin_remote) = false;' - - - + - lambda: 'id(relay2_change_origin_remote) = false;' \ No newline at end of file diff --git a/esphome/esp-loungesouthrightswitch.yaml b/esphome/esp-loungesouthrightswitch.yaml index 68cefdd..aa46bf5 100644 --- a/esphome/esp-loungesouthrightswitch.yaml +++ b/esphome/esp-loungesouthrightswitch.yaml @@ -1,37 +1,82 @@ -########################################################################################## -########################################################################################## -# LOUNGE SOUTH RIGHT LIGHTSWITCH +#:########################################################################################:# +# TITLE: LOUNGE SOUTH RIGHT LIGHTSWITCH +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungesouthrightswitch.yaml +#:########################################################################################:# +# VERSIONS: +# V4.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V4.0 2025-10-04 Copied from other device -########################################################################################## -# Zemismart KS-811 Triple push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ -# -# NOTES -# - -########################################################################################## -########################################################################################## +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Triple push button +# - ESP8266 based +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# - Relay 1 output on GPIO13 +# - Relay 2 output on GPIO12 +# - Relay 3 output on GPIO14 +# - Button 1 input on GPIO16 +# - Button 2 input on GPIO5 +# - Button 3 input on GPIO4 +# - Status LED on GPIO2 +#:########################################################################################:# +# OPERATION NOTES: +# - Lounge South Right switch with 3 outputs: +# 1) Spare +# 2) Wall Washer Right +# 3) Breakfast Bar LEDs +# - Button 1 toggles Relay_1 locally +# - Button 2 toggles Relay_2 locally +# - Button 3 single click: +# - Offline and HA Loss manual override ON: +# - Toggles Relay_3 locally +# - Online: +# - No local action is taken +# - On API client connect: +# - Applies HA Loss manual override state to Relay_3 +# - HA Loss manual override defaults ON and is restored after reboot +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network online): +# - API disconnects and device switches to manual/offline behavior +# - Button 1 and Button 2 continue to toggle relays locally +# - Button 3 can toggle Relay_3 locally when HA Loss manual override is ON +# b) MQTT offline (or HA/MQTT offline): +# - This yaml does not currently depend on MQTT for its switch logic +# - Local button control continues to work +# - Button 3 can toggle Relay_3 locally when HA Loss manual override is ON +# c) Entire WiFi/Network offline: +# - Device operates in local manual/offline behavior only +# - Local button control continues to work +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-loungesouthrightswitch" friendly_name: "Lounge South Right Lightswitch (3)" - description_comment: "Lounge South Right Lightswitch using a Zemismart KS-811 Triple Push Button. Spare (1), Wall Washer Right (2), Breakfastbar LEDs (3)" - device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Lounge South Right Lightswitch using a Zemismart KS-811 Triple Push Button. Spare (1), Wall Washer Right (2), Breakfastbar LEDs (3) (Layout V1.1)" + device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Zemismart Technologies.KS-811 Triple" # Project Details - project_version: "v4.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Zemismart Technologies.KS-811 Triple" # Project Details + project_version: "v4.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-loungesouthrightswitch_ip - #mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic - #mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} # Device Settings #relay_icon: "mdi:lightbulb-group" @@ -46,12 +91,13 @@ substitutions: # Switch Naming switch_1_name: "Spare" switch_2_name: "Wall Washer Right" - switch_3_name: "Breakfast Bar LEDs" # Connected to another esphome device at the breakfast bar LEDs + switch_3_name: "Breakfast Bar LEDs" # Connected to another esphome device at the breakfast bar LEDs -######################################################################################### -# PACKAGES: Included Common Packages +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -59,6 +105,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -73,23 +120,23 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml - + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -99,6 +146,9 @@ esphome: name: "${project_name}" version: "${project_version}" +#:########################################################################################:# +# HOME ASSISTANT API: +#:########################################################################################:# api: on_client_connected: then: @@ -120,54 +170,54 @@ api: level: WARN format: "API disconnected: switching to manual/offline behavior" -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -############################################# +#:########################################################################################:# logger: level: "${log_level}" #INFO Level suggested, or DEBUG for testing #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -######################################################################################### -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: number: GPIO2 - inverted: yes + inverted: true -######################################################################################### -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO16 mode: INPUT - inverted: True - use_interrupt: false # GPO16 pin doesn't support interrupts so use polling. Only supresses a warning. + inverted: true + use_interrupt: false # GPIO16 pin doesn't support interrupts so use polling. Only suppresses a warning. name: "Button 1: ${switch_1_name}" on_press: - switch.toggle: Relay_1 - platform: gpio pin: - number: GPIO05 + number: GPIO5 mode: INPUT - inverted: True + inverted: true name: "Button 2: ${switch_2_name}" on_press: - switch.toggle: Relay_2 @@ -176,7 +226,7 @@ binary_sensor: pin: number: GPIO4 mode: INPUT - inverted: True + inverted: true name: "Button 3: ${switch_3_name}" on_multi_click: - timing: @@ -186,16 +236,17 @@ binary_sensor: - if: condition: and: - - not: api.connected + - not: + api.connected: - switch.is_on: ha_loss_override then: - switch.toggle: Relay_3 else: [] -######################################################################################### -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: - platform: gpio name: "Relay 1: ${switch_1_name}" @@ -218,5 +269,4 @@ switch: name: "HA Loss manual override" id: ha_loss_override optimistic: true - restore_mode: RESTORE_DEFAULT_ON - + restore_mode: RESTORE_DEFAULT_ON \ No newline at end of file diff --git a/esphome/esp-loungewestswitch.yaml b/esphome/esp-loungewestswitch.yaml index 4845993..27c48e3 100644 --- a/esphome/esp-loungewestswitch.yaml +++ b/esphome/esp-loungewestswitch.yaml @@ -1,38 +1,83 @@ -########################################################################################## -########################################################################################## -# LOUNGE WEST SWITCH (Single Switch from entranceway) +#:########################################################################################:# +# TITLE: LOUNGE WEST SWITCH (Single Switch from entranceway) +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-loungewestswitch.yaml +#:########################################################################################:# +# VERSIONS: +# V4.1 2026-03-11 Updated yaml to zorruno layout V1.1 # V4.0 2025-10-04 Copy from other device -########################################################################################## -# Zemismart KS-811 Single push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Single push button +# - ESP8266 based +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# - Button input on GPIO0 +# - Relay output on GPIO12 +# - Status LED on GPIO2 +#:########################################################################################:# +# OPERATION NOTES: +# - Single wall switch used for Lounge West / entranceway control +# - This device uses Home Assistant scene calls when API is connected +# - Single click: +# - Online and HA Loss manual override ON: +# - If last scene is not "All Off", call scene "All Off" +# - If last scene is "All Off", call scene "Bright" +# - Offline and HA Loss manual override ON: +# - Toggle physical Relay_1 +# - Double click: +# - Online only, calls Home Assistant script for scene "Night Light" +# - Long hold (4s+): +# - Online only, calls Home Assistant script for scene "All Off" +# - Also fires Home Assistant event esphome.lounge_switch_hold +# - On API client connect: +# - Applies override state to Relay_1 +# - HA Loss manual override switch defaults ON and is restored after reboot +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network online): +# - API will disconnect and device switches to manual/offline behavior +# - Single click can still toggle Relay_1 when HA Loss manual override is ON +# - Double click and long hold actions that require Home Assistant are ignored # -# NOTES -# - +# b) MQTT offline (or HA/MQTT offline): +# - This yaml does not currently depend on MQTT for its switch logic +# - If Home Assistant/API is offline, device falls back to manual/offline behavior +# - Single click can still toggle Relay_1 when HA Loss manual override is ON # -########################################################################################## -########################################################################################## +# c) Entire WiFi/Network offline: +# - Device operates in local manual/offline behavior only +# - Single click can still toggle Relay_1 when HA Loss manual override is ON +# - Double click and long hold Home Assistant scene/event actions are unavailable +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-loungewestswitch" friendly_name: "Lounge West Single Switch (1)" - description_comment: "Main Lounge from entranceway lightswitch using a Zemismart KS-811 Single Push Button. Main Lights (1)" - device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Main Lounge from entranceway lightswitch using a Zemismart KS-811 Single Push Button. Main Lights (1) (Layout V1.1)" + device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Zemismart Technologies.KS-811 Single" # Project Details - project_version: "v4.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Zemismart Technologies.KS-811 Single" # Project Details + project_version: "v4.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-loungewestswitch_ip - #mqtt_command_main_topic: !secret mqtt_local_command_main_topic - #mqtt_status_main_topic: !secret mqtt_local_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} # Device Settings log_level: "DEBUG" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE @@ -49,14 +94,15 @@ substitutions: #mqtt_remote_status_topic: "${mqtt_status_main_topic}/${mqtt_remote_device_name}" # Topic we will use to view status locally without HA #mqtt_remote_device_command_on: "On" #mqtt_remote_device_command_off: "Off" - + # Switch/Relay/Button Naming & Icons switch_1_name: "Main Lights" # NOTE there is no physical connection to the lights on this switch, it is connected to the dimmer ESPhome for the pelmet lights - -######################################################################################### -# PACKAGES: Included Common Packages + +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -64,6 +110,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}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### @@ -78,10 +125,10 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml - + #### SNTP (Only use if you want/need accurate timeclocks) #### #common_sntp: !include common/sntp_common.yaml @@ -91,10 +138,10 @@ packages: #diag_debug: !include common/include_debug_diag_sensors.yaml #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -125,44 +172,44 @@ api: level: WARN format: "API disconnected: switching to manual/offline behavior" -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -######################################################################################### +#:########################################################################################:# logger: level: "${log_level}" #INFO Level suggested, or DEBUG for testing #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -######################################################################################### -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: - number: GPIO02 - inverted: yes + number: GPIO2 + inverted: true -######################################################################################### -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO0 mode: INPUT - inverted: True + inverted: true name: "Button 1: ${switch_1_name}" on_multi_click: @@ -183,7 +230,7 @@ binary_sensor: scene_name: "Night Light" - logger.log: level: INFO - format: "BTN: Double click → Scene Night Light" + format: "BTN: Double click -> Scene Night Light" else: - logger.log: level: INFO @@ -191,8 +238,8 @@ binary_sensor: # --- Single short click --- # Online (and override ON): use HA's last scene to decide. - # If last != "All Off" → send "All Off" - # If last == "All Off" → send "Bright" + # If last != "All Off" -> send "All Off" + # If last == "All Off" -> send "Bright" # Offline (and override ON): toggle physical Relay_1 - timing: - ON for at most 0.5s @@ -218,7 +265,7 @@ binary_sensor: scene_name: "All Off" - logger.log: level: INFO - format: "BTN: Single click (online) → Last scene was not 'All Off' → Set 'All Off'" + format: "BTN: Single click (online) -> Last scene was not 'All Off' -> Set 'All Off'" else: - homeassistant.service: service: script.lounge_set_scene @@ -226,7 +273,7 @@ binary_sensor: scene_name: "Bright" - logger.log: level: INFO - format: "BTN: Single click (online) → Last scene was 'All Off' → Set 'Bright'" + format: "BTN: Single click (online) -> Last scene was 'All Off' -> Set 'Bright'" else: # OFFLINE path: only act if override ON; toggle physical relay - if: @@ -238,17 +285,18 @@ binary_sensor: then: - if: condition: - lambda: 'return id(Relay_1).state;' + lambda: |- + return id(Relay_1).state; then: - switch.turn_off: Relay_1 - logger.log: level: INFO - format: "BTN: Single click (offline) → Relay_1 OFF" + format: "BTN: Single click (offline) -> Relay_1 OFF" else: - switch.turn_on: Relay_1 - logger.log: level: INFO - format: "BTN: Single click (offline) → Relay_1 ON" + format: "BTN: Single click (offline) -> Relay_1 ON" else: - logger.log: level: INFO @@ -272,33 +320,32 @@ binary_sensor: action: "hold" - logger.log: level: INFO - format: "BTN: Long press → Scene All Off + HA event (hold)" + format: "BTN: Long press -> Scene All Off + HA event (hold)" else: - logger.log: level: INFO format: "BTN: Long press ignored (no HA connection)" -######################################################################################### -# TEXT SENSOR COMPONENT -# -######################################################################################### +#:########################################################################################:# +# TEXT SENSOR COMPONENT: +# https://esphome.io/components/text_sensor/ +#:########################################################################################:# text_sensor: - platform: homeassistant id: ha_last_scene entity_id: input_text.lounge_last_scene - # logging: helpful when testing on_value: - logger.log: level: DEBUG format: "HA last scene now: %s" args: ["x.c_str()"] - -######################################################################################### -# SWITCH COMPONENT + +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: -# GPIO13 for KS-811 first button UNLESS it is KS-811-1 then it is GPIO12 + # GPIO13 for KS-811 first button UNLESS it is KS-811-1 then it is GPIO12 - platform: gpio name: "Relay 1: ${switch_1_name}" pin: GPIO12 @@ -310,6 +357,4 @@ switch: name: "HA Loss manual override" id: ha_loss_override optimistic: true - restore_mode: RESTORE_DEFAULT_ON - - + restore_mode: RESTORE_DEFAULT_ON \ No newline at end of file diff --git a/esphome/esp-mainbathroomlights.yaml b/esphome/esp-mainbathroomlights.yaml index af77b66..bc1eda0 100644 --- a/esphome/esp-mainbathroomlights.yaml +++ b/esphome/esp-mainbathroomlights.yaml @@ -1,38 +1,81 @@ -########################################################################################## -########################################################################################## -# MAIN BATHROOM LIGHTSWITCH 2 (OBK Converted, BK7231N) +#:########################################################################################:# +# TITLE: MAIN BATHROOM LIGHTSWITCH 2 (OBK Converted, BK7231N) +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-mainbathroomlights.yaml +#:########################################################################################:# +# VERSIONS: +# V2.2 2026-03-11 Updated yaml to zorruno layout V1.1 # V2.1 2026-02-23 Button 3 multi-click publishes MQTT commands to bathroom fan (1x/2x/3x) # V2.0 2026-02-04 Reflash into new switch (old switch electrical failure, now a BK) # V1.0 2025-11-23 Initial -########################################################################################## -# Zemismart KS-811 Triple push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ -# -# NOTES -# - -# -########################################################################################## -########################################################################################## +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Triple push button +# - BK7231N based switch +# - BK72XX board: generic-bk7231n-qfn32-tuya +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# OPERATION NOTES: +# - Main bathroom switch with 3 outputs: +# 1) Main Lights +# 2) Shower Lights +# 3) Cabinet Lights +# - Button 1 toggles Relay_2 (as currently coded in the source yaml) +# - Button 2 toggles Relay_2 +# - Button 3 immediate press action turns OFF Relay_2 and Relay_3 +# - Button 3 also sends MQTT commands to the bathroom fan based on click count: +# - 1 click -> command 1 +# - 2 clicks -> command 2 +# - 3 clicks -> command 3 +# - Relay 1 turn_on action also turns ON Relay_2 and Relay_3 +# - Virtual group switch "All Main Bathroom Lights" allows grouped control in Home Assistant +#:########################################################################################:# +# MQTT COMMANDS: +# - Remote device command topic: +# - ${mqtt_remote_device1_command_topic} +# - Button 3 single click publishes: +# - ${mqtt_remote_device1_command1} +# - Button 3 double click publishes: +# - ${mqtt_remote_device1_command2} +# - Button 3 triple click publishes: +# - ${mqtt_remote_device1_command3} +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Local button control continues to operate the relays. +# - Button 3 MQTT fan commands can still publish if MQTT broker is online. +# - Virtual group switch in HA will be unavailable until HA returns. +# b) MQTT offline (or HA/MQTT offline): +# - Local button control continues to operate the relays. +# - Button 3 fan MQTT commands will not be sent. +# c) Entire WiFi/Network offline: +# - Local button control continues to operate the relays. +# - No MQTT control or status is available. +# - Accurate time is not needed; SNTP is not required for operation. +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-mainbathroomlights" friendly_name: "Main Bathroom Lightswitch (3)" - description_comment: "BK7231N - Main Bathroom Lightswitch using a Zemismart KS-811 Triple Push Button. Main Lights (1), Shower Lights (2), Cabinet Lights (3)" + description_comment: "BK7231N - Main Bathroom Lightswitch using a Zemismart KS-811 Triple Push Button. Main Lights (1), Shower Lights (2), Cabinet Lights (3) (Layout V1.1)" device_area: "Main Bathroom" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "Zemismart Technologies.KS-811 Triple BK7231N" # Project Details - project_version: "v2.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_version: "v2.2" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names - static_ip_address: !secret esp-garageentrylights2_ip + static_ip_address: !secret esp-mainbathroomlights_ip mqtt_command_main_topic: !secret mqtt_command_main_topic #mqtt_status_main_topic: !secret mqtt_status_main_topic @@ -65,10 +108,10 @@ substitutions: mqtt_remote_device1_command2: "20" mqtt_remote_device1_command3: "30" -########################################################################################## +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -94,28 +137,31 @@ packages: #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - #diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + #diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -# Package item removals +#:########################################################################################:# +# PACKAGE ITEM REMOVALS / OVERRIDES: +#:########################################################################################:# wifi: min_auth_mode: !remove # The WPA2 only works on esp32/8266 - reboot_timeout: 15min # override the selection from from the common package - fast_connect: false # (optional) force off, in case package vars change + reboot_timeout: 15min # override the selection from the common package + fast_connect: false # optional; force off in case package vars change mqtt: keepalive: 15s # overriding the value from the common package -########################################################################################## -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" @@ -129,36 +175,36 @@ esphome: # then: # - switch.turn_on: Relay_3 -########################################################################################## -# BUILD FOR BK CHIPSET +#:########################################################################################:# +# BUILD FOR BK CHIPSET: # bk72xx # https://devices.esphome.io/board/bk72xx/ -########################################################################################## +#:########################################################################################:# bk72xx: board: generic-bk7231n-qfn32-tuya -########################################################################################## -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -########################################################################################## +#:########################################################################################:# logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing - baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + level: "${log_level}" # INFO Level suggested, or DEBUG for testing + baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) id: logger_id -########################################################################################## -# STATUS LED +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -########################################################################################## +#:########################################################################################:# status_led: pin: number: P22 #GPIO22 inverted: true -########################################################################################## -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -########################################################################################## +#:########################################################################################:# binary_sensor: - platform: gpio pin: @@ -235,10 +281,10 @@ binary_sensor: topic: "${mqtt_remote_device1_command_topic}" payload: "${mqtt_remote_device1_command3}" -########################################################################################## -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -########################################################################################## +#:########################################################################################:# switch: - platform: gpio name: "Relay 1: ${switch_1_name}" @@ -261,10 +307,10 @@ switch: id: Relay_3 restore_mode: ${relay_restore_mode} -########################################################################################## -# TEMPLATE COMPONENT -########################################################################################## +#:########################################################################################:# +# TEMPLATE COMPONENT: # Virtual group switch for Home Assistant +#:########################################################################################:# - platform: template name: "All Main Bathroom Lights" id: all_main_bathroom_lights diff --git a/esphome/esp-maindishwasherpower.yaml b/esphome/esp-maindishwasherpower.yaml index 0b28e79..7f469e7 100644 --- a/esphome/esp-maindishwasherpower.yaml +++ b/esphome/esp-maindishwasherpower.yaml @@ -1,34 +1,67 @@ -########################################################################################## -########################################################################################## -# MAIN DISHWASHER POWER -# Controlled by a Athom Smart Plug V3 -# package_import_url: github://athom-tech/athom-configs/athom-smart-plug.yaml -# +#:########################################################################################:# +# TITLE: MAIN DISHWASHER POWER +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-maindishwasherpower.yaml +#:########################################################################################:# +# VERSIONS: +# V3.5 2026-03-11 Updated yaml to zorruno layout V1.1 # V3.4 2025-07-30 Changed to Athom V3 # V1.1 2025-06-12 package added for energy entities # V1.0 2025-06-10 YAML Tidyups -# -########################################################################################## -########################################################################################## +#:########################################################################################:# +# HARDWARE: +# - Athom Smart Plug V3 +# - ESP32-C3 based +# - Relay output on GPIO5 +# - Local power button on GPIO3 +# - Power monitoring via Athom V3 common package +# - package_import_url reference: github://athom-tech/athom-configs/athom-smart-plug.yaml +#:########################################################################################:# +# OPERATION NOTES: +# - Controls power to the main dishwasher +# - Uses Athom Smart Plug V3 hardware and Athom V3 common power monitor package +# - Relay is turned ON at boot +# - Local power button toggles the relay +# - Relay status is exposed as a template binary sensor +# - Power/energy monitoring entities are provided by the included Athom V3 package +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT online): +# - Device continues operating normally +# - Relay can still be controlled locally by the hardware power button +# - MQTT remains available if your broker is online +# +# b) MQTT offline (or HA/MQTT offline): +# - Device continues operating locally +# - Relay control and local power monitoring continue to work +# +# c) Entire WiFi/Network offline: +# - Device continues operating locally +# - Relay control and local power monitoring continue to work +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-maindishwasherpower" friendly_name: "Main Dishwasher Power" - description_comment: "Main Dishwasher Power Monitor :: Athom Smart Plug Power Monitor V3" - device_area: "Kitchen" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. - + description_comment: "Main Dishwasher Power Monitor :: Athom Smart Plug Power Monitor V3 (Layout V1.1)" + device_area: "Kitchen" + # Project Naming - project_name: "Athom Technology.Smart Plug V3" # Project Details - project_version: "v1.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Athom Technology.Smart Plug V3" + project_version: "v3.5" # Passwords - api_key: !secret esp-maindishwasherpower_api_key # unfortunately you can't use substitutions inside secrets names - ota_pass: !secret esp-maindishwasherpower_ota_pass # unfortunately you can't use substitutions inside secrets names + api_key: !secret esp-maindishwasherpower_api_key + ota_pass: !secret esp-maindishwasherpower_ota_pass static_ip_address: !secret esp-maindishwasherpower_ip # If we are changing IP addresses, you must update the current IP address here, otherwise it remains @@ -36,17 +69,18 @@ substitutions: current_ip_address: ${static_ip_address} # Device Settings - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + log_level: "INFO" + update_interval: "60s" - # Device Settings + # Relay / Load Settings relay_icon: "mdi:dishwasher" - current_limit : "10" # Current Limit in Amps. AU Plug = 10. IL, BR, EU, UK, US Plug = 16. - -########################################################################################## -# PACKAGES: Included Common Packages + current_limit: "10" # Current Limit in Amps. AU Plug = 10. IL, BR, EU, UK, US Plug = 16. + +#:########################################################################################:# +# PACKAGES: +# Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -54,8 +88,8 @@ packages: vars: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" - local_ota_pass: "${ota_pass}" local_current_ip_address: "${current_ip_address}" + local_ota_pass: "${ota_pass}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -69,34 +103,35 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### #common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - common_sntp: !include common/sntp_common.yaml + common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - diag_debug: !include common/include_debug_diag_sensors.yaml - diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + diag_debug: !include common/include_debug_diag_sensors.yaml + diag_resetcount: !include common/include_resetcount_diag_sensors.yaml - # Device Specific included packages - common_athompowermonV3: !include + #### DEVICE SPECIFIC INCLUDED PACKAGES #### + common_athompowermonv3: !include file: common/athompowermonv3_common.yaml vars: local_current_limit: "${current_limit}" -########################################################################################## -# ESPHome +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" #Appears on the esphome page in HA - area: "${device_area}" - name_add_mac_suffix: False + comment: "${description_comment}" + area: "${device_area}" + name_add_mac_suffix: false min_version: 2024.6.0 project: name: "${project_name}" @@ -108,19 +143,19 @@ esphome: on_boot: priority: 200 then: - - switch.turn_on: "relay" + - switch.turn_on: relay -########################################################################################## -# ESP Platform and Framework +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: # https://esphome.io/components/esp32.html -########################################################################################## +#:########################################################################################:# esp32: board: esp32-c3-devkitm-1 flash_size: 4MB variant: ESP32C3 framework: - type: esp-idf # "esp-idf" OR "arduino". Suggested ESP-IDF Framework, or Plug Out the UART Cable Might Cause ESP32 Hang. - version: recommended # recommended, latest or dev + type: esp-idf + version: recommended preferences: flash_write_interval: 5min @@ -128,24 +163,24 @@ preferences: esp32_improv: authorizer: none -########################################################################################## -# ESPHome LOGGING +#:########################################################################################:# +# LOGGER: # https://esphome.io/components/logger.html -########################################################################################## +#:########################################################################################:# logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing + level: "${log_level}" #baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) #esp8266_store_log_strings_in_flash: false #tx_buffer_size: 64 -########################################################################################## -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -########################################################################################## +#:########################################################################################:# binary_sensor: - platform: gpio pin: - number: GPIO03 + number: GPIO3 mode: INPUT_PULLUP inverted: true name: "Power Button" @@ -156,24 +191,22 @@ binary_sensor: - min_length: 20ms max_length: 500ms then: - - switch.toggle: - id: relay - + - switch.toggle: relay + - platform: template name: "Relay Status" lambda: |- return id(relay).state; -################################################################################################# -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -################################################################################################# +#:########################################################################################:# switch: - platform: gpio name: "Power Output" - pin: GPIO05 + pin: GPIO5 id: relay - restore_mode: RESTORE_DEFAULT_ON # Ensures the relay is restored (or off) at boot - #internal: true # Hides the switch from Home Assistant - icon: "${relay_icon}" - + restore_mode: RESTORE_DEFAULT_ON + #internal: true + icon: "${relay_icon}" \ No newline at end of file diff --git a/esphome/esp-mainhallwaylights1.yaml b/esphome/esp-mainhallwaylights1.yaml new file mode 100644 index 0000000..0a77559 --- /dev/null +++ b/esphome/esp-mainhallwaylights1.yaml @@ -0,0 +1,187 @@ +#:########################################################################################:# +# TITLE: MAIN HALLWAY LIGHTSWITCH 1 (BK7231N) +# zorruno.com layout +#:########################################################################################:# +# REPO: +# +#:########################################################################################:# +# VERSIONS: +# V1.0 2026-04-03 Initial +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Single push button +# - BK7231N based switch +# - BK72XX board: generic-bk7231n-qfn32-tuya +# - pinout/schematic: +# https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# OPERATION NOTES: +# - Main bathroom switch with 1 output: +# 1) Main Hallway Lights +# +#:########################################################################################:# +# MQTT COMMANDS: +# - +#:########################################################################################:# +# OFFLINE NOTES: +# +#:########################################################################################:# + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions +# If NOT using a secrets file, just replace these with the passwords etc (in quotes) +#:########################################################################################:# +substitutions: + # Device Naming + device_name: "esp-mainhallwaylights1" + friendly_name: "Main Hallway Lightswitch (1)" + description_comment: "BK7231N - Main Hallway Lightswitch using a Zemismart KS-811 Single Push Button. Main Hallway Lights (1)" + device_area: "Main Hallway" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Zemismart Technologies.KS-811 Triple BK7231N" # Project Details + project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords + api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names + static_ip_address: !secret esp-mainhallwaylights1_ip + mqtt_command_main_topic: !secret mqtt_command_main_topic + #mqtt_status_main_topic: !secret mqtt_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + + # Device Settings + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for for general sensors etc + + # Default relay restore mode + # Options: RESTORE_DEFAULT_OFF, RESTORE_DEFAULT_ON, ALWAYS_ON, ALWAYS_OFF + relay_restore_mode: "RESTORE_DEFAULT_OFF" + + # Switch Naming + switch_1_name: "Main Hallway Lights" + +#:########################################################################################:# +# PACKAGES: Included Common Packages +# https://esphome.io/components/packages.html +#:########################################################################################:# +packages: + #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### + common_wifi: !include + file: common/network_common.yaml + vars: + local_device_name: "${device_name}" + local_static_ip_address: "${static_ip_address}" + local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" + + #### HOME ASSISTANT API (choose encryption or no encryption options) #### + common_api: !include + file: common/api_common.yaml + #file: common/api_common_noencryption.yaml + vars: + local_api_key: "${api_key}" + + #### MQTT #### + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + + #### WEB PORTAL #### + #common_webportal: !include common/webportal_common.yaml + + #### SNTP (Only use if you want/need accurate timeclocks) #### + #common_sntp: !include common/sntp_common.yaml + + #### DIAGNOSTICS Sensors #### + diag_basic: !include common/include_basic_diag_sensors.yaml + #diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + +#:########################################################################################:# +# PACKAGE ITEM REMOVALS / OVERRIDES: +#:########################################################################################:# +wifi: + min_auth_mode: !remove # The WPA2 only works on esp32/8266 + reboot_timeout: 15min # override the selection from the common package + fast_connect: false # optional; force off in case package vars change + +mqtt: + keepalive: 15s # overriding the value from the common package + +#:########################################################################################:# +# ESPHOME: +# https://esphome.io/components/esphome.html +#:########################################################################################:# +esphome: + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" # Appears on the esphome page in HA + area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" +# on_boot: +# priority: 200 +# then: +# - switch.turn_on: Relay_3 + +#:########################################################################################:# +# BUILD FOR BK CHIPSET: +# bk72xx +# https://devices.esphome.io/board/bk72xx/ +#:########################################################################################:# +bk72xx: + board: generic-bk7231n-qfn32-tuya + +#:########################################################################################:# +# LOGGER: +# https://esphome.io/components/logger.html +#:########################################################################################:# +logger: + level: "${log_level}" # INFO Level suggested, or DEBUG for testing + baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + id: logger_id + +#:########################################################################################:# +# STATUS LED: +# https://esphome.io/components/status_led.html +#:########################################################################################:# +status_led: + pin: + number: P22 #GPIO22 + inverted: true + +#:########################################################################################:# +# BINARY SENSORS: +# https://esphome.io/components/binary_sensor/ +#:########################################################################################:# +binary_sensor: + - platform: gpio + pin: + number: P17 + mode: + input: true + pullup: true + inverted: true + name: "Button 1: ${switch_1_name}" + on_press: + - delay: 50ms + - switch.toggle: Relay_1 + + +#:########################################################################################:# +# SWITCH COMPONENT: +# https://esphome.io/components/switch/ +#:########################################################################################:# +switch: + - platform: gpio + name: "Relay 1: ${switch_1_name}" + pin: P14 #GPIO14 + id: Relay_1 + restore_mode: ${relay_restore_mode} diff --git a/esphome/esp-mainhallwaylights2.yaml b/esphome/esp-mainhallwaylights2.yaml new file mode 100644 index 0000000..73368b1 --- /dev/null +++ b/esphome/esp-mainhallwaylights2.yaml @@ -0,0 +1,193 @@ +#:########################################################################################:# +# TITLE: MAIN HALLWAY LIGHTSWITCH 2 (BK7231N) +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-mainhallwaylights2.yaml +#:########################################################################################:# +# VERSIONS: +# V1.1 2026-04-03 Updated yaml to zorruno layout V1.1; corrected KS-811 single naming and operation notes; updated BK7231N single-switch pin mapping +# V1.0 2026-04-03 Initial +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Single push button +# - BK7231N based switch +# - BK72XX board: generic-bk7231n-qfn32-tuya +# - BK7231N single-switch pin mapping checked against KS-811 BK references +#:########################################################################################:# +# OPERATION NOTES: +# - Main hallway nightlight switch with 1 output: +# 1) Main Hallway Nightlights +# - A single press of the physical button toggles Relay 1 ON/OFF +# - Status LED uses P22 +#:########################################################################################:# +# MQTT COMMANDS: +# - None +#:########################################################################################:# +# OFFLINE NOTES: +# - a) Home Assistant offline (network and MQTT online): +# - Device remains on WiFi and MQTT +# - Physical button still toggles relay locally +# - b) MQTT offline (or Home Assistant and MQTT offline): +# - Physical button still toggles relay locally +# - Remote control/state sync is unavailable until MQTT returns +# - c) Entire WiFi/network offline: +# - Physical button still toggles relay locally +# - Accurate time is not needed; SNTP is not used +#:########################################################################################:# + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions +# If NOT using a secrets file, just replace these with the passwords etc (in quotes) +#:########################################################################################:# +substitutions: + # Device Naming + device_name: "esp-mainhallwaylights2" + friendly_name: "Main Hallway Nightlights (1)" + description_comment: "BK7231N - Main Hallway Nightlights using a Zemismart KS-811 Single Push Button. Main Hallway Nightlights (1) (Layout V1.1)" + device_area: "Main Hallway" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Zemismart Technologies.KS-811 Single BK7231N" # Project Details + project_version: "v1.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords + api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names + static_ip_address: !secret esp-mainhallwaylights2_ip + mqtt_command_main_topic: !secret mqtt_command_main_topic + #mqtt_status_main_topic: !secret mqtt_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} + + # Device Settings + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for for general sensors etc + + # Default relay restore mode + # Options: RESTORE_DEFAULT_OFF, RESTORE_DEFAULT_ON, ALWAYS_ON, ALWAYS_OFF + relay_restore_mode: "RESTORE_DEFAULT_OFF" + + # Switch Naming + switch_1_name: "Main Hallway Nightlights" + +#:########################################################################################:# +# PACKAGES: Included Common Packages +# https://esphome.io/components/packages.html +#:########################################################################################:# +packages: + #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### + common_wifi: !include + file: common/network_common.yaml + vars: + local_device_name: "${device_name}" + local_static_ip_address: "${static_ip_address}" + local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" + + #### HOME ASSISTANT API (choose encryption or no encryption options) #### + common_api: !include + file: common/api_common.yaml + #file: common/api_common_noencryption.yaml + vars: + local_api_key: "${api_key}" + + #### MQTT #### + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + + #### WEB PORTAL #### + #common_webportal: !include common/webportal_common.yaml + + #### SNTP (Only use if you want/need accurate timeclocks) #### + #common_sntp: !include common/sntp_common.yaml + + #### DIAGNOSTICS Sensors #### + diag_basic: !include common/include_basic_diag_sensors.yaml + #diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + +#:########################################################################################:# +# PACKAGE ITEM REMOVALS / OVERRIDES: +#:########################################################################################:# +wifi: + min_auth_mode: !remove # The WPA2 only works on esp32/8266 + reboot_timeout: 15min # override the selection from the common package + fast_connect: false # optional; force off in case package vars change + +mqtt: + keepalive: 15s # overriding the value from the common package + +#:########################################################################################:# +# ESPHOME: +# https://esphome.io/components/esphome.html +#:########################################################################################:# +esphome: + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" # Appears on the esphome page in HA + area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" + +#:########################################################################################:# +# BUILD FOR BK CHIPSET: +# bk72xx +# https://devices.esphome.io/board/bk72xx/ +#:########################################################################################:# +bk72xx: + board: generic-bk7231n-qfn32-tuya + +#:########################################################################################:# +# LOGGER: +# https://esphome.io/components/logger.html +#:########################################################################################:# +logger: + level: "${log_level}" # INFO Level suggested, or DEBUG for testing + baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + id: logger_id + +#:########################################################################################:# +# STATUS LED: +# https://esphome.io/components/status_led.html +#:########################################################################################:# +status_led: + pin: + number: P22 # GPIO22 + inverted: true + +#:########################################################################################:# +# BINARY SENSORS: +# https://esphome.io/components/binary_sensor/ +#:########################################################################################:# +binary_sensor: + - platform: gpio + id: button_1 + internal: true + pin: + number: P24 # GPIO24 + mode: + input: true + pullup: true + inverted: true + filters: + - delayed_on: 20ms + on_press: + - switch.toggle: Relay_1 + +#:########################################################################################:# +# SWITCH COMPONENT: +# https://esphome.io/components/switch/ +#:########################################################################################:# +switch: + - platform: gpio + name: "Relay 1: ${switch_1_name}" + pin: P16 # GPIO16 + id: Relay_1 + restore_mode: ${relay_restore_mode} \ No newline at end of file diff --git a/esphome/esp-mainkitchenlights.yaml b/esphome/esp-mainkitchenlights.yaml index 5742f50..ba25205 100644 --- a/esphome/esp-mainkitchenlights.yaml +++ b/esphome/esp-mainkitchenlights.yaml @@ -1,59 +1,77 @@ -########################################################################################## -########################################################################################## -# Main Kitchen LIGHTSWITCH -# V3.7 2025-09-14 upload to this lightswitch from copy -# -########################################################################################## -# Zemismart KS-811 Double push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ -# -# NOTES -# - Light switch with 2 sets of lights -# -########################################################################################## -########################################################################################## +#:########################################################################################:# +# TITLE: MAIN KITCHEN LIGHTSWITCH +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-mainkitchenlights.yaml +#:########################################################################################:# +# VERSIONS: +# V3.8 2026-03-11 Updated yaml to zorruno layout V1.1 +# V3.7 2025-09-14 Upload to this lightswitch from copy +#:########################################################################################:# +# HARDWARE: +# - Zemismart KS-811 Double push button (KS-811-2) +# - ESP8266 (esp01_1m class) +# - Buttons: GPIO16 (Button 1), GPIO05 (Button 2) +# - Relays: GPIO13 (Relay 1), GPIO12 (Relay 2) +# - Status LED: GPIO2 (inverted) +# - Reference: https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +#:########################################################################################:# +# OPERATION NOTES: +# - 2 button wall switch controlling 2 relays +# - Button 1 toggles Relay 1 (Main Lights) +# - Button 2 toggles Relay 2 (Benchtop Lights) +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant OFFLINE, but Network and MQTT ONLINE +# - Physical buttons still toggle the relays locally +# - If MQTT is online, any standard MQTT diagnostics from your common package continue to publish +# b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) +# - Physical buttons still toggle the relays locally +# - HA control via API remains available (switch entities still work) +# c) Entire WiFi/Network OFFLINE +# - Physical buttons still toggle the relays locally (standalone operation) +# - Accurate time is not needed (SNTP not required) +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS + +#:########################################################################################:# +# SUBSTITUTIONS: Specific device variable substitutions # If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# substitutions: - # Device Naming + # Device Naming device_name: "esp-mainkitchenlights" friendly_name: "Main Kitchen Lightswitch (2)" - description_comment: "Main Kitchen lightswitch using a Zemismart KS-811 Double Push Button. Main Lights (1), Bench Lights (2)" - device_area: "Kitchen" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Main Kitchen lightswitch using a Zemismart KS-811 Double Push Button. Main Lights (1), Bench Lights (2) (Layout V1.1)" + device_area: "Kitchen" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming - project_name: "Zemismart Technologies.KS-811 Double" # Project Details - project_version: "v3.7" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_name: "Zemismart Technologies.KS-811 Double" # Project Details + project_version: "v3.8" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords & Secrets api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names static_ip_address: !secret esp-mainkitchenlights_ip - #mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic - #mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + + # If we are changing IP addresses, you must update the current IP address here, otherwise it remains + # Don't forget to switch it back when changed. + current_ip_address: ${static_ip_address} # Device Settings - #relay_icon: "mdi:lightbulb-group" - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for for general sensors etc - # MQTT LOCAL Controls - #mqtt_device_name: "bedroom2-lights" - #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA - #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA - # Switch Naming switch_1_name: "Main Lights" switch_2_name: "Benchtop Lights" - #switch_3_name: "Nil" -######################################################################################### + +#:########################################################################################:# # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include @@ -62,6 +80,7 @@ packages: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" + local_current_ip_address: "${current_ip_address}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -75,73 +94,74 @@ packages: file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - + #### WEB PORTAL #### common_webportal: !include common/webportal_common.yaml + #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml + #common_sntp: !include common/sntp_common.yaml #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + #diag_debug: !include common/include_debug_diag_sensors.yaml + #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml -######################################################################################### -# ESPHome + +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -######################################################################################### +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" # Appears on the ESPHome page in HA area: "${device_area}" project: name: "${project_name}" version: "${project_version}" -# on_boot: -# priority: 200 -# then: -# - switch.turn_on: Relay_2 # Stays on permanently -######################################################################################### -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -######################################################################################### + +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: board: esp01_1m - early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + early_pin_init: false # Recommended false where switches are involved. Defaults to true. board_flash_mode: dout # Default is dout -######################################################################################### -# ESPHome Logging Enable -# https://esphome.io/components/logger.html -############################################# -logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing - #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 -######################################################################################### -# STATUS LED +#:########################################################################################:# +# LOGGING: +# https://esphome.io/components/logger.html +#:########################################################################################:# +logger: + level: "${log_level}" + #baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + + +#:########################################################################################:# +# STATUS LED: # https://esphome.io/components/status_led.html -######################################################################################### +#:########################################################################################:# status_led: pin: number: GPIO2 - inverted: yes + inverted: true -######################################################################################### -# BINARY SENSORS + +#:########################################################################################:# +# BINARY SENSORS: # https://esphome.io/components/binary_sensor/ -######################################################################################### +#:########################################################################################:# binary_sensor: - platform: gpio pin: number: GPIO16 mode: INPUT - inverted: True + inverted: true + use_interrupt: false # GPIO16 pin doesn't support interrupts so use polling (suppresses warning). name: "Button 1: ${switch_1_name}" on_press: - switch.toggle: Relay_1 @@ -150,25 +170,16 @@ binary_sensor: pin: number: GPIO05 mode: INPUT - inverted: True + inverted: true name: "Button 2: ${switch_2_name}" on_press: - switch.toggle: Relay_2 -# KS-811-2 is a double only -# - platform: gpio -# pin: -# number: GPIO4 -# mode: INPUT -# inverted: True -# name: "Button 3: ${switch_3_name}" -# on_press: -# - switch.toggle: Relay_3 -######################################################################################### -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH COMPONENT: # https://esphome.io/components/switch/ -######################################################################################### +#:########################################################################################:# switch: - platform: gpio name: "Relay 1: ${switch_1_name}" @@ -178,12 +189,4 @@ switch: - platform: gpio name: "Relay 2: ${switch_2_name}" pin: GPIO12 - id: Relay_2 - -# KS-811-2 is a double only -# - platform: gpio -# name: "Relay 3: ${switch_3_name}" -# pin: GPIO14 -# id: Relay_3 - - + id: Relay_2 \ No newline at end of file diff --git a/esphome/esp-masterbathtowelrail.yaml b/esphome/esp-masterbathtowelrail.yaml index 02e2860..189c1c2 100644 --- a/esphome/esp-masterbathtowelrail.yaml +++ b/esphome/esp-masterbathtowelrail.yaml @@ -1,8 +1,12 @@ #:########################################################################################:# # TITLE: MASTER BATHROOM HEATED TOWEL RAIL -# zorruno.com layout v1.0 2026 +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-masterbathtowelrail.yaml #:########################################################################################:# # VERSIONS: +# V2.3 2026-03-11 Updated yaml to zorruno layout V1.1 # V2.2 2026-01-30 Added Morning/Evening Timer enable switches (gate timer windows) # V2.1 2025-06-12 Added select and button to chose modes, added countdown & startup to boost # V2.0 2025-06-05 YAML Tidyups @@ -10,8 +14,8 @@ # V1.0 2025-02-14 Initial Version #:########################################################################################:# # HARDWARE: -# Controlled by a Sonoff Basic -# pinout/schematic: https://devices.esphome.io/devices/sonoff-basic-r4-v1.0/ +# - Controlled by a Sonoff Basic +# - pinout/schematic: https://devices.esphome.io/devices/sonoff-basic-r4-v1.0/ #:########################################################################################:# # OPERATION NOTES: # - It allows the device to work in a standalone timer style operation @@ -21,7 +25,7 @@ # - It uses SNTP for time setting (but obviously only if wifi & networking are working) # - It will default to an internal timer if no wifi. To reset internal timer, reboot the device at 12pm (noon) # - If on a network and there is a MQTT server, you can set the on/off times via MQTT (See below commands) -# - You can set 4 modes ON/OFF/TIMER/BOOST via MQTT. Setting BOOST gives you a oneshot operation +# - You can set 4 modes ON/OFF/TIMER/BOOST via MQTT. Setting BOOST gives you a oneshot operation # - Any new timer times set via MQTT will be remembered though a reboot # - On startup, or a reboot, the device will always turn on for the BOOST Duration (BOOST mode, default 2 hours) # - TIMER mode will always be switched on after BOOST mode is complete @@ -30,7 +34,7 @@ #:########################################################################################:# # MQTT COMMANDS: # Values will be set in place on the update_interval time, not immediately -# Use 00:00 in 24hr format for time setting. (Note there is no weekday/weekend setting) +# Use 00:00 in 24hr format for time setting. (Note there is no weekday/weekend setting) # mqtt_timer_topic/morning-on/06:00 : Time device will go on # mqtt_timer_topic/morning-off/08:00 : Time device will go off # mqtt_timer_topic/evening-on/09:00 : Time device will go on @@ -39,7 +43,7 @@ # mqtt_timer_topic/operation/ON : Device permanently on # mqtt_timer_topic/operation/OFF : Device permanently off # mqtt_timer_topic/operation/TIMER : Device will obey timer settings -# mqtt_timer_topic/operation/BOOST : Turn on for (boost_duration) minutes then BOOST (also on startup) +# mqtt_timer_topic/operation/BOOST : Turn on for (boost_duration) minutes then BOOST (also on startup) # # operation_mode: # 0 = OFF @@ -50,15 +54,14 @@ # OFFLINE NOTES: # a) Home Assistant OFFLINE, but Network and MQTT ONLINE # - The towel rail will stick to its assigned schedule (and should remember on reboot) -# - Shedule times and on/off switching can still occur via MQTT +# - Schedule times and on/off switching can still occur via MQTT # - Other switches such as the IR Heater/Fan combo can still command the towel rail # b) HA/MQTT OFFLINE -# With no automation controllers, the HTR will still remember its timing functions, and will -# turn on once or twice per day. If internet/wifi is still available, timing will be accurate. +# - With no automation controllers, the HTR will still remember its timing functions, and will +# turn on once or twice per day. If internet/wifi is still available, timing will be accurate. # c) Internet/Wifi OFFLINE -# The HTR will still come on once or twice per day (depending on previous settings) however -# timing will likely shift. To make timing more accurate, it can be powered down then up at 12pm. -# Obviously this may drift again over time. +# - The HTR will still come on once or twice per day (depending on previous settings) +# - Timeclocks will drift without SNTP and can be reset by power cycling at 12pm (midday) #:########################################################################################:# #:########################################################################################:# @@ -69,12 +72,12 @@ substitutions: # Device Naming device_name: "esp-masterbathtowelrail" friendly_name: "Master Bathroom Towelrail" - description_comment: "Sonoff Basic controlling ON/OFF/Timer for the Heated Towel Rail in the Master Bathroom" + description_comment: "Sonoff Basic controlling ON/OFF/Timer for the Heated Towel Rail in the Master Bathroom (Layout V1.1)" device_area: "Main Bathroom" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "Sonoff Technologies.Sonoff Basic V1" # Project Details - project_version: "v2.2" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_version: "v2.3" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # Passwords api_key: !secret esp-masterbathtowelrail_api_key # unfortunately you can't use substitutions inside secrets names @@ -109,8 +112,8 @@ packages: vars: local_device_name: "${device_name}" local_static_ip_address: "${static_ip_address}" - local_ota_pass: "${ota_pass}" local_current_ip_address: "${current_ip_address}" + local_ota_pass: "${ota_pass}" #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include @@ -606,7 +609,7 @@ sensor: unit_of_measurement: "mins" accuracy_decimals: "0" update_interval: "${update_interval}" - internal: True # No need to show this in Home Assistant + internal: true # No need to show this in Home Assistant lambda: |- return id(current_mins); @@ -787,4 +790,4 @@ interval: //id(mqtt_client).publish("${mqtt_timer_topic}/operation", "TIMER"); } } - - script.execute: evaluate_relay_state + - script.execute: evaluate_relay_state \ No newline at end of file diff --git a/esphome/esp-officeduallights.yaml b/esphome/esp-officeduallights.yaml index 2d860a9..15d1146 100644 --- a/esphome/esp-officeduallights.yaml +++ b/esphome/esp-officeduallights.yaml @@ -1,204 +1,222 @@ -############################################# -############################################# -# OFFICE DUAL LIGHT CONTROL -# - Overhead cool white lights -# - Right hand warm bunker light +#:########################################################################################:# +# TITLE: OFFICE DUAL LIGHT CONTROL +# zorruno.com layout v1.1 2026 +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-officeduallights.yaml +#:########################################################################################:# +# VERSIONS: +# V2.5 2026-03-11 Updated yaml to zorruno layout V1.1 +# V2.4 2025-06-30 Tidied up MQTT direct relay control (esps can control each other via MQTT) +# V2.3 2025-06-18 Added MQTT direct relay control +#:########################################################################################:# +# HARDWARE: +# - Sonoff Dual R1 +# - ESP8266 based +# - 2 x relay outputs +# - 2 x local push buttons +# - Relay control via UART serial commands +# - Status LED on GPIO13 +#:########################################################################################:# +# OPERATION NOTES: +# - Controls 2 office light circuits: +# - Overhead cool white lights +# - Right hand warm bunker light +# - Local button 1 toggles relay/light 1 +# - Local button 2 toggles relay/light 2 +# - Relay state changes are sent out via MQTT status topics +# - Template binary lights drive the template relay switches +# - Sonoff Dual R1 requires UART serial packets to operate the physical relays # -# Controlled by a Sonoff Dual R1 -# A sonoff dual uses serial data to turn the relays on/off +# MQTT COMMANDS: +# - Command relay 1: +# - ${mqtt_local_command_topic}/relay1/set ON or OFF +# - Command relay 2: +# - ${mqtt_local_command_topic}/relay2/set ON or OFF +# - Relay 1 status publishes to: +# - ${mqtt_local_status_topic}/relay1/state +# - Relay 2 status publishes to: +# - ${mqtt_local_status_topic}/relay2/state +#:########################################################################################:# +# OFFLINE NOTES: +# a) Home Assistant offline (network and MQTT still online): +# - Device continues to operate from local buttons +# - Device can still be controlled directly by MQTT +# - Relay status still publishes by MQTT if broker is available # -# V2.4 - 2025-06-30 Tidied up MQTT direct relay control (esps can control each other via MQTT) -# V2.3 - 2025-06-18 Added MQTT direct relay control +# b) MQTT offline (or HA and MQTT both offline): +# - Device continues to operate from local buttons only +# - No direct inter-ESP MQTT control available +# - No MQTT state feedback available # -# NOTES: -# Command the lights on with MQTT -# ${mqtt_local_command_full_topic}/relay1/set ON or OFF -# ${mqtt_local_command_full_topic}/relay2/set ON or OFF -# ${mqtt_local_status_full_topic}/relay1/set ON or OFF -# ${mqtt_local_status_full_topic}/relay2/set ON or OFF -# -########################################################################################## -########################################################################################## +# c) Entire WiFi / Network offline: +# - Device continues to operate from local buttons only +# - No HA control or MQTT control/status available +# - Accurate time is not needed; SNTP is not required for operation +#:########################################################################################:# -########################################################################################## -# SPECIFIC DEVICE VARIABLE SUBSTITUTIONS -# If NOT using a secrets file, just replace these with the passwords etc (in quotes) -########################################################################################## +#:########################################################################################:# +# SUBSTITUTIONS: +# Specific device variable substitutions +#:########################################################################################:# substitutions: # Device Naming device_name: "esp-officeduallights" friendly_name: "Office Dual Lights" - description_comment: "Dual Office Lights (Overhead and right hand Bunker) :: Sonoff Dual R1" - device_area: "Office" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + description_comment: "Dual Office Lights (Overhead and right hand Bunker) :: Sonoff Dual R1 (Layout V1.1)" + device_area: "Office" # Project Naming - project_name: "Sonoff Technologies.Sonoff Dual R1" # Project Details - project_version: "v2.3" # Project V denotes release of yaml file, allowing checking of deployed vs latest version - - # Passwords & Secrets + project_name: "Sonoff Technologies.Sonoff Dual R1" + project_version: "v2.5" + + # Passwords and Secrets api_key: !secret esp-api_key - ota_pass: !secret esp-ota_pass - static_ip_address: !secret esp-officeduallights_ip # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-officeduallights_ip + current_ip_address: ${static_ip_address} mqtt_local_command_main_topic: !secret mqtt_command_main_topic mqtt_local_status_main_topic: !secret mqtt_status_main_topic - + # Device Settings relay_icon: "mdi:lightbulb-group" - log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE - update_interval: "60s" # update time for for general sensors etc + log_level: "NONE" + update_interval: "60s" # MQTT Controls mqtt_device_name: "office-dual-lights" - mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA - mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" + mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Switch Naming - switch_1_name: "Dual L1 Relay" - relay_1_icon: "mdi:lightbulb" - light_1_name: "Light 1 (Right Hand Bunker Light)" - switch_2_name: "Dual L2 Relay" - relay_2_icon: "mdi:lightbulb" - light_2_name: "Light 2 (Cool White Overhead Lights)" + switch_1_name: "Dual L1 Relay" + relay_1_icon: "mdi:lightbulb" + light_1_name: "Light 1 (Right Hand Bunker Light)" -########################################################################################## -# PACKAGES: Included Common Packages + switch_2_name: "Dual L2 Relay" + relay_2_icon: "mdi:lightbulb" + light_2_name: "Light 2 (Cool White Overhead Lights)" + +#:########################################################################################:# +# PACKAGES: +# Included common packages # https://esphome.io/components/packages.html -########################################################################################## +#:########################################################################################:# packages: - #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml 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}" - #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include file: common/api_common.yaml - #file: common/api_common_noencryption.yaml + # file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" - #### MQTT #### common_mqtt: !include file: common/mqtt_common.yaml vars: local_device_name: "${device_name}" - - #### WEB PORTAL #### - #common_webportal: !include common/webportal_common.yaml - #### SNTP (Only use if you want/need accurate timeclocks) #### - #common_sntp: !include common/sntp_common.yaml - #### DIAGNOSTICS Sensors #### - diag_basic: !include common/include_basic_diag_sensors.yaml - diag_more: !include common/include_more_diag_sensors.yaml - #diag_debug: !include common/include_debug_diag_sensors.yaml - #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + # common_webportal: !include common/webportal_common.yaml + # common_sntp: !include common/sntp_common.yaml -########################################################################################## -# ESPHome + diag_basic: !include common/include_basic_diag_sensors.yaml + diag_more: !include common/include_more_diag_sensors.yaml + # diag_debug: !include common/include_debug_diag_sensors.yaml + # diag_resetcount: !include common/include_resetcount_diag_sensors.yaml + +#:########################################################################################:# +# ESPHOME: # https://esphome.io/components/esphome.html -########################################################################################## +#:########################################################################################:# esphome: name: "${device_name}" friendly_name: "${friendly_name}" - comment: "${description_comment}" # Appears on the esphome page in HA + comment: "${description_comment}" area: "${device_area}" -# platformio_options: -# build_flags: -# - "-Os" # optimize for size -# - "-Wl,--gc-sections" # drop unused code/data -# - "-fno-exceptions" # strip C++ exceptaions -# - "-fno-rtti" # strip C++ RTTI -########################################################################################## -# ESP Platform and Framework -# https://esphome.io/components/esp32.html -########################################################################################## +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266.html +#:########################################################################################:# esp8266: - board: esp01_1m # The original sonoff basic - restore_from_flash: False # restore some values on reboot + board: esp01_1m + restore_from_flash: false preferences: flash_write_interval: 5min mdns: - disabled: True + disabled: true -########################################################################################## -# ESPHome Logging Enable +#:########################################################################################:# +# LOGGER: +# Sonoff Dual cannot use UART logging because UART is required for relay control # https://esphome.io/components/logger.html -########################################################################################## -# NOTE: Sonoff Dual CANNOT send serial data to log -############################################### +#:########################################################################################:# logger: - level: "${log_level}" #INFO Level suggested, or DEBUG for testing - baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM, Serial control) - #esp8266_store_log_strings_in_flash: false - #tx_buffer_size: 64 + level: "${log_level}" + baud_rate: 0 -########################################################################################## -# UART Bus +#:########################################################################################:# +# UART BUS: # https://esphome.io/components/uart.html -########################################################################################## +#:########################################################################################:# uart: tx_pin: GPIO01 rx_pin: GPIO03 baud_rate: 19200 - #data_bits: 8 - #stop_bits: 1 - #parity: EVEN -########################################################################################## -# MQTT COMMANDS -# This adds device-specific MQTT command triggers to the common MQTT configuration. -########################################################################################## +#:########################################################################################:# +# MQTT: +# Device-specific MQTT command triggers +#:########################################################################################:# mqtt: - # Direct MQTT control for relays via serial commands on_message: - # Relay 1 control - topic: "${mqtt_local_command_topic}/relay1/set" payload: "ON" then: - switch.turn_on: relay_1 - light.turn_on: light_1 + - topic: "${mqtt_local_command_topic}/relay1/set" payload: "OFF" then: - switch.turn_off: relay_1 - - light.turn_off: light_1 + - light.turn_off: light_1 - # Relay 2 control - topic: "${mqtt_local_command_topic}/relay2/set" payload: "ON" then: - switch.turn_on: relay_2 - light.turn_on: light_2 + - topic: "${mqtt_local_command_topic}/relay2/set" payload: "OFF" then: - switch.turn_off: relay_2 - light.turn_off: light_2 -########################################################################################## -# STATUS LED +#:########################################################################################:# +# STATUS LED: +# Sonoff Dual LED is on GPIO13 # https://esphome.io/components/status_led.html -########################################################################################## -# Sonoff Dual LED is GPIO13 -############################################# +#:########################################################################################:# status_led: pin: number: GPIO13 - inverted: yes + inverted: true -########################################################################################## -# BINARY SENSORS +#:########################################################################################:# +# BINARY SENSORS: +# Sonoff Dual R1 buttons are GPIO04 and GPIO14 # https://esphome.io/components/binary_sensor/ -########################################################################################## -# Sonoff Dual R1 buttons are GPIO04, GPIO14 -############################################# +#:########################################################################################:# binary_sensor: - platform: gpio pin: @@ -218,12 +236,11 @@ binary_sensor: on_press: - switch.toggle: relay_2 -########################################################################################## -# SWITCH COMPONENT +#:########################################################################################:# +# SWITCH: +# Sonoff Dual R1 requires serial data packets to switch the relays # https://esphome.io/components/switch/ -########################################################################################## -# Sonoff Dual R1 requires serial data to switch -############################################# +#:########################################################################################:# switch: - platform: template name: "${switch_1_name}" @@ -234,7 +251,7 @@ switch: turn_on_action: - mqtt.publish: topic: "${mqtt_local_status_topic}/relay1/state" - payload: "ON" + payload: "ON" - if: condition: switch.is_off: relay_2 @@ -245,7 +262,7 @@ switch: turn_off_action: - mqtt.publish: topic: "${mqtt_local_status_topic}/relay1/state" - payload: "OFF" + payload: "OFF" - if: condition: switch.is_off: relay_2 @@ -253,6 +270,7 @@ switch: - uart.write: [0xA0, 0x04, 0x00, 0xA1] else: - uart.write: [0xA0, 0x04, 0x02, 0xA1] + - platform: template name: "${switch_2_name}" id: relay_2 @@ -262,7 +280,7 @@ switch: turn_on_action: - mqtt.publish: topic: "${mqtt_local_status_topic}/relay2/state" - payload: "ON" + payload: "ON" - if: condition: switch.is_off: relay_1 @@ -273,7 +291,7 @@ switch: turn_off_action: - mqtt.publish: topic: "${mqtt_local_status_topic}/relay2/state" - payload: "OFF" + payload: "OFF" - if: condition: switch.is_off: relay_1 @@ -282,30 +300,38 @@ switch: else: - uart.write: [0xA0, 0x04, 0x01, 0xA1] -################################################################################ -# TEMPLATE OUTPUTS: drive the real relays when the light state changes -################################################################################ +#:########################################################################################:# +# OUTPUTS: +# Template outputs drive the relay template switches when the light state changes +# https://esphome.io/components/output/ +#:########################################################################################:# output: - platform: template id: light_output_1 type: binary write_action: - lambda: |- - if (state) id(relay_1).turn_on(); - else id(relay_1).turn_off(); + if (state) { + id(relay_1).turn_on(); + } else { + id(relay_1).turn_off(); + } - platform: template id: light_output_2 type: binary write_action: - lambda: |- - if (state) id(relay_2).turn_on(); - else id(relay_2).turn_off(); + if (state) { + id(relay_2).turn_on(); + } else { + id(relay_2).turn_off(); + } -########################################################################################## -# LIGHT COMPONENT +#:########################################################################################:# +# LIGHT: # https://esphome.io/components/light/ -########################################################################################## +#:########################################################################################:# light: - platform: binary name: "${light_1_name}" @@ -313,6 +339,6 @@ light: output: light_output_1 - platform: binary - name: "Light 2 (Cool White Overhead Lights)" + name: "${light_2_name}" id: light_2 - output: light_output_2 + output: light_output_2 \ No newline at end of file diff --git a/packages/battery_levels.yaml b/packages/battery_levels.yaml.oldtemp similarity index 100% rename from packages/battery_levels.yaml rename to packages/battery_levels.yaml.oldtemp diff --git a/packages/entrance_spot_person_detection.yaml b/packages/entrance_spot_person_detection.yaml new file mode 100644 index 0000000..c72b277 --- /dev/null +++ b/packages/entrance_spot_person_detection.yaml @@ -0,0 +1,177 @@ +#:########################################################################################:# +# TITLE: ENTRANCE SPOT PERSON DETECTION +# PACKAGE: entrance_spot_person_detection.yaml +#:########################################################################################:# +# PURPOSE: +# - Turn on the entrance illumination when a configured motion/visitor/presence source +# becomes active. +# - Temporarily force the illumination ramp number to 1 second for fast response. +# - Restore the original ramp value after the sequence completes. +# - Restart the timing whenever any configured trigger entity activates again. +# +# HOW THIS PACKAGE IS STRUCTURED: +# - Trigger entities are stored in groups for easy future maintenance. +# - The automation listens for state_changed events and checks whether the changed +# entity is a member of one of those groups. +# - This avoids the limitation of group-state triggers, which would not retrigger +# if the group was already active from an earlier sensor. +# +# TO ADD MORE TRIGGERS LATER: +# - Add more binary sensors under: +# group.entrance_spot_person_detection_binary_sensors +# - Add more device trackers under: +# group.entrance_spot_person_detection_device_trackers +# +# DEVICE TRACKER NOTE: +# - Device trackers often indicate presence using the state "home". +# - If a tracker uses a different detected/present state, change the +# tracker_active_state value below. +#:########################################################################################:# + +group: + entrance_spot_person_detection_binary_sensors: + name: Entrance Spot Person Detection Binary Sensors + entities: + #- binary_sensor.esp_entmulti_outside_entrance_multisensor_moving_target + - binary_sensor.view_road_front_door_visitor + #- binary_sensor.view_road_front_door_motion + - binary_sensor.view_road_front_door_person + + entrance_spot_person_detection_device_trackers: + name: Entrance Spot Person Detection Device Trackers + entities: + - device_tracker.byd_atto3_ibeacon_bur4c2a_bermuda_tracker + +input_number: + entrance_spot_person_detection_saved_ramp: + name: Entrance Spot Person Detection Saved Ramp + min: 0 + max: 720 + step: 1 + mode: box + icon: mdi:timer-cog + +input_boolean: + entrance_spot_person_detection_ramp_saved: + name: Entrance Spot Person Detection Ramp Saved + icon: mdi:content-save-check + +automation: + - alias: Entrance Spot Person Detection + id: entrance_spot_person_detection + description: > + Turn on the front entranceway doorbell illumination when a configured binary + sensor or device tracker activates. Temporarily force the ramp to 1 second, + then restore the previous ramp setting after the sequence completes. + mode: restart + trigger: + # Listen for all entity state changes, then filter below so we only respond + # to configured sensors/trackers becoming active. + - platform: event + event_type: state_changed + + variables: + # Easy-edit entities. + light_switch_entity: switch.front_entranceway_led_light_controls_doorbell_illumination + ramp_number_entity: number.front_entranceway_led_light_controls_doorbell_illumination_ramp + + # Easy-edit groups. + binary_sensor_group_entity: group.entrance_spot_person_detection_binary_sensors + device_tracker_group_entity: group.entrance_spot_person_detection_device_trackers + + # Easy-edit active states. + binary_sensor_active_state: "on" + tracker_active_state: "home" + + # State-change details from the event trigger. + changed_entity_id: "{{ trigger.event.data.entity_id if trigger.event.data is defined else none }}" + old_state_value: > + {{ trigger.event.data.old_state.state if trigger.event.data.old_state is not none else none }} + new_state_value: > + {{ trigger.event.data.new_state.state if trigger.event.data.new_state is not none else none }} + + # Members of the configured groups. + binary_sensor_entities: > + {{ state_attr(binary_sensor_group_entity, 'entity_id') | default([], true) }} + device_tracker_entities: > + {{ state_attr(device_tracker_group_entity, 'entity_id') | default([], true) }} + + # Trigger logic. + binary_sensor_triggered: > + {{ + changed_entity_id in binary_sensor_entities + and old_state_value != binary_sensor_active_state + and new_state_value == binary_sensor_active_state + }} + + device_tracker_triggered: > + {{ + changed_entity_id in device_tracker_entities + and old_state_value != tracker_active_state + and new_state_value == tracker_active_state + }} + + condition: + # Only continue if the changed entity is one of our configured trigger entities + # and it has transitioned into its active/detected state. + - condition: template + value_template: > + {{ binary_sensor_triggered or device_tracker_triggered }} + + action: + # Save the original ramp value only once per active detection cycle. + # Because the automation uses restart mode, repeated triggers will restart + # the sequence without overwriting the original saved ramp value. + - choose: + - conditions: + - condition: state + entity_id: input_boolean.entrance_spot_person_detection_ramp_saved + state: "off" + sequence: + - service: input_number.set_value + target: + entity_id: input_number.entrance_spot_person_detection_saved_ramp + data: + value: > + {{ states(ramp_number_entity) | float(1) }} + + - service: input_boolean.turn_on + target: + entity_id: input_boolean.entrance_spot_person_detection_ramp_saved + + # Force the illumination ramp to 1 second for a fast response. + - service: number.set_value + target: + entity_id: "{{ ramp_number_entity }}" + data: + value: 5 + + # Turn on the entrance illumination. + # The controlled device/light logic is expected to turn itself off later. + - service: switch.turn_on + target: + entity_id: "{{ light_switch_entity }}" + + # Hold briefly, then restore the ramp once activity has stopped retriggering + # the automation for this cycle. + - delay: "00:00:03" + + # Restore the original ramp value that was active before detection. + - service: number.set_value + target: + entity_id: "{{ ramp_number_entity }}" + data: + value: > + {{ states('input_number.entrance_spot_person_detection_saved_ramp') | float(1) }} + + # Clear the saved-state flag ready for the next fresh trigger cycle. + - service: input_boolean.turn_off + target: + entity_id: input_boolean.entrance_spot_person_detection_ramp_saved + + # Optional tidy reset of the helper value. + - service: input_number.set_value + target: + entity_id: input_number.entrance_spot_person_detection_saved_ramp + data: + value: 0 diff --git a/packages/gas_heater_operation.yaml b/packages/gas_heater_operation.yaml.old2026 similarity index 100% rename from packages/gas_heater_operation.yaml rename to packages/gas_heater_operation.yaml.old2026 diff --git a/packages/openhasp_lounge1_wallplate.yaml b/packages/openhasp_lounge1_wallplate.yaml index c87c35a..ee51697 100644 --- a/packages/openhasp_lounge1_wallplate.yaml +++ b/packages/openhasp_lounge1_wallplate.yaml @@ -1,144 +1,546 @@ ############################################################################### -# PACKAGE: OpenHASP Thermostat (MQTT-only, all BUTTON objects) +# PACKAGE: OpenHASP Thermostat / Gas Heater Control # NODE/TOPIC ROOT: hasp/openhasp_1/ +# +# PAGE OBJECTS USED +# - p1b1 = main temperature display +# - p1b2 = alternating Setpoint / Humidity display +# - p1b3 = setpoint down +# - p1b4 = setpoint up +# - p1b5 = heater status text +# - p1b6 = heater operation / flame button ############################################################################### +############################################################################### +# HELPERS +############################################################################### +input_boolean: + hasp_setpoint_hold_active: + name: HASP Setpoint Hold Active + initial: false + input_number: - lounge_setpoint: - name: Lounge Setpoint - min: 10 - max: 30 - step: 0.5 + # How long Setpoint and Humidity are each shown before rotating + hasp_setpoint_humidity_cycle_seconds: + name: HASP Setpoint Humidity Cycle Seconds + min: 1 + max: 60 + step: 1 mode: box - unit_of_measurement: "℃" - initial: 21.5 + unit_of_measurement: s + initial: 10 + + # After the setpoint changes, hold the setpoint screen for this long + hasp_setpoint_hold_seconds: + name: HASP Setpoint Hold Seconds + min: 1 + max: 60 + step: 1 + mode: box + unit_of_measurement: s + initial: 15 + +############################################################################### +# MQTT ENTITIES +############################################################################### +mqtt: + sensor: + - name: "Lounge Environment Humidity MQTT" + unique_id: "lounge_environment_humidity_mqtt" + state_topic: "viewroad-status/lounge-environment/humidity" ############################################################################### # AUTOMATIONS ############################################################################### automation: - # --- PUSH LABEL TEXTS (on buttons) ---------------------------------------- + # ------------------------------------------------------------------------- + # Main temperature display + # - Shows normal lounge temperature + # - If heater test mode is ON, shows the test temperature instead + # - Normalises values so we do not get duplicated °C or long float strings + # ------------------------------------------------------------------------- - id: hasp_temp_to_btn_text alias: "HASP: update temp (p1b1.text)" mode: queued trigger: - platform: state - entity_id: sensor.lounge_environment_lounge_environment_temperature + entity_id: + - sensor.lounge_environment_lounge_environment_temperature + - switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_test_mode + - sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_test_mode_temp action: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b1.text" - payload: "{{ states('sensor.lounge_environment_lounge_environment_temperature')|float(0)|round(1) }} °C" - - - id: hasp_setpoint_to_btn_text - alias: "HASP: update setpoint (p1b2.text)" - mode: queued - trigger: - - platform: state - entity_id: input_number.lounge_setpoint - action: - - service: mqtt.publish - data: - topic: "hasp/openhasp_1/command/p1b2.text" - payload: "Set: {{ states('input_number.lounge_setpoint')|float(0)|round(1) }} °C" - qos: 1 - retain: true + payload: > + {% if is_state('switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_test_mode', 'on') %} + {% set raw = states('sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_test_mode_temp') %} + {% else %} + {% set raw = states('sensor.lounge_environment_lounge_environment_temperature') %} + {% endif %} + {% set cleaned = raw + | replace('°C', '') + | replace('° C', '') + | replace('C', '') + | trim %} + {% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %} + {{ cleaned | float(0) | round(1) }} °C + {% else %} + -- °C + {% endif %} + # ------------------------------------------------------------------------- + # Heater status text at bottom of screen + # ------------------------------------------------------------------------- - id: hasp_heater_status_to_btn_text alias: "HASP: update heater status (p1b5.text)" mode: queued trigger: - platform: state - entity_id: switch.lounge_heater + entity_id: sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_status_text action: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b5.text" payload: > - {% if is_state('sensor.gas_heater_operating','ON') %} - HEAT ON - {% else %} - HEAT OFF - {% endif %} + {% set s = states('sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_status_text') %} + {{ s if s not in ['unknown', 'unavailable', ''] else 'HEATER --' }} - # --- BUTTON HANDLING FROM THE PLATE (listens on /state/) ------------------ - - id: hasp_btn_up_increment - alias: "HASP: p1b3 up -> increment setpoint" + # ------------------------------------------------------------------------- + # When setpoint changes: + # - immediately show Setpoint + # - hold it for hold_seconds + # - then allow normal Setpoint/Humidity rotation again + # ------------------------------------------------------------------------- + - id: hasp_setpoint_changed_hold_display + alias: "HASP: show setpoint immediately and hold" + mode: restart + trigger: + - platform: state + entity_id: sensor.rinnai_neo_gas_heater_setpoint_text + action: + - service: input_boolean.turn_on + target: + entity_id: input_boolean.hasp_setpoint_hold_active + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b2.text" + payload: > + {% set s = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} + {{ 'Setpoint: ' ~ (s if s not in ['unknown', 'unavailable', ''] else '--') }} + + - delay: + seconds: "{{ states('input_number.hasp_setpoint_hold_seconds') | int(15) }}" + + - service: input_boolean.turn_off + target: + entity_id: input_boolean.hasp_setpoint_hold_active + + # ------------------------------------------------------------------------- + # Up / Down buttons on the HASP plate + # These call the existing HA button entities + # ------------------------------------------------------------------------- + - id: hasp_btn_up_press + alias: "HASP: p1b4 up -> heater setpoint UP" mode: queued trigger: - platform: mqtt topic: "hasp/openhasp_1/state/p1b4" condition: - condition: template - value_template: "{{ trigger.payload_json.event|default('') == 'up' }}" + value_template: "{{ trigger.payload_json.event | default('') == 'up' }}" action: - - service: input_number.increment + - service: button.press target: - entity_id: input_number.lounge_setpoint + entity_id: button.rinnai_neo_gas_heater_rinnai_neo_gas_heater_setpoint_up - - id: hasp_btn_down_decrement - alias: "HASP: p1b4 up -> decrement setpoint" + - id: hasp_btn_down_press + alias: "HASP: p1b3 up -> heater setpoint DOWN" mode: queued trigger: - platform: mqtt topic: "hasp/openhasp_1/state/p1b3" condition: - condition: template - value_template: "{{ trigger.payload_json.event|default('') == 'up' }}" + value_template: "{{ trigger.payload_json.event | default('') == 'up' }}" action: - - service: input_number.decrement + - service: button.press target: - entity_id: input_number.lounge_setpoint + entity_id: button.rinnai_neo_gas_heater_rinnai_neo_gas_heater_setpoint_down - # --- PUSH INITIAL VALUES ON HA START / PANEL ONLINE ----------------------- - - id: hasp_push_on_ha_start - alias: "HASP: push texts on HA start" + # ------------------------------------------------------------------------- + # Middle flame button + # - Tap toggles heater operation + # ------------------------------------------------------------------------- + - id: hasp_btn_heat_toggle + alias: "HASP: p1b6 up -> heater operation toggle" mode: queued + trigger: + - platform: mqtt + topic: "hasp/openhasp_1/state/p1b6" + condition: + - condition: template + value_template: "{{ trigger.payload_json.event | default('') == 'up' }}" + action: + - service: switch.toggle + target: + entity_id: switch.rinnai_neo_gas_heater_heater_operation + + # ------------------------------------------------------------------------- + # Flame button appearance + # - Operation OFF: solid light grey background, white flame + # - Operation ON, flame OFF: solid dark background, white flame + # - Operation ON, flame ON: solid dark background, continuous red/orange flicker + # ------------------------------------------------------------------------- + - id: hasp_heat_button_state + alias: "HASP: update heat button state (p1b6)" + mode: restart + trigger: + - platform: state + entity_id: + - switch.rinnai_neo_gas_heater_heater_operation + - switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + action: + - choose: + # OFF → dark grey (same as your other inactive buttons) + - conditions: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "off" + sequence: + - service: script.turn_off + target: + entity_id: script.hasp_heat_flame_flicker + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text" + payload: "\uE238" + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FFFFFF" + + # solid dark grey (no gradient) + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_color" + payload: "#2F3240" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" + payload: "#2F3240" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.border_color" + payload: "#2F3240" + + # ON (not firing) → theme blue + - conditions: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "on" + - condition: state + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + state: "off" + sequence: + - service: script.turn_off + target: + entity_id: script.hasp_heat_flame_flicker + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text" + payload: "\uE238" + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FFFFFF" + + # MATCH THEME BLUE + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_color" + payload: "#0095D9" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" + payload: "#00B6FF" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.border_color" + payload: "#0095D9" + + # ON + flame → blue background + flicker + - conditions: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "on" + - condition: state + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + state: "on" + sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text" + payload: "\uE238" + + # keep blue background + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_color" + payload: "#0095D9" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" + payload: "#00B6FF" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.border_color" + payload: "#0095D9" + + - service: script.turn_on + target: + entity_id: script.hasp_heat_flame_flicker + + # ------------------------------------------------------------------------- + # Start / restart display when HA starts + # ------------------------------------------------------------------------- + - id: hasp_start_on_ha_start + alias: "HASP: start display loop on HA start" trigger: - platform: homeassistant event: start action: - - service: script.hasp_push_all_texts + - service: script.hasp_push_static_texts + - service: script.turn_on + target: + entity_id: script.hasp_rotate_setpoint_humidity - - id: hasp_push_on_panel_online - alias: "HASP: push texts when panel goes online" - mode: queued + # ------------------------------------------------------------------------- + # Re-push screen state when panel comes online + # ------------------------------------------------------------------------- + - id: hasp_start_on_panel_online + alias: "HASP: start display loop when panel goes online" trigger: - platform: mqtt - topic: "hasp/openhasp_1/status" + topic: "hasp/openhasp_1/LWT" condition: - condition: template value_template: "{{ trigger.payload == 'online' }}" action: - delay: "00:00:05" - - service: script.hasp_push_all_texts + - service: script.hasp_push_static_texts + - service: script.turn_on + target: + entity_id: script.hasp_rotate_setpoint_humidity ############################################################################### -# SCRIPT: Push all texts to buttons +# SCRIPTS ############################################################################### script: - hasp_push_all_texts: - alias: "HASP: push all texts" + # ------------------------------------------------------------------------- + # Push all current values / colours to the panel + # Useful on HA startup and panel reconnect + # ------------------------------------------------------------------------- + hasp_push_static_texts: + alias: "HASP: push static texts" mode: queued sequence: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b1.text" - payload: "{{ states('sensor.lounge_environment_lounge_environment_temperature')|float(0)|round(1) }} °C" - - - service: mqtt.publish - data: - topic: "hasp/openhasp_1/command/p1b2.text" - payload: "Set: {{ states('input_number.lounge_setpoint')|float(0)|round(1) }} °C" - qos: 1 - retain: true + payload: > + {% if is_state('switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_test_mode', 'on') %} + {% set raw = states('sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_test_mode_temp') %} + {% else %} + {% set raw = states('sensor.lounge_environment_lounge_environment_temperature') %} + {% endif %} + {% set cleaned = raw + | replace('°C', '') + | replace('° C', '') + | replace('C', '') + | trim %} + {% if cleaned not in ['unknown', 'unavailable', '', 'none', 'None'] %} + {{ cleaned | float(0) | round(1) }} °C + {% else %} + -- °C + {% endif %} - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b5.text" payload: > - {% if is_state('sensor.gas_heater_operating','ON') %} - HEAT ON - {% else %} - HEAT OFF - {% endif %} + {% set s = states('sensor.rinnai_neo_gas_heater_rinnai_neo_gas_heater_status_text') %} + {{ s if s not in ['unknown', 'unavailable', ''] else 'HEATER --' }} + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b2.text" + payload: > + {% set s = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} + {{ 'Setpoint: ' ~ (s if s not in ['unknown', 'unavailable', ''] else '--') }} + + # Push middle flame button state + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text" + payload: "\uE238" + + - choose: + - conditions: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "off" + sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FFFFFF" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_color" + payload: "#2F3240" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" + payload: "#2F3240" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.border_color" + payload: "#2F3240" + + - conditions: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "on" + - condition: state + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + state: "off" + sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FFFFFF" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_color" + payload: "#0095D9" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" + payload: "#00B6FF" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.border_color" + payload: "#0095D9" + + - conditions: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "on" + - condition: state + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + state: "on" + sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_color" + payload: "#0095D9" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.bg_grad_color" + payload: "#00B6FF" + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.border_color" + payload: "#0095D9" + - service: script.turn_on + target: + entity_id: script.hasp_heat_flame_flicker + + # ------------------------------------------------------------------------- + # Rotate the middle information line between Setpoint and Humidity + # Pauses humidity display while the setpoint hold flag is active + # ------------------------------------------------------------------------- + hasp_rotate_setpoint_humidity: + alias: "HASP: rotate setpoint and humidity" + mode: restart + sequence: + - repeat: + while: + - condition: template + value_template: "{{ true }}" + sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b2.text" + payload: > + {% set s = states('sensor.rinnai_neo_gas_heater_setpoint_text') %} + {{ 'Setpoint: ' ~ (s if s not in ['unknown', 'unavailable', ''] else '--') }} + + - delay: + seconds: "{{ states('input_number.hasp_setpoint_humidity_cycle_seconds') | int(10) }}" + + - condition: state + entity_id: input_boolean.hasp_setpoint_hold_active + state: "off" + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b2.text" + payload: > + {% set h = states('sensor.lounge_environment_humidity_mqtt') %} + {% if h in ['unknown', 'unavailable', ''] %} + Humidity: Unknown + {% else %} + Humidity: {{ h }}% + {% endif %} + + - delay: + seconds: "{{ states('input_number.hasp_setpoint_humidity_cycle_seconds') | int(10) }}" + + # ------------------------------------------------------------------------- + # Continuous flame flicker while heater operation is ON and flame/power is ON + # Only the icon colour flickers. Background stays fixed. + # Flicker colours are red <-> orange + # ------------------------------------------------------------------------- + hasp_heat_flame_flicker: + alias: "HASP: heat flame flicker" + mode: restart + sequence: + - repeat: + while: + - condition: state + entity_id: switch.rinnai_neo_gas_heater_heater_operation + state: "on" + - condition: state + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + state: "on" + sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FF3030" + - delay: "00:00:00.35" + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FF8C00" + - delay: "00:00:00.20" + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FF5A36" + - delay: "00:00:00.30" + + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FFA500" + - delay: "00:00:00.18" diff --git a/packages/presense_sense.yaml.old b/packages/presense_sense.yaml.old deleted file mode 100644 index dc691fc..0000000 --- a/packages/presense_sense.yaml.old +++ /dev/null @@ -1,98 +0,0 @@ -# ESPresence Sensing -# https://espresense.com/home_assistant -# - -# In the secrets.yaml file you want something like this to match each one. -# Obviously you don't need to use secrets, but it helps if you are sharing your -# home assistant config with others. -# -# btb09_uID: My_tracked_item_name_(ID)" -# btb09_dID: "known:xxxxxxxxxxxx" -# btb09_name: "My Tracked Item Name (ID)" -# btb09_topic: espresense/devices/known:xxxxxxxxxxxx - -sensor: - - platform: mqtt_room - unique_id: !secret btb01_uID - device_id: !secret btb01_dID - name: !secret btb01_name - state_topic: !secret btb01_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb02_uID - device_id: !secret btb02_dID - name: !secret btb02_name - state_topic: !secret btb02_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb03_uID - device_id: !secret btb03_dID - name: !secret btb03_name - state_topic: !secret btb03_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb04_uID - device_id: !secret btb04_dID - name: !secret btb04_name - state_topic: !secret btb04_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb05_uID - device_id: !secret btb05_dID - name: !secret btb05_name - state_topic: !secret btb05_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb06_uID - device_id: !secret btb06_dID - name: !secret btb06_name - state_topic: !secret btb06_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb07_uID - device_id: !secret btb07_dID - name: !secret btb07_name - state_topic: !secret btb07_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb08_uID - device_id: !secret btb08_dID - name: !secret btb08_name - state_topic: !secret btb08_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb09_uID - device_id: !secret btb09_dID - name: !secret btb09_name - state_topic: !secret btb09_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb10_uID - device_id: !secret btb10_dID - name: !secret btb10_name - state_topic: !secret btb10_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb11_uID - device_id: !secret btb11_dID - name: !secret btb11_name - state_topic: !secret btb11_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home - - platform: mqtt_room - unique_id: !secret btb12_uID - device_id: !secret btb12_dID - name: !secret btb12_name - state_topic: !secret btb12_topic - timeout: 60 - away_timeout: 120 # number of seconds after which the enitity will get status not_home