From f14bbbd23a6b224ed0f95abede08c829801f6f88 Mon Sep 17 00:00:00 2001 From: root Date: Tue, 28 Apr 2026 18:50:15 +1200 Subject: [PATCH] additional esphome devices and fixes --- .../brands/integrations/edgeos/dark_logo.png | Bin 0 -> 50070 bytes .../homekit_controller/dark_logo.png | Bin 0 -> 20933 bytes .../brands/integrations/matter/dark_logo.png | Bin 0 -> 10309 bytes .cache/brands/integrations/script/icon.png | Bin 1805 -> 1703 bytes .../brands/integrations/sensor/dark_icon.png | Bin 0 -> 3627 bytes .cache/brands/integrations/sensor/icon.png | Bin 0 -> 3627 bytes .../brands/integrations/zha/dark_icon@2x.png | Bin 0 -> 49625 bytes .ha_run.lock | 2 +- ...60221 => esp-athombulbflasher.yaml.sample} | 0 ...l => esp-bed1bedsideathombulb.yaml.sample} | 0 esphome/esp-bedrm1airfilter.yaml | 624 ++++++++++++++++++ esphome/esp-centralstairs-top.yaml | 71 +- ...ml => esp-dinpowermonitor-pmb.yaml.sample} | 0 esphome/esp-gasheater.yaml | 373 ++++++----- ...aml => esp-loungemainsdimmer1.yaml.sample} | 0 ...yaml => esp-loungemoesdimmer1.yaml.sample} | 0 ...yaml => esp-loungemoesdimmer2.yaml.sample} | 0 ...mp1s.yaml => esp-midesklamp1s.yaml.sample} | 0 ...xmulti1.yaml => esp-nexmulti1.yaml.sample} | 0 ...temp => esp-nfcaccess1-33ad74.yaml.sample} | 0 esphome/esp-officelights copy.yaml.old | 177 ----- ...ulb2.yaml => esp-rgblampbulb2.yaml.sample} | 0 ...downstairs_bulk_lights_on_from_stairs.yaml | 88 +++ .../office_lights_power_backup_occupancy.yaml | 72 +- packages/openhasp_lounge1_wallplate.yaml | 116 +--- 25 files changed, 1042 insertions(+), 481 deletions(-) create mode 100644 .cache/brands/integrations/edgeos/dark_logo.png create mode 100644 .cache/brands/integrations/homekit_controller/dark_logo.png create mode 100644 .cache/brands/integrations/matter/dark_logo.png create mode 100644 .cache/brands/integrations/sensor/dark_icon.png create mode 100644 .cache/brands/integrations/sensor/icon.png create mode 100644 .cache/brands/integrations/zha/dark_icon@2x.png rename esphome/{esp-athombulbflasher.yaml.final20260221 => esp-athombulbflasher.yaml.sample} (100%) rename esphome/{esp-bed1bedsideathombulb.yaml => esp-bed1bedsideathombulb.yaml.sample} (100%) create mode 100644 esphome/esp-bedrm1airfilter.yaml rename esphome/{esp-dinpowermonitor-pmb.yaml => esp-dinpowermonitor-pmb.yaml.sample} (100%) rename esphome/{esp-loungemainsdimmer1.yaml => esp-loungemainsdimmer1.yaml.sample} (100%) rename esphome/{esp-loungemoesdimmer1.yaml => esp-loungemoesdimmer1.yaml.sample} (100%) rename esphome/{esp-loungemoesdimmer2.yaml => esp-loungemoesdimmer2.yaml.sample} (100%) rename esphome/{esp-midesklamp1s.yaml => esp-midesklamp1s.yaml.sample} (100%) rename esphome/{esp-nexmulti1.yaml => esp-nexmulti1.yaml.sample} (100%) rename esphome/{esp-nfcaccess1-33ad74.yaml.temp => esp-nfcaccess1-33ad74.yaml.sample} (100%) delete mode 100644 esphome/esp-officelights copy.yaml.old rename esphome/{esp-rgblampbulb2.yaml => esp-rgblampbulb2.yaml.sample} (100%) create mode 100644 packages/downstairs_bulk_lights_on_from_stairs.yaml diff --git a/.cache/brands/integrations/edgeos/dark_logo.png b/.cache/brands/integrations/edgeos/dark_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..c6f92e314d8d42cb7043c3f5fba2093d286f17ab GIT binary patch literal 50070 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

?GDA-M$#_vd?u3#T_fqP&N)VpEz#wY(- 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 T8p6{U=s$>>o@%wSO~n5Pw$+#} literal 0 HcmV?d00001 diff --git a/.cache/brands/integrations/homekit_controller/dark_logo.png b/.cache/brands/integrations/homekit_controller/dark_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..defa5d0bc35f829e9c5954951e026fdf2bb8839a GIT binary patch literal 20933 zcmV))K#ISKP)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw002=? 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 literal 0 HcmV?d00001 diff --git a/.cache/brands/integrations/matter/dark_logo.png b/.cache/brands/integrations/matter/dark_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..0e69c0be81aae74ee5da742100a035751daaf08c GIT binary patch literal 10309 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 E0TbLLLI3~& literal 1805 zcmZ`(2{e>z82)B4laZ@j`!$i$a<58GsHw3O$`TVMYqqNtB1=L|Gi3>t7D{BRZkfgm zSz9clk|fEvm2E6pLP#28EKPHNGnrfW)_30Xe9yZ*?|aUF{x6+x~tn5u87YGD^A^p5zP3txte90T^7sm;^bK zfW`w19?0Pd$rPYY0ooLxi^(*gPXn3|^JV~T1~7yM5&Gnu0!@TM5lDw2Y|ouXNC#4b z++3jogkmC+&E)~e=tBEiDV#3aL5y>P!d|HTJ0ffpi-^eFIH5t)Aro_mh$7JFe>a(5 zKvX8$;r|F_zYTtMMLLjzFe@$)4Hb_TDSwAhqp<6{;QXpT3JL^*MP3QY&?n9ewY9bb zFgOA!fs({5lvyMzr=+ZkU81JGRAbq4%@r$G{jp~4I&B?YJ^hWFHg7R7HZe8ZVQyh* zWkawf?sjx?cJuVwyU)kh&p#kAC^#fMBJ$`l(s9a(lTpzzv2pQd&L<^bx}1`lo|S#= z`mG!)Etj5`UsQ6xth}PK>fxiu)it%x>R&WA{r#q$-O<_G|88Jtcx3d$*eA{emp3&% zGy9qU<>GRj0kkR1%W}I()?i6e1^~$Q<|fAW;ccVr0lQy~l_=wDmVGmu&Y;?+VWURr6dZp z*+=`b49T|>?2Aee#b#37g_HbquEn6xG!2$WjXP|_`Qm=J7?#y>u#ELukis19SgDny zOKPquFkXZ-?riE)>q@)n44X7pF(m5t&DQM;S7zuV?M$;eePYI%tXK=~*fv&tsO?H=mW}KSJ_~e%K|`!oV8q~s zc3t>}S{QYqlbaiEr1no0m`Xp8JH=Qxu_4@cSyjX)Fzq>9wm8hY$c*xrDy7A+i?%{w zLm|7X%{??L^gy_vRjW(-pb(7 z3u@RLRduD^yv{(1dTrOCp#%9rfY;us*r8K~9(>7DH9E+_cAK(80I`3wkxk|R@MVsH zA>~X2b^GHjXhIGNO>l9Ar7ObEGeVJvEb0*2sl))FQoRM9+|h^3Hfz{McyILxR)sMJ z@85*a0y|9@_1x=i{)pwa*O9M!gWKU)3&#wRTL3m0Eul9SQ;(d1lKpOZ)F=V_*uPUI4Qd6`D<$*62~ z&0}9=Zb*~m-eAxz{xi-VgF9KABh_czrR66unSy>tsphDDQGR!0{AMH?vYhOV diff --git a/.cache/brands/integrations/sensor/dark_icon.png b/.cache/brands/integrations/sensor/dark_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8047c88ce14766eb816b9a5836c02cd520b126 GIT binary patch literal 3627 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 literal 0 HcmV?d00001 diff --git a/.cache/brands/integrations/sensor/icon.png b/.cache/brands/integrations/sensor/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ac8047c88ce14766eb816b9a5836c02cd520b126 GIT binary patch literal 3627 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 literal 0 HcmV?d00001 diff --git a/.cache/brands/integrations/zha/dark_icon@2x.png b/.cache/brands/integrations/zha/dark_icon@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..f9a4a9edfb1e26187e0d70dee46c85e695cb94aa GIT binary patch literal 49625 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⪙GGVX;q*uOEfI| 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 S@!k&r8=vJ=WUD?J2mKF$oStp~ literal 0 HcmV?d00001 diff --git a/.ha_run.lock b/.ha_run.lock index 53e1e76..af610aa 100644 --- a/.ha_run.lock +++ b/.ha_run.lock @@ -1 +1 @@ -{"pid": 67, "version": 1, "ha_version": "2026.4.4", "start_ts": 1777063274.5674608} \ No newline at end of file +{"pid": 67, "version": 1, "ha_version": "2026.4.4", "start_ts": 1777174011.4286706} \ No newline at end of file diff --git a/esphome/esp-athombulbflasher.yaml.final20260221 b/esphome/esp-athombulbflasher.yaml.sample similarity index 100% rename from esphome/esp-athombulbflasher.yaml.final20260221 rename to esphome/esp-athombulbflasher.yaml.sample diff --git a/esphome/esp-bed1bedsideathombulb.yaml b/esphome/esp-bed1bedsideathombulb.yaml.sample similarity index 100% rename from esphome/esp-bed1bedsideathombulb.yaml rename to esphome/esp-bed1bedsideathombulb.yaml.sample diff --git a/esphome/esp-bedrm1airfilter.yaml b/esphome/esp-bedrm1airfilter.yaml new file mode 100644 index 0000000..c8ce93c --- /dev/null +++ b/esphome/esp-bedrm1airfilter.yaml @@ -0,0 +1,624 @@ +#:########################################################################################:# +# TITLE: IKEA AIR FILTER - BEDROOM 1 +# zorruno.com layout v1.1 2026 +# This is a conversion of the IKEA FORNUFTIG Air Filter unit to add smart control. +# +# References: +# - https://www.youtube.com/watch?v=WB4xxhgggHQ from 3ATIVE VFX +# - https://github.com/3ative/ikea-air-filter from 3ATIVE VFX +# - https://github.com/dgalue/Ikea-Air-Purifier-ESP32-Homespan from dgalue +#:########################################################################################:# +# REPO: +# https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-bedrm1airfilter.yaml +#:########################################################################################:# +# VERSIONS: +# V1.2 2026-04-27 Converted filter replacement logic from pulse-count based to kRevs based. +# Added editable Replacement Threshold number in kRevs. +# Added Reset Replacement Threshold button to restore default 19000 kRevs. +# Added fan pulse to revolution conversion substitutions. +# Updated Filter Age to display accumulated fan use in kRevs. +# Updated Clean/Dirty and LED logic to use fan kRevs rather than raw pulses. +# V1.1 2026-04-27 Updated yaml to zorruno layout V1.1. +# Added D5 panel dirty LED flashing at 500ms on/off. +# Decoupled onboard LED from fan MOSFET state. +# Reset now clears pulse total, restored age value and both dirty LEDs. +# Added fuller hardware, operation and offline notes. +# V1.0 2025-07-21 First Setup. +#:########################################################################################:# +# HARDWARE: +# - IKEA FORNUFTIG wall mount air filter conversion. +# - Wemos D1 Mini ESP8266. +# - D2: Fan MOSFET enable output. +# - D4: D1 Mini onboard LED, active low, used as filter dirty indicator. +# - D5: IKEA unit panel dirty LED, active high, flashes when filter is dirty. +# - D6: Fan pulse counter / tacho input. +# - D7: Fan PWM output. +# - Fan tacho hardware has been modified so the ESP8266 sees a clean 3.3V signal. +#:########################################################################################:# +# OPERATION NOTES: +# - Fan speed slider is 0 to 6. +# - Speed 0 turns the fan MOSFET off and sets PWM frequency to 0. +# - Speeds 1 to 6 turn the fan MOSFET on, enable 50 percent duty drive and set +# PWM frequency to speed * 50Hz. +# - Fan Rate is calculated from raw tacho pulses using fan_revs_per_pulse. +# - Filter Age is tracked in kRevs, meaning 1000 fan revolutions. +# - Default replacement threshold is 19000 kRevs, stored in substitutions. +# - Replacement Threshold is editable from Home Assistant as a number entity. +# - Reset Replacement Threshold restores the editable threshold back to the default. +# - When Filter Age is greater than or equal to Replacement Threshold, the +# onboard LED turns on steady, the panel LED flashes at 500ms on/off, and +# Filter State changes to Dirty. +# - Reset button clears the filter age counter, restored filter age value, +# Filter State, and both dirty LEDs. +#:########################################################################################:# +# MQTT COMMANDS: +# - MQTT common package is included for standard device availability/status. +# - No local custom MQTT command topics are currently defined in this file. +#:########################################################################################:# +# OFFLINE NOTES: +# a) HA offline (network and MQTT online) +# - Device fan speed and dirty indicator logic continue locally. +# - HA entities will not be available until HA/API reconnects. +# b) MQTT offline +# - No custom MQTT commands are required for the local fan/dirty logic. +# - HA API control remains available if HA and WiFi are online. +# c) Entire WiFi/Network offline +# - Device fan speed and filter age logic continue locally once booted. +# - SNTP is not needed; this device does not use accurate timeclocks. +#:########################################################################################:# + + +#:########################################################################################:# +# 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-bedrm1airfilter" + friendly_name: "Bedroom 1 Air Filter" + description_comment: "Wall Mount Air Filter :: D1 Mini ESP8266 (Layout V1.1)" + device_area: "Bedroom 1" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Generic.D1 Mini" # Project Details + project_version: "v1.2" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords and Secrets + api_key: !secret esp-api_key + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-bedrm1airfilter_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} + + # Device Settings + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for general sensors etc + + # MQTT LOCAL Controls + #mqtt_device_name: "bedrm1airfilter" + #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic used to command this locally without HA + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic used to view status locally without HA + + # Filter Settings + # This is a usage approximation based on fan revolutions, not calendar time. + # fan_revs_per_pulse is also used to convert pulse_counter pulses/min to RPM. + # fan_krevs_per_pulse converts raw pulse total to 1000 fan revolutions. + fan_revs_per_pulse: "0.06" + fan_krevs_per_pulse: "0.00006" + filter_replacement_default_krevs: "19000" + + +#:########################################################################################:# +# 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 + +#:########################################################################################:# +# 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: # Restore the saved filter age counter and dirty warning state on boot. + priority: -100 + then: + - delay: 200ms + + # Restore the raw pulse total from the saved filter age in kRevs. + # raw_pulses = kRevs * 1000 / revs_per_pulse + - pulse_counter.set_total_pulses: + id: filter_counter + value: !lambda |- + return static_cast((id(filter_age_krevs) * 1000.0f) / ${fan_revs_per_pulse}); + + # Restore Clean/Dirty state and warning LEDs. + - script.execute: update_filter_state + +#:########################################################################################:# +# ESP PLATFORM AND FRAMEWORK: +# https://esphome.io/components/esp8266/ +#:########################################################################################:# +esp8266: + board: d1_mini # Generic Board + restore_from_flash: true # Restore selected values on reboot. + +preferences: + flash_write_interval: 5min + +mdns: + disabled: false # Disabling will make the build file smaller, and the device is still available via static IP. + +#:########################################################################################:# +# GLOBAL VARIABLES: +# https://esphome.io/guides/automations.html#global-variables +#:########################################################################################:# +globals: + # Save the filter age value in kRevs and restore it on boot. + # This replaces the old pulse-based/global filtered age value. + - id: filter_age_krevs + type: float + restore_value: true + initial_value: "0.0" + + # Save total fan runtime in seconds and restore it on boot. + # This is used to display total runtime hours in Home Assistant. + - id: fan_runtime_seconds + type: uint32_t + restore_value: true + initial_value: "0" + + # Runtime session start/update marker. + # This does not need to be restored because it only applies to the current boot. + - id: fan_runtime_last_ms + type: uint32_t + restore_value: false + initial_value: "0" + +#:########################################################################################:# +# LOGGING: ESPHome Logging Enable +# https://esphome.io/components/logger.html +#:########################################################################################:# +logger: + level: "${log_level}" # INFO 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. + +#:########################################################################################:# +# BUTTON COMPONENT: +# https://esphome.io/components/button/ +#:########################################################################################:# +button: + # Reset Button for Filter Age + - platform: template + name: "${friendly_name} Filter EOL Reset" + id: reset_button + icon: mdi:restart + + # Reset the filter age counter and clear the dirty indicators. + on_press: + - pulse_counter.set_total_pulses: + id: filter_counter + value: 0 + + - lambda: |- + id(filter_age_krevs) = 0.0f; + + - script.execute: update_filter_state + + # Immediately save the reset filter age value to flash. + - lambda: |- + global_preferences->sync(); + + # Reset Button for Total Fan Runtime + - platform: template + name: "${friendly_name} Reset Runhours" + id: reset_runtime_button + icon: mdi:timer-refresh-outline + on_press: + - lambda: |- + id(fan_runtime_seconds) = 0; + id(fan_runtime_last_ms) = id(fan_mosfet).state ? millis() : 0; + id(fan_runtime_hours).publish_state(0.0f); + + - lambda: |- + global_preferences->sync(); + + # Reset Button for Filter Replacement Threshold + - platform: template + name: "${friendly_name} EOL Threshold = Default" + id: reset_replacement_threshold_button + icon: mdi:restore + on_press: + - number.set: + id: filter_replacement_krevs + value: ${filter_replacement_default_krevs} + - script.execute: update_filter_state + - lambda: |- + global_preferences->sync(); + + # Test Button for IKEA panel dirty LED on D5. + # This is retained for easy hardware testing. + #- platform: template + # name: "${friendly_name} Test Panel LED" + # id: test_panel_led_button + # icon: mdi:led-on + # on_press: + # - output.turn_on: panel_led_output + # - delay: 2s + # - output.turn_off: panel_led_output + +#:########################################################################################:# +# NUMBER COMPONENT: +# https://esphome.io/components/number/ +#:########################################################################################:# +number: + # Slider for Fan Speed 0-6, 0 = Off, 6 = Max + - platform: template + name: "${friendly_name} Fan Speed" + id: fan_speed + icon: mdi:air-filter + update_interval: never + optimistic: true + min_value: 0 + max_value: 6 + initial_value: 0 + step: 1 + set_action: + - if: + condition: + # Is the slider 1 or above? + lambda: |- + return x >= 1; + then: + # Turn on the fan MOSFET and enable the PWM drive. + - switch.turn_on: fan_mosfet + - servo.write: + id: fan_motor + level: 1 + + # Change the PWM signal based on the slider value. + # 50Hz steps are based on the tested value used by the original IKEA device. + - output.esp8266_pwm.set_frequency: + id: fan_pwm + frequency: !lambda |- + return x * 50; + + else: + # Turn off the fan MOSFET and set PWM to 0. + - switch.turn_off: fan_mosfet + - output.esp8266_pwm.set_frequency: + id: fan_pwm + frequency: !lambda |- + return 0; + + # Editable filter replacement threshold in 1000 fan revolutions. + # Default is 19000 kRevs, which is about 19 million fan revolutions. + - platform: template + name: "${friendly_name} Filter EOL Threshold" + id: filter_replacement_krevs + icon: mdi:counter + mode: box + unit_of_measurement: "kRevs" + optimistic: true + restore_value: true + initial_value: ${filter_replacement_default_krevs} + min_value: 1 + max_value: 100000 + step: 100 + set_action: + - script.execute: update_filter_state + - lambda: |- + global_preferences->sync(); + +#:########################################################################################:# +# BINARY SENSOR COMPONENT: +# https://esphome.io/components/binary_sensor/ +#:########################################################################################:# +binary_sensor: + # Internal binary state used by ESPHome logic. + # The public HA display is handled by the text_sensor below so it can show + # Clean / Dirty instead of Off / On. + - platform: template + id: filter_dirty + internal: true + lambda: |- + float threshold = id(filter_replacement_krevs).state; + + if (isnan(threshold) || threshold <= 0.0f) { + threshold = ${filter_replacement_default_krevs}; + } + + return id(filter_age_krevs) >= threshold; + +#:########################################################################################:# +# TEXT SENSOR COMPONENT: +# https://esphome.io/components/text_sensor/ +#:########################################################################################:# +text_sensor: + # Public filter status for Home Assistant. + # This avoids Unknown/Off/On wording and always displays Clean or Dirty. + - platform: template + name: "${friendly_name} Filter EOL State" + id: filter_dirty_text + icon: mdi:air-filter + update_interval: 5s + lambda: |- + float threshold = id(filter_replacement_krevs).state; + + if (isnan(threshold) || threshold <= 0.0f) { + threshold = ${filter_replacement_default_krevs}; + } + + if (id(filter_age_krevs) >= threshold) { + return std::string("Dirty"); + } + + return std::string("Clean"); + +#:########################################################################################:# +# SENSOR COMPONENT: +# https://esphome.io/components/sensor/ +#:########################################################################################:# +sensor: + + # Total fan runtime in hours. + # Counts whenever the fan MOSFET is on, regardless of selected speed. + - platform: template + name: "${friendly_name} Fan Runhours" + id: fan_runtime_hours + icon: mdi:timer-outline + unit_of_measurement: "h" + device_class: duration + state_class: total_increasing + accuracy_decimals: 1 + update_interval: 60s + lambda: |- + return id(fan_runtime_seconds) / 3600.0f; + + # Fan speed calculated from the fan tacho pulse rate. + # pulse_counter reports pulses/min, then fan_revs_per_pulse converts it to RPM. + - platform: pulse_counter + name: "${friendly_name} Fan Speed" + pin: + number: D6 + mode: + input: true + pullup: false + id: filter_counter + unit_of_measurement: "RPM" + accuracy_decimals: 0 + count_mode: + rising_edge: INCREMENT + falling_edge: DISABLE + update_interval: 2s + filters: + - multiply: ${fan_revs_per_pulse} + + total: + # Filter age is displayed in kRevs, meaning 1000 fan revolutions. + # raw_pulses * fan_krevs_per_pulse = kRevs + name: "${friendly_name} Filter Age" + icon: mdi:counter + unit_of_measurement: "kRevs" + accuracy_decimals: 0 + filters: + - multiply: ${fan_krevs_per_pulse} + on_value: + then: + - if: + condition: + switch.is_on: fan_mosfet + then: + # Only save trusted filter age while the fan is deliberately running. + - lambda: |- + id(filter_age_krevs) = x; + - script.execute: update_filter_state + +#:########################################################################################:# +# SERVO COMPONENT: +# https://esphome.io/components/servo/ +# Not a servo here, but is the most appropriate component for the required output behaviour. +#:########################################################################################:# +servo: + # Set the PWM signal to 50 percent duty cycle. + - id: fan_motor + output: fan_pwm + max_level: 50% + +#:########################################################################################:# +# OUTPUT COMPONENT: +# https://esphome.io/components/output/ +#:########################################################################################:# +output: + # Fan PWM output. + - platform: esp8266_pwm + id: fan_pwm + pin: + number: D7 + + # Filter Dirty LED output on the IKEA unit. + # This is active high: output ON means D5 goes high and lights the LED. + - platform: gpio + id: panel_led_output + pin: + number: D5 + inverted: false + +#:########################################################################################:# +# SWITCH COMPONENT: +# https://esphome.io/components/switch/ +#:########################################################################################:# +switch: + # Control the fan motor power MOSFET. + # When the fan starts, reset the raw pulse counter total to the last trusted + # stored age so idle noise is ignored before real fan use begins. + # Runtime is counted whenever this switch is on, regardless of fan speed. + - platform: gpio + pin: D2 + id: fan_mosfet + restore_mode: ALWAYS_OFF + on_turn_on: + - lambda: |- + id(fan_runtime_last_ms) = millis(); + + - pulse_counter.set_total_pulses: + id: filter_counter + value: !lambda |- + return static_cast((id(filter_age_krevs) * 1000.0f) / ${fan_revs_per_pulse}); + + on_turn_off: + - lambda: |- + const uint32_t now = millis(); + + if (id(fan_runtime_last_ms) != 0) { + const uint32_t elapsed_seconds = (now - id(fan_runtime_last_ms)) / 1000; + + if (elapsed_seconds > 0) { + id(fan_runtime_seconds) += elapsed_seconds; + } + + id(fan_runtime_last_ms) = 0; + id(fan_runtime_hours).publish_state(id(fan_runtime_seconds) / 3600.0f); + } + + # Filter Dirty LED 1: D1 Mini onboard LED. + # D4 is active low on most D1 Mini boards. + - platform: gpio + id: onboard_led + pin: + number: D4 + inverted: true + restore_mode: ALWAYS_OFF + + # Filter Dirty LED 2: IKEA unit panel LED. + # This template switch starts/stops the flashing script and mirrors the + # warning state to the D1 Mini onboard LED. + - platform: template + name: "${friendly_name} Filter EOL Reached" + id: panel_led + optimistic: true + restore_mode: ALWAYS_OFF + turn_on_action: + - switch.turn_on: onboard_led + - script.execute: panel_led_flash + turn_off_action: + - script.stop: panel_led_flash + - output.turn_off: panel_led_output + - switch.turn_off: onboard_led + +#:########################################################################################:# +# INTERVAL COMPONENT: +# https://esphome.io/components/interval/ +#:########################################################################################:# +interval: + # Add runtime while the fan is operating. + # This uses millis() so the count is based on elapsed time, not just interval ticks. + - interval: 10s + then: + - if: + condition: + switch.is_on: fan_mosfet + then: + - lambda: |- + const uint32_t now = millis(); + + if (id(fan_runtime_last_ms) == 0) { + id(fan_runtime_last_ms) = now; + return; + } + + const uint32_t elapsed_seconds = (now - id(fan_runtime_last_ms)) / 1000; + + if (elapsed_seconds > 0) { + id(fan_runtime_seconds) += elapsed_seconds; + id(fan_runtime_last_ms) += elapsed_seconds * 1000; + id(fan_runtime_hours).publish_state(id(fan_runtime_seconds) / 3600.0f); + } + +#:########################################################################################:# +# SCRIPT COMPONENT: +# https://esphome.io/components/script/ +#:########################################################################################:# +script: + # Update the filter state and warning LEDs using kRevs rather than raw pulses. + - id: update_filter_state + mode: restart + then: + - if: + condition: + lambda: |- + float threshold = id(filter_replacement_krevs).state; + + if (isnan(threshold) || threshold <= 0.0f) { + threshold = ${filter_replacement_default_krevs}; + } + + return id(filter_age_krevs) >= threshold; + then: + - switch.turn_on: onboard_led + - switch.turn_on: panel_led + - lambda: |- + id(filter_dirty_text).publish_state("Dirty"); + else: + - switch.turn_off: panel_led + - switch.turn_off: onboard_led + - lambda: |- + id(filter_dirty_text).publish_state("Clean"); + + # Flash the IKEA panel dirty LED continuously at 500ms on / 500ms off. + # The loop is intentionally unconditional; switch.turn_off stops the script. + - id: panel_led_flash + mode: restart + then: + - while: + condition: + lambda: |- + return true; + then: + - output.turn_on: panel_led_output + - delay: 500ms + - output.turn_off: panel_led_output + - delay: 500ms \ No newline at end of file diff --git a/esphome/esp-centralstairs-top.yaml b/esphome/esp-centralstairs-top.yaml index 981175d..14230e2 100644 --- a/esphome/esp-centralstairs-top.yaml +++ b/esphome/esp-centralstairs-top.yaml @@ -6,6 +6,7 @@ # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-centralstairs-top.yaml #:########################################################################################:# # VERSIONS: +# V3.8 2026-04-26 Added Downstairs Lights Bulk Activation virtual switch toggled by Button 1 double-click # V3.7 2025-09-24 Upload to this device # V3.5 2025-07-24 YAML tidyups #:########################################################################################:# @@ -15,7 +16,8 @@ #:########################################################################################:# # OPERATION NOTES: # - Light switch at top of the central stairs -# - Button 1 controls Main Stair Lights via MQTT (remote device), using Relay 1 as a local mirror state +# - Button 1 single-click controls Main Stair Lights via MQTT (remote device), using Relay 1 as a local mirror state +# - Button 1 double-click toggles the Downstairs Lights Bulk Activation virtual switch for HA automations # - Button 2 toggles Relay 2 (Stair Footer Lights) - physically connected # - On MQTT connect, publishes current Relay 2 state to mqtt_status_topic_2 to keep remote status aligned #:########################################################################################:# @@ -27,20 +29,27 @@ # Remote device 2 (Stair Footer Lights): # - Command topic: ${mqtt_command_topic_2} -> ON,OFF # - Status topic: ${mqtt_status_topic_2} -> ON,OFF +# +# HA virtual switch: +# - Downstairs Lights Bulk Activation is exposed as a virtual switch for Home Assistant automations +# - No custom MQTT command/status topic is defined for this virtual switch #:########################################################################################:# # OFFLINE NOTES: # a) Home Assistant OFFLINE, but Network and MQTT ONLINE -# - Button 1 continues to publish MQTT commands for main stair lights +# - Button 1 single-click continues to publish MQTT commands for main stair lights +# - Button 1 double-click still toggles the local virtual switch, but HA automations will not act until HA returns # - Button 2 continues to toggle Relay 2 locally # - Relay 2 state continues to be published to mqtt_status_topic_2 # - HA entities are unavailable until HA returns # b) MQTT OFFLINE (but WiFi/Network and HA API ONLINE) # - Button 2 still toggles Relay 2 locally and is controllable via HA API # - Button 1 cannot control main stair lights (MQTT publish fails) +# - Button 1 double-click can still toggle the virtual switch via HA API # - Any MQTT state sync to remote devices will not occur while MQTT is down # c) Entire WiFi/Network OFFLINE # - Button 2 continues to toggle Relay 2 locally (standalone) # - Button 1 cannot control main stair lights (no network transport) +# - Button 1 double-click can toggle the local virtual switch state, but HA will not see it until network returns # - Timeclocks will drift without network (SNTP). Time of day can be reset by powering off then on again at 12pm (midday) #:########################################################################################:# @@ -74,7 +83,7 @@ substitutions: # Project Naming project_name: "Zemismart Technologies.KS-811 Double" # Project Details - project_version: "v2.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + project_version: "v2.1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version # MQTT Controls mqtt_command_main_topic: !secret mqtt_command_main_topic @@ -256,21 +265,38 @@ binary_sensor: - delayed_on: 30ms - delayed_off: 30ms name: "Button 1: ${switch_1_name}" - on_press: - # Toggle the remote Main Stair Lights via COMMAND topic, based on our mirrored state - - if: - condition: - lambda: 'return id(Relay_1).state;' - then: - - mqtt.publish: - topic: "${mqtt_command_topic_1}" - payload: "${mqtt_command_OFF}" - retain: false - else: - - mqtt.publish: - topic: "${mqtt_command_topic_1}" - payload: "${mqtt_command_ON}" - retain: false + on_multi_click: + # Double-click toggles a HA-visible virtual switch only. The double-click pattern is + # listed before the single-click pattern so a double-click does not also trigger the + # Main Stair Lights single-click MQTT action. + - timing: + - ON for at most 600ms + - OFF for at most 500ms + - ON for at most 600ms + - OFF for at least 150ms + then: + - switch.toggle: downstairs_lights_bulk_activation + + # Single-click toggles the remote Main Stair Lights via COMMAND topic, based on our + # mirrored Relay 1 state. This now waits for the click sequence to finish so it can + # distinguish a single-click from a double-click. + - timing: + - ON for at most 600ms + - OFF for at least 500ms + then: + - if: + condition: + lambda: 'return id(Relay_1).state;' + then: + - mqtt.publish: + topic: "${mqtt_command_topic_1}" + payload: "${mqtt_command_OFF}" + retain: false + else: + - mqtt.publish: + topic: "${mqtt_command_topic_1}" + payload: "${mqtt_command_ON}" + retain: false - platform: gpio pin: @@ -289,6 +315,15 @@ binary_sensor: # https://esphome.io/components/switch/ #:########################################################################################:# switch: + - platform: template + name: "Downstairs Lights Bulk Activation" + id: downstairs_lights_bulk_activation + icon: "mdi:lightbulb-group" + optimistic: true + restore_mode: ALWAYS_OFF + # HA automation helper only. Double-click Button 1 to toggle this switch on/off. + # It does not drive a relay directly and has no custom MQTT command/status topic. + - platform: gpio name: "Relay 1: ${switch_1_name}" pin: GPIO13 diff --git a/esphome/esp-dinpowermonitor-pmb.yaml b/esphome/esp-dinpowermonitor-pmb.yaml.sample similarity index 100% rename from esphome/esp-dinpowermonitor-pmb.yaml rename to esphome/esp-dinpowermonitor-pmb.yaml.sample diff --git a/esphome/esp-gasheater.yaml b/esphome/esp-gasheater.yaml index 112848c..9bb1df4 100644 --- a/esphome/esp-gasheater.yaml +++ b/esphome/esp-gasheater.yaml @@ -6,10 +6,12 @@ # https://home.fox.co.nz/gitea/zorruno/zorruno-homeassistant/src/branch/master/esphome/esp-gasheater.yaml #:########################################################################################:# # VERSIONS: -# V1.11 2026-04-21 Reboot now enters temporary FULL OFF hold before returning to BYPASS; -# FULL OFF is remembered across reboots if it was already active -# V1.10 2026-04-21 Added FULL OFF mode and reboot-safe shutdown to force heater OFF -# after ESPHome restart; fixed stray setpoint typo +# V1.11 2026-04-26 Restored Heater Operation after regression; restored fast optimistic +# master setpoint number with debounced MQTT publish; restored proportional +# flame tuning; kept current GPIO12/13/14 relay mapping +# V1.10 2026-04-25 Reworked OFF-state enforcement so non-BYPASS modes actively force the +# heater fully OFF when power is intended OFF; reboot now forces heater +# OFF before returning to BYPASS (Remote Only) # V1.8 2026-04-21 Physical testing, swapped GPIO12 and 14 (had the buttons/relays inverted) # 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 @@ -54,8 +56,8 @@ # - Flame Down step button # - Setpoint helper entities are available via: # - Setpoint Text -# - Setpoint Up (+0.5 °C) -# - Setpoint Down (-0.5 °C) +# - Setpoint Up (+${setpoint_step_c} °C) +# - Setpoint Down (-${setpoint_step_c} °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 @@ -63,19 +65,18 @@ # - 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) -# - FULL OFF mode is a stronger safety state than BYPASS: -# - If either heater LED shows the heater is still on, ESPHome will pulse the power -# button after a short delay to force the heater OFF -# - On normal ESPHome startup, the controller first enters FULL OFF for a short hold time -# to verify the heater is really off, then returns to BYPASS (Remote Only). -# - If FULL OFF was already active before reboot, FULL OFF is restored and remembered. +# - OFF = force heater Power OFF and set Mode to BYPASS (Remote Only) +# - In any mode except BYPASS (Remote Only), if the controller intends heater power OFF +# but either heater LED still shows the heater ON, ESPHome will pulse the heater ON/OFF +# button to force it fully OFF. +# - On every ESPHome restart (including yaml upload or power loss), the controller first +# forces the heater OFF, then returns 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. +# - If the heater is turned on externally while in AUTO and the controller intended it +# to be ON, 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: @@ -125,9 +126,12 @@ substitutions: api_key: !secret esp-api_key ota_pass: !secret esp-ota_pass static_ip_address: !secret esp-gasheater_ip + #mqtt_local_command_topic: !secret mqtt_command_main_topic + #mqtt_local_status_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_command_main_topic: !secret mqtt_command_main_topic - mqtt_local_status_main_topic: !secret mqtt_status_main_topic # Device Settings log_level: "INFO" @@ -145,9 +149,10 @@ substitutions: temp_stale_timeout_min: "20" fast_ramp_seconds: "240" fast_ramp_step_s: "4" - safe_power_off_delay_s: "2" - full_off_check_interval_s: "5" - boot_full_off_hold_s: "10" + setpoint_mqtt_debounce_ms: "500" + power_off_verify_delay_s: "2" + power_off_check_interval_s: "30" + boot_force_off_attempts: "3" # Optional anti short-cycle (set to "0" to disable either one) min_on_minutes: "1" @@ -171,7 +176,23 @@ substitutions: ######################################################################################## setpoint_min_c: "6.0" setpoint_max_c: "32.0" - setpoint_step_c: "0.1" + setpoint_step_c: "0.2" + + + ######################################################################################## + # PROPORTIONAL FLAME CONTROL + # - proportional_aggression = 1.0 keeps the base thresholds unchanged + # - >1.0 makes AUTO more aggressive (higher flame for the same temperature error) + # - <1.0 makes AUTO softer + # - individual flame_level_X_diff_c values can still be fine tuned + ######################################################################################## + proportional_aggression: "3.0" + flame_level_7_diff_c: "3.0" + flame_level_6_diff_c: "2.5" + flame_level_5_diff_c: "2.0" + flame_level_4_diff_c: "1.5" + flame_level_3_diff_c: "1.0" + flame_level_2_diff_c: "0.5" ########################################################################################## # PACKAGES: Included Common Packages @@ -195,6 +216,9 @@ packages: vars: local_device_name: "${device_name}" + #### WEB PORTAL #### + #common_webportal: !include common/webportal_common.yaml + common_sntp: !include file: common/sntp_common.yaml @@ -216,43 +240,19 @@ esphome: on_boot: priority: -100 then: - - script.execute: recompute_powered_state - lambda: |- - 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(); - } + // After any ESPHome restart, the controller must return to a safe OFF state. + id(power_intended_on) = false; + + // Keep the internal float mirror aligned with the user-facing number entity. + id(setpoint_c) = id(setpoint_number).state; id(last_temp_ms) = millis(); id(warmup_until_ms) = millis() + (${warmup_seconds} * 1000UL); - - if: - condition: - lambda: 'return id(full_off_persist);' - then: - - logger.log: "Boot: FULL OFF was active before reboot; restoring FULL OFF." - - select.set: - id: mode_select - option: "FULL OFF" - - script.execute: enforce_full_off - else: - - logger.log: "Boot: entering temporary FULL OFF hold before BYPASS." - - select.set: - id: mode_select - option: "FULL OFF" - - script.execute: enforce_full_off - - delay: ${boot_full_off_hold_s}s - - script.execute: recompute_powered_state - - if: - condition: - lambda: 'return !id(powered_state).state;' - then: - - logger.log: "Boot: heater appears OFF after FULL OFF hold; switching to BYPASS." - - select.set: - id: mode_select - option: "BYPASS (Remote Only)" - else: - - logger.log: "Boot: heater still appears ON after FULL OFF hold; staying in FULL OFF." + - script.execute: recompute_powered_state + - delay: 1s + - script.execute: boot_force_heater_off + ########################################################################################## # ESP PLATFORM ########################################################################################## @@ -340,6 +340,13 @@ globals: restore_value: no initial_value: "false" + # Controller intent for heater power in non-BYPASS modes. + # false = heater should be OFF and ESPHome will enforce OFF if LEDs still show ON. + - id: power_intended_on + type: bool + restore_value: no + initial_value: "false" + # Bench-test logical power state used only when Test Mode is enabled - id: test_powered type: bool @@ -364,13 +371,6 @@ globals: restore_value: no initial_value: "false" - # Persist whether FULL OFF was the active mode before reboot. - # If true, reboot returns to FULL OFF instead of temporary FULL OFF then BYPASS. - - id: full_off_persist - type: bool - restore_value: yes - initial_value: "false" - ########################################################################################## # ESPHOME LOGGING ENABLE ########################################################################################## @@ -393,14 +393,9 @@ binary_sensor: inverted: ${red_led_inverted} filters: - delayed_on_off: 50ms - entity_category: diagnostic + #entity_category: diagnostic on_state: - script.execute: recompute_powered_state - - if: - condition: - lambda: 'return !id(test_mode_enabled).state && id(mode_select).state == "FULL OFF" && (id(led_operating_blue).state || id(led_standby_red).state);' - then: - - script.execute: enforce_full_off - platform: gpio id: led_operating_blue @@ -413,14 +408,9 @@ binary_sensor: inverted: ${blue_led_inverted} filters: - delayed_on_off: 50ms - entity_category: diagnostic + #entity_category: diagnostic on_state: - script.execute: recompute_powered_state - - if: - condition: - lambda: 'return !id(test_mode_enabled).state && id(mode_select).state == "FULL OFF" && (id(led_operating_blue).state || id(led_standby_red).state);' - then: - - script.execute: enforce_full_off - platform: template id: powered_state @@ -433,7 +423,12 @@ binary_sensor: } - if: condition: - lambda: 'return !id(test_mode_enabled).state && (id(mode_select).state == "AUTO") && (!id(self_power_on));' + lambda: 'return !id(test_mode_enabled).state && id(mode_select).state != "BYPASS (Remote Only)" && !id(power_intended_on) && !id(self_power_on);' + then: + - script.execute: enforce_heater_off + - if: + condition: + lambda: 'return !id(test_mode_enabled).state && (id(mode_select).state == "AUTO") && id(power_intended_on) && (!id(self_power_on));' then: - lambda: |- id(ramp_until_ms) = millis() + (${fast_ramp_seconds} * 1000UL); @@ -481,6 +476,7 @@ switch: icon: mdi:test-tube optimistic: true restore_mode: ALWAYS_OFF + internal: true turn_on_action: - lambda: |- // Preserve current logical power state when entering Test Mode @@ -516,6 +512,8 @@ switch: option: "AUTO" turn_off_action: + - lambda: |- + id(power_intended_on) = false; - switch.turn_off: power_switch - select.set: id: mode_select @@ -523,16 +521,20 @@ switch: - platform: template id: power_switch - name: "${friendly_name} Power" + name: "${friendly_name} Activate Flame" icon: mdi:power lambda: |- return id(powered_state).state; turn_on_action: + - lambda: |- + if (id(mode_select).state != "BYPASS (Remote Only)" || id(test_mode_enabled).state) { + id(power_intended_on) = true; + } - if: condition: - lambda: 'return (id(mode_select).state == "BYPASS (Remote Only)" || id(mode_select).state == "FULL OFF") && !id(test_mode_enabled).state;' + lambda: 'return id(mode_select).state == "BYPASS (Remote Only)" && !id(test_mode_enabled).state;' then: - - logger.log: "BYPASS/FULL OFF: ignoring Power ON." + - logger.log: "BYPASS (Remote Only): ignoring Power ON." else: - if: condition: @@ -550,6 +552,10 @@ switch: - script.execute: after_power_on_reset_to_auto turn_off_action: + - lambda: |- + if (id(mode_select).state != "BYPASS (Remote Only)" || id(test_mode_enabled).state) { + id(power_intended_on) = false; + } - if: condition: lambda: 'return id(mode_select).state == "BYPASS (Remote Only)" && !id(test_mode_enabled).state;' @@ -600,15 +606,23 @@ sensor: float v = x; const float vmin = ${setpoint_min_c}; const float vmax = ${setpoint_max_c}; + const float step = ${setpoint_step_c}; if (v < vmin) v = vmin; if (v > vmax) v = vmax; + v = roundf(v / step) * step; id(sp_suppress_mqtt) = true; - const float step = ${setpoint_step_c}; - id(setpoint_c) = roundf(v / step) * step; - number.set: id: setpoint_number - value: !lambda 'return id(setpoint_c);' + value: !lambda |- + float v = x; + const float vmin = ${setpoint_min_c}; + const float vmax = ${setpoint_max_c}; + const float step = ${setpoint_step_c}; + if (v < vmin) v = vmin; + if (v > vmax) v = vmax; + v = roundf(v / step) * step; + return v; - lambda: |- id(sp_suppress_mqtt) = false; @@ -626,6 +640,10 @@ text_sensor: 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"); @@ -653,22 +671,12 @@ text_sensor: return std::string("Off (Test)"); } - if (mode == "FULL OFF") { - if (id(led_operating_blue).state) return std::string("Full Off (Operating)"); - if (id(led_standby_red).state) return std::string("Full Off (Standby)"); - return std::string("Full Off (Off)"); - } - 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 (!use_test_temp && id(room_temp_lost_fault)) { - return std::string("Fault (Room Temperature Lost)"); - } - if (mode == "MANUAL") { if (id(led_operating_blue).state) { char buf[32]; @@ -696,10 +704,10 @@ text_sensor: id: setpoint_text name: "Setpoint Text" icon: mdi:thermometer - update_interval: 1s + update_interval: 500ms lambda: |- char buf[16]; - snprintf(buf, sizeof(buf), "%.1f °C", id(setpoint_c)); + snprintf(buf, sizeof(buf), "%.1f °C", id(setpoint_number).state); return std::string(buf); - platform: template @@ -707,6 +715,7 @@ text_sensor: name: "${friendly_name} Test Mode Temp" icon: mdi:thermometer-chevron-up update_interval: 1s + internal: true lambda: |- char buf[20]; snprintf(buf, sizeof(buf), "%.1f °C", id(test_temp_c)); @@ -715,28 +724,22 @@ text_sensor: ########################################################################################## # SELECT COMPONENT ########################################################################################## -# Mode meanings: -# - AUTO = thermostat active -# - MANUAL = manual flame control allowed -# - BYPASS (Remote Only) = ESPHome control bypassed, heater may still be used externally -# - FULL OFF = ESPHome actively forces the heater OFF if it detects either LED on select: - platform: template id: mode_select name: "Mode" - options: ["AUTO","MANUAL","BYPASS (Remote Only)","FULL OFF"] + options: ["AUTO","MANUAL","BYPASS (Remote Only)"] optimistic: true initial_option: "BYPASS (Remote Only)" restore_value: false set_action: - lambda: |- - id(full_off_persist) = (x == "FULL OFF"); - if (x != "AUTO") id(room_temp_lost_fault) = false; - - if: - condition: - lambda: 'return x == "FULL OFF";' - then: - - script.execute: enforce_full_off + if (x == "BYPASS (Remote Only)") { + id(power_intended_on) = false; + } + if (x != "AUTO") { + id(room_temp_lost_fault) = false; + } - platform: template id: flame_level_select @@ -755,12 +758,13 @@ select: else: - if: condition: - lambda: 'return id(mode_select).state == "AUTO" || id(mode_select).state == "MANUAL";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - select.set: id: mode_select option: "MANUAL" - lambda: |- + id(power_intended_on) = true; int target = atoi(x.c_str()); if (target < 1) target = 1; if (target > 7) target = 7; @@ -793,7 +797,7 @@ select: else: - script.execute: adjust_to_desired else: - - logger.log: "BYPASS/FULL OFF: ignoring Flame Level selection." + - logger.log: "BYPASS (Remote Only): ignoring Flame Level selection." ########################################################################################## # BUTTON COMPONENT @@ -805,14 +809,16 @@ button: on_press: - if: condition: - lambda: 'return id(mode_select).state == "AUTO" || id(mode_select).state == "MANUAL";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: + - lambda: |- + id(power_intended_on) = true; - select.set: id: mode_select option: "MANUAL" - script.execute: step_up_once else: - - logger.log: "BYPASS/FULL OFF: ignoring Flame Up (step)." + - logger.log: "BYPASS (Remote Only): ignoring Flame Up (step)." - platform: template id: btn_flame_down @@ -820,14 +826,16 @@ button: on_press: - if: condition: - lambda: 'return id(mode_select).state == "AUTO" || id(mode_select).state == "MANUAL";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: + - lambda: |- + id(power_intended_on) = true; - select.set: id: mode_select option: "MANUAL" - script.execute: step_down_once else: - - logger.log: "BYPASS/FULL OFF: ignoring Flame Down (step)." + - logger.log: "BYPASS (Remote Only): ignoring Flame Down (step)." - platform: template id: btn_calibrate_min @@ -841,39 +849,37 @@ button: 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; - // Snap to the nearest configured step to avoid float drift - v = roundf(v / step) * step; - id(setpoint_c) = v; - number.set: id: setpoint_number - value: !lambda 'return id(setpoint_c);' + value: !lambda |- + const float step = ${setpoint_step_c}; + float v = id(setpoint_number).state + step; + const float vmax = ${setpoint_max_c}; + if (v > vmax) v = vmax; + v = roundf(v / step) * step; + return v; - 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; - // Snap to the nearest configured step to avoid float drift - v = roundf(v / step) * step; - id(setpoint_c) = v; - number.set: id: setpoint_number - value: !lambda 'return id(setpoint_c);' + value: !lambda |- + const float step = ${setpoint_step_c}; + float v = id(setpoint_number).state - step; + const float vmin = ${setpoint_min_c}; + if (v < vmin) v = vmin; + v = roundf(v / step) * step; + return v; ########################################################################################## # NUMBER COMPONENT ########################################################################################## number: + # User-facing setpoint control. + # This number is the master source of truth for the setpoint so HA/OpenHASP reacts immediately. - platform: template id: setpoint_number name: "${friendly_name} Setpoint" @@ -883,8 +889,9 @@ number: max_value: ${setpoint_max_c} step: ${setpoint_step_c} mode: slider - lambda: |- - return id(setpoint_c); + optimistic: true + restore_value: true + initial_value: 21.0 set_action: - lambda: |- const float step = ${setpoint_step_c}; @@ -894,13 +901,7 @@ number: lambda: |- return !id(sp_suppress_mqtt); then: - - mqtt.publish: - topic: "viewroad-status/lounge-gasheater/setpoint" - retain: true - payload: !lambda |- - char buf[16]; - snprintf(buf, sizeof(buf), "%.1f", x); - return std::string(buf); + - script.execute: publish_setpoint_mqtt # Bench-test room temperature slider used by AUTO whenever Test Mode is ON. - platform: template @@ -912,6 +913,7 @@ number: max_value: 40.0 step: 0.1 mode: slider + internal: true lambda: |- return id(test_temp_c); set_action: @@ -930,19 +932,34 @@ interval: then: - script.execute: auto_control_tick - # In FULL OFF, keep checking that the heater is really off. - - interval: ${full_off_check_interval_s}s + # Outside BYPASS, if the controller intends power OFF but LEDs still show ON, + # keep checking and force the heater OFF. + - interval: ${power_off_check_interval_s}s then: - if: condition: - lambda: 'return !id(test_mode_enabled).state && id(mode_select).state == "FULL OFF" && id(powered_state).state;' + lambda: 'return !id(test_mode_enabled).state && id(mode_select).state != "BYPASS (Remote Only)" && !id(power_intended_on) && id(powered_state).state && !id(self_power_on);' then: - - script.execute: enforce_full_off + - script.execute: enforce_heater_off ########################################################################################## # SCRIPT COMPONENT ########################################################################################## script: + # Debounced setpoint MQTT mirror. + # Keeps HA/OpenHASP setpoint changes responsive while avoiding retained-MQTT bursts. + - id: publish_setpoint_mqtt + mode: restart + then: + - delay: ${setpoint_mqtt_debounce_ms}ms + - mqtt.publish: + topic: "viewroad-status/lounge-gasheater/setpoint" + retain: true + payload: !lambda |- + char buf[16]; + snprintf(buf, sizeof(buf), "%.1f", id(setpoint_c)); + return std::string(buf); + # 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 @@ -954,6 +971,8 @@ script: if (id(status_text).state.size() == 0) return std::string("Unknown"); return id(status_text).state; + # Recompute the helper powered state from LEDs or the Test Mode override. + # Status MQTT publishing is handled by status_text on_value so we avoid duplicate publishes here. - id: recompute_powered_state then: - lambda: |- @@ -964,20 +983,42 @@ script: id(test_mode_enabled).state ? id(test_powered) : led_powered; id(powered_state).publish_state(new_state); - - script.execute: publish_status - # FULL OFF enforcement helper. - # After a short delay, if the heater still looks on, pulse the power button once. - - id: enforce_full_off + # Force heater OFF after an ESPHome reboot before returning to BYPASS. + - id: boot_force_heater_off mode: restart then: - - delay: ${safe_power_off_delay_s}s + - repeat: + count: ${boot_force_off_attempts} + then: + - script.execute: recompute_powered_state + - if: + condition: + lambda: 'return !id(test_mode_enabled).state && id(powered_state).state;' + then: + - logger.log: "Boot: heater appears ON, pulsing power to force OFF." + - script.execute: press_power + - script.wait: press_with_gap + - delay: ${power_off_verify_delay_s}s + - script.execute: recompute_powered_state + - select.set: + id: mode_select + option: "BYPASS (Remote Only)" + - lambda: |- + id(power_intended_on) = false; + + # In non-BYPASS modes, if the controller intends power OFF but LEDs still show ON, + # pulse the heater ON/OFF button to force the heater fully OFF. + - id: enforce_heater_off + mode: restart + then: + - delay: ${power_off_verify_delay_s}s - script.execute: recompute_powered_state - if: condition: - lambda: 'return !id(test_mode_enabled).state && id(mode_select).state == "FULL OFF" && id(powered_state).state;' + lambda: 'return !id(test_mode_enabled).state && id(mode_select).state != "BYPASS (Remote Only)" && !id(power_intended_on) && id(powered_state).state && !id(self_power_on);' then: - - logger.log: "FULL OFF: heater still appears ON, pulsing power to force OFF." + - logger.log: "Heater should be OFF but LEDs still show ON. Pulsing power to force OFF." - script.execute: press_power # Low-level relay click helper. @@ -1020,25 +1061,25 @@ script: then: - if: condition: - lambda: 'return id(mode_select).state == "AUTO" || id(mode_select).state == "MANUAL";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - script.execute: id: press_with_gap which: "up" else: - - logger.log: "BYPASS/FULL OFF: ignoring UP press." + - logger.log: "BYPASS (Remote Only): ignoring UP press." - id: press_down then: - if: condition: - lambda: 'return id(mode_select).state == "AUTO" || id(mode_select).state == "MANUAL";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: - script.execute: id: press_with_gap which: "down" else: - - logger.log: "BYPASS/FULL OFF: ignoring DOWN press." + - logger.log: "BYPASS (Remote Only): ignoring DOWN press." # Step one flame level UP and only update the visible level after the relay click finishes. - id: step_up_once @@ -1155,8 +1196,10 @@ script: then: - if: condition: - lambda: 'return id(mode_select).state == "AUTO" || id(mode_select).state == "MANUAL";' + lambda: 'return id(mode_select).state != "BYPASS (Remote Only)";' then: + - lambda: |- + id(power_intended_on) = true; - if: condition: lambda: 'return id(test_mode_enabled).state;' @@ -1238,6 +1281,7 @@ script: if (t <= low && can_turn_on) { ESP_LOGI("gas", "AUTO: below setpoint -> ON"); + id(power_intended_on) = true; id(press_power).execute(); if (id(test_mode_enabled).state) { id(test_powered) = true; @@ -1250,6 +1294,7 @@ script: if (t >= high && can_turn_off) { ESP_LOGI("gas", "AUTO: above setpoint -> OFF"); + id(power_intended_on) = false; id(press_power).execute(); if (id(test_mode_enabled).state) { id(test_powered) = false; @@ -1263,13 +1308,19 @@ script: float diff = sp - t; int target = 1; - if (diff > 3.0f) target = 7; - 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; + // Proportional flame mapping: + // - A higher proportional_aggression lowers the effective thresholds and makes + // the controller choose higher flame levels sooner. + // - The individual flame_level_X_diff_c substitutions still allow fine tuning. + const float k = ${proportional_aggression}; + + if (diff >= (${flame_level_7_diff_c} / k)) target = 7; + else if (diff >= (${flame_level_6_diff_c} / k)) target = 6; + else if (diff >= (${flame_level_5_diff_c} / k)) target = 5; + else if (diff >= (${flame_level_4_diff_c} / k)) target = 4; + else if (diff >= (${flame_level_3_diff_c} / k)) target = 3; + else if (diff >= (${flame_level_2_diff_c} / k)) target = 2; + else target = 1; id(desired_level) = target; id(target_confirmed) = (target == id(last_level_target)); diff --git a/esphome/esp-loungemainsdimmer1.yaml b/esphome/esp-loungemainsdimmer1.yaml.sample similarity index 100% rename from esphome/esp-loungemainsdimmer1.yaml rename to esphome/esp-loungemainsdimmer1.yaml.sample diff --git a/esphome/esp-loungemoesdimmer1.yaml b/esphome/esp-loungemoesdimmer1.yaml.sample similarity index 100% rename from esphome/esp-loungemoesdimmer1.yaml rename to esphome/esp-loungemoesdimmer1.yaml.sample diff --git a/esphome/esp-loungemoesdimmer2.yaml b/esphome/esp-loungemoesdimmer2.yaml.sample similarity index 100% rename from esphome/esp-loungemoesdimmer2.yaml rename to esphome/esp-loungemoesdimmer2.yaml.sample diff --git a/esphome/esp-midesklamp1s.yaml b/esphome/esp-midesklamp1s.yaml.sample similarity index 100% rename from esphome/esp-midesklamp1s.yaml rename to esphome/esp-midesklamp1s.yaml.sample diff --git a/esphome/esp-nexmulti1.yaml b/esphome/esp-nexmulti1.yaml.sample similarity index 100% rename from esphome/esp-nexmulti1.yaml rename to esphome/esp-nexmulti1.yaml.sample diff --git a/esphome/esp-nfcaccess1-33ad74.yaml.temp b/esphome/esp-nfcaccess1-33ad74.yaml.sample similarity index 100% rename from esphome/esp-nfcaccess1-33ad74.yaml.temp rename to esphome/esp-nfcaccess1-33ad74.yaml.sample diff --git a/esphome/esp-officelights copy.yaml.old b/esphome/esp-officelights copy.yaml.old deleted file mode 100644 index 553ecd5..0000000 --- a/esphome/esp-officelights copy.yaml.old +++ /dev/null @@ -1,177 +0,0 @@ -############################################# -############################################# -# OFFICE MAIN LIGHTSWITCH -# V2.0 2025-06-05 YAML Tidyups -# V1.0 2025-05-31 Initial Version -############################################# -# Zemismart KS-811 Triple push button -# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ -# -# NOTES -# - -# -############################################# -############################################# - -############################################# -# 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-officelights" - friendly_name: "Office Main Lightswitch (3)" - description_comment: "Office Main Lightswitch using a Zemismart KS-811 Triple Push Button. Bunker Light A (1), Spare A (2), Spare B (3)" - device_area: "Office" # 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: "v2.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-officelights_ip - - # 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 - - # Switch Naming - switch_1_name: "Nighttime Lights" # Only one light (Bunker Light) actually connected to this relay - switch_2_name: "Daytime Lights" # This is virtual only, no power connected to 2nd relay - switch_3_name: "Spare" # 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 - file: common/network_common.yaml - vars: - local_device_name: "${device_name}" - local_static_ip_address: "${static_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 - #### 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 - -############################################# -# 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 - -############################################# -# 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 -# 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 - id: logger_id - -############################################# -# STATUS LED -# https://esphome.io/components/status_led.html -############################################# -status_led: - pin: - number: GPIO2 - inverted: yes - -############################################# -# BINARY SENSORS -# https://esphome.io/components/binary_sensor/ -############################################# -binary_sensor: - - platform: gpio - pin: - number: GPIO16 - mode: INPUT - inverted: True - use_interrupt: False # GPIO16 pin doesn't support interrupts so use polling. Only supresses a warning. - name: "Button 1: ${switch_1_name}" - on_press: - - switch.toggle: Relay_1 - - - platform: gpio - pin: - number: GPIO05 - mode: INPUT - inverted: True - name: "Button 2: ${switch_2_name}" - on_press: - - switch.toggle: Relay_2 - - - platform: gpio - pin: - number: GPIO4 - mode: INPUT - inverted: True - name: "Button 3: ${switch_3_name}" - on_press: - - switch.toggle: Relay_3 - -############################################# -# SWITCH COMPONENT -# https://esphome.io/components/switch/ -############################################# -switch: - - platform: gpio - name: "Relay 1: ${switch_1_name}" - pin: GPIO13 - id: Relay_1 - - platform: gpio - name: "Relay 2: ${switch_2_name}" - pin: GPIO12 - id: Relay_2 - - platform: gpio - name: "Relay 3: ${switch_3_name}" - pin: GPIO14 - id: Relay_3 \ No newline at end of file diff --git a/esphome/esp-rgblampbulb2.yaml b/esphome/esp-rgblampbulb2.yaml.sample similarity index 100% rename from esphome/esp-rgblampbulb2.yaml rename to esphome/esp-rgblampbulb2.yaml.sample diff --git a/packages/downstairs_bulk_lights_on_from_stairs.yaml b/packages/downstairs_bulk_lights_on_from_stairs.yaml new file mode 100644 index 0000000..4044b03 --- /dev/null +++ b/packages/downstairs_bulk_lights_on_from_stairs.yaml @@ -0,0 +1,88 @@ +################################################################################ +# PACKAGE: Downstairs Lights Bulk Activation +# FILE: packages/downstairs_lights_bulk_activation.yaml +# +# Version: 1.0 +# Date: 2026-04-26 +# +# Notes: +# - Uses the virtual switch: +# switch.central_stair_lightswitch_top_2_downstairs_lights_bulk_activation +# +# - When the virtual switch turns ON: +# Turns ON the listed downstairs lights, but only if each light is currently OFF. +# +# - When the virtual switch turns OFF: +# Turns OFF the listed downstairs lights, but only if each light is currently ON. +# +# - No action is taken unless: +# input_boolean.downstairs_flat_occupied is ON. +################################################################################ + +automation: + - id: downstairs_lights_bulk_activation + alias: "Downstairs Lights Bulk Activation" + description: > + V1.0 - 2026-04-26: Bulk ON/OFF control for downstairs lights from the + central stair lightswitch virtual switch. Only operates when the downstairs + flat occupied input_boolean is ON. + + mode: single + + trigger: + - platform: state + entity_id: switch.central_stair_lightswitch_top_2_downstairs_lights_bulk_activation + to: + - "on" + - "off" + + condition: + - condition: state + entity_id: input_boolean.downstairs_flat_occupied + state: "off" + + action: + - choose: + ###################################################################### + # BULK ACTIVATION ON: + # Turn lights ON, but only where they are currently OFF. + ###################################################################### + - conditions: + - condition: state + entity_id: switch.central_stair_lightswitch_top_2_downstairs_lights_bulk_activation + state: "on" + sequence: + - repeat: + for_each: + - switch.esp_centralstairs_bottom_relay_1_main_stair_lights_lower + - switch.esp_downstloungemain_relay_1_main_lights + - switch.esp_downstkitchlights_relay_2_kitchen_light + - switch.esp_downstkitchlights_relay_1_dining_light + sequence: + - condition: template + value_template: "{{ is_state(repeat.item, 'off') }}" + - service: switch.turn_on + target: + entity_id: "{{ repeat.item }}" + + ###################################################################### + # BULK ACTIVATION OFF: + # Turn lights OFF, but only where they are currently ON. + ###################################################################### + - conditions: + - condition: state + entity_id: switch.central_stair_lightswitch_top_2_downstairs_lights_bulk_activation + state: "off" + sequence: + - repeat: + for_each: + - switch.esp_centralstairs_bottom_relay_1_main_stair_lights_lower + - switch.esp_downstloungemain_relay_1_main_lights + - switch.esp_downstkitchlights_relay_2_kitchen_light + - switch.esp_downstkitchlights_relay_1_dining_light + sequence: + - condition: template + value_template: "{{ is_state(repeat.item, 'on') }}" + - service: switch.turn_off + target: + entity_id: "{{ repeat.item }}" diff --git a/packages/office_lights_power_backup_occupancy.yaml b/packages/office_lights_power_backup_occupancy.yaml index 93e7ee1..92a2b2f 100644 --- a/packages/office_lights_power_backup_occupancy.yaml +++ b/packages/office_lights_power_backup_occupancy.yaml @@ -132,15 +132,15 @@ automation: target: entity_id: switch.esp_officedeskrightgpo_office_right_hand_gpo - - alias: "Turn on Office USB Hub if needed" - if: - - condition: state - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply - state: "off" - then: - - action: switch.turn_on - target: - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + #- alias: "Turn on Office USB Hub if needed" + # if: + # - condition: state + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + # state: "off" + # then: + # - action: switch.turn_on + # target: + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply ############################################################## # Lights. @@ -294,15 +294,15 @@ automation: target: entity_id: switch.esp_officeelvcontrol_office_elv_power_supply - - alias: "Turn off Office USB Hub power supply if needed" - if: - - condition: state - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply - state: "on" - then: - - action: switch.turn_off - target: - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + #- alias: "Turn off Office USB Hub power supply if needed" + # if: + # - condition: state + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + # state: "on" + # then: + # - action: switch.turn_off + # target: + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply ############################################################## # Manual master/latch relay off last. @@ -395,15 +395,15 @@ automation: target: entity_id: switch.esp_officeelvcontrol_office_elv_power_supply - - alias: "Turn off Office USB Hub power supply if needed" - if: - - condition: state - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply - state: "on" - then: - - action: switch.turn_off - target: - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + #- alias: "Turn off Office USB Hub power supply if needed" + # if: + # - condition: state + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + # state: "on" + # then: + # - action: switch.turn_off + # target: + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply ############################################################## # Manual master/latch relay off last. @@ -456,15 +456,15 @@ automation: target: entity_id: switch.esp_officedeskrightgpo_office_right_hand_gpo - - alias: "Turn on Office USB Hub power supply if needed" - if: - - condition: state - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply - state: "off" - then: - - action: switch.turn_on - target: - entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + # alias: "Turn on Office USB Hub power supply if needed" + # if: + # - condition: state + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply + # state: "off" + # then: + # - action: switch.turn_on + # target: + # entity_id: switch.esp_officeusbhubpower_usb_hub_power_supply ############################################################## # Lights. diff --git a/packages/openhasp_lounge1_wallplate.yaml b/packages/openhasp_lounge1_wallplate.yaml index ee51697..1de0a94 100644 --- a/packages/openhasp_lounge1_wallplate.yaml +++ b/packages/openhasp_lounge1_wallplate.yaml @@ -56,7 +56,6 @@ automation: # ------------------------------------------------------------------------- # 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 @@ -64,20 +63,13 @@ automation: mode: queued trigger: - platform: state - 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 + entity_id: sensor.lounge_environment_lounge_environment_temperature action: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b1.text" 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 raw = states('sensor.lounge_environment_lounge_environment_temperature') %} {% set cleaned = raw | replace('°C', '') | replace('° C', '') @@ -189,9 +181,9 @@ automation: # ------------------------------------------------------------------------- # 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 + # - Operation OFF: dark grey background, light grey flame + # - Operation ON, Activate Flame OFF: theme blue background, white flame + # - Operation ON, Activate Flame ON: theme blue background, solid red flame # ------------------------------------------------------------------------- - id: hasp_heat_button_state alias: "HASP: update heat button state (p1b6)" @@ -200,19 +192,15 @@ automation: - platform: state entity_id: - switch.rinnai_neo_gas_heater_heater_operation - - switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_power + - switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame action: - choose: - # OFF → dark grey (same as your other inactive buttons) + # Heater Operation OFF -> dark grey button, light grey flame - 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" @@ -221,9 +209,8 @@ automation: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" - payload: "#FFFFFF" + payload: "#C0C0C0" - # solid dark grey (no gradient) - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" @@ -237,19 +224,15 @@ automation: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#2F3240" - # ON (not firing) → theme blue + # Heater Operation ON, flame OFF -> blue button, white flame - 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 + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame 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" @@ -260,7 +243,6 @@ automation: 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" @@ -274,13 +256,13 @@ automation: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#0095D9" - # ON + flame → blue background + flicker + # Heater Operation ON, flame ON -> blue button, red flame - 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 + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame state: "on" sequence: - service: mqtt.publish @@ -288,7 +270,11 @@ automation: topic: "hasp/openhasp_1/command/p1b6.text" payload: "\uE238" - # keep blue background + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FF3030" + - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" @@ -302,10 +288,6 @@ automation: 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 # ------------------------------------------------------------------------- @@ -354,11 +336,7 @@ script: data: topic: "hasp/openhasp_1/command/p1b1.text" 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 raw = states('sensor.lounge_environment_lounge_environment_temperature') %} {% set cleaned = raw | replace('°C', '') | replace('° C', '') @@ -391,6 +369,7 @@ script: payload: "\uE238" - choose: + # Heater Operation OFF -> dark grey button, light grey flame - conditions: - condition: state entity_id: switch.rinnai_neo_gas_heater_heater_operation @@ -399,7 +378,7 @@ script: - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.text_color" - payload: "#FFFFFF" + payload: "#C0C0C0" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" @@ -413,12 +392,13 @@ script: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#2F3240" + # Heater Operation ON, flame OFF -> blue button, white flame - 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 + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame state: "off" sequence: - service: mqtt.publish @@ -438,14 +418,19 @@ script: topic: "hasp/openhasp_1/command/p1b6.border_color" payload: "#0095D9" + # Heater Operation ON, flame ON -> blue button, red flame - 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 + entity_id: switch.rinnai_neo_gas_heater_rinnai_neo_gas_heater_activate_flame state: "on" sequence: + - service: mqtt.publish + data: + topic: "hasp/openhasp_1/command/p1b6.text_color" + payload: "#FF3030" - service: mqtt.publish data: topic: "hasp/openhasp_1/command/p1b6.bg_color" @@ -458,9 +443,6 @@ script: 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 @@ -502,45 +484,3 @@ script: - 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"