From e96344e3ad355365c01bb025191959b5ab7016b8 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 8 Oct 2025 19:21:28 +1300 Subject: [PATCH] esphome lounge switches and scene control --- .ha_run.lock | 1 + automations/two_way_light_switching.yaml | 10 +- esphome/common/include_my_mqtt_commands.yaml | 8 + .../include_resetcount_diag_sensors.yaml | 72 +- esphome/common/mqtt_common.yaml | 1 - esphome/esp-3dprinterpow.yaml | 1 + esphome/esp-attobattery.yaml | 71 +- esphome/esp-bedrm2ceilingfan.yaml | 27 +- esphome/esp-bedrm2fanswitch.yaml | 27 +- esphome/esp-bedrm2lights.yaml | 29 +- esphome/esp-bedrm3ceilingfan.yaml | 37 +- esphome/esp-bedrm3fanswitch.yaml | 29 +- esphome/esp-bedrm3lights.yaml | 29 +- esphome/esp-breakfastbarleds.yaml | 120 +- esphome/esp-centralstairs-bottom.yaml | 29 +- esphome/esp-centralstairs-top.yaml | 29 +- esphome/esp-datacupboardpower-left.yaml | 37 +- esphome/esp-datacupboardpower-right.yaml | 37 +- esphome/esp-downstairsdishwasher.yaml | 37 +- esphome/esp-downstairskitchleds.yaml | 115 +- esphome/esp-downstbathswitch.yaml | 67 +- esphome/esp-downstbathtowelrail.yaml | 29 +- esphome/esp-downstbedrm2lights.yaml | 29 +- esphome/esp-downstkitchlights.yaml | 29 +- esphome/esp-downstloungeentry.yaml | 29 +- esphome/esp-downstloungemain.yaml | 26 +- esphome/esp-downstloungeoutside.yaml | 26 +- esphome/esp-downstmasterbedrmlights.yaml | 29 +- esphome/esp-entbtproxy.yaml | 26 +- esphome/esp-entmulti.yaml | 36 +- esphome/esp-entrancebathrmlights.yaml | 26 +- esphome/esp-entrancelightswitch.yaml | 26 +- esphome/esp-flysprayer1.yaml | 26 +- esphome/esp-laundrydrypow.yaml | 26 +- esphome/esp-laundryenv.yaml | 26 +- esphome/esp-laundrylights.yaml | 14 +- esphome/esp-laundryplugpow.yaml | 26 +- esphome/esp-laundrywashpow.yaml | 26 +- esphome/esp-lounge6chdimmer.yaml | 29 +- esphome/esp-loungebookshelfleds.yaml | 124 +- esphome/esp-loungecabinetleds2.yaml | 120 +- esphome/esp-loungemiddleswitch.yaml | 395 +++++ esphome/esp-loungenorthswitch.yaml | 315 ++++ esphome/esp-loungepelmetleds.yaml | 1408 +++++++++++++++++ esphome/esp-loungesouthleftswitch.yaml | 188 +++ esphome/esp-loungesouthrightswitch.yaml | 221 +++ esphome/esp-loungewestswitch.yaml | 315 ++++ esphome/esp-mainbathfancombo.yaml | 26 +- esphome/esp-mainbathlights.yaml | 26 +- esphome/esp-maindishwasherpower.yaml | 28 +- esphome/esp-mainkitchenlights.yaml | 26 +- esphome/esp-masterbathtowelrail.yaml | 38 +- esphome/esp-midesklamp1s.yaml | 26 +- esphome/esp-occupancyoffice.yaml | 26 +- esphome/esp-occupancystair.yaml | 26 +- esphome/esp-officeduallights.yaml | 38 +- esphome/esp-officeelvcontrol.yaml | 26 +- esphome/esp-officelights.yaml | 26 +- esphome/esp-officeusbhubpower.yaml | 26 +- esphome/esp-poolpumppower.yaml | 36 +- esphome/esp-underhouselights.yaml | 26 +- packages/lounge_lighting_scenes.yaml | 331 ++++ 62 files changed, 4189 insertions(+), 925 deletions(-) create mode 100644 .ha_run.lock create mode 100644 esphome/common/include_my_mqtt_commands.yaml create mode 100644 esphome/esp-loungemiddleswitch.yaml create mode 100644 esphome/esp-loungenorthswitch.yaml create mode 100644 esphome/esp-loungepelmetleds.yaml create mode 100644 esphome/esp-loungesouthleftswitch.yaml create mode 100644 esphome/esp-loungesouthrightswitch.yaml create mode 100644 esphome/esp-loungewestswitch.yaml create mode 100644 packages/lounge_lighting_scenes.yaml diff --git a/.ha_run.lock b/.ha_run.lock new file mode 100644 index 0000000..6a441fc --- /dev/null +++ b/.ha_run.lock @@ -0,0 +1 @@ +{"pid": 67, "version": 1, "ha_version": "2025.10.1", "start_ts": 1759647901.614362} \ No newline at end of file diff --git a/automations/two_way_light_switching.yaml b/automations/two_way_light_switching.yaml index adca7f8..0d69c00 100644 --- a/automations/two_way_light_switching.yaml +++ b/automations/two_way_light_switching.yaml @@ -11,20 +11,20 @@ state: "on" sequence: - service: switch.turn_on - entity_id: switch.tasmo_ks811d_5613_lounge_4b + entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1 default: - service: switch.turn_off - entity_id: switch.tasmo_ks811d_5613_lounge_4b + entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1 - id: "Two_Way_Lights_-_Garage_Corridor_-_2" alias: "Two Way Lights - Garage Corridor - 2" trigger: - platform: state - entity_id: switch.tasmo_ks811d_5613_lounge_4b + entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1 action: - choose: - conditions: - condition: state - entity_id: switch.tasmo_ks811d_5613_lounge_4b + entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1 state: "on" sequence: - service: switch.turn_on @@ -46,7 +46,7 @@ state: "on" sequence: - service: switch.turn_on - entity_id: switch.tasmo_sbas_0407_garagelight + entity_id: switch.esp_loungesouthleftswitch_relay_2_outside_light_1 default: - service: switch.turn_off entity_id: switch.tasmo_sbas_0407_garagelight diff --git a/esphome/common/include_my_mqtt_commands.yaml b/esphome/common/include_my_mqtt_commands.yaml new file mode 100644 index 0000000..c63a862 --- /dev/null +++ b/esphome/common/include_my_mqtt_commands.yaml @@ -0,0 +1,8 @@ +substitutions: + mqtt_command_main_topic: !secret mqtt_command_main_topic + mqtt_status_main_topic: !secret mqtt_status_main_topic + + # MQTT REMOTE Controls + mqtt_remote1_device_name: "3dprinter-power" + mqtt_remote1_command_topic: "${mqtt_command_main_topic}/${mqtt_remote1_device_name}" # Topic we will use to command this locally without HA + mqtt_remote1_status_topic: "${mqtt_status_main_topic}/${mqtt_remote1_device_name}" # Topic we will use to view status locally without HA \ No newline at end of file diff --git a/esphome/common/include_resetcount_diag_sensors.yaml b/esphome/common/include_resetcount_diag_sensors.yaml index 85dd29b..7611cdd 100644 --- a/esphome/common/include_resetcount_diag_sensors.yaml +++ b/esphome/common/include_resetcount_diag_sensors.yaml @@ -115,7 +115,6 @@ button: # SCRIPTS ########################################################################################## script: - # Classify last reset exactly once per boot - id: classify_reset_once mode: restart then: @@ -123,40 +122,60 @@ script: // Guard: only run once per boot if (id(reset_classified_this_boot)) return; - // Read raw reason string (examples: "Power on", "External System", - // "Software/System restart", "Fatal exception:29", "WDT reset") - String reason = ESP.getResetReason(); + // Build a human-readable reason string that's valid on both ESP8266 and ESP32 + std::string reason; + int cat = 0; // 1=power, 2=software, 3=crash - // Category: 1=power, 2=software, 3=crash - int cat = 0; + #if defined(ARDUINO_ARCH_ESP8266) + // ESP8266: use Arduino core helper, returns Arduino String + reason = std::string(ESP.getResetReason().c_str()); - // Crash has priority if phrases appear (rare but be explicit) - if (reason.indexOf("Watchdog") >= 0 || reason.indexOf("WDT") >= 0 || - reason.indexOf("Exception") >= 0 || reason.indexOf("exception") >= 0) { - cat = 3; // crash - } - // Software/System restart (HA/API/OTA initiated) - else if (reason.indexOf("Software") >= 0 || reason.indexOf("System") >= 0) { - cat = 2; // software - } - // Power-like causes (power-on, external reset pin/button, deep sleep wake) - else if (reason.indexOf("Power") >= 0 || reason.indexOf("External") >= 0 || - reason.indexOf("Deep") >= 0) { - cat = 1; // power - } - // Anything else -> crash bucket - else { + // Classify (string match like your original) + if (reason.find("Watchdog") != std::string::npos || + reason.find("WDT") != std::string::npos || + reason.find("Exception")!= std::string::npos || + reason.find("exception")!= std::string::npos) { + cat = 3; + } else if (reason.find("Software") != std::string::npos || + reason.find("System") != std::string::npos) { + cat = 2; + } else if (reason.find("Power") != std::string::npos || + reason.find("External") != std::string::npos || + reason.find("Deep") != std::string::npos) { + cat = 1; + } else { + cat = 3; + } + + #elif defined(ARDUINO_ARCH_ESP32) + // ESP32: use IDF enum and map to text + categories directly + esp_reset_reason_t r = esp_reset_reason(); + switch (r) { + case ESP_RST_POWERON: reason = "Power on"; cat = 1; break; + case ESP_RST_EXT: reason = "External reset"; cat = 1; break; // reset pin/button + case ESP_RST_SW: reason = "Software reset"; cat = 2; break; // OTA/API/HA/etc. + case ESP_RST_PANIC: reason = "Panic/exception"; cat = 3; break; + case ESP_RST_INT_WDT: reason = "Interrupt WDT"; cat = 3; break; + case ESP_RST_TASK_WDT: reason = "Task WDT"; cat = 3; break; + case ESP_RST_WDT: reason = "Other WDT"; cat = 3; break; + case ESP_RST_DEEPSLEEP: reason = "Deep sleep wake"; cat = 1; break; + case ESP_RST_BROWNOUT: reason = "Brownout"; cat = 1; break; // power-ish + case ESP_RST_SDIO: reason = "SDIO reset"; cat = 3; break; + default: reason = "Unknown reset reason"; cat = 3; break; + } + #else + // Fallback for any other arch (very unlikely in your setup) + reason = "Unknown platform reset"; cat = 3; - } + #endif + // Increment counters if (cat == 1) id(power_reset_count) += 1; if (cat == 2) id(software_reset_count) += 1; if (cat == 3) id(crash_reset_count) += 1; - // Publish reason text now + // Publish reason and mark done id(last_reset_reason_txt).publish_state(reason.c_str()); - - // Mark done for this boot id(reset_classified_this_boot) = true; # Publish the three counters (kept separate so we can reuse) @@ -181,3 +200,4 @@ interval: - script.execute: classify_reset_once - script.execute: publish_reset_status # On later passes, the guard prevents re-counting and this block does nothing. + diff --git a/esphome/common/mqtt_common.yaml b/esphome/common/mqtt_common.yaml index b0dbee0..c628867 100644 --- a/esphome/common/mqtt_common.yaml +++ b/esphome/common/mqtt_common.yaml @@ -10,7 +10,6 @@ substitutions: ############################################# # MQTT Monitoring # https://esphome.io/components/mqtt.html?highlight=mqtt -# MUST also have api enabled if you enable MQTT ############################################# mqtt: broker: ${mqtt_server} diff --git a/esphome/esp-3dprinterpow.yaml b/esphome/esp-3dprinterpow.yaml index c13924d..ae9c203 100644 --- a/esphome/esp-3dprinterpow.yaml +++ b/esphome/esp-3dprinterpow.yaml @@ -72,6 +72,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 diff --git a/esphome/esp-attobattery.yaml b/esphome/esp-attobattery.yaml index 6ad38b2..dab905a 100644 --- a/esphome/esp-attobattery.yaml +++ b/esphome/esp-attobattery.yaml @@ -42,6 +42,46 @@ substitutions: log_level: "DEBUG" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "60s" # update time for for general sensors etc +########################################################################################## +# 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 + 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 @@ -79,37 +119,6 @@ logger: ota: - platform: web_server # Uncomment if you want to be able to do OTA with the web interface -########################################################################################## -# PACKAGES: Included Common Packages -# https://esphome.io/components/packages.html -########################################################################################## -packages: - 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}" - common_api: !include - #file: common/api_common_noencryption.yaml - 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_lite.yaml - #file: common/sensors_common.yaml - vars: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" - ########################################################################################## # MQTT COMMANDS # This adds device-specific MQTT command triggers to the common MQTT configuration. diff --git a/esphome/esp-bedrm2ceilingfan.yaml b/esphome/esp-bedrm2ceilingfan.yaml index 2e542bb..c943ac7 100644 --- a/esphome/esp-bedrm2ceilingfan.yaml +++ b/esphome/esp-bedrm2ceilingfan.yaml @@ -66,29 +66,38 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-bedrm2fanswitch.yaml b/esphome/esp-bedrm2fanswitch.yaml index cb15920..1e2beef 100644 --- a/esphome/esp-bedrm2fanswitch.yaml +++ b/esphome/esp-bedrm2fanswitch.yaml @@ -70,29 +70,38 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-bedrm2lights.yaml b/esphome/esp-bedrm2lights.yaml index e571459..8a791be 100644 --- a/esphome/esp-bedrm2lights.yaml +++ b/esphome/esp-bedrm2lights.yaml @@ -53,30 +53,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-bedrm3ceilingfan.yaml b/esphome/esp-bedrm3ceilingfan.yaml index 5cd630f..0d6e077 100644 --- a/esphome/esp-bedrm3ceilingfan.yaml +++ b/esphome/esp-bedrm3ceilingfan.yaml @@ -65,30 +65,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 @@ -103,16 +114,10 @@ esphome: priority : -100 then: - delay: 200ms - #- fan.toggle: ifan02_fan - #- fan.toggle: ifan02_fan - #- delay: 200ms - #- light.toggle: ifan02_light - #- delay: 1ms - #- light.toggle: ifan02_light - #- delay: 1s - mqtt.publish: topic: "${mqtt_local_status_topic}/speed/state" payload: !lambda 'return to_string(id(speed_value));' + # platformio_options: # build_flags: # - "-Os" # optimize for size diff --git a/esphome/esp-bedrm3fanswitch.yaml b/esphome/esp-bedrm3fanswitch.yaml index 04bb972..1345475 100644 --- a/esphome/esp-bedrm3fanswitch.yaml +++ b/esphome/esp-bedrm3fanswitch.yaml @@ -69,30 +69,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-bedrm3lights.yaml b/esphome/esp-bedrm3lights.yaml index eba1b65..4449d06 100644 --- a/esphome/esp-bedrm3lights.yaml +++ b/esphome/esp-bedrm3lights.yaml @@ -66,30 +66,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-breakfastbarleds.yaml b/esphome/esp-breakfastbarleds.yaml index ab62ca2..0a14847 100644 --- a/esphome/esp-breakfastbarleds.yaml +++ b/esphome/esp-breakfastbarleds.yaml @@ -106,8 +106,8 @@ packages: #### 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.yaml + file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" @@ -124,9 +124,9 @@ packages: #### 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_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 @@ -179,6 +179,9 @@ esphome: # Boot complete: allow OFF handlers again - lambda: 'id(booting) = false;' + # NEW: force indicator OFF after boot logic + - output.turn_off: green_led_out + # Only if you want to play with build flags... # platformio_options: # build_unflags: @@ -200,10 +203,10 @@ esp8266: restore_from_flash: true # restore some values on reboot mdns: - disabled: false # Disabling will make the build file smaller (and device is still available via static IP) + disabled: true # Disabling will make the build file smaller (and device is still available via static IP) preferences: - flash_write_interval: 5sec # enough time to update values for reboots, but not enough to wear flash + flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash ########################################################################################## # GLOBAL VARIABLES @@ -269,11 +272,6 @@ globals: type: int restore_value: false initial_value: '0' - # last non-zero actual 0..100 used, for stable "Restore Brightness" - - id: last_nonzero_brightness_pct - type: float - restore_value: true - initial_value: '0.0' # target for "Restore Brightness" scripted ramp - id: restore_target_pct type: float @@ -284,17 +282,12 @@ globals: type: bool restore_value: false initial_value: 'false' - # volatile (non-persistent) last non-zero brightness during ramps - - id: last_nonzero_tmp - type: float - restore_value: false - initial_value: '0.0' # guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF - id: booting type: bool restore_value: false initial_value: 'true' -# true only while we are performing a ramp-down that briefly turns the light ON to hit the floor + # 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 @@ -396,8 +389,6 @@ button: # Stop any pending scripts (and their delayed actions) - script.stop: ramp_on_script - script.stop: ramp_off_script - - script.stop: led_flash_up - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- // We are no longer ramping (up or down) @@ -414,14 +405,14 @@ button: call.perform(); } - // Persist the exact frozen level so "Restore Brightness" survives a reboot + // Persist the exact frozen level so restore survives a reboot if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; id(last_brightness_pct) = pct; - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; } + ######################################################################################### # SELECT COMPONENT # https://esphome.io/components/select/index.html @@ -462,8 +453,8 @@ binary_sensor: pullup: true inverted: true filters: - - delayed_on: 20ms - - delayed_off: 20ms + - delayed_on: 30ms + - delayed_off: 30ms on_press: - if: condition: @@ -494,29 +485,16 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 250ms # consider 200ms if you want fewer updates + update_interval: 1s # consider 200ms if you want fewer updates lambda: |- const auto &cv = id(mosfet_leds).current_values; return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; on_value: then: - lambda: |- - const auto &cv_now = id(mosfet_leds).current_values; - - // Only persist exact last brightness while actually ON, - // and not during the OFF ramp's brief floor-kick. - if (cv_now.is_on()) { - if (x > 0.5f) { - if (!id(is_ramping)) id(last_nonzero_brightness_pct) = x; - id(last_nonzero_tmp) = x; - } - } else { - if (x > 0.5f) id(last_nonzero_tmp) = x; - } - // If not suppressing sync, update the 0..100 slider only when its INT changes if (!id(suppress_slider_sync)) { - float actual = x; + float actual = x; // x is current Output (%) float minp = (float) id(min_brightness_pct); float maxp = (float) id(max_brightness_pct); if (maxp <= minp) maxp = minp + 1.0f; @@ -530,13 +508,14 @@ sensor: id(led_output_set_pct).publish_state(pos_i); } } + - platform: template id: mosfet_output_pwm_pct name: "${friendly_name} Output PWM (%)" unit_of_measurement: "%" icon: mdi:square-wave accuracy_decimals: 1 - update_interval: 250ms + update_interval: 1s lambda: |- const auto &cv = id(mosfet_leds).current_values; if (!cv.is_on()) return 0.0f; @@ -547,6 +526,7 @@ sensor: if (pwm > 1.0f) pwm = 1.0f; return pwm * 100.0f; + ########################################################################################## # OUTPUT COMPONENT # https://esphome.io/components/light/index.html @@ -741,11 +721,7 @@ number: if (maxp <= minp) maxp = minp + 1.0f; float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; - id(last_brightness_pct) = out_pct; // persist exact target now - if (out_pct > 0.5f) { - id(last_nonzero_brightness_pct) = out_pct; - id(last_nonzero_tmp) = out_pct; - } + id(last_brightness_pct) = out_pct; // persist exact target now - delay: 400ms - lambda: 'id(suppress_slider_sync) = false;' @@ -785,43 +761,14 @@ number: # Scripts can be executed nearly anywhere in your device configuration with a single call. ########################################################################################## script: - # Blink pattern while ramping UP: quick double-blink, pause, repeat - - id: led_flash_up - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 100ms - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 400ms - # Blink pattern while ramping DOWN: steady slow blink - - id: led_flash_down - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 250ms - - output.turn_off: green_led_out - - delay: 250ms - # Script: ramp up from current level. Obey global max. + # 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;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at at least the floor without a visible "pop". - if: condition: @@ -858,25 +805,22 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp to a specific target (Restore Brightness path) + # Script: ramp to a specific target (Restore Brightness path). (LED ON while ramping) - id: ramp_to_target_script mode: restart then: - lambda: 'id(is_ramping) = true;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at the floor cleanly. - if: condition: @@ -919,18 +863,17 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp down from current level to floor, then cleanly cut to OFF + + # Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping) - id: ramp_off_script mode: restart then: @@ -938,8 +881,7 @@ script: id(is_ramping) = true; id(ramping_for_off) = true; - script.stop: ramp_on_script - - script.stop: led_flash_up - - script.execute: led_flash_down + - output.turn_on: green_led_out - light.turn_on: id: mosfet_leds brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' @@ -960,7 +902,6 @@ script: id: mosfet_leds transition_length: 150ms - delay: 150ms - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; @@ -1021,3 +962,4 @@ script: - light.turn_off: id: mosfet_leds transition_length: 0s + - 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-centralstairs-bottom.yaml b/esphome/esp-centralstairs-bottom.yaml index 5b3af7f..ee8d513 100644 --- a/esphome/esp-centralstairs-bottom.yaml +++ b/esphome/esp-centralstairs-bottom.yaml @@ -66,30 +66,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-centralstairs-top.yaml b/esphome/esp-centralstairs-top.yaml index 7403e2f..3ed486a 100644 --- a/esphome/esp-centralstairs-top.yaml +++ b/esphome/esp-centralstairs-top.yaml @@ -65,30 +65,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-datacupboardpower-left.yaml b/esphome/esp-datacupboardpower-left.yaml index 0fe551b..593bdc8 100644 --- a/esphome/esp-datacupboardpower-left.yaml +++ b/esphome/esp-datacupboardpower-left.yaml @@ -42,9 +42,10 @@ substitutions: # 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: - - # Network and Wi-Fi + #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml vars: @@ -52,32 +53,30 @@ packages: local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" - # Native API + #### 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}" - local_api_key: "5dW+2PdmYb7ovzvt/tGPbLU6XfBHsQeeUgZ5/ImQFA8=" + local_api_key: "${api_key}" -# # Web Portal -# common_webportal: !include -# file: common/webportal_common.yaml - - # MQTT + #### 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 - # Time/SNTP - common_sntp: !include - file: common/sntp_common.yaml - - common_general_sensors: !include - file: common/sensors_common.yaml - vars: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + #### 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 # Device Specific included packages # Athom Power Monitor Plug V2 (No Relay) diff --git a/esphome/esp-datacupboardpower-right.yaml b/esphome/esp-datacupboardpower-right.yaml index c6f6fba..b1576f2 100644 --- a/esphome/esp-datacupboardpower-right.yaml +++ b/esphome/esp-datacupboardpower-right.yaml @@ -43,9 +43,10 @@ substitutions: # 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: - - # Network and Wi-Fi + #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml vars: @@ -53,32 +54,30 @@ packages: local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" - # Native API + #### 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}" - local_api_key: "tZ/djAp4qiM0wYCgUa1amg+wK7KTF9xR8bUFCaeVskM=" + local_api_key: "${api_key}" - # Web Portal - common_webportal: !include - file: common/webportal_common.yaml - - # MQTT + #### 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 - # Time/SNTP - common_sntp: !include - file: common/sntp_common.yaml - - common_general_sensors: !include - file: common/sensors_common.yaml - vars: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + #### 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 # Device Specific included packages # Athom Power Monitor Plug V2 (No Relay) diff --git a/esphome/esp-downstairsdishwasher.yaml b/esphome/esp-downstairsdishwasher.yaml index 5e8d58c..cd8cb73 100644 --- a/esphome/esp-downstairsdishwasher.yaml +++ b/esphome/esp-downstairsdishwasher.yaml @@ -43,45 +43,46 @@ substitutions: sensor_update_interval: "10s" relay_restore_mode: RESTORE_DEFAULT_ON hide_energy_sensor: "true" - + ########################################################################################## # 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: - - # Network and Wifi + #### 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}" - - # Network and Wifi + + #### 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}" - -# # Web Portal -# common_webportal: !include -# file: common/webportal_common.yaml - # MQTT + #### 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 - # Time/SNMP - common_sntp: !include - file: common/sntp_common.yaml - common_general_sensors: !include - file: common/sensors_common.yaml - vars: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + #### 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 # Device Specific included packages # Athom Power Monitor Plug diff --git a/esphome/esp-downstairskitchleds.yaml b/esphome/esp-downstairskitchleds.yaml index 9010e52..00b8a54 100644 --- a/esphome/esp-downstairskitchleds.yaml +++ b/esphome/esp-downstairskitchleds.yaml @@ -28,7 +28,7 @@ # - "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 +# 9. Green LED rule: ON while any ramp script is executing, otherwise OFF. 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: @@ -94,7 +94,7 @@ substitutions: 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: "1000hz" # PWM output Frequency. High enough to avoid audible/visible artifacts + pwm_frequency: "1000 hz" # PWM output Frequency. High enough to avoid audible/visible artifacts # Device Specific GPIO (so we can easily update for other devices) device_status_led: GPIO02 @@ -190,6 +190,9 @@ esphome: # Boot complete: allow OFF handlers again - lambda: 'id(booting) = false;' + # NEW: force indicator OFF after boot logic + - output.turn_off: green_led_out + # Only if you want to play with build flags... # platformio_options: # build_unflags: @@ -211,10 +214,10 @@ esp8266: restore_from_flash: true # restore some values on reboot mdns: - disabled: false # Disabling will make the build file smaller (and device is still available via static IP) + disabled: true # Disabling will make the build file smaller (and device is still available via static IP) preferences: - flash_write_interval: 5sec # enough time to update values for reboots, but not enough to wear flash + flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash ########################################################################################## # GLOBAL VARIABLES @@ -280,11 +283,6 @@ globals: type: int restore_value: false initial_value: '0' - # last non-zero actual 0..100 used, for stable "Restore Brightness" - - id: last_nonzero_brightness_pct - type: float - restore_value: true - initial_value: '0.0' # target for "Restore Brightness" scripted ramp - id: restore_target_pct type: float @@ -295,17 +293,12 @@ globals: type: bool restore_value: false initial_value: 'false' - # volatile (non-persistent) last non-zero brightness during ramps - - id: last_nonzero_tmp - type: float - restore_value: false - initial_value: '0.0' # guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF - id: booting type: bool restore_value: false initial_value: 'true' -# true only while we are performing a ramp-down that briefly turns the light ON to hit the floor + # 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 @@ -407,8 +400,6 @@ button: # Stop any pending scripts (and their delayed actions) - script.stop: ramp_on_script - script.stop: ramp_off_script - - script.stop: led_flash_up - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- // We are no longer ramping (up or down) @@ -425,14 +416,14 @@ button: call.perform(); } - // Persist the exact frozen level so "Restore Brightness" survives a reboot + // Persist the exact frozen level so restore survives a reboot if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; id(last_brightness_pct) = pct; - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; } + ######################################################################################### # SELECT COMPONENT # https://esphome.io/components/select/index.html @@ -473,8 +464,8 @@ binary_sensor: pullup: true inverted: true filters: - - delayed_on: 20ms - - delayed_off: 20ms + - delayed_on: 30ms + - delayed_off: 30ms on_press: - if: condition: @@ -505,29 +496,16 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 250ms # consider 200ms if you want fewer updates + update_interval: 1s # consider 200ms if you want fewer updates lambda: |- const auto &cv = id(mosfet_leds).current_values; return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; on_value: then: - lambda: |- - const auto &cv_now = id(mosfet_leds).current_values; - - // Only persist exact last brightness while actually ON, - // and not during the OFF ramp's brief floor-kick. - if (cv_now.is_on()) { - if (x > 0.5f) { - if (!id(is_ramping)) id(last_nonzero_brightness_pct) = x; - id(last_nonzero_tmp) = x; - } - } else { - if (x > 0.5f) id(last_nonzero_tmp) = x; - } - // If not suppressing sync, update the 0..100 slider only when its INT changes if (!id(suppress_slider_sync)) { - float actual = x; + float actual = x; // x is current Output (%) float minp = (float) id(min_brightness_pct); float maxp = (float) id(max_brightness_pct); if (maxp <= minp) maxp = minp + 1.0f; @@ -541,13 +519,14 @@ sensor: id(led_output_set_pct).publish_state(pos_i); } } + - platform: template id: mosfet_output_pwm_pct name: "${friendly_name} Output PWM (%)" unit_of_measurement: "%" icon: mdi:square-wave accuracy_decimals: 1 - update_interval: 250ms + update_interval: 1s lambda: |- const auto &cv = id(mosfet_leds).current_values; if (!cv.is_on()) return 0.0f; @@ -558,6 +537,7 @@ sensor: if (pwm > 1.0f) pwm = 1.0f; return pwm * 100.0f; + ########################################################################################## # OUTPUT COMPONENT # https://esphome.io/components/light/index.html @@ -752,11 +732,7 @@ number: if (maxp <= minp) maxp = minp + 1.0f; float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; - id(last_brightness_pct) = out_pct; // persist exact target now - if (out_pct > 0.5f) { - id(last_nonzero_brightness_pct) = out_pct; - id(last_nonzero_tmp) = out_pct; - } + id(last_brightness_pct) = out_pct; // persist exact target now - delay: 400ms - lambda: 'id(suppress_slider_sync) = false;' @@ -796,43 +772,14 @@ number: # Scripts can be executed nearly anywhere in your device configuration with a single call. ########################################################################################## script: - # Blink pattern while ramping UP: quick double-blink, pause, repeat - - id: led_flash_up - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 100ms - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 400ms - # Blink pattern while ramping DOWN: steady slow blink - - id: led_flash_down - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 250ms - - output.turn_off: green_led_out - - delay: 250ms - # Script: ramp up from current level. Obey global max. + # 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;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at at least the floor without a visible "pop". - if: condition: @@ -869,25 +816,22 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp to a specific target (Restore Brightness path) + # Script: ramp to a specific target (Restore Brightness path). (LED ON while ramping) - id: ramp_to_target_script mode: restart then: - lambda: 'id(is_ramping) = true;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at the floor cleanly. - if: condition: @@ -930,18 +874,17 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp down from current level to floor, then cleanly cut to OFF + + # Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping) - id: ramp_off_script mode: restart then: @@ -949,8 +892,7 @@ script: id(is_ramping) = true; id(ramping_for_off) = true; - script.stop: ramp_on_script - - script.stop: led_flash_up - - script.execute: led_flash_down + - output.turn_on: green_led_out - light.turn_on: id: mosfet_leds brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' @@ -971,7 +913,6 @@ script: id: mosfet_leds transition_length: 150ms - delay: 150ms - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; @@ -1032,3 +973,5 @@ script: - light.turn_off: id: mosfet_leds transition_length: 0s + - output.turn_off: green_led_out # make sure LED is off if no ramp + diff --git a/esphome/esp-downstbathswitch.yaml b/esphome/esp-downstbathswitch.yaml index 8a29552..0952542 100644 --- a/esphome/esp-downstbathswitch.yaml +++ b/esphome/esp-downstbathswitch.yaml @@ -1,22 +1,22 @@ -############################################# -############################################# +########################################################################################## +########################################################################################## # DOWNSTAIRS BATHROOM MAIN LIGHTSWITCH # V2.0 2025-06-05 YAML Tidyups # V1.0 2025-02-14 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-downstbathswitch" @@ -46,70 +46,81 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 -############################################# +########################################################################################## # ESP Platform and Framework # https://esphome.io/components/esp32.html -############################################# +########################################################################################## esp8266: board: esp01_1m -############################################# +########################################################################################## # 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 # https://esphome.io/components/status_led.html -############################################# +########################################################################################## status_led: pin: number: GPIO2 inverted: True -############################################# +########################################################################################## # BINARY SENSORS # https://esphome.io/components/binary_sensor/ -############################################# +########################################################################################## binary_sensor: - platform: gpio pin: @@ -199,10 +210,10 @@ binary_sensor: else: - switch.turn_on: Relay_3 -############################################# +########################################################################################## # SWITCH COMPONENT # https://esphome.io/components/switch/ -############################################# +########################################################################################## switch: - platform: gpio name: "Relay 1: ${switch_1_name}" diff --git a/esphome/esp-downstbathtowelrail.yaml b/esphome/esp-downstbathtowelrail.yaml index 56a4532..4e24909 100644 --- a/esphome/esp-downstbathtowelrail.yaml +++ b/esphome/esp-downstbathtowelrail.yaml @@ -82,30 +82,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-downstbedrm2lights.yaml b/esphome/esp-downstbedrm2lights.yaml index 1de3f39..a33b2e0 100644 --- a/esphome/esp-downstbedrm2lights.yaml +++ b/esphome/esp-downstbedrm2lights.yaml @@ -55,30 +55,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-downstkitchlights.yaml b/esphome/esp-downstkitchlights.yaml index e6e7dc6..5ad2d2a 100644 --- a/esphome/esp-downstkitchlights.yaml +++ b/esphome/esp-downstkitchlights.yaml @@ -42,30 +42,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-downstloungeentry.yaml b/esphome/esp-downstloungeentry.yaml index 632bf7d..a44b2b0 100644 --- a/esphome/esp-downstloungeentry.yaml +++ b/esphome/esp-downstloungeentry.yaml @@ -61,30 +61,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-downstloungemain.yaml b/esphome/esp-downstloungemain.yaml index 4931de4..e984a89 100644 --- a/esphome/esp-downstloungemain.yaml +++ b/esphome/esp-downstloungemain.yaml @@ -56,29 +56,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-downstloungeoutside.yaml b/esphome/esp-downstloungeoutside.yaml index 6668ec4..2c1fcbb 100644 --- a/esphome/esp-downstloungeoutside.yaml +++ b/esphome/esp-downstloungeoutside.yaml @@ -56,29 +56,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-downstmasterbedrmlights.yaml b/esphome/esp-downstmasterbedrmlights.yaml index c9ac794..91460ac 100644 --- a/esphome/esp-downstmasterbedrmlights.yaml +++ b/esphome/esp-downstmasterbedrmlights.yaml @@ -55,30 +55,41 @@ substitutions: # 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 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-entbtproxy.yaml b/esphome/esp-entbtproxy.yaml index 0fb592a..180a333 100644 --- a/esphome/esp-entbtproxy.yaml +++ b/esphome/esp-entbtproxy.yaml @@ -31,29 +31,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-entmulti.yaml b/esphome/esp-entmulti.yaml index 16ba455..0643ff0 100644 --- a/esphome/esp-entmulti.yaml +++ b/esphome/esp-entmulti.yaml @@ -49,10 +49,6 @@ substitutions: # https://esphome.io/components/packages.html ########################################################################################## packages: - ################################################## - # MANDATORY packages (won't compile without them!) - ################################################## - #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml @@ -61,20 +57,12 @@ packages: local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" - ################################################## - # OPTIONAL packages (comment if you don't want them) - ################################################## - #### 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}" - - #### WEB PORTAL #### - #common_webportal: !include - # file: common/webportal_common.yaml #### MQTT #### common_mqtt: !include @@ -82,24 +70,16 @@ packages: 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 - # file: common/sntp_common.yaml + common_sntp: !include common/sntp_common.yaml - #### DIAGNOSTICS Lite Sensors #### - # Option of everything, or a lite version - common_lite_sensors: !include - file: common/sensors_common_lite.yaml - - #### DIAGNOSTICS General Sensors #### - # Option of everything, or a lite version - common_general_sensors: !include - file: common/sensors_common.yaml - - #### DEBUGGING Sensors #### - # A count of various resets - #common_resetcount_debugging: !include - # file: common/resetcount_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 diff --git a/esphome/esp-entrancebathrmlights.yaml b/esphome/esp-entrancebathrmlights.yaml index dd29caa..e02bc2f 100644 --- a/esphome/esp-entrancebathrmlights.yaml +++ b/esphome/esp-entrancebathrmlights.yaml @@ -55,29 +55,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-entrancelightswitch.yaml b/esphome/esp-entrancelightswitch.yaml index 43bfdad..1f20d3b 100644 --- a/esphome/esp-entrancelightswitch.yaml +++ b/esphome/esp-entrancelightswitch.yaml @@ -55,29 +55,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-flysprayer1.yaml b/esphome/esp-flysprayer1.yaml index cd88ffd..b2347d5 100644 --- a/esphome/esp-flysprayer1.yaml +++ b/esphome/esp-flysprayer1.yaml @@ -75,29 +75,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 CORE CONFIGURATION diff --git a/esphome/esp-laundrydrypow.yaml b/esphome/esp-laundrydrypow.yaml index b778b1f..461dfbb 100644 --- a/esphome/esp-laundrydrypow.yaml +++ b/esphome/esp-laundrydrypow.yaml @@ -35,29 +35,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-laundryenv.yaml b/esphome/esp-laundryenv.yaml index 75a261f..b2c2045 100644 --- a/esphome/esp-laundryenv.yaml +++ b/esphome/esp-laundryenv.yaml @@ -35,29 +35,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-laundrylights.yaml b/esphome/esp-laundrylights.yaml index 6fe56f9..39d332a 100644 --- a/esphome/esp-laundrylights.yaml +++ b/esphome/esp-laundrylights.yaml @@ -58,10 +58,6 @@ substitutions: # https://esphome.io/components/packages.html ########################################################################################## packages: - ################################################## - # MANDATORY packages (won't compile without them!) - ################################################## - #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml @@ -70,10 +66,6 @@ packages: local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" - ################################################## - # OPTIONAL packages (comment if you don't want them) - ################################################## - #### HOME ASSISTANT API (choose encryption or no encryption options) #### common_api: !include file: common/api_common.yaml @@ -88,14 +80,14 @@ packages: 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_debug: !include common/include_debug_diag_sensors.yaml #diag_resetcount: !include common/include_resetcount_diag_sensors.yaml ######################################################################################### diff --git a/esphome/esp-laundryplugpow.yaml b/esphome/esp-laundryplugpow.yaml index e13d821..d67304b 100644 --- a/esphome/esp-laundryplugpow.yaml +++ b/esphome/esp-laundryplugpow.yaml @@ -35,29 +35,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-laundrywashpow.yaml b/esphome/esp-laundrywashpow.yaml index 264db42..69642dc 100644 --- a/esphome/esp-laundrywashpow.yaml +++ b/esphome/esp-laundrywashpow.yaml @@ -35,29 +35,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-lounge6chdimmer.yaml b/esphome/esp-lounge6chdimmer.yaml index 8ed612e..f21a664 100644 --- a/esphome/esp-lounge6chdimmer.yaml +++ b/esphome/esp-lounge6chdimmer.yaml @@ -89,8 +89,16 @@ substitutions: min_output_2: "0.20f" min_output_3: "0.20f" min_output_4: "0.20f" - min_output_5: "0.20f" - min_output_6: "0.20f" + min_output_5: "0.10f" + min_output_6: "0.10f" + + # Per-channel gamma correct + gamma_output_1: "2.2" + gamma_output_2: "2.2" + gamma_output_3: "2.2" + gamma_output_4: "1" + gamma_output_5: "2.2" + gamma_output_6: "2.2" ######################################################################################### # PACKAGES: Included Common Packages @@ -122,6 +130,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 @@ -214,42 +223,42 @@ light: output: dmx_1 id: light_test_1 default_transition_length: 10s - gamma_correct: 2.2 + gamma_correct: ${gamma_output_1} restore_mode: ALWAYS_ON - platform: monochromatic name: ${output_2_name} output: dmx_2 id: light_test_2 default_transition_length: 10s - gamma_correct: 2.2 + gamma_correct: ${gamma_output_2} restore_mode: ALWAYS_ON - platform: monochromatic name: ${output_3_name} output: dmx_3 id: light_test_3 default_transition_length: 10s - gamma_correct: 2.2 + gamma_correct: ${gamma_output_3} restore_mode: ALWAYS_ON - platform: monochromatic name: ${output_4_name} output: dmx_4 id: light_test_4 default_transition_length: 10s - gamma_correct: 1 + gamma_correct: ${gamma_output_4} restore_mode: ALWAYS_ON - platform: monochromatic name: ${output_5_name} output: dmx_5 id: light_test_5 - default_transition_length: 10s - gamma_correct: 1 + default_transition_length: 3s + gamma_correct: ${gamma_output_5} restore_mode: RESTORE_DEFAULT_OFF - platform: monochromatic name: ${output_6_name} output: dmx_6 id: light_test_6 - default_transition_length: 10s - gamma_correct: 1 + default_transition_length: 3s + gamma_correct: ${gamma_output_6} restore_mode: RESTORE_DEFAULT_OFF ########################################################################################## diff --git a/esphome/esp-loungebookshelfleds.yaml b/esphome/esp-loungebookshelfleds.yaml index 57c2bc8..ce83182 100644 --- a/esphome/esp-loungebookshelfleds.yaml +++ b/esphome/esp-loungebookshelfleds.yaml @@ -91,7 +91,6 @@ substitutions: device_usr_button: GPIO04 # this is just a fake/safeish choice so it compiles with my generic yaml device_fading_led: GPIO13 # this is just a fake/safeish choice so it compiles with my generic yaml - ########################################################################################## # PACKAGES: Included Common Packages # https://esphome.io/components/packages.html @@ -125,26 +124,22 @@ packages: #### 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_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: - platformio_options: - build_flags: - - -DVTABLES_IN_FLASH - - -DPIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY name: "${device_name}" friendly_name: "${friendly_name}" comment: "${description_comment}" area: "${device_area}" on_boot: # Run later so everything is initialised before we touch states. - priority: 150 + priority: 200 then: # Keep the HA dropdown in sync with the stored mode - lambda: |- @@ -184,6 +179,9 @@ esphome: # Boot complete: allow OFF handlers again - lambda: 'id(booting) = false;' + # NEW: force indicator OFF after boot logic + - output.turn_off: green_led_out + # Only if you want to play with build flags... # platformio_options: # build_unflags: @@ -208,7 +206,7 @@ mdns: disabled: true # Disabling will make the build file smaller (and device is still available via static IP) preferences: - flash_write_interval: 10sec # enough time to update values for reboots, but not enough to wear flash + flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash ########################################################################################## # GLOBAL VARIABLES @@ -274,11 +272,6 @@ globals: type: int restore_value: false initial_value: '0' - # last non-zero actual 0..100 used, for stable "Restore Brightness" - - id: last_nonzero_brightness_pct - type: float - restore_value: true - initial_value: '0.0' # target for "Restore Brightness" scripted ramp - id: restore_target_pct type: float @@ -289,17 +282,12 @@ globals: type: bool restore_value: false initial_value: 'false' - # volatile (non-persistent) last non-zero brightness during ramps - - id: last_nonzero_tmp - type: float - restore_value: false - initial_value: '0.0' # guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF - id: booting type: bool restore_value: false initial_value: 'true' -# true only while we are performing a ramp-down that briefly turns the light ON to hit the floor + # 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 @@ -328,7 +316,6 @@ status_led: # This adds device-specific MQTT command triggers to the common MQTT configuration. ########################################################################################## mqtt: - reboot_timeout: 0s on_message: # Light control to ramp up - topic: "${mqtt_local_command_topic}/light/set" @@ -402,8 +389,6 @@ button: # Stop any pending scripts (and their delayed actions) - script.stop: ramp_on_script - script.stop: ramp_off_script - - script.stop: led_flash_up - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- // We are no longer ramping (up or down) @@ -420,14 +405,14 @@ button: call.perform(); } - // Persist the exact frozen level so "Restore Brightness" survives a reboot + // Persist the exact frozen level so restore survives a reboot if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; id(last_brightness_pct) = pct; - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; } + ######################################################################################### # SELECT COMPONENT # https://esphome.io/components/select/index.html @@ -468,8 +453,8 @@ binary_sensor: pullup: true inverted: true filters: - - delayed_on: 20ms - - delayed_off: 20ms + - delayed_on: 30ms + - delayed_off: 30ms on_press: - if: condition: @@ -500,29 +485,16 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 500ms # consider higher if you want fewer updates + update_interval: 1s # consider 200ms if you want fewer updates lambda: |- const auto &cv = id(mosfet_leds).current_values; return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; on_value: then: - lambda: |- - const auto &cv_now = id(mosfet_leds).current_values; - - // Only persist exact last brightness while actually ON, - // and not during the OFF ramp's brief floor-kick. - if (cv_now.is_on()) { - if (x > 0.5f) { - if (!id(is_ramping)) id(last_nonzero_brightness_pct) = x; - id(last_nonzero_tmp) = x; - } - } else { - if (x > 0.5f) id(last_nonzero_tmp) = x; - } - // If not suppressing sync, update the 0..100 slider only when its INT changes if (!id(suppress_slider_sync)) { - float actual = x; + float actual = x; // x is current Output (%) float minp = (float) id(min_brightness_pct); float maxp = (float) id(max_brightness_pct); if (maxp <= minp) maxp = minp + 1.0f; @@ -536,13 +508,14 @@ sensor: id(led_output_set_pct).publish_state(pos_i); } } + - platform: template id: mosfet_output_pwm_pct name: "${friendly_name} Output PWM (%)" unit_of_measurement: "%" icon: mdi:square-wave accuracy_decimals: 1 - update_interval: 500ms + update_interval: 1s lambda: |- const auto &cv = id(mosfet_leds).current_values; if (!cv.is_on()) return 0.0f; @@ -553,6 +526,7 @@ sensor: if (pwm > 1.0f) pwm = 1.0f; return pwm * 100.0f; + ########################################################################################## # OUTPUT COMPONENT # https://esphome.io/components/light/index.html @@ -738,7 +712,7 @@ number: float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; return out_pct / 100.0f; - transition_length: 500ms + transition_length: 250ms - lambda: |- id(ramp_switch_target_on) = true; float pos = id(led_output_set_pct).state; // 1..100 @@ -747,11 +721,7 @@ number: if (maxp <= minp) maxp = minp + 1.0f; float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; - id(last_brightness_pct) = out_pct; // persist exact target now - if (out_pct > 0.5f) { - id(last_nonzero_brightness_pct) = out_pct; - id(last_nonzero_tmp) = out_pct; - } + id(last_brightness_pct) = out_pct; // persist exact target now - delay: 400ms - lambda: 'id(suppress_slider_sync) = false;' @@ -791,42 +761,14 @@ number: # Scripts can be executed nearly anywhere in your device configuration with a single call. ########################################################################################## script: - # Blink pattern while ramping UP: quick double-blink, pause, repeat - - id: led_flash_up - mode: restart - then: - - repeat: - count: 1000000000 # effectively forever, but cancellable - then: - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 100ms - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 400ms - # Blink pattern while ramping DOWN: steady slow blink - - id: led_flash_down - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 250ms - - output.turn_off: green_led_out - - delay: 250ms - # Script: ramp up from current level. Obey global max. + # 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;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at at least the floor without a visible "pop". - if: condition: @@ -863,25 +805,22 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp to a specific target (Restore Brightness path) + # Script: ramp to a specific target (Restore Brightness path). (LED ON while ramping) - id: ramp_to_target_script mode: restart then: - lambda: 'id(is_ramping) = true;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at the floor cleanly. - if: condition: @@ -924,18 +863,17 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp down from current level to floor, then cleanly cut to OFF + + # Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping) - id: ramp_off_script mode: restart then: @@ -943,8 +881,7 @@ script: id(is_ramping) = true; id(ramping_for_off) = true; - script.stop: ramp_on_script - - script.stop: led_flash_up - - script.execute: led_flash_down + - output.turn_on: green_led_out - light.turn_on: id: mosfet_leds brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' @@ -965,7 +902,6 @@ script: id: mosfet_leds transition_length: 150ms - delay: 150ms - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; @@ -1026,3 +962,5 @@ script: - light.turn_off: id: mosfet_leds transition_length: 0s + - output.turn_off: green_led_out # make sure LED is off if no ramp + diff --git a/esphome/esp-loungecabinetleds2.yaml b/esphome/esp-loungecabinetleds2.yaml index 3a911a0..d3de992 100644 --- a/esphome/esp-loungecabinetleds2.yaml +++ b/esphome/esp-loungecabinetleds2.yaml @@ -111,8 +111,8 @@ packages: #### 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.yaml + file: common/api_common_noencryption.yaml vars: local_api_key: "${api_key}" @@ -129,9 +129,9 @@ packages: #### 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_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 @@ -184,6 +184,9 @@ esphome: # Boot complete: allow OFF handlers again - lambda: 'id(booting) = false;' + # NEW: force indicator OFF after boot logic + - output.turn_off: green_led_out + # Only if you want to play with build flags... # platformio_options: # build_unflags: @@ -205,10 +208,10 @@ esp8266: restore_from_flash: true # restore some values on reboot mdns: - disabled: false # Disabling will make the build file smaller (and device is still available via static IP) + disabled: true # Disabling will make the build file smaller (and device is still available via static IP) preferences: - flash_write_interval: 5sec # enough time to update values for reboots, but not enough to wear flash + flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash ########################################################################################## # GLOBAL VARIABLES @@ -274,11 +277,6 @@ globals: type: int restore_value: false initial_value: '0' - # last non-zero actual 0..100 used, for stable "Restore Brightness" - - id: last_nonzero_brightness_pct - type: float - restore_value: true - initial_value: '0.0' # target for "Restore Brightness" scripted ramp - id: restore_target_pct type: float @@ -289,17 +287,12 @@ globals: type: bool restore_value: false initial_value: 'false' - # volatile (non-persistent) last non-zero brightness during ramps - - id: last_nonzero_tmp - type: float - restore_value: false - initial_value: '0.0' # guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF - id: booting type: bool restore_value: false initial_value: 'true' -# true only while we are performing a ramp-down that briefly turns the light ON to hit the floor + # 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 @@ -401,8 +394,6 @@ button: # Stop any pending scripts (and their delayed actions) - script.stop: ramp_on_script - script.stop: ramp_off_script - - script.stop: led_flash_up - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- // We are no longer ramping (up or down) @@ -419,14 +410,14 @@ button: call.perform(); } - // Persist the exact frozen level so "Restore Brightness" survives a reboot + // Persist the exact frozen level so restore survives a reboot if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; id(last_brightness_pct) = pct; - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; } + ######################################################################################### # SELECT COMPONENT # https://esphome.io/components/select/index.html @@ -467,8 +458,8 @@ binary_sensor: pullup: true inverted: true filters: - - delayed_on: 20ms - - delayed_off: 20ms + - delayed_on: 30ms + - delayed_off: 30ms on_press: - if: condition: @@ -499,29 +490,16 @@ sensor: unit_of_measurement: "%" icon: mdi:percent accuracy_decimals: 0 - update_interval: 250ms # consider 200ms if you want fewer updates + update_interval: 1s # consider 200ms if you want fewer updates lambda: |- const auto &cv = id(mosfet_leds).current_values; return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; on_value: then: - lambda: |- - const auto &cv_now = id(mosfet_leds).current_values; - - // Only persist exact last brightness while actually ON, - // and not during the OFF ramp's brief floor-kick. - if (cv_now.is_on()) { - if (x > 0.5f) { - if (!id(is_ramping)) id(last_nonzero_brightness_pct) = x; - id(last_nonzero_tmp) = x; - } - } else { - if (x > 0.5f) id(last_nonzero_tmp) = x; - } - // If not suppressing sync, update the 0..100 slider only when its INT changes if (!id(suppress_slider_sync)) { - float actual = x; + float actual = x; // x is current Output (%) float minp = (float) id(min_brightness_pct); float maxp = (float) id(max_brightness_pct); if (maxp <= minp) maxp = minp + 1.0f; @@ -535,13 +513,14 @@ sensor: id(led_output_set_pct).publish_state(pos_i); } } + - platform: template id: mosfet_output_pwm_pct name: "${friendly_name} Output PWM (%)" unit_of_measurement: "%" icon: mdi:square-wave accuracy_decimals: 1 - update_interval: 250ms + update_interval: 1s lambda: |- const auto &cv = id(mosfet_leds).current_values; if (!cv.is_on()) return 0.0f; @@ -552,6 +531,7 @@ sensor: if (pwm > 1.0f) pwm = 1.0f; return pwm * 100.0f; + ########################################################################################## # OUTPUT COMPONENT # https://esphome.io/components/light/index.html @@ -746,11 +726,7 @@ number: if (maxp <= minp) maxp = minp + 1.0f; float out_pct = minp + (pos * (maxp - minp) / 100.0f); if (out_pct > maxp) out_pct = maxp; - id(last_brightness_pct) = out_pct; // persist exact target now - if (out_pct > 0.5f) { - id(last_nonzero_brightness_pct) = out_pct; - id(last_nonzero_tmp) = out_pct; - } + id(last_brightness_pct) = out_pct; // persist exact target now - delay: 400ms - lambda: 'id(suppress_slider_sync) = false;' @@ -790,43 +766,14 @@ number: # Scripts can be executed nearly anywhere in your device configuration with a single call. ########################################################################################## script: - # Blink pattern while ramping UP: quick double-blink, pause, repeat - - id: led_flash_up - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 100ms - - output.turn_on: green_led_out - - delay: 100ms - - output.turn_off: green_led_out - - delay: 400ms - # Blink pattern while ramping DOWN: steady slow blink - - id: led_flash_down - mode: restart - then: - - while: - condition: - lambda: 'return true;' - then: - - output.turn_on: green_led_out - - delay: 250ms - - output.turn_off: green_led_out - - delay: 250ms - # Script: ramp up from current level. Obey global max. + # 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;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at at least the floor without a visible "pop". - if: condition: @@ -863,25 +810,22 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp to a specific target (Restore Brightness path) + # Script: ramp to a specific target (Restore Brightness path). (LED ON while ramping) - id: ramp_to_target_script mode: restart then: - lambda: 'id(is_ramping) = true;' - script.stop: ramp_off_script - - script.stop: led_flash_down - - script.execute: led_flash_up + - output.turn_on: green_led_out # Ensure we start at the floor cleanly. - if: condition: @@ -924,18 +868,17 @@ script: 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);' - - script.stop: led_flash_up - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; const auto &cv = id(mosfet_leds).current_values; if (cv.is_on()) { float pct = cv.get_brightness() * 100.0f; - id(last_brightness_pct) = pct; // persist final level - if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct; + id(last_brightness_pct) = pct; // persist final level } - # Script: ramp down from current level to floor, then cleanly cut to OFF + + # Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping) - id: ramp_off_script mode: restart then: @@ -943,8 +886,7 @@ script: id(is_ramping) = true; id(ramping_for_off) = true; - script.stop: ramp_on_script - - script.stop: led_flash_up - - script.execute: led_flash_down + - output.turn_on: green_led_out - light.turn_on: id: mosfet_leds brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' @@ -965,7 +907,6 @@ script: id: mosfet_leds transition_length: 150ms - delay: 150ms - - script.stop: led_flash_down - output.turn_off: green_led_out - lambda: |- id(is_ramping) = false; @@ -1026,3 +967,4 @@ script: - light.turn_off: id: mosfet_leds transition_length: 0s + - 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-loungemiddleswitch.yaml b/esphome/esp-loungemiddleswitch.yaml new file mode 100644 index 0000000..ed017be --- /dev/null +++ b/esphome/esp-loungemiddleswitch.yaml @@ -0,0 +1,395 @@ +########################################################################################## +########################################################################################## +# LOUNGE MIDDLE LIGHTSwITCH +# 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 +# - +# +########################################################################################## +########################################################################################## + +########################################################################################## +# 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)" + 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 + + # 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 + + # 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: "lounge-main-lights" + #mqtt_local_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + + # Switch/Relay/Button Naming & Icons + #relay_icon: "mdi:lightbulb-group" + switch_1_name: "Downlights South" # Lights are connected via DMX dimmer (another esphome controller) (4 Downlights) + 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 +# 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}" + +api: + on_client_connected: + then: + - logger.log: + level: INFO + format: "API connected: applying override (override=%s)" + args: ['id(ha_loss_override).state ? "true" : "false"'] + - if: + condition: + switch.is_on: ha_loss_override + then: + - switch.turn_on: Relay_1 + - switch.turn_on: Relay_2 + else: + - switch.turn_off: Relay_1 + - switch.turn_off: Relay_2 + + on_client_disconnected: + then: + - logger.log: + level: WARN + format: "API disconnected: switching to manual/offline behavior" + +######################################################################################### +# 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 + +######################################################################################### +# STATUS LED +# https://esphome.io/components/status_led.html +######################################################################################### +status_led: + pin: + number: GPIO02 + inverted: yes + +######################################################################################### +# 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 + - platform: gpio + pin: + number: GPIO16 + mode: INPUT + inverted: True + name: "Button 1: ${switch_1_name}" + on_multi_click: + + # --- 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" + # Offline (and override ON): toggle physical Relay_1 + - timing: + - ON for at most 0.5s + - OFF for at least 0.5s + then: + - if: + condition: + and: + - switch.is_on: ha_loss_override + - api.connected: + then: + - if: + condition: + lambda: |- + // Defensive: treat empty/unknown as "not All Off" so we go to a safe "All Off". + auto s = id(ha_last_scene).state; + if (s.empty() || s == "unknown" || s == "unavailable") return true; + return s != "All Off"; + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "All Off" + - logger.log: + level: INFO + format: "BTN1: Single click (online) → Last scene was not 'All Off' → Set 'All Off'" + else: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "Bright" + - logger.log: + level: INFO + format: "BTN1: Single click (online) → Last scene was 'All Off' → Set 'Bright'" + else: + # OFFLINE path: only act if override ON; toggle physical relay + - if: + condition: + and: + - switch.is_on: ha_loss_override + - not: + api.connected: + then: + - if: + condition: + lambda: 'return id(Relay_1).state;' + then: + - switch.turn_off: Relay_1 + - logger.log: + level: INFO + format: "BTN1: Single click (offline) → Relay_1 OFF" + else: + - switch.turn_on: Relay_1 + - logger.log: + level: INFO + format: "BTN1: Single click (offline) → Relay_1 ON" + else: + - logger.log: + level: INFO + format: "BTN1: Single click ignored (override OFF)" + +# GPIO05 for second button (only for KS-811-2 Double or -3 Triple) + - platform: gpio + pin: + number: GPIO05 + mode: INPUT + inverted: True + name: "Button 2: ${switch_2_name}" + on_multi_click: + # --- 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" + # Offline (and override ON): toggle physical Relay_1 + - timing: + - ON for at most 0.5s + - OFF for at least 0.5s + then: + - if: + condition: + and: + - switch.is_on: ha_loss_override + - api.connected: + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "TV General" + - logger.log: + level: INFO + format: "BTN2: Single click (online) → Set 'TV General' Scene" + else: + # OFFLINE path: only act if override ON; toggle physical relay + - if: + condition: + and: + - switch.is_on: ha_loss_override + - not: + api.connected: + then: + - if: + condition: + lambda: 'return id(Relay_2).state;' + then: + - switch.turn_off: Relay_2 + - logger.log: + level: INFO + format: "BTN2: Single click (offline) → Relay_2 OFF" + else: + - switch.turn_on: Relay_1 + - logger.log: + level: INFO + format: "BTN2: Single click (offline) → Relay_2 ON" + else: + - logger.log: + level: INFO + format: "BTN: Single click ignored" + +# GPIO04 for third button (only for KS-811-3 Triple) + - platform: gpio + pin: + number: GPIO4 + mode: INPUT + inverted: True + name: "Button 3: ${switch_3_name}" + on_multi_click: + # --- 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" + # Offline (and override ON): toggle physical Relay_1 + - timing: + - ON for at most 0.5s + - OFF for at least 0.5s + then: + - if: + condition: + and: + - switch.is_on: ha_loss_override + - api.connected: + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "Reading On/Off" + - logger.log: + level: INFO + format: "BTN2: Single click (online) → Set 'Reaading On/Off' Scene" + else: + # OFFLINE path: only act if override ON; toggle physical relay + - if: + condition: + and: + - switch.is_on: ha_loss_override + - not: + api.connected: + then: + - if: + condition: + lambda: 'return id(Relay_2).state;' + then: + - switch.turn_off: Relay_2 + - logger.log: + level: INFO + format: "BTN2: Single click (offline) → Relay_2 OFF" + else: + - switch.turn_on: Relay_1 + - logger.log: + level: INFO + format: "BTN2: Single click (offline) → Relay_2 ON" + else: + - logger.log: + level: INFO + format: "BTN: Single click ignored" + +######################################################################################### +# TEXT SENSOR COMPONENT +# +######################################################################################### +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 +# https://esphome.io/components/switch/ +######################################################################################### +switch: +# GPIO13 for KS-811 first button UNLESS it is KS-811-1 then it is GIPO12 + - platform: gpio + name: "Relay 1: ${switch_1_name}" + pin: GPIO13 + id: Relay_1 + restore_mode: RESTORE_DEFAULT_ON + + # GPIO12 for second relay (only for KS-811-2 Double or -3 Triple) + - platform: gpio + name: "Relay 2: ${switch_2_name}" + pin: GPIO12 + id: Relay_2 + restore_mode: RESTORE_DEFAULT_ON + + # GPIO14 for third relay (only for KS-811-3 Triple) + - platform: gpio + name: "Relay 3: ${switch_3_name}" + pin: GPIO14 + id: Relay_3 + + # HA Loss manual override (default ON; persists across restarts) + - platform: template + name: "HA Loss manual override" + id: ha_loss_override + optimistic: true + restore_mode: RESTORE_DEFAULT_ON + diff --git a/esphome/esp-loungenorthswitch.yaml b/esphome/esp-loungenorthswitch.yaml new file mode 100644 index 0000000..ea9b74b --- /dev/null +++ b/esphome/esp-loungenorthswitch.yaml @@ -0,0 +1,315 @@ +########################################################################################## +########################################################################################## +# LOUNGE NORTH SWITCH (Single Switch into hallway) +# 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/ +# +# 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-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. + + # 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 + + # 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 + + # Device Settings + log_level: "DEBUG" # 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: "lounge-north-switch" + #mqtt_local_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + #mqtt_remote_device_name: "lounge-main-lights" + #mqtt_remote_device_command_topic: "${mqtt_command_main_topic}/${mqtt_remote_device_name}" + #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 +# 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}" + +api: + on_client_connected: + then: + - logger.log: + level: INFO + format: "API connected: applying override (override=%s)" + args: ['id(ha_loss_override).state ? "true" : "false"'] + - if: + condition: + switch.is_on: ha_loss_override + then: + - switch.turn_on: Relay_1 + else: + - switch.turn_off: Relay_1 + + on_client_disconnected: + then: + - logger.log: + level: WARN + format: "API disconnected: switching to manual/offline behavior" + +######################################################################################### +# 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 + +######################################################################################### +# STATUS LED +# https://esphome.io/components/status_led.html +######################################################################################### +status_led: + pin: + number: GPIO02 + inverted: yes + +######################################################################################### +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +######################################################################################### +binary_sensor: + - platform: gpio + pin: + number: GPIO0 + mode: INPUT + inverted: True + name: "Button 1: ${switch_1_name}" + on_multi_click: + + # --- Double click: send "Night Light" (only if HA connected). --- + - timing: + - ON for at most 0.5s + - OFF for at most 0.5s + - ON for at most 0.5s + - OFF for at least 0.2s + then: + - if: + condition: + api.connected: + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "Night Light" + - logger.log: + level: INFO + format: "BTN: Double click → Scene Night Light" + else: + - logger.log: + level: INFO + format: "BTN: Double click ignored (no HA connection)" + + # --- 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" + # Offline (and override ON): toggle physical Relay_1 + - timing: + - ON for at most 0.5s + - OFF for at least 0.5s + then: + - if: + condition: + and: + - switch.is_on: ha_loss_override + - api.connected: + then: + - if: + condition: + lambda: |- + // Defensive: treat empty/unknown as "not All Off" so we go to a safe "All Off". + auto s = id(ha_last_scene).state; + if (s.empty() || s == "unknown" || s == "unavailable") return true; + return s != "All Off"; + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "All Off" + - logger.log: + level: INFO + format: "BTN: Single click (online) → Last scene was not 'All Off' → Set 'All Off'" + else: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "Bright" + - logger.log: + level: INFO + format: "BTN: Single click (online) → Last scene was 'All Off' → Set 'Bright'" + else: + # OFFLINE path: only act if override ON; toggle physical relay + - if: + condition: + and: + - switch.is_on: ha_loss_override + - not: + api.connected: + then: + - if: + condition: + lambda: 'return id(Relay_1).state;' + then: + - switch.turn_off: Relay_1 + - logger.log: + level: INFO + 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" + else: + - logger.log: + level: INFO + format: "BTN: Single click ignored (override OFF)" + + # --- Long hold: ON for at least 4s (only if HA connected) --- + - timing: + - ON for at least 4s + then: + - if: + condition: + api.connected: + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "All Off" + - homeassistant.event: + event: esphome.lounge_switch_hold + data: + action: "hold" + - logger.log: + level: INFO + 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: + - 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 +# https://esphome.io/components/switch/ +######################################################################################### +switch: +# 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 + id: Relay_1 + restore_mode: RESTORE_DEFAULT_ON + + # HA Loss manual override (default ON; persists across restarts) + - platform: template + name: "HA Loss manual override" + id: ha_loss_override + optimistic: true + restore_mode: RESTORE_DEFAULT_ON + + diff --git a/esphome/esp-loungepelmetleds.yaml b/esphome/esp-loungepelmetleds.yaml new file mode 100644 index 0000000..c41eb30 --- /dev/null +++ b/esphome/esp-loungepelmetleds.yaml @@ -0,0 +1,1408 @@ +########################################################################################## +########################################################################################## +# Title: LOUNGE - PELMET LEDS (H801, 2x Monochrome PWM) +# Repo: (new) +# +# v2.1-dual - 2025-09-30 Per-channel Min/Max caps moved internal (YAML-only), no HA sliders. +# 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) +# +# ------------------------------------------ +# OPERATION (as of v2.0) +# ------------------------------------------ +# 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 (should be no on/off blip/flash). +# - "Remain Off": stays off on boot. +# 9. The fading LEDs flash while fading (different patterns for up/down). Channel A uses the **RED** LED on GPIO5. +# Channel B uses the **GREEN** LED on GPIO1 (UART TX; logger baud=0 to free it). +# 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 / Fade Down / Fade Stop buttons +# - Fade Up/Down toggle switch +# - Normal On/Off switch (quick ramp up/down) +# - 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: 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 fading status for Channel A) +# GPIO01 Green LED (used to display fading status for Channel B) [UART TX, logger baud=0] +# +########################################################################################## +########################################################################################## + +########################################################################################## +# 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-loungepelmetleds" # yaml file should be device_name.yaml + friendly_name: "Lounge Pelmet LEDs" + description_comment: "Lounge Pelmet LEDs :: H801 dual-channel monochrome" + device_area: "Lounge" # Allows the ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "H801.5xMOSFET" # 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 + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-loungepelmetleds_ip # CHANGE THIS + + # MQTT LOCAL Controls + mqtt_local_device_name_A: "lounge-pelmetleds_A" + mqtt_local_device_name_B: "lounge-pelmetleds_B" + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + mqtt_local_command_topic_A: "${mqtt_local_command_main_topic}/${mqtt_local_device_name_A}" + mqtt_local_status_topic_A: "${mqtt_local_status_main_topic}/${mqtt_local_device_name_A}" + mqtt_local_command_topic_B: "${mqtt_local_command_main_topic}/${mqtt_local_device_name_B}" + mqtt_local_status_topic_B: "${mqtt_local_status_main_topic}/${mqtt_local_device_name_B}" + mqtt_local_device_command_ON: "ON" + mqtt_local_device_command_OFF: "OFF" + + # Device Specific Settings (shared defaults applied per channel below) + log_level: "NONE" + update_interval: "20s" + led_gamma: "1.2" + pwm_frequency: "1000hz" + max_on_default_hours: "24" + + # Per-channel output caps (%), internal-only (no HA sliders) + minimum_led_output_A: "1" + maximum_led_output_A: "90" + minimum_led_output_B: "1" + maximum_led_output_B: "90" + + # Device Specific GPIO + device_status_led: GPIO02 + device_mosfet_out_A: GPIO12 + device_mosfet_out_B: GPIO13 + device_fading_led_A: GPIO05 + device_fading_led_B: GPIO01 + +########################################################################################## +# PACKAGES +########################################################################################## +packages: + 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}" + + common_api: !include + #file: common/api_common.yaml + file: common/api_common_noencryption.yaml + vars: + local_api_key: "${api_key}" + + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + + #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 + +########################################################################################## +# ESPHome CORE CONFIGURATION +########################################################################################## +esphome: + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" + area: "${device_area}" + on_boot: + priority: 200 + then: + - lambda: |- + switch (id(restart_mode)) { + case 0: id(restart_action).publish_state("Fade up to full"); break; + case 1: id(restart_action).publish_state("Restore Brightness"); break; + case 2: default: id(restart_action).publish_state("Remain Off"); break; + } + - if: + condition: + lambda: 'return id(restart_mode) == 0;' + then: + - lambda: 'id(ramp_switch_target_on_A) = true;' + - lambda: 'id(ramp_switch_target_on_B) = true;' + - script.execute: ramp_on_script_A + - script.execute: ramp_on_script_B + - if: + condition: + lambda: 'return id(restart_mode) == 1;' + then: + - script.execute: deferred_restore_brightness_A + - script.execute: deferred_restore_brightness_B + - if: + condition: + lambda: 'return id(restart_mode) == 2;' + then: + - script.stop: ramp_on_script_A + - script.stop: ramp_off_script_A + - lambda: 'id(ramp_switch_target_on_A) = false;' + - light.turn_off: + id: mosfet_leds_A + transition_length: 0s + - script.stop: ramp_on_script_B + - script.stop: ramp_off_script_B + - lambda: 'id(ramp_switch_target_on_B) = false;' + - light.turn_off: + id: mosfet_leds_B + transition_length: 0s + - lambda: 'id(booting) = false;' + +########################################################################################## +# ESP PLATFORM AND FRAMEWORK +########################################################################################## +esp8266: + board: esp01_1m + restore_from_flash: true + +mdns: + disabled: false + +preferences: + flash_write_interval: 5sec + +########################################################################################## +# GLOBAL VARIABLES +########################################################################################## +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 + initial_value: "${maximum_led_output_B}" + + # Max on hours (shared) + - id: max_on_hours + type: int + restore_value: true + initial_value: "${max_on_default_hours}" + + # Per-channel Fade Up/Down times (seconds -> ms) + - id: ramp_up_ms_A + type: int + restore_value: true + initial_value: '5000' + - id: ramp_down_ms_A + type: int + restore_value: true + initial_value: '10000' + - id: ramp_up_ms_B + type: int + restore_value: true + initial_value: '5000' + - id: ramp_down_ms_B + type: int + restore_value: true + initial_value: '10000' + + # Restart Action. (0=Fade full, 1=Restore brightness, 2=Remain off) + - id: restart_mode + type: int + restore_value: true + initial_value: '0' + + # Per-channel runtime state (A) + - id: ramp_switch_target_on_A + type: bool + restore_value: true + initial_value: 'false' + - id: suppress_slider_sync_A + type: bool + restore_value: false + initial_value: 'false' + - id: last_brightness_pct_A + type: float + restore_value: true + initial_value: '0.0' + - id: last_set_pos_A + type: int + restore_value: false + initial_value: '-1' + - id: last_ramp_ms_A + type: int + restore_value: false + initial_value: '0' + - id: last_nonzero_brightness_pct_A + type: float + restore_value: true + initial_value: '0.0' + - id: restore_target_pct_A + type: float + restore_value: false + initial_value: '0.0' + - id: is_ramping_A + type: bool + restore_value: false + initial_value: 'false' + - id: last_nonzero_tmp_A + type: float + restore_value: false + initial_value: '0.0' + - id: ramping_for_off_A + type: bool + restore_value: false + initial_value: 'false' + + # Per-channel runtime state (B) + - id: ramp_switch_target_on_B + type: bool + restore_value: true + initial_value: 'false' + - id: suppress_slider_sync_B + type: bool + restore_value: false + initial_value: 'false' + - id: last_brightness_pct_B + type: float + restore_value: true + initial_value: '0.0' + - id: last_set_pos_B + type: int + restore_value: false + initial_value: '-1' + - id: last_ramp_ms_B + type: int + restore_value: false + initial_value: '0' + - id: last_nonzero_brightness_pct_B + type: float + restore_value: true + initial_value: '0.0' + - id: restore_target_pct_B + type: float + restore_value: false + initial_value: '0.0' + - id: is_ramping_B + type: bool + restore_value: false + initial_value: 'false' + - id: last_nonzero_tmp_B + type: float + restore_value: false + initial_value: '0.0' + - id: ramping_for_off_B + type: bool + restore_value: false + initial_value: 'false' + + # Guard for startup behaviour + - id: booting + type: bool + restore_value: false + initial_value: 'true' + +########################################################################################## +# LOGGER +########################################################################################## +logger: + level: "${log_level}" + baud_rate: 0 + +######################################################################################### +# STATUS LED +######################################################################################### +#status_led: +# pin: +# number: ${device_status_led} +# inverted: true + +########################################################################################## +# MQTT COMMANDS +########################################################################################## +mqtt: + 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: + - platform: template + id: mosfet_ramp_switch_a + name: "${friendly_name} A Fade Up/Down" + icon: mdi:led-strip-variant + lambda: |- + return id(ramp_switch_target_on_A); + turn_on_action: + - lambda: |- + id(ramp_switch_target_on_A) = true; + - script.stop: ramp_off_script_A + - script.execute: ramp_on_script_A + turn_off_action: + - lambda: |- + id(ramp_switch_target_on_A) = false; + - script.stop: ramp_on_script_A + - script.execute: ramp_off_script_A + + - platform: template + id: mosfet_ramp_switch_b + name: "${friendly_name} B Fade Up/Down" + icon: mdi:led-strip-variant + lambda: |- + return id(ramp_switch_target_on_B); + turn_on_action: + - lambda: |- + id(ramp_switch_target_on_B) = true; + - script.stop: ramp_off_script_B + - script.execute: ramp_on_script_B + turn_off_action: + - lambda: |- + id(ramp_switch_target_on_B) = false; + - script.stop: ramp_on_script_B + - script.execute: ramp_off_script_B + +################################################################################################# +# BUTTONS (none) +################################################################################################# + +######################################################################################### +# SELECTS +######################################################################################### +select: + - platform: template + id: restart_action + name: "${friendly_name} Restart Action" + icon: mdi:restart + optimistic: true + options: + - "Fade up to full" + - "Restore Brightness" + - "Remain Off" + initial_option: "Restore Brightness" + set_action: + - lambda: |- + if (x == "Fade up to full") { + id(restart_mode) = 0; + } else if (x == "Restore Brightness") { + id(restart_mode) = 1; + } else { + id(restart_mode) = 2; + } + +########################################################################################## +# SENSORS +########################################################################################## +sensor: + # Channel A: Output % (pre-gamma) + - platform: template + id: mosfet_output_pct_A + name: "${friendly_name} A Output (%)" + unit_of_measurement: "%" + icon: mdi:percent + accuracy_decimals: 0 + update_interval: 250ms + lambda: |- + const auto &cv = id(mosfet_leds_A).current_values; + return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; + on_value: + then: + - lambda: |- + const auto &cv_now = id(mosfet_leds_A).current_values; + if (cv_now.is_on()) { + if (x > 0.5f) { + if (!id(is_ramping_A)) id(last_nonzero_brightness_pct_A) = x; + id(last_nonzero_tmp_A) = x; + } + } else { + if (x > 0.5f) id(last_nonzero_tmp_A) = x; + } + if (!id(suppress_slider_sync_A)) { + float actual = x; + float minp = (float) id(min_brightness_pct_A); + float maxp = (float) id(max_brightness_pct_A); + if (maxp <= minp) maxp = minp + 1.0f; + float pos = (actual <= 0.0f) ? 0.0f : ((actual - minp) * 100.0f / (maxp - minp)); + if (pos < 0.0f) pos = 0.0f; + if (pos > 100.0f) pos = 100.0f; + int pos_i = (int) floorf(pos + 0.5f); + if (pos_i != id(last_set_pos_A)) { + id(last_set_pos_A) = pos_i; + id(led_output_set_pct_A).publish_state(pos_i); + } + } + + # Channel A: Output PWM % (post-gamma approx) + - platform: template + id: mosfet_output_pwm_pct_A + name: "${friendly_name} A Output PWM (%)" + unit_of_measurement: "%" + icon: mdi:square-wave + accuracy_decimals: 1 + update_interval: 250ms + lambda: |- + const auto &cv = id(mosfet_leds_A).current_values; + if (!cv.is_on()) return 0.0f; + const float lin = cv.get_brightness(); // 0..1 linear brightness + const float gamma = (float) atof("${led_gamma}"); + float pwm = powf(lin, gamma); + if (pwm < 0.0f) pwm = 0.0f; + if (pwm > 1.0f) pwm = 1.0f; + return pwm * 100.0f; + + # Channel B: Output % (pre-gamma) + - platform: template + id: mosfet_output_pct_B + name: "${friendly_name} B Output (%)" + unit_of_measurement: "%" + icon: mdi:percent + accuracy_decimals: 0 + update_interval: 250ms + lambda: |- + const auto &cv = id(mosfet_leds_B).current_values; + return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; + on_value: + then: + - lambda: |- + const auto &cv_now = id(mosfet_leds_B).current_values; + if (cv_now.is_on()) { + if (x > 0.5f) { + if (!id(is_ramping_B)) id(last_nonzero_brightness_pct_B) = x; + id(last_nonzero_tmp_B) = x; + } + } else { + if (x > 0.5f) id(last_nonzero_tmp_B) = x; + } + if (!id(suppress_slider_sync_B)) { + float actual = x; + float minp = (float) id(min_brightness_pct_B); + float maxp = (float) id(max_brightness_pct_B); + if (maxp <= minp) maxp = minp + 1.0f; + float pos = (actual <= 0.0f) ? 0.0f : ((actual - minp) * 100.0f / (maxp - minp)); + if (pos < 0.0f) pos = 0.0f; + if (pos > 100.0f) pos = 100.0f; + int pos_i = (int) floorf(pos + 0.5f); + if (pos_i != id(last_set_pos_B)) { + id(last_set_pos_B) = pos_i; + id(led_output_set_pct_B).publish_state(pos_i); + } + } + + # Channel B: Output PWM % (post-gamma approx) + - platform: template + id: mosfet_output_pwm_pct_B + name: "${friendly_name} B Output PWM (%)" + unit_of_measurement: "%" + icon: mdi:square-wave + accuracy_decimals: 1 + update_interval: 250ms + lambda: |- + const auto &cv = id(mosfet_leds_B).current_values; + if (!cv.is_on()) return 0.0f; + const float lin = cv.get_brightness(); + const float gamma = (float) atof("${led_gamma}"); + float pwm = powf(lin, gamma); + if (pwm < 0.0f) pwm = 0.0f; + if (pwm > 1.0f) pwm = 1.0f; + return pwm * 100.0f; + +########################################################################################## +# OUTPUTS +########################################################################################## +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} + frequency: ${pwm_frequency} + + - platform: gpio + id: fading_led_out_A + 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: + - platform: monochromatic + id: mosfet_leds_A + name: "${friendly_name} A" + output: mosfet_pwm_A + restore_mode: RESTORE_DEFAULT_OFF + default_transition_length: 2s + icon: mdi:led-strip-variant + gamma_correct: "${led_gamma}" + + on_turn_on: + - mqtt.publish: + topic: "${mqtt_local_status_topic_A}/lightA/state" + payload: "${mqtt_local_device_command_ON}" + retain: true + - lambda: |- + if (!id(ramping_for_off_A)) { + id(ramp_switch_target_on_A) = true; + } + - script.stop: max_on_watchdog_A + - if: + condition: + lambda: 'return id(max_on_hours) > 0;' + then: + - script.execute: max_on_watchdog_A + + on_turn_off: + - if: + condition: + lambda: 'return !id(booting);' + then: + - mqtt.publish: + topic: "${mqtt_local_status_topic_A}/lightA/state" + payload: "${mqtt_local_device_command_OFF}" + retain: true + - lambda: 'id(ramp_switch_target_on_A) = false;' + - script.stop: max_on_watchdog_A + - lambda: |- + id(last_brightness_pct_A) = 0.0f; + id(last_set_pos_A) = 0; + id(led_output_set_pct_A).publish_state(0); + + on_state: + - lambda: |- + const float cap = id(max_brightness_pct_A) / 100.0f; + const auto &cv = id(mosfet_leds_A).current_values; + if (cv.is_on() && cv.get_brightness() > cap + 0.001f) { + auto call = id(mosfet_leds_A).make_call(); + call.set_state(true); + call.set_brightness(cap); + call.set_transition_length(0); + call.perform(); + } + + - platform: monochromatic + id: mosfet_leds_B + name: "${friendly_name} B" + output: mosfet_pwm_B + restore_mode: RESTORE_DEFAULT_OFF + default_transition_length: 2s + icon: mdi:led-strip-variant + gamma_correct: "${led_gamma}" + + on_turn_on: + - mqtt.publish: + topic: "${mqtt_local_status_topic_B}/lightB/state" + payload: "${mqtt_local_device_command_ON}" + retain: true + - lambda: |- + if (!id(ramping_for_off_B)) { + id(ramp_switch_target_on_B) = true; + } + - script.stop: max_on_watchdog_B + - if: + condition: + lambda: 'return id(max_on_hours) > 0;' + then: + - script.execute: max_on_watchdog_B + + on_turn_off: + - if: + condition: + lambda: 'return !id(booting);' + then: + - mqtt.publish: + topic: "${mqtt_local_status_topic_B}/lightB/state" + payload: "${mqtt_local_device_command_OFF}" + retain: true + - lambda: 'id(ramp_switch_target_on_B) = false;' + - script.stop: max_on_watchdog_B + - lambda: |- + id(last_brightness_pct_B) = 0.0f; + id(last_set_pos_B) = 0; + id(led_output_set_pct_B).publish_state(0); + + on_state: + - lambda: |- + const float cap = id(max_brightness_pct_B) / 100.0f; + const auto &cv = id(mosfet_leds_B).current_values; + if (cv.is_on() && cv.get_brightness() > cap + 0.001f) { + auto call = id(mosfet_leds_B).make_call(); + call.set_state(true); + call.set_brightness(cap); + call.set_transition_length(0); + call.perform(); + } + +########################################################################################## +# NUMBERS +########################################################################################## +number: + - platform: template + id: cfg_ramp_up_s_A + name: "${friendly_name} A Fade Up Time (s)" + entity_category: config + unit_of_measurement: s + icon: mdi:timer-sand + mode: slider + min_value: 0 + max_value: 60 + step: 1 + lambda: |- + return (float) id(ramp_up_ms_A) / 1000.0f; + set_action: + - lambda: |- + int secs = (int) floorf(x + 0.5f); + if (secs < 0) secs = 0; + if (secs > 60) secs = 60; + id(ramp_up_ms_A) = secs * 1000; + id(cfg_ramp_up_s_A).publish_state((float) secs); + + - platform: template + id: cfg_ramp_down_s_A + name: "${friendly_name} A Fade Down Time (s)" + entity_category: config + unit_of_measurement: s + icon: mdi:timer-sand-complete + mode: slider + min_value: 0 + max_value: 60 + step: 1 + lambda: |- + return (float) id(ramp_down_ms_A) / 1000.0f; + set_action: + - lambda: |- + int secs = (int) floorf(x + 0.5f); + if (secs < 0) secs = 0; + if (secs > 60) secs = 60; + id(ramp_down_ms_A) = secs * 1000; + id(cfg_ramp_down_s_A).publish_state((float) secs); + + - platform: template + id: cfg_ramp_up_s_B + name: "${friendly_name} B Fade Up Time (s)" + entity_category: config + unit_of_measurement: s + icon: mdi:timer-sand + mode: slider + min_value: 0 + max_value: 60 + step: 1 + lambda: |- + return (float) id(ramp_up_ms_B) / 1000.0f; + set_action: + - lambda: |- + int secs = (int) floorf(x + 0.5f); + if (secs < 0) secs = 0; + if (secs > 60) secs = 60; + id(ramp_up_ms_B) = secs * 1000; + id(cfg_ramp_up_s_B).publish_state((float) secs); + + - platform: template + id: cfg_ramp_down_s_B + name: "${friendly_name} B Fade Down Time (s)" + entity_category: config + unit_of_measurement: s + icon: mdi:timer-sand-complete + mode: slider + min_value: 0 + max_value: 60 + step: 1 + lambda: |- + return (float) id(ramp_down_ms_B) / 1000.0f; + set_action: + - lambda: |- + int secs = (int) floorf(x + 0.5f); + if (secs < 0) secs = 0; + if (secs > 60) secs = 60; + 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)" + icon: mdi:tune + mode: slider + min_value: 0 + max_value: 100 + 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 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 + float pos = (actual - minp) * 100.0f / (maxp - minp); + if (pos < 0.0f) pos = 0.0f; + if (pos > 100.0f) pos = 100.0f; + return floorf(pos + 0.5f); + set_action: + - if: + condition: + lambda: 'return x <= 0.0f;' + then: + - lambda: 'id(suppress_slider_sync_A) = true;' + - script.stop: ramp_on_script_A + - script.stop: ramp_off_script_A + - light.turn_off: + id: mosfet_leds_A + transition_length: 200ms + - lambda: |- + id(ramp_switch_target_on_A) = false; + id(led_output_set_pct_A).publish_state(0); + id(last_brightness_pct_A) = 0.0f; + id(last_set_pos_A) = 0; + - delay: 400ms + - lambda: 'id(suppress_slider_sync_A) = false;' + else: + - lambda: |- + id(suppress_slider_sync_A) = true; + float pos = x; // 0..100 + if (pos < 1.0f) pos = 1.0f; // 0 is OFF + if (pos > 100.0f) pos = 100.0f; + id(led_output_set_pct_A).publish_state((int) floorf(pos + 0.5f)); + - script.stop: ramp_off_script_A + - script.stop: ramp_on_script_A + - light.turn_on: + id: mosfet_leds_A + brightness: !lambda |- + float pos = id(led_output_set_pct_A).state; // 1..100 + 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; + return out_pct / 100.0f; + transition_length: 250ms + - lambda: |- + id(ramp_switch_target_on_A) = true; + float pos = id(led_output_set_pct_A).state; // 1..100 + 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; + id(last_brightness_pct_A) = out_pct; + if (out_pct > 0.5f) { + id(last_nonzero_brightness_pct_A) = out_pct; + id(last_nonzero_tmp_A) = out_pct; + } + - delay: 400ms + - lambda: 'id(suppress_slider_sync_A) = false;' + + - platform: template + id: led_output_set_pct_B + name: "${friendly_name} B Output Set (0-100)" + icon: mdi:tune + mode: slider + min_value: 0 + max_value: 100 + 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 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 + float pos = (actual - minp) * 100.0f / (maxp - minp); + if (pos < 0.0f) pos = 0.0f; + if (pos > 100.0f) pos = 100.0f; + return floorf(pos + 0.5f); + set_action: + - if: + condition: + lambda: 'return x <= 0.0f;' + then: + - lambda: 'id(suppress_slider_sync_B) = true;' + - script.stop: ramp_on_script_B + - script.stop: ramp_off_script_B + - light.turn_off: + id: mosfet_leds_B + transition_length: 200ms + - lambda: |- + id(ramp_switch_target_on_B) = false; + id(led_output_set_pct_B).publish_state(0); + id(last_brightness_pct_B) = 0.0f; + id(last_set_pos_B) = 0; + - delay: 400ms + - lambda: 'id(suppress_slider_sync_B) = false;' + else: + - lambda: |- + id(suppress_slider_sync_B) = true; + float pos = x; // 0..100 + if (pos < 1.0f) pos = 1.0f; // 0 is OFF + if (pos > 100.0f) pos = 100.0f; + id(led_output_set_pct_B).publish_state((int) floorf(pos + 0.5f)); + - script.stop: ramp_off_script_B + - script.stop: ramp_on_script_B + - light.turn_on: + id: mosfet_leds_B + brightness: !lambda |- + float pos = id(led_output_set_pct_B).state; // 1..100 + 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; + return out_pct / 100.0f; + transition_length: 250ms + - lambda: |- + id(ramp_switch_target_on_B) = true; + float pos = id(led_output_set_pct_B).state; // 1..100 + 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; + id(last_brightness_pct_B) = out_pct; // persist exact target now + if (out_pct > 0.5f) { + id(last_nonzero_brightness_pct_B) = out_pct; + id(last_nonzero_tmp_B) = out_pct; + } + - delay: 400ms + - lambda: 'id(suppress_slider_sync_B) = false;' + + # Shared "Max On" hours + - platform: template + id: cfg_max_on_hours + name: "${friendly_name} Max On (h)" + entity_category: config + unit_of_measurement: h + icon: mdi:timer-cog + mode: slider + min_value: 0 + max_value: 48 + step: 1 + lambda: |- + return (float) id(max_on_hours); + set_action: + - lambda: |- + int hrs = (int) x; + if (hrs < 0) hrs = 0; + if (hrs > 48) hrs = 48; + id(max_on_hours) = hrs; + id(cfg_max_on_hours).publish_state((float) hrs); + - if: + condition: + lambda: 'return id(mosfet_leds_A).current_values.is_on();' + then: + - script.stop: max_on_watchdog_A + - if: + condition: + lambda: 'return id(max_on_hours) > 0;' + then: + - script.execute: max_on_watchdog_A + - if: + condition: + lambda: 'return id(mosfet_leds_B).current_values.is_on();' + then: + - script.stop: max_on_watchdog_B + - if: + condition: + lambda: 'return id(max_on_hours) > 0;' + then: + - script.execute: max_on_watchdog_B + +########################################################################################## +# SCRIPTS +########################################################################################## +script: + # Blink patterns while ramping (A) + - id: led_flash_up_A + mode: restart + then: + - while: + condition: + lambda: 'return true;' + then: + - output.turn_on: fading_led_out_A + - delay: 100ms + - output.turn_off: fading_led_out_A + - delay: 100ms + - output.turn_on: fading_led_out_A + - delay: 100ms + - output.turn_off: fading_led_out_A + - delay: 400ms + + - id: led_flash_down_A + mode: restart + then: + - while: + condition: + lambda: 'return true;' + then: + - output.turn_on: fading_led_out_A + - delay: 250ms + - output.turn_off: fading_led_out_A + - delay: 250ms + + # Blink patterns while ramping (B) + - id: led_flash_up_B + mode: restart + then: + - while: + condition: + lambda: 'return true;' + then: + - output.turn_on: fading_led_out_B + - delay: 100ms + - output.turn_off: fading_led_out_B + - delay: 100ms + - output.turn_on: fading_led_out_B + - delay: 100ms + - output.turn_off: fading_led_out_B + - delay: 400ms + + - id: led_flash_down_B + mode: restart + then: + - while: + condition: + lambda: 'return true;' + then: + - output.turn_on: fading_led_out_B + - delay: 250ms + - output.turn_off: fading_led_out_B + - delay: 250ms + + # Ramps: Channel A + - id: ramp_on_script_A + mode: restart + then: + - lambda: 'id(is_ramping_A) = true;' + - script.stop: ramp_off_script_A + - script.stop: led_flash_down_A + - script.execute: led_flash_up_A + - if: + condition: + lambda: |- + const auto &cv = id(mosfet_leds_A).current_values; + const float floor = id(min_brightness_pct_A) / 100.0f; + return (!cv.is_on()) || (cv.get_brightness() + 0.0005f < floor); + then: + - light.turn_on: + id: mosfet_leds_A + brightness: !lambda 'return id(min_brightness_pct_A) / 100.0f;' + transition_length: 80ms + - light.turn_on: + id: mosfet_leds_A + brightness: !lambda 'return id(max_brightness_pct_A) / 100.0f;' + transition_length: !lambda |- + const auto &cv = id(mosfet_leds_A).current_values; + const float floor = id(min_brightness_pct_A) / 100.0f; + const float cap = id(max_brightness_pct_A) / 100.0f; + if (cap <= floor + 0.0005f) { id(last_ramp_ms_A) = 0; return (uint32_t) 0; } + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr + 0.0005f < floor) { + id(last_ramp_ms_A) = id(ramp_up_ms_A); + return (uint32_t) id(last_ramp_ms_A); + } + if (curr > cap) curr = cap; + if (curr < floor) curr = floor; + float frac = (cap - curr) / (cap - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + id(last_ramp_ms_A) = (int) (id(ramp_up_ms_A) * frac); + return (uint32_t) id(last_ramp_ms_A); + - delay: !lambda 'return (uint32_t) id(last_ramp_ms_A);' + - script.stop: led_flash_up_A + - output.turn_off: fading_led_out_A + - lambda: |- + id(is_ramping_A) = false; + const auto &cv = id(mosfet_leds_A).current_values; + if (cv.is_on()) { + float pct = cv.get_brightness() * 100.0f; + id(last_brightness_pct_A) = pct; + if (pct > 0.5f) id(last_nonzero_brightness_pct_A) = pct; + } + + - id: ramp_to_target_script_A + mode: restart + then: + - lambda: 'id(is_ramping_A) = true;' + - script.stop: ramp_off_script_A + - script.stop: led_flash_down_A + - script.execute: led_flash_up_A + - if: + condition: + lambda: |- + const auto &cv = id(mosfet_leds_A).current_values; + const float floor = id(min_brightness_pct_A) / 100.0f; + return (!cv.is_on()) || (cv.get_brightness() + 0.0005f < floor); + then: + - light.turn_on: + id: mosfet_leds_A + brightness: !lambda 'return id(min_brightness_pct_A) / 100.0f;' + transition_length: 80ms + - light.turn_on: + id: mosfet_leds_A + brightness: !lambda |- + float cap_pct = id(restore_target_pct_A); + float maxp = (float) id(max_brightness_pct_A); + if (cap_pct > maxp) cap_pct = maxp; + return cap_pct / 100.0f; + transition_length: !lambda |- + const auto &cv = id(mosfet_leds_A).current_values; + const float floor = id(min_brightness_pct_A) / 100.0f; + float cap = id(restore_target_pct_A) / 100.0f; + const float maxp = id(max_brightness_pct_A) / 100.0f; + if (cap > maxp) cap = maxp; + if (cap <= floor + 0.0005f) { id(last_ramp_ms_A) = 0; return (uint32_t) 0; } + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr + 0.0005f < floor) { + id(last_ramp_ms_A) = id(ramp_up_ms_A); + return (uint32_t) id(last_ramp_ms_A); + } + if (curr > cap) curr = cap; + if (curr < floor) curr = floor; + float frac = (cap - curr) / (cap - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + id(last_ramp_ms_A) = (int) (id(ramp_up_ms_A) * frac); + return (uint32_t) id(last_ramp_ms_A); + - delay: !lambda 'return (uint32_t) id(last_ramp_ms_A);' + - script.stop: led_flash_up_A + - output.turn_off: fading_led_out_A + - lambda: |- + id(is_ramping_A) = false; + const auto &cv = id(mosfet_leds_A).current_values; + if (cv.is_on()) { + float pct = cv.get_brightness() * 100.0f; + id(last_brightness_pct_A) = pct; + if (pct > 0.5f) id(last_nonzero_brightness_pct_A) = pct; + } + + - id: ramp_off_script_A + mode: restart + then: + - lambda: |- + id(is_ramping_A) = true; + id(ramping_for_off_A) = true; + - script.stop: ramp_on_script_A + - script.stop: led_flash_up_A + - script.execute: led_flash_down_A + - light.turn_on: + id: mosfet_leds_A + brightness: !lambda 'return id(min_brightness_pct_A) / 100.0f;' + transition_length: !lambda |- + const auto &cv = id(mosfet_leds_A).current_values; + const float floor = id(min_brightness_pct_A) / 100.0f; + float curr = cv.get_brightness(); + if (curr < floor) curr = floor; + const float denom = (1.0f - floor); + if (denom <= 0.0005f) { id(last_ramp_ms_A) = 0; return (uint32_t) 0; } + float frac = (curr - floor) / denom; + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + id(last_ramp_ms_A) = (int) (id(ramp_down_ms_A) * frac); + return (uint32_t) id(last_ramp_ms_A); + - delay: !lambda 'return (uint32_t) id(last_ramp_ms_A);' + - light.turn_off: + id: mosfet_leds_A + transition_length: 150ms + - delay: 150ms + - script.stop: led_flash_down_A + - output.turn_off: fading_led_out_A + - lambda: |- + id(is_ramping_A) = false; + id(ramping_for_off_A) = false; + id(last_brightness_pct_A) = 0.0f; + id(last_set_pos_A) = 0; + id(led_output_set_pct_A).publish_state(0); + + - id: max_on_watchdog_A + mode: restart + then: + - if: + condition: + lambda: 'return id(max_on_hours) > 0;' + then: + - delay: !lambda 'return (uint32_t) (id(max_on_hours) * 3600000UL);' + - if: + condition: + lambda: 'return id(mosfet_leds_A).current_values.is_on();' + then: + - lambda: |- + id(ramp_switch_target_on_A) = false; + id(mosfet_ramp_switch_a).publish_state(false); + - script.stop: ramp_on_script_A + - script.execute: ramp_off_script_A + + - id: deferred_restore_brightness_A + mode: restart + then: + - delay: 5s + - lambda: |- + float target = id(last_brightness_pct_A); + 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; + id(restore_target_pct_A) = target; + - if: + condition: + lambda: 'return id(restore_target_pct_A) > 0.5f;' + then: + - lambda: |- + id(ramp_switch_target_on_A) = true; + id(suppress_slider_sync_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;' + else: + - lambda: 'id(ramp_switch_target_on_A) = false;' + - light.turn_off: + id: mosfet_leds_A + transition_length: 0s + + # Ramps: Channel B + - id: ramp_on_script_B + mode: restart + then: + - lambda: 'id(is_ramping_B) = true;' + - script.stop: ramp_off_script_B + - script.stop: led_flash_down_B + - script.execute: led_flash_up_B + - if: + condition: + lambda: |- + const auto &cv = id(mosfet_leds_B).current_values; + const float floor = id(min_brightness_pct_B) / 100.0f; + return (!cv.is_on()) || (cv.get_brightness() + 0.0005f < floor); + then: + - light.turn_on: + id: mosfet_leds_B + brightness: !lambda 'return id(min_brightness_pct_B) / 100.0f;' + transition_length: 80ms + - light.turn_on: + id: mosfet_leds_B + brightness: !lambda 'return id(max_brightness_pct_B) / 100.0f;' + transition_length: !lambda |- + const auto &cv = id(mosfet_leds_B).current_values; + const float floor = id(min_brightness_pct_B) / 100.0f; + const float cap = id(max_brightness_pct_B) / 100.0f; + if (cap <= floor + 0.0005f) { id(last_ramp_ms_B) = 0; return (uint32_t) 0; } + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr + 0.0005f < floor) { + id(last_ramp_ms_B) = id(ramp_up_ms_B); + return (uint32_t) id(last_ramp_ms_B); + } + if (curr > cap) curr = cap; + if (curr < floor) curr = floor; + float frac = (cap - curr) / (cap - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + id(last_ramp_ms_B) = (int) (id(ramp_up_ms_B) * frac); + return (uint32_t) id(last_ramp_ms_B); + - delay: !lambda 'return (uint32_t) id(last_ramp_ms_B);' + - script.stop: led_flash_up_B + - output.turn_off: fading_led_out_B + - lambda: |- + id(is_ramping_B) = false; + const auto &cv = id(mosfet_leds_B).current_values; + if (cv.is_on()) { + float pct = cv.get_brightness() * 100.0f; + id(last_brightness_pct_B) = pct; + if (pct > 0.5f) id(last_nonzero_brightness_pct_B) = pct; + } + + - id: ramp_to_target_script_B + mode: restart + then: + - lambda: 'id(is_ramping_B) = true;' + - script.stop: ramp_off_script_B + - script.stop: led_flash_down_B + - script.execute: led_flash_up_B + - if: + condition: + lambda: |- + const auto &cv = id(mosfet_leds_B).current_values; + const float floor = id(min_brightness_pct_B) / 100.0f; + return (!cv.is_on()) || (cv.get_brightness() + 0.0005f < floor); + then: + - light.turn_on: + id: mosfet_leds_B + brightness: !lambda 'return id(min_brightness_pct_B) / 100.0f;' + transition_length: 80ms + - light.turn_on: + id: mosfet_leds_B + brightness: !lambda |- + float cap_pct = id(restore_target_pct_B); + float maxp = (float) id(max_brightness_pct_B); + if (cap_pct > maxp) cap_pct = maxp; + return cap_pct / 100.0f; + transition_length: !lambda |- + const auto &cv = id(mosfet_leds_B).current_values; + const float floor = id(min_brightness_pct_B) / 100.0f; + float cap = id(restore_target_pct_B) / 100.0f; + const float maxp = id(max_brightness_pct_B) / 100.0f; + if (cap > maxp) cap = maxp; + if (cap <= floor + 0.0005f) { id(last_ramp_ms_B) = 0; return (uint32_t) 0; } + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr + 0.0005f < floor) { + id(last_ramp_ms_B) = id(ramp_up_ms_B); + return (uint32_t) id(last_ramp_ms_B); + } + if (curr > cap) curr = cap; + if (curr < floor) curr = floor; + float frac = (cap - curr) / (cap - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + id(last_ramp_ms_B) = (int) (id(ramp_up_ms_B) * frac); + return (uint32_t) id(last_ramp_ms_B); + - delay: !lambda 'return (uint32_t) id(last_ramp_ms_B);' + - script.stop: led_flash_up_B + - output.turn_off: fading_led_out_B + - lambda: |- + id(is_ramping_B) = false; + const auto &cv = id(mosfet_leds_B).current_values; + if (cv.is_on()) { + float pct = cv.get_brightness() * 100.0f; + id(last_brightness_pct_B) = pct; + if (pct > 0.5f) id(last_nonzero_brightness_pct_B) = pct; + } + + - id: ramp_off_script_B + mode: restart + then: + - lambda: |- + id(is_ramping_B) = true; + id(ramping_for_off_B) = true; + - script.stop: ramp_on_script_B + - script.stop: led_flash_up_B + - script.execute: led_flash_down_B + - light.turn_on: + id: mosfet_leds_B + brightness: !lambda 'return id(min_brightness_pct_B) / 100.0f;' + transition_length: !lambda |- + const auto &cv = id(mosfet_leds_B).current_values; + const float floor = id(min_brightness_pct_B) / 100.0f; + float curr = cv.get_brightness(); + if (curr < floor) curr = floor; + const float denom = (1.0f - floor); + if (denom <= 0.0005f) { id(last_ramp_ms_B) = 0; return (uint32_t) 0; } + float frac = (curr - floor) / denom; + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + id(last_ramp_ms_B) = (int) (id(ramp_down_ms_B) * frac); + return (uint32_t) id(last_ramp_ms_B); + - delay: !lambda 'return (uint32_t) id(last_ramp_ms_B);' + - light.turn_off: + id: mosfet_leds_B + transition_length: 150ms + - delay: 150ms + - script.stop: led_flash_down_B + - output.turn_off: fading_led_out_B + - lambda: |- + id(is_ramping_B) = false; + id(ramping_for_off_B) = false; + id(last_brightness_pct_B) = 0.0f; + id(last_set_pos_B) = 0; + id(led_output_set_pct_B).publish_state(0); + + - id: max_on_watchdog_B + mode: restart + then: + - if: + condition: + lambda: 'return id(max_on_hours) > 0;' + then: + - delay: !lambda 'return (uint32_t) (id(max_on_hours) * 3600000UL);' + - if: + condition: + lambda: 'return id(mosfet_leds_B).current_values.is_on();' + then: + - lambda: |- + id(ramp_switch_target_on_B) = false; + id(mosfet_ramp_switch_b).publish_state(false); + - script.stop: ramp_on_script_B + - script.execute: ramp_off_script_B + + - id: deferred_restore_brightness_B + mode: restart + then: + - delay: 5s + - lambda: |- + float target = id(last_brightness_pct_B); + 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; + id(restore_target_pct_B) = target; + - if: + condition: + lambda: 'return id(restore_target_pct_B) > 0.5f;' + then: + - lambda: |- + id(ramp_switch_target_on_B) = true; + id(suppress_slider_sync_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;' + else: + - lambda: 'id(ramp_switch_target_on_B) = false;' + - light.turn_off: + id: mosfet_leds_B + transition_length: 0s diff --git a/esphome/esp-loungesouthleftswitch.yaml b/esphome/esp-loungesouthleftswitch.yaml new file mode 100644 index 0000000..862281f --- /dev/null +++ b/esphome/esp-loungesouthleftswitch.yaml @@ -0,0 +1,188 @@ +########################################################################################## +########################################################################################## +# LOUNGE SOUTH LEFT LIGHTSWITCH +# 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/ +# +# 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-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. + + # 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 + + # 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 + #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: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 + + # 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: "Wall Washer Left" + switch_2_name: "Outside Light 1" + #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 + 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_2 + +######################################################################################### +# 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 + +######################################################################################### +# 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 + 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 + +# 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 +# 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 + +# KS-811-2 is a double only +# - platform: gpio +# name: "Relay 3: ${switch_3_name}" +# pin: GPIO14 +# id: Relay_3 + + diff --git a/esphome/esp-loungesouthrightswitch.yaml b/esphome/esp-loungesouthrightswitch.yaml new file mode 100644 index 0000000..cec2b56 --- /dev/null +++ b/esphome/esp-loungesouthrightswitch.yaml @@ -0,0 +1,221 @@ +########################################################################################## +########################################################################################## +# LOUNGE SOUTH RIGHT LIGHTSWITCH +# 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 +# - +########################################################################################## +########################################################################################## + +########################################################################################## +# 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-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. + + # 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 + + # 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 + + # 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 + + # 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: "Spare" + switch_2_name: "Wall Washer Right" + switch_3_name: "Breakfast Bar LEDs" # Connected to another esphome device at the breakfast bar LEDs + +######################################################################################### +# 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}" + +api: + on_client_connected: + then: + - logger.log: + level: INFO + format: "API connected: applying override (override=%s)" + args: ['id(ha_loss_override).state ? "true" : "false"'] + - if: + condition: + switch.is_on: ha_loss_override + then: + - switch.turn_on: Relay_3 + else: + - switch.turn_off: Relay_3 + + on_client_disconnected: + then: + - logger.log: + level: WARN + format: "API disconnected: switching to manual/offline behavior" + +######################################################################################### +# 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 + +######################################################################################### +# 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 + 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_multi_click: + - timing: + - ON for at most 0.5s + - OFF for at least 0.5s + then: + - if: + condition: + and: + - not: api.connected + - switch.is_on: ha_loss_override + then: + - switch.toggle: Relay_3 + else: [] + +######################################################################################### +# 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 + restore_mode: RESTORE_DEFAULT_ON + + # HA Loss manual override (default ON; persists across restarts) + - platform: template + name: "HA Loss manual override" + id: ha_loss_override + optimistic: true + restore_mode: RESTORE_DEFAULT_ON + diff --git a/esphome/esp-loungewestswitch.yaml b/esphome/esp-loungewestswitch.yaml new file mode 100644 index 0000000..4845993 --- /dev/null +++ b/esphome/esp-loungewestswitch.yaml @@ -0,0 +1,315 @@ +########################################################################################## +########################################################################################## +# LOUNGE WEST SWITCH (Single Switch from entranceway) +# 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/ +# +# 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-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. + + # 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 + + # 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 + + # Device Settings + log_level: "DEBUG" # 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: "lounge-north-switch" + #mqtt_local_command_topic: "${mqtt_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + #mqtt_remote_device_name: "lounge-main-lights" + #mqtt_remote_device_command_topic: "${mqtt_command_main_topic}/${mqtt_remote_device_name}" + #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 +# 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}" + +api: + on_client_connected: + then: + - logger.log: + level: INFO + format: "API connected: applying override (override=%s)" + args: ['id(ha_loss_override).state ? "true" : "false"'] + - if: + condition: + switch.is_on: ha_loss_override + then: + - switch.turn_on: Relay_1 + else: + - switch.turn_off: Relay_1 + + on_client_disconnected: + then: + - logger.log: + level: WARN + format: "API disconnected: switching to manual/offline behavior" + +######################################################################################### +# 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 + +######################################################################################### +# STATUS LED +# https://esphome.io/components/status_led.html +######################################################################################### +status_led: + pin: + number: GPIO02 + inverted: yes + +######################################################################################### +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +######################################################################################### +binary_sensor: + - platform: gpio + pin: + number: GPIO0 + mode: INPUT + inverted: True + name: "Button 1: ${switch_1_name}" + on_multi_click: + + # --- Double click: send "Night Light" (only if HA connected). --- + - timing: + - ON for at most 0.5s + - OFF for at most 0.5s + - ON for at most 0.5s + - OFF for at least 0.2s + then: + - if: + condition: + api.connected: + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "Night Light" + - logger.log: + level: INFO + format: "BTN: Double click → Scene Night Light" + else: + - logger.log: + level: INFO + format: "BTN: Double click ignored (no HA connection)" + + # --- 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" + # Offline (and override ON): toggle physical Relay_1 + - timing: + - ON for at most 0.5s + - OFF for at least 0.5s + then: + - if: + condition: + and: + - switch.is_on: ha_loss_override + - api.connected: + then: + - if: + condition: + lambda: |- + // Defensive: treat empty/unknown as "not All Off" so we go to a safe "All Off". + auto s = id(ha_last_scene).state; + if (s.empty() || s == "unknown" || s == "unavailable") return true; + return s != "All Off"; + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "All Off" + - logger.log: + level: INFO + format: "BTN: Single click (online) → Last scene was not 'All Off' → Set 'All Off'" + else: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "Bright" + - logger.log: + level: INFO + format: "BTN: Single click (online) → Last scene was 'All Off' → Set 'Bright'" + else: + # OFFLINE path: only act if override ON; toggle physical relay + - if: + condition: + and: + - switch.is_on: ha_loss_override + - not: + api.connected: + then: + - if: + condition: + lambda: 'return id(Relay_1).state;' + then: + - switch.turn_off: Relay_1 + - logger.log: + level: INFO + 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" + else: + - logger.log: + level: INFO + format: "BTN: Single click ignored (override OFF)" + + # --- Long hold: ON for at least 4s (only if HA connected) --- + - timing: + - ON for at least 4s + then: + - if: + condition: + api.connected: + then: + - homeassistant.service: + service: script.lounge_set_scene + data: + scene_name: "All Off" + - homeassistant.event: + event: esphome.lounge_switch_hold + data: + action: "hold" + - logger.log: + level: INFO + 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: + - 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 +# https://esphome.io/components/switch/ +######################################################################################### +switch: +# 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 + id: Relay_1 + restore_mode: RESTORE_DEFAULT_ON + + # HA Loss manual override (default ON; persists across restarts) + - platform: template + name: "HA Loss manual override" + id: ha_loss_override + optimistic: true + restore_mode: RESTORE_DEFAULT_ON + + diff --git a/esphome/esp-mainbathfancombo.yaml b/esphome/esp-mainbathfancombo.yaml index d5b2bb9..d468970 100644 --- a/esphome/esp-mainbathfancombo.yaml +++ b/esphome/esp-mainbathfancombo.yaml @@ -52,29 +52,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-mainbathlights.yaml b/esphome/esp-mainbathlights.yaml index 8dbba63..6e3bf4c 100644 --- a/esphome/esp-mainbathlights.yaml +++ b/esphome/esp-mainbathlights.yaml @@ -35,29 +35,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-maindishwasherpower.yaml b/esphome/esp-maindishwasherpower.yaml index 6be2108..826fb1d 100644 --- a/esphome/esp-maindishwasherpower.yaml +++ b/esphome/esp-maindishwasherpower.yaml @@ -44,31 +44,39 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 - # Device Specific included packages + #### 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 + + # Device Specific included packages common_athompowermonV3: !include file: common/athompowermonv3_common.yaml vars: diff --git a/esphome/esp-mainkitchenlights.yaml b/esphome/esp-mainkitchenlights.yaml index 84882b6..eda0b7a 100644 --- a/esphome/esp-mainkitchenlights.yaml +++ b/esphome/esp-mainkitchenlights.yaml @@ -55,29 +55,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-masterbathtowelrail.yaml b/esphome/esp-masterbathtowelrail.yaml index b916abb..4d25d61 100644 --- a/esphome/esp-masterbathtowelrail.yaml +++ b/esphome/esp-masterbathtowelrail.yaml @@ -83,29 +83,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 @@ -116,12 +124,12 @@ esphome: friendly_name: "${friendly_name}" 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 +# 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 on_boot: priority: 900 # High priority to run after globals are initialized then: diff --git a/esphome/esp-midesklamp1s.yaml b/esphome/esp-midesklamp1s.yaml index 74cdb7e..9f6ead5 100644 --- a/esphome/esp-midesklamp1s.yaml +++ b/esphome/esp-midesklamp1s.yaml @@ -52,29 +52,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-occupancyoffice.yaml b/esphome/esp-occupancyoffice.yaml index fd162ce..48f9864 100644 --- a/esphome/esp-occupancyoffice.yaml +++ b/esphome/esp-occupancyoffice.yaml @@ -42,29 +42,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-occupancystair.yaml b/esphome/esp-occupancystair.yaml index 2679675..d2d12bf 100644 --- a/esphome/esp-occupancystair.yaml +++ b/esphome/esp-occupancystair.yaml @@ -54,29 +54,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 CORE CONFIGURATION diff --git a/esphome/esp-officeduallights.yaml b/esphome/esp-officeduallights.yaml index 1999399..0d70984 100644 --- a/esphome/esp-officeduallights.yaml +++ b/esphome/esp-officeduallights.yaml @@ -65,29 +65,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 @@ -98,12 +106,12 @@ esphome: friendly_name: "${friendly_name}" 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++ exceptaions - - "-fno-rtti" # strip C++ RTTI +# 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 diff --git a/esphome/esp-officeelvcontrol.yaml b/esphome/esp-officeelvcontrol.yaml index 8d8751e..002449e 100644 --- a/esphome/esp-officeelvcontrol.yaml +++ b/esphome/esp-officeelvcontrol.yaml @@ -48,29 +48,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-officelights.yaml b/esphome/esp-officelights.yaml index 62fcace..c11f2db 100644 --- a/esphome/esp-officelights.yaml +++ b/esphome/esp-officelights.yaml @@ -47,29 +47,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-officeusbhubpower.yaml b/esphome/esp-officeusbhubpower.yaml index ae97ba3..38e89a0 100644 --- a/esphome/esp-officeusbhubpower.yaml +++ b/esphome/esp-officeusbhubpower.yaml @@ -48,29 +48,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/esphome/esp-poolpumppower.yaml b/esphome/esp-poolpumppower.yaml index 6a27bf2..ebabe16 100644 --- a/esphome/esp-poolpumppower.yaml +++ b/esphome/esp-poolpumppower.yaml @@ -86,10 +86,6 @@ substitutions: # https://esphome.io/components/packages.html ########################################################################################## packages: - ################################################## - # MANDATORY packages (won't compile without them!) - ################################################## - #### WIFI, Network (Static/DHCP/IPV6 etc), Fallback AP, Safemode #### common_wifi: !include file: common/network_common.yaml @@ -98,20 +94,12 @@ packages: local_static_ip_address: "${static_ip_address}" local_ota_pass: "${ota_pass}" - ################################################## - # OPTIONAL packages (comment if you don't want them) - ################################################## - #### 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}" - - #### WEB PORTAL #### - #common_webportal: !include - # file: common/webportal_common.yaml #### MQTT #### common_mqtt: !include @@ -119,24 +107,16 @@ packages: 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 - file: common/sntp_common.yaml + common_sntp: !include common/sntp_common.yaml - #### DIAGNOSTICS Lite Sensors #### - # Option of everything, or a lite version - common_lite_sensors: !include - file: common/sensors_common_lite.yaml - - #### DIAGNOSTICS General Sensors #### - # Option of everything, or a lite version - common_general_sensors: !include - file: common/sensors_common.yaml - - #### DEBUGGING Sensors #### - # A count of various resets - #common_resetcount_debugging: !include - # file: common/resetcount_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 # Device Specific included packages common_athompowermonV3: !include diff --git a/esphome/esp-underhouselights.yaml b/esphome/esp-underhouselights.yaml index c2b658e..863525a 100644 --- a/esphome/esp-underhouselights.yaml +++ b/esphome/esp-underhouselights.yaml @@ -59,29 +59,37 @@ substitutions: # 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}" - #common_webportal: !include - # file: common/webportal_common.yaml + + #### MQTT #### 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: - local_friendly_name: "${friendly_name}" - local_update_interval: "${update_interval}" + + #### 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 diff --git a/packages/lounge_lighting_scenes.yaml b/packages/lounge_lighting_scenes.yaml new file mode 100644 index 0000000..64d7430 --- /dev/null +++ b/packages/lounge_lighting_scenes.yaml @@ -0,0 +1,331 @@ +# yaml-language-server: $schema=null +############################################################################### +# PACKAGE: Lounge scenes (delta-only settings) + manual override +############################################################################### + +input_select: + lounge_scene: + name: Lounge Scene + options: + - "Select Scene:" + - Bright + - TV General + - Movie + - Reading On/Off + - Night Light + - Warm Cozy + - All Off + initial: "Select Scene:" + +input_boolean: + lounge_manual_override: + name: Lounge Lighting Scene Manual Override + initial: off + +input_text: + lounge_last_scene: + name: Lounge Last Scene + initial: "All Off" + max: 40 + +timer: + lounge_override_timer: + name: Lounge Lighting Scene Override Timer + duration: "02:00:00" + +############################################################################### +# SCRIPTS +############################################################################### +script: + lounge_set_scene: + alias: "Lounge: Set scene by name" + mode: restart + fields: + scene_name: + description: One of the options from input_select.lounge_scene + sequence: + - service: input_select.select_option + target: { entity_id: input_select.lounge_scene } + data: + option: "{{ scene_name }}" + + # NEW: Wait briefly for HA to commit the new state (avoids race) + - wait_template: "{{ states('input_select.lounge_scene') == scene_name }}" + timeout: "00:00:02" + continue_on_timeout: true + + - service: script.lounge_apply_and_reset + + lounge_apply_scene: + alias: "Lounge: Apply current scene" + mode: restart + sequence: + - variables: + sel: "{{ states('input_select.lounge_scene') }}" + ##################################################################### + # EXCLUDED SCENES (these are temp scenes, not remembered as last) + ##################################################################### + excluded_scenes: + - "Select Scene:" + - "Reading On/Off" + #- "Night Light" + ##################################################################### + # SCENE SETTINGS (delta only - only list entities you want to change) + ##################################################################### + scene_settings: + Bright: + light.esp_lounge6chdimmer_couch_spots_left: 00 + light.esp_lounge6chdimmer_couch_spots_right: 00 + #light.esp_lounge6chdimmer_dining_table_light: 100 + light.esp_lounge6chdimmer_lounge_downlights_centre: 100 # Centre Downlights (x6, dimmable) + light.esp_lounge6chdimmer_lounge_downlights_south: 100 # South Downlights (x4, dimmable) + light.esp_lounge6chdimmer_lounge_rafter_buttons: 100 # Buttons in Rafters (x3, dimmable) + switch.esp_loungemiddleswitch_relay_3_downlights_north: "on" # North Downlights (x2 over stairs, non dimmable) + light.esp_breakfastbarleds_breakfast_bar_leds: 90 + light.esp_loungecabinetleds2_lounge_cabinet_leds: 90 + light.esp_loungebookshelfleds_lounge_bookshelf_leds: 90 + light.tasmo_h801_loungeled1_6180_a: 90 + light.tasmo_h801_loungeled1_6180_b: 90 + switch.lounge_cupboard_dual_usb_xus09_l2: on + switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: on # Back wall wallwasher Left + switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: on # Back wall wallwasher right + switch.tasmo_ks811t_0702_lounge_3c: on # North Downlights (x2 over stairs, non dimmable) + switch.esp_loungenorthswitch_relay_1_main_lights: on # Single switch to hallway relay output (Pelmet LEDs) + + Movie: + #light.esp_lounge6chdimmer_couch_spots_left: 40 + #light.esp_lounge6chdimmer_couch_spots_right: 40 + #light.esp_lounge6chdimmer_dining_table_light: 100 + light.esp_lounge6chdimmer_lounge_downlights_centre: 20 # Centre Downlights (x6, dimmable) + light.esp_lounge6chdimmer_lounge_downlights_south: 20 # South Downlights (x4, dimmable) + light.esp_lounge6chdimmer_lounge_rafter_buttons: 20 # Buttons in Rafters (x3, dimmable) + light.esp_breakfastbarleds_breakfast_bar_leds: 40 + light.esp_loungecabinetleds2_lounge_cabinet_leds: 40 + light.esp_loungebookshelfleds_lounge_bookshelf_leds: 40 + light.tasmo_h801_loungeled1_6180_a: 60 + light.tasmo_h801_loungeled1_6180_b: 60 + switch.esp_loungemiddleswitch_relay_3_downlights_north: off # North Downlights (x2 over stairs, non dimmable) switch.lounge_cupboard_dual_usb_xus09_l2: "on" + switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: off # Back wall wallwasher Left + switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: off # Back wall wallwasher right + switch.esp_loungenorthswitch_relay_1_main_lights: on # Single switch to hallway relay output (Pelmet LEDs) + + Night Light: + #light.esp_lounge6chdimmer_couch_spots_left: 40 + #light.esp_lounge6chdimmer_couch_spots_right: 40 + #light.esp_lounge6chdimmer_dining_table_light: 100 + light.esp_lounge6chdimmer_lounge_downlights_centre: 5 # Centre Downlights (x6, dimmable) + #light.esp_lounge6chdimmer_lounge_downlights_south: 20 # South Downlights (x4, dimmable) + light.esp_lounge6chdimmer_lounge_rafter_buttons: 5 # Buttons in Rafters (x3, dimmable) + switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: off # Back wall wallwasher Left + switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: off # Back wall wallwasher right + + Reading On/Off: + light.esp_lounge6chdimmer_couch_spots_left: toggle_75 + light.esp_lounge6chdimmer_couch_spots_right: toggle_75 + #light.esp_lounge6chdimmer_dining_table_light: 60 + #light.esp_lounge6chdimmer_lounge_downlights_centre: 45 + #light.esp_lounge6chdimmer_lounge_downlights_south: 35 + #light.esp_lounge6chdimmer_lounge_rafter_buttons: 20 + #switch.tasmo_ks811t_0702_lounge_3c: on + + Warm Cozy: + light.esp_lounge6chdimmer_couch_spots_left: 30 + light.esp_lounge6chdimmer_couch_spots_right: 30 + light.esp_lounge6chdimmer_lounge_rafter_buttons: 15 + light.esp_breakfastbarleds_breakfast_bar_leds: 25 + light.esp_loungecabinetleds2_lounge_cabinet_leds: 30 + light.esp_loungebookshelfleds_lounge_bookshelf_leds: 30 + light.tasmo_h801_loungeled1_6180_a: 25 + light.tasmo_h801_loungeled1_6180_b: 25 + switch.lounge_cupboard_dual_usb_xus09_l2: on + switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: on # Back wall wallwasher Left + switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: on # Back wall wallwasher right + + TV General: + light.esp_lounge6chdimmer_couch_spots_left: 50 + light.esp_lounge6chdimmer_couch_spots_right: 50 + #light.esp_lounge6chdimmer_dining_table_light: 100 + light.esp_lounge6chdimmer_lounge_downlights_centre: 40 # Centre Downlights (x6, dimmable) + light.esp_lounge6chdimmer_lounge_downlights_south: 40 # South Downlights (x4, dimmable) + light.esp_lounge6chdimmer_lounge_rafter_buttons: 40 # Buttons in Rafters (x3, dimmable) + light.esp_breakfastbarleds_breakfast_bar_leds: 60 + light.esp_loungecabinetleds2_lounge_cabinet_leds: 60 + light.esp_loungebookshelfleds_lounge_bookshelf_leds: 60 + light.tasmo_h801_loungeled1_6180_a: 60 + light.tasmo_h801_loungeled1_6180_b: 60 + switch.esp_loungemiddleswitch_relay_3_downlights_north: off # North Downlights (x2 over stairs, non dimmable) switch.lounge_cupboard_dual_usb_xus09_l2: "on" + switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: off # Back wall wallwasher Left + switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: off # Back wall wallwasher right + switch.esp_loungenorthswitch_relay_1_main_lights: on # Single switch to hallway relay output (Pelmet LEDs) + + All Off: + light.esp_lounge6chdimmer_couch_spots_left: 0 + light.esp_lounge6chdimmer_couch_spots_right: 0 + light.esp_lounge6chdimmer_dining_table_light: 0 + light.esp_lounge6chdimmer_lounge_downlights_centre: 0 # Centre Downlights (x6, dimmable) + light.esp_lounge6chdimmer_lounge_downlights_south: 0 # South Downlights (x4, dimmable) + light.esp_lounge6chdimmer_lounge_rafter_buttons: 0 # Buttons in Rafters (x3, dimmable) + switch.esp_loungemiddleswitch_relay_3_downlights_north: "off" # North Downlights (x2 over stairs, non dimmable) + light.esp_breakfastbarleds_breakfast_bar_leds: 0 + light.esp_loungecabinetleds2_lounge_cabinet_leds: 0 + light.esp_loungebookshelfleds_lounge_bookshelf_leds: 0 + light.tasmo_h801_loungeled1_6180_a: 0 + light.tasmo_h801_loungeled1_6180_b: 0 + switch.lounge_cupboard_dual_usb_xus09_l2: off + switch.esp_loungesouthleftswitch_relay_1_wall_washer_left: off # Back wall wallwasher Left + switch.esp_loungesouthrightswitch_relay_2_wall_washer_right: off # Back wall wallwasher right + switch.esp_loungenorthswitch_relay_1_main_lights: off # Single switch to hallway relay output (Pelmet LEDs) + + ##################################################################### + ##################################################################### + ##################################################################### + + # Only remember scenes that are not excluded + - choose: + - conditions: "{{ sel not in excluded_scenes }}" + sequence: + - service: input_text.set_value + target: { entity_id: input_text.lounge_last_scene } + data: + value: "{{ sel }}" + + - repeat: + for_each: "{{ (scene_settings.get(sel, {})).keys() | list }}" + sequence: + - variables: + ent: "{{ repeat.item }}" + val: "{{ (scene_settings.get(sel, {}))[ent] }}" + is_light: "{{ ent.startswith('light.') }}" + is_switch: "{{ ent.startswith('switch.') }}" + is_num: "{{ val is number }}" + vstr: "{{ (val|string) if not is_num else '' }}" + is_toggle: "{{ (not is_num) and (vstr|lower).startswith('toggle') }}" + toggle_pct: "{{ (vstr.split('_')|last)|int if ('_' in vstr) else 100 }}" + currently_on: "{{ is_state(ent, 'on') }}" + + - choose: + # 1) Lights: toggle[_NN] -> if on turn off, else turn on to NN (default 100) + - conditions: "{{ is_light and is_toggle }}" + sequence: + - choose: + - conditions: "{{ currently_on }}" + sequence: + - service: light.turn_off + data: + entity_id: "{{ ent }}" + default: + - service: light.turn_on + data: + entity_id: "{{ ent }}" + brightness_pct: "{{ toggle_pct }}" + + # 2) Switches: toggle -> flip state + - conditions: "{{ is_switch and is_toggle }}" + sequence: + - service: switch.toggle + data: + entity_id: "{{ ent }}" + + # 3) Lights: numeric brightness (0 = off) + - conditions: "{{ is_light and is_num and (val|int) > 0 }}" + sequence: + - service: light.turn_on + data: + entity_id: "{{ ent }}" + brightness_pct: "{{ val|int }}" + - conditions: "{{ is_light and is_num and (val|int) == 0 }}" + sequence: + - service: light.turn_off + data: + entity_id: "{{ ent }}" + + # 4) Lights: textual/boolean on/off + - conditions: "{{ is_light and not is_num and (val in [true, 'on', 'On', 'ON']) }}" + sequence: + - service: light.turn_on + data: + entity_id: "{{ ent }}" + - conditions: "{{ is_light and not is_num and (val in [false, 'off', 'Off', 'OFF']) }}" + sequence: + - service: light.turn_off + data: + entity_id: "{{ ent }}" + + # 5) Switches: textual/boolean on/off + - conditions: "{{ is_switch and (val in [true, 'on', 'On', 'ON']) }}" + sequence: + - service: switch.turn_on + data: + entity_id: "{{ ent }}" + - conditions: "{{ is_switch and (val in [false, 'off', 'Off', 'OFF']) }}" + sequence: + - service: switch.turn_off + data: + entity_id: "{{ ent }}" + + lounge_apply_and_reset: + alias: "Lounge: Apply scene + reset selector" + mode: restart + sequence: + - service: script.lounge_apply_scene + - delay: "00:00:05" + - service: input_select.select_option + target: { entity_id: input_select.lounge_scene } + data: + option: "Select Scene:" + +############################################################################### +# AUTOMATIONS +############################################################################### +automation: + - id: lounge_apply_on_selector_change + alias: "Lounge - Apply when selector changes" + trigger: + - platform: state + entity_id: input_select.lounge_scene + condition: + - condition: state + entity_id: input_boolean.lounge_manual_override + state: "off" + - condition: template + value_template: "{{ trigger.to_state.state != 'Select Scene:' }}" + action: + - service: script.turn_on + target: + entity_id: script.lounge_apply_and_reset + + - id: lounge_tv_on_sets_tv_bias + alias: "Lounge - TV on sets TV General (unless override)" + trigger: + - platform: state + entity_id: remote.lounge_tv + to: "on" + for: "00:00:02" #small debounce + condition: + - condition: state + entity_id: input_boolean.lounge_manual_override + state: "off" + - condition: template + value_template: "{{ states('input_text.lounge_last_scene') != 'All Off' }}" + action: + - service: script.lounge_set_scene + data: + scene_name: "TV General" + + - id: lounge_tv_off_sets_bright + alias: "Lounge - TV off sets Bright (unless override)" + trigger: + - platform: state + entity_id: remote.lounge_tv + to: "off" + for: "00:00:02" #small debounce + condition: + - condition: state + entity_id: input_boolean.lounge_manual_override + state: "off" + - condition: template + value_template: "{{ states('input_text.lounge_last_scene') != 'All Off' }}" + action: + - service: script.lounge_set_scene + data: + scene_name: "Bright"