diff --git a/esphome/common/network_common.yaml b/esphome/common/network_common.yaml index 7e8523c..7e2e8d5 100644 --- a/esphome/common/network_common.yaml +++ b/esphome/common/network_common.yaml @@ -51,6 +51,7 @@ wifi: subnet: ${static_ip_subnet} dns1: ${static_ip_dns1} dns2: ${static_ip_dns2} + use_address: ${local_static_ip_address} ap: # Details for fallback hotspot in case wifi connection fails https://esphome.io/components/wifi.html#access-point-mode ssid: ${local_device_name} AP password: ${fallback_ap_password} diff --git a/esphome/common/sensors_common.yaml b/esphome/common/sensors_common.yaml index d924dd2..ffdb562 100644 --- a/esphome/common/sensors_common.yaml +++ b/esphome/common/sensors_common.yaml @@ -64,6 +64,12 @@ text_sensor: icon: mdi:clock-start update_interval: ${local_update_interval} entity_category: "diagnostic" + - platform: template + name: "Last Reset Reason" + update_interval: 30s + lambda: |- + return { ESP.getResetReason().c_str() }; + entity_category: diagnostic ################################################################################################### # Creates a sensor of the uptime of the device, in formatted days, hours, minutes and seconds diff --git a/esphome/esp-bedrm2ceilingfan copy.yaml b/esphome/esp-bedrm2ceilingfan copy.yaml new file mode 100644 index 0000000..cf10a8e --- /dev/null +++ b/esphome/esp-bedrm2ceilingfan copy.yaml @@ -0,0 +1,381 @@ +########################################################################################## +########################################################################################## +# CEILING FAN - BEDROOM 2 +# - 3 speed fan using Sonoff IFan02 +# - Also, single Light Output +# +# Controlled by a Sonoff IFan 02 +# +# V1.0 - 2025-07-21 First Setup (and replacement of Tasmota) +# +# NOTES: +# Command the fan with MQTT +# ${mqtt_local_command_full_topic}/speed/set 1,2,3,0,+,- +# ${mqtt_local_command_full_topic}/light/set ON,OFF +# Status of the fan is in MQTT +# ${mqtt_local_command_full_topic}/speed/state 1,2,3,0 +# ${mqtt_local_command_full_topic}/light/state ON,OFF +# +########################################################################################## +########################################################################################## + +########################################################################################## +# 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-bedrm2ceilingfan" + friendly_name: "Bedroom 2 Ceiling Fan" + description_comment: "3 Speed Overhead Ceiling Fan Bedroom 2 :: Sonoff ifan02" + device_area: "Bedroom 2" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Sonoff Technologies.Sonoff ifan02" # Project Details + project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords & Secrets + api_key: !secret esp-api_key + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-bedrm2ceilingfan_ip # unfortunately you can't use substitutions inside secrets names + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_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: "bedroom2-ceilingfan" + mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + + # Button Naming & Icons + + # Switch/Relay Naming & Icons + #relay_icon: "mdi:lightbulb-group" + light_1_name: "Fan Light" + switch_2_name: "Fan 2 Relay" + switch_3_name: "Fan 3 Relay" + switch_4_name: "Fan 4 Relay" + +########################################################################################## +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# 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}" + on_boot: # This weird toggle thing makes sure the states get restored on reboot + 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 +# - "-Wl,--gc-sections" # drop unused code/data +# - "-fno-exceptions" # strip C++ exceptaions +# - "-fno-rtti" # strip C++ RTTI + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp01_1m # The original sonoff basic + restore_from_flash: True # restore some values on reboot + +preferences: + flash_write_interval: 5min + +mdns: + disabled: True # Disabling will make the build file smaller (and it is still available via static IP) + +########################################################################################## +# GLOBAL VARIABLES +########################################################################################## +globals: + - id: speed_value + type: int + restore_value: yes + initial_value: '0' + +########################################################################################## +# 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, Serial control) + #esp8266_store_log_strings_in_flash: false + #tx_buffer_size: 64 + +########################################################################################## +# MQTT COMMANDS +# This adds device-specific MQTT command triggers to the common MQTT configuration. +########################################################################################## +mqtt: + on_message: + # Light control + - topic: "${mqtt_local_command_topic}/light/set" + payload: "ON" + then: + - light.turn_on: ifan02_light + - topic: "${mqtt_local_command_topic}/light/set" + payload: "OFF" + then: + - light.turn_off: ifan02_light + + # Fan speed control (0–3) + ramp up/down (+ / -) + - topic: "${mqtt_local_command_topic}/speed/set" + then: + # 1) Compute new speed_value based on payload + - lambda: |- + std::string s = x; + int val = id(speed_value); + if (s == "+") { + val++; + } else if (s == "-") { + val--; + } else if (s.size() && isdigit(s[0])) { + val = atoi(s.c_str()); + } else { + ESP_LOGE("ifan02", "Invalid speed payload: '%s'", x.c_str()); + return; + } + // Clamp between 0 and 3 + if (val < 0) val = 0; + if (val > 3) val = 3; + id(speed_value) = val; + + # 2) Drive the fan based on the new value + - if: + condition: + lambda: 'return id(speed_value) == 0;' + then: + - fan.turn_off: ifan02_fan + else: + - fan.turn_on: + id: ifan02_fan + speed: !lambda 'return id(speed_value);' + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +# Sonoff ifan02 has relays, but they don't need to be shown in HA because +# the speed of the fan is the important part (and combinations of the relays give that) +########################################################################################## +switch: + - platform: gpio + name: "${switch_3_name}" + pin: GPIO4 + id: fan3sw + restore_mode: RESTORE_DEFAULT_OFF + internal: true + - platform: gpio + name: "${switch_2_name}" + pin: GPIO5 + id: fan2sw + restore_mode: RESTORE_DEFAULT_OFF + internal: true + - platform: gpio + name: "${switch_4_name}" + pin: GPIO15 + id: fan4sw + restore_mode: RESTORE_DEFAULT_OFF + internal: true + +########################################################################################## +# SELECT COMPONENT +# https://esphome.io/components/select/index.html +########################################################################################## +select: + - platform: template + name: "Bedroom 2 Fan Speed" + id: bedroom2_fan_speed_select + options: + - "Off" + - "Low" + - "Medium" + - "High" + update_interval: 1s + lambda: |- + switch (id(speed_value)) { + case 1: return esphome::optional("Low"); + case 2: return esphome::optional("Medium"); + case 3: return esphome::optional("High"); + default: return esphome::optional("Off"); + } + set_action: + # OFF + - if: + condition: + lambda: 'return x == "Off";' + then: + - lambda: |- + id(speed_value) = 0; + - fan.turn_off: ifan02_fan + # LOW (1) + - if: + condition: + lambda: 'return x == "Low";' + then: + - lambda: |- + id(speed_value) = 1; + - fan.turn_on: + id: ifan02_fan + speed: 1 + # MEDIUM (2) + - if: + condition: + lambda: 'return x == "Medium";' + then: + - lambda: |- + id(speed_value) = 2; + - fan.turn_on: + id: ifan02_fan + speed: 2 + # HIGH (3) + - if: + condition: + lambda: 'return x == "High";' + then: + - lambda: |- + id(speed_value) = 3; + - fan.turn_on: + id: ifan02_fan + speed: 3 + +################################################################################ +# TEMPLATE OUTPUTS: drive the real relays when the states change +################################################################################ +output: + - platform: gpio + pin: GPIO12 + id: lightrelay + - platform: template + type: float + id: fan_decode + write_action: + - lambda: |- + if (state < 0.25) { + id(fan2sw).turn_off(); + id(fan3sw).turn_off(); + id(fan4sw).turn_off(); + } + else if (state < 0.5) { + id(fan2sw).turn_on(); + id(fan3sw).turn_off(); + id(fan4sw).turn_off(); + } + else if (state < 0.75) { + id(fan2sw).turn_on(); + id(fan3sw).turn_on(); + id(fan4sw).turn_off(); + } + else { + id(fan2sw).turn_on(); + id(fan3sw).turn_off(); + id(fan4sw).turn_on(); + } + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/ +########################################################################################## +light: + - platform: binary + name: "${light_1_name}" + output: lightrelay + restore_mode: RESTORE_DEFAULT_OFF + id: ifan02_light + # publish status updates when the light turns on/off: + on_turn_on: + - mqtt.publish: + topic: "${mqtt_local_status_topic}/light/state" + payload: "ON" + on_turn_off: + - mqtt.publish: + topic: "${mqtt_local_status_topic}/light/state" + payload: "OFF" + +########################################################################################## +# FAN COMPONENT +# https://esphome.io/components/fan/index.html +########################################################################################## +fan: + - platform: speed + output: fan_decode + name: "Fan" + id: ifan02_fan + speed_count: 3 + restore_mode: RESTORE_DEFAULT_OFF + # whenever you explicitly set a speed (1–3): + on_speed_set: + - lambda: |- + id(speed_value) = x; + - mqtt.publish: + topic: "${mqtt_local_status_topic}/speed/state" + payload: !lambda 'return to_string(id(speed_value));' + # whenever the fan goes fully off: + on_turn_off: + - lambda: |- + id(speed_value) = 0; + - mqtt.publish: + topic: "${mqtt_local_status_topic}/speed/state" + payload: "0" + # whenever the fan goes off→on (e.g. via HA’s Fan switch): + on_turn_on: + - lambda: |- + // bump 0→1 if we were off + if (id(speed_value) == 0) id(speed_value) = 1; + - fan.turn_on: + id: ifan02_fan + speed: !lambda 'return id(speed_value);' + - mqtt.publish: + topic: "${mqtt_local_status_topic}/speed/state" + payload: !lambda 'return to_string(id(speed_value));' \ No newline at end of file diff --git a/esphome/esp-bedrm2lights.yaml b/esphome/esp-bedrm2lights.yaml index f41347e..e571459 100644 --- a/esphome/esp-bedrm2lights.yaml +++ b/esphome/esp-bedrm2lights.yaml @@ -1,6 +1,6 @@ ########################################################################################## ########################################################################################## -# LAUNDRY MAIN LIGHTSWITCH +# BEDROOM 2 LIGHTSWITCH # V3.5 2025-07-24 YAML tidyups ########################################################################################## # Zemismart KS-811 Double push button diff --git a/esphome/esp-bedrm3ceilingfan.yaml b/esphome/esp-bedrm3ceilingfan.yaml new file mode 100644 index 0000000..5cd630f --- /dev/null +++ b/esphome/esp-bedrm3ceilingfan.yaml @@ -0,0 +1,381 @@ +########################################################################################## +########################################################################################## +# CEILING FAN - BEDROOM 3 +# - 3 speed fan using Sonoff IFan02 +# - Also, single Light Output +# +# Controlled by a Sonoff IFan 02 +# +# V1.0 - 2025-07-21 First Setup (and replacement of Tasmota) +# +# NOTES: +# Command the fan with MQTT +# ${mqtt_local_command_full_topic}/speed/set 1,2,3,0,+,- +# ${mqtt_local_command_full_topic}/light/set ON,OFF +# Status of the fan is in MQTT +# ${mqtt_local_command_full_topic}/speed/state 1,2,3,0 +# ${mqtt_local_command_full_topic}/light/state ON,OFF +# +########################################################################################## +########################################################################################## + +########################################################################################## +# 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-bedrm3ceilingfan" + friendly_name: "Bedroom 3 Ceiling Fan" + description_comment: "3 Speed Overhead Ceiling Fan Bedroom 3 :: Sonoff ifan02" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Sonoff Technologies.Sonoff ifan02" # Project Details + project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords & Secrets + api_key: !secret esp-api_key + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-bedrm3ceilingfan_ip # unfortunately you can't use substitutions inside secrets names + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_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: "bedroom3-ceilingfan" + mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + + # Button Naming & Icons + + # Switch/Relay Naming & Icons + #relay_icon: "mdi:lightbulb-group" + light_1_name: "Fan Light" + switch_2_name: "Fan 2 Relay" + switch_3_name: "Fan 3 Relay" + switch_4_name: "Fan 4 Relay" + +########################################################################################## +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# 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}" + on_boot: # This weird toggle thing makes sure the states get restored on reboot + 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 +# - "-Wl,--gc-sections" # drop unused code/data +# - "-fno-exceptions" # strip C++ exceptaions +# - "-fno-rtti" # strip C++ RTTI + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp01_1m # The original sonoff basic + restore_from_flash: True # restore some values on reboot + +preferences: + flash_write_interval: 5min + +mdns: + disabled: True # Disabling will make the build file smaller (and it is still available via static IP) + +########################################################################################## +# GLOBAL VARIABLES +########################################################################################## +globals: + - id: speed_value + type: int + restore_value: yes + initial_value: '0' + +########################################################################################## +# 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, Serial control) + #esp8266_store_log_strings_in_flash: false + #tx_buffer_size: 64 + +########################################################################################## +# MQTT COMMANDS +# This adds device-specific MQTT command triggers to the common MQTT configuration. +########################################################################################## +mqtt: + on_message: + # Light control + - topic: "${mqtt_local_command_topic}/light/set" + payload: "ON" + then: + - light.turn_on: ifan02_light + - topic: "${mqtt_local_command_topic}/light/set" + payload: "OFF" + then: + - light.turn_off: ifan02_light + + # Fan speed control (0–3) + ramp up/down (+ / -) + - topic: "${mqtt_local_command_topic}/speed/set" + then: + # 1) Compute new speed_value based on payload + - lambda: |- + std::string s = x; + int val = id(speed_value); + if (s == "+") { + val++; + } else if (s == "-") { + val--; + } else if (s.size() && isdigit(s[0])) { + val = atoi(s.c_str()); + } else { + ESP_LOGE("ifan02", "Invalid speed payload: '%s'", x.c_str()); + return; + } + // Clamp between 0 and 3 + if (val < 0) val = 0; + if (val > 3) val = 3; + id(speed_value) = val; + + # 2) Drive the fan based on the new value + - if: + condition: + lambda: 'return id(speed_value) == 0;' + then: + - fan.turn_off: ifan02_fan + else: + - fan.turn_on: + id: ifan02_fan + speed: !lambda 'return id(speed_value);' + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +# Sonoff ifan02 has relays, but they don't need to be shown in HA because +# the speed of the fan is the important part (and combinations of the relays give that) +########################################################################################## +switch: + - platform: gpio + name: "${switch_3_name}" + pin: GPIO4 + id: fan3sw + restore_mode: RESTORE_DEFAULT_OFF + internal: true + - platform: gpio + name: "${switch_2_name}" + pin: GPIO5 + id: fan2sw + restore_mode: RESTORE_DEFAULT_OFF + internal: true + - platform: gpio + name: "${switch_4_name}" + pin: GPIO15 + id: fan4sw + restore_mode: RESTORE_DEFAULT_OFF + internal: true + +########################################################################################## +# SELECT COMPONENT +# https://esphome.io/components/select/index.html +########################################################################################## +select: + - platform: template + name: "Bedroom 2 Fan Speed" + id: bedroom2_fan_speed_select + options: + - "Off" + - "Low" + - "Medium" + - "High" + update_interval: 1s + lambda: |- + switch (id(speed_value)) { + case 1: return esphome::optional("Low"); + case 2: return esphome::optional("Medium"); + case 3: return esphome::optional("High"); + default: return esphome::optional("Off"); + } + set_action: + # OFF + - if: + condition: + lambda: 'return x == "Off";' + then: + - lambda: |- + id(speed_value) = 0; + - fan.turn_off: ifan02_fan + # LOW (1) + - if: + condition: + lambda: 'return x == "Low";' + then: + - lambda: |- + id(speed_value) = 1; + - fan.turn_on: + id: ifan02_fan + speed: 1 + # MEDIUM (2) + - if: + condition: + lambda: 'return x == "Medium";' + then: + - lambda: |- + id(speed_value) = 2; + - fan.turn_on: + id: ifan02_fan + speed: 2 + # HIGH (3) + - if: + condition: + lambda: 'return x == "High";' + then: + - lambda: |- + id(speed_value) = 3; + - fan.turn_on: + id: ifan02_fan + speed: 3 + +################################################################################ +# TEMPLATE OUTPUTS: drive the real relays when the states change +################################################################################ +output: + - platform: gpio + pin: GPIO12 + id: lightrelay + - platform: template + type: float + id: fan_decode + write_action: + - lambda: |- + if (state < 0.25) { + id(fan2sw).turn_off(); + id(fan3sw).turn_off(); + id(fan4sw).turn_off(); + } + else if (state < 0.5) { + id(fan2sw).turn_on(); + id(fan3sw).turn_off(); + id(fan4sw).turn_off(); + } + else if (state < 0.75) { + id(fan2sw).turn_on(); + id(fan3sw).turn_on(); + id(fan4sw).turn_off(); + } + else { + id(fan2sw).turn_on(); + id(fan3sw).turn_off(); + id(fan4sw).turn_on(); + } + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/ +########################################################################################## +light: + - platform: binary + name: "${light_1_name}" + output: lightrelay + restore_mode: RESTORE_DEFAULT_OFF + id: ifan02_light + # publish status updates when the light turns on/off: + on_turn_on: + - mqtt.publish: + topic: "${mqtt_local_status_topic}/light/state" + payload: "ON" + on_turn_off: + - mqtt.publish: + topic: "${mqtt_local_status_topic}/light/state" + payload: "OFF" + +########################################################################################## +# FAN COMPONENT +# https://esphome.io/components/fan/index.html +########################################################################################## +fan: + - platform: speed + output: fan_decode + name: "Fan" + id: ifan02_fan + speed_count: 3 + restore_mode: RESTORE_DEFAULT_OFF + # whenever you explicitly set a speed (1–3): + on_speed_set: + - lambda: |- + id(speed_value) = x; + - mqtt.publish: + topic: "${mqtt_local_status_topic}/speed/state" + payload: !lambda 'return to_string(id(speed_value));' + # whenever the fan goes fully off: + on_turn_off: + - lambda: |- + id(speed_value) = 0; + - mqtt.publish: + topic: "${mqtt_local_status_topic}/speed/state" + payload: "0" + # whenever the fan goes off→on (e.g. via HA’s Fan switch): + on_turn_on: + - lambda: |- + // bump 0→1 if we were off + if (id(speed_value) == 0) id(speed_value) = 1; + - fan.turn_on: + id: ifan02_fan + speed: !lambda 'return id(speed_value);' + - mqtt.publish: + topic: "${mqtt_local_status_topic}/speed/state" + payload: !lambda 'return to_string(id(speed_value));' \ No newline at end of file diff --git a/esphome/esp-bedrm3fanswitch copy.yaml.old b/esphome/esp-bedrm3fanswitch copy.yaml.old new file mode 100644 index 0000000..04bb972 --- /dev/null +++ b/esphome/esp-bedrm3fanswitch copy.yaml.old @@ -0,0 +1,265 @@ +########################################################################################## +########################################################################################## +# BEDROOM 3 FAN SWITCH +# +# Controlled by a Zemismart KS-811 Triple push button +# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# +# V1.0 - 2025-07-23 First Setup (and replacement of Tasmota) +# +# NOTES +# - Switch for Ceiling Fan +# - 3 Switches, Up, Down and Off +# - Remote commands to the fan ${mqtt_remote_command_full_topic}/speed/set 1,2,3,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-bedrm3fanswitch" + friendly_name: "Bedroom 3 Fan Wall Switch (3)" + description_comment: "Switch for Bedroom 3 Ceiling Fan using Zemismart KS-811 Triple Push Button. Speed Up (1), Speed Down (2), Fan Off (3)" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Zemismart Technologies.KS-811-3 (Triple)" # Project Details + project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + #entity_prefix: "Main Bathroom" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + + # Passwords + api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names + static_ip_address: !secret esp-bedrm3fanswitch_ip + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + + # Device Settings + #relay_icon: "mdi:heating-coil" + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for for general sensors etc + + # MQTT LOCAL Controls + #mqtt_device_name: "bedroom2-ceilingfan-switch" + #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + mqtt_remote_device_name: "bedroom3-ceilingfan" + mqtt_remote_device_command_topic: "${mqtt_local_command_main_topic}/${mqtt_remote_device_name}/speed/set" + mqtt_remote_device_command1: "+" + mqtt_remote_device_command2: "-" + mqtt_remote_device_command3: "0" + mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_remote_device_name}/speed/state" # Topic we will use to view status locally without HA + + # Button Naming & Icons + + # Switch/Relay Naming & Icons + #relay_icon: "mdi:heating-coil" + switch_1_name: "Fan Speed Up" # This is virtual only, no power connected to 1st relay + switch_2_name: "Fan Speed Down" # This is virtual only, no power connected to 2nd relay + switch_3_name: "Fan Off" # This is virtual only, no power connected to 3rd relay + +########################################################################################## +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# 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}" + 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: 200 +# then: +# - switch.turn_on: Relay_3 + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp01_1m + early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + board_flash_mode: dout # Default is dout + +########################################################################################## +# ESPHome Logging Enable +# https://esphome.io/components/logger.html +########################################################################################## +logger: + level: "${log_level}" #INFO Level suggested, or DEBUG for testing + #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + #esp8266_store_log_strings_in_flash: false + #tx_buffer_size: 64 + +########################################################################################## +# STATUS LED +# https://esphome.io/components/status_led.html +########################################################################################## +# Status LED for KS-811 is GPIO02 +########################################################################################## +status_led: + pin: + number: GPIO02 + inverted: yes + +########################################################################################## +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +########################################################################################## +# Buttons for KS-811-3 are GPIO16, GPIO05, GPIO04 +########################################################################################## +binary_sensor: + - platform: gpio + pin: + number: GPIO16 + mode: INPUT + inverted: True + name: "Button 1: ${switch_1_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command1}" + + - platform: gpio + pin: + number: GPIO05 + mode: INPUT + inverted: True + name: "Button 2: ${switch_2_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command2}" + + - platform: gpio + pin: + number: GPIO4 + mode: INPUT + inverted: True + name: "Button 3: ${switch_3_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command3}" + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +# Relays for KS-811-3 are GPIO13, GPIO12, GPIO14 +########################################################################################## +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 + +mqtt: + on_message: + - topic: "${mqtt_local_status_topic}" + then: + - lambda: |- + int val = atoi(x.c_str()); + ESP_LOGI("fan_switch", "Received requested speed: %d", val); + + // Desired states + bool r1 = false; + bool r2 = false; + bool r3 = false; + + switch (val) { + case 1: + r3 = true; + break; + case 2: + r2 = true; + r3 = true; + break; + case 3: + r1 = true; + r2 = true; + r3 = true; + break; + case 0: + default: + // all remain false + break; + } + + // Only change relays if necessary + if (id(Relay_1).state != r1) { + if (r1) { + id(Relay_1).turn_on(); + } else { + id(Relay_1).turn_off(); + } + } + + if (id(Relay_2).state != r2) { + if (r2) { + id(Relay_2).turn_on(); + } else { + id(Relay_2).turn_off(); + } + } + + if (id(Relay_3).state != r3) { + if (r3) { + id(Relay_3).turn_on(); + } else { + id(Relay_3).turn_off(); + } + } \ No newline at end of file diff --git a/esphome/esp-bedrm3fanswitch.yaml b/esphome/esp-bedrm3fanswitch.yaml new file mode 100644 index 0000000..04bb972 --- /dev/null +++ b/esphome/esp-bedrm3fanswitch.yaml @@ -0,0 +1,265 @@ +########################################################################################## +########################################################################################## +# BEDROOM 3 FAN SWITCH +# +# Controlled by a Zemismart KS-811 Triple push button +# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# +# V1.0 - 2025-07-23 First Setup (and replacement of Tasmota) +# +# NOTES +# - Switch for Ceiling Fan +# - 3 Switches, Up, Down and Off +# - Remote commands to the fan ${mqtt_remote_command_full_topic}/speed/set 1,2,3,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-bedrm3fanswitch" + friendly_name: "Bedroom 3 Fan Wall Switch (3)" + description_comment: "Switch for Bedroom 3 Ceiling Fan using Zemismart KS-811 Triple Push Button. Speed Up (1), Speed Down (2), Fan Off (3)" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Zemismart Technologies.KS-811-3 (Triple)" # Project Details + project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + #entity_prefix: "Main Bathroom" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + + # Passwords + api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names + static_ip_address: !secret esp-bedrm3fanswitch_ip + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + + # Device Settings + #relay_icon: "mdi:heating-coil" + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for for general sensors etc + + # MQTT LOCAL Controls + #mqtt_device_name: "bedroom2-ceilingfan-switch" + #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + mqtt_remote_device_name: "bedroom3-ceilingfan" + mqtt_remote_device_command_topic: "${mqtt_local_command_main_topic}/${mqtt_remote_device_name}/speed/set" + mqtt_remote_device_command1: "+" + mqtt_remote_device_command2: "-" + mqtt_remote_device_command3: "0" + mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_remote_device_name}/speed/state" # Topic we will use to view status locally without HA + + # Button Naming & Icons + + # Switch/Relay Naming & Icons + #relay_icon: "mdi:heating-coil" + switch_1_name: "Fan Speed Up" # This is virtual only, no power connected to 1st relay + switch_2_name: "Fan Speed Down" # This is virtual only, no power connected to 2nd relay + switch_3_name: "Fan Off" # This is virtual only, no power connected to 3rd relay + +########################################################################################## +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# 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}" + 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: 200 +# then: +# - switch.turn_on: Relay_3 + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp01_1m + early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + board_flash_mode: dout # Default is dout + +########################################################################################## +# ESPHome Logging Enable +# https://esphome.io/components/logger.html +########################################################################################## +logger: + level: "${log_level}" #INFO Level suggested, or DEBUG for testing + #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + #esp8266_store_log_strings_in_flash: false + #tx_buffer_size: 64 + +########################################################################################## +# STATUS LED +# https://esphome.io/components/status_led.html +########################################################################################## +# Status LED for KS-811 is GPIO02 +########################################################################################## +status_led: + pin: + number: GPIO02 + inverted: yes + +########################################################################################## +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +########################################################################################## +# Buttons for KS-811-3 are GPIO16, GPIO05, GPIO04 +########################################################################################## +binary_sensor: + - platform: gpio + pin: + number: GPIO16 + mode: INPUT + inverted: True + name: "Button 1: ${switch_1_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command1}" + + - platform: gpio + pin: + number: GPIO05 + mode: INPUT + inverted: True + name: "Button 2: ${switch_2_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command2}" + + - platform: gpio + pin: + number: GPIO4 + mode: INPUT + inverted: True + name: "Button 3: ${switch_3_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command3}" + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +# Relays for KS-811-3 are GPIO13, GPIO12, GPIO14 +########################################################################################## +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 + +mqtt: + on_message: + - topic: "${mqtt_local_status_topic}" + then: + - lambda: |- + int val = atoi(x.c_str()); + ESP_LOGI("fan_switch", "Received requested speed: %d", val); + + // Desired states + bool r1 = false; + bool r2 = false; + bool r3 = false; + + switch (val) { + case 1: + r3 = true; + break; + case 2: + r2 = true; + r3 = true; + break; + case 3: + r1 = true; + r2 = true; + r3 = true; + break; + case 0: + default: + // all remain false + break; + } + + // Only change relays if necessary + if (id(Relay_1).state != r1) { + if (r1) { + id(Relay_1).turn_on(); + } else { + id(Relay_1).turn_off(); + } + } + + if (id(Relay_2).state != r2) { + if (r2) { + id(Relay_2).turn_on(); + } else { + id(Relay_2).turn_off(); + } + } + + if (id(Relay_3).state != r3) { + if (r3) { + id(Relay_3).turn_on(); + } else { + id(Relay_3).turn_off(); + } + } \ No newline at end of file diff --git a/esphome/esp-bedrm3fanswitch.yaml.old b/esphome/esp-bedrm3fanswitch.yaml.old new file mode 100644 index 0000000..04bb972 --- /dev/null +++ b/esphome/esp-bedrm3fanswitch.yaml.old @@ -0,0 +1,265 @@ +########################################################################################## +########################################################################################## +# BEDROOM 3 FAN SWITCH +# +# Controlled by a Zemismart KS-811 Triple push button +# pinout/schematic https://community.home-assistant.io/t/zemismart-ks-811-working-with-esphome/ +# +# V1.0 - 2025-07-23 First Setup (and replacement of Tasmota) +# +# NOTES +# - Switch for Ceiling Fan +# - 3 Switches, Up, Down and Off +# - Remote commands to the fan ${mqtt_remote_command_full_topic}/speed/set 1,2,3,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-bedrm3fanswitch" + friendly_name: "Bedroom 3 Fan Wall Switch (3)" + description_comment: "Switch for Bedroom 3 Ceiling Fan using Zemismart KS-811 Triple Push Button. Speed Up (1), Speed Down (2), Fan Off (3)" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Zemismart Technologies.KS-811-3 (Triple)" # Project Details + project_version: "v1" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + #entity_prefix: "Main Bathroom" # Simple device name where we want to prefix a sensor or switch, eg "Load" Current. + + # Passwords + api_key: !secret esp-api_key # unfortunately you can't use substitutions inside secrets names + ota_pass: !secret esp-ota_pass # unfortunately you can't use substitutions inside secrets names + static_ip_address: !secret esp-bedrm3fanswitch_ip + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic + + # Device Settings + #relay_icon: "mdi:heating-coil" + log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + update_interval: "60s" # update time for for general sensors etc + + # MQTT LOCAL Controls + #mqtt_device_name: "bedroom2-ceilingfan-switch" + #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + mqtt_remote_device_name: "bedroom3-ceilingfan" + mqtt_remote_device_command_topic: "${mqtt_local_command_main_topic}/${mqtt_remote_device_name}/speed/set" + mqtt_remote_device_command1: "+" + mqtt_remote_device_command2: "-" + mqtt_remote_device_command3: "0" + mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_remote_device_name}/speed/state" # Topic we will use to view status locally without HA + + # Button Naming & Icons + + # Switch/Relay Naming & Icons + #relay_icon: "mdi:heating-coil" + switch_1_name: "Fan Speed Up" # This is virtual only, no power connected to 1st relay + switch_2_name: "Fan Speed Down" # This is virtual only, no power connected to 2nd relay + switch_3_name: "Fan Off" # This is virtual only, no power connected to 3rd relay + +########################################################################################## +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# 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}" + 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: 200 +# then: +# - switch.turn_on: Relay_3 + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp01_1m + early_pin_init: False # Initialise pins early to known values. Recommended false where switches are involved. Defaults to True. + board_flash_mode: dout # Default is dout + +########################################################################################## +# ESPHome Logging Enable +# https://esphome.io/components/logger.html +########################################################################################## +logger: + level: "${log_level}" #INFO Level suggested, or DEBUG for testing + #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + #esp8266_store_log_strings_in_flash: false + #tx_buffer_size: 64 + +########################################################################################## +# STATUS LED +# https://esphome.io/components/status_led.html +########################################################################################## +# Status LED for KS-811 is GPIO02 +########################################################################################## +status_led: + pin: + number: GPIO02 + inverted: yes + +########################################################################################## +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +########################################################################################## +# Buttons for KS-811-3 are GPIO16, GPIO05, GPIO04 +########################################################################################## +binary_sensor: + - platform: gpio + pin: + number: GPIO16 + mode: INPUT + inverted: True + name: "Button 1: ${switch_1_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command1}" + + - platform: gpio + pin: + number: GPIO05 + mode: INPUT + inverted: True + name: "Button 2: ${switch_2_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command2}" + + - platform: gpio + pin: + number: GPIO4 + mode: INPUT + inverted: True + name: "Button 3: ${switch_3_name}" + on_press: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic}" + payload: "${mqtt_remote_device_command3}" + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +# Relays for KS-811-3 are GPIO13, GPIO12, GPIO14 +########################################################################################## +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 + +mqtt: + on_message: + - topic: "${mqtt_local_status_topic}" + then: + - lambda: |- + int val = atoi(x.c_str()); + ESP_LOGI("fan_switch", "Received requested speed: %d", val); + + // Desired states + bool r1 = false; + bool r2 = false; + bool r3 = false; + + switch (val) { + case 1: + r3 = true; + break; + case 2: + r2 = true; + r3 = true; + break; + case 3: + r1 = true; + r2 = true; + r3 = true; + break; + case 0: + default: + // all remain false + break; + } + + // Only change relays if necessary + if (id(Relay_1).state != r1) { + if (r1) { + id(Relay_1).turn_on(); + } else { + id(Relay_1).turn_off(); + } + } + + if (id(Relay_2).state != r2) { + if (r2) { + id(Relay_2).turn_on(); + } else { + id(Relay_2).turn_off(); + } + } + + if (id(Relay_3).state != r3) { + if (r3) { + id(Relay_3).turn_on(); + } else { + id(Relay_3).turn_off(); + } + } \ No newline at end of file diff --git a/esphome/esp-bedrm3lights.yaml b/esphome/esp-bedrm3lights.yaml new file mode 100644 index 0000000..eba1b65 --- /dev/null +++ b/esphome/esp-bedrm3lights.yaml @@ -0,0 +1,238 @@ +########################################################################################## +########################################################################################## +# BEDROOM 3 LIGHTSWITCH +# V3.5 2025-07-24 YAML tidyups +########################################################################################## +# 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-bedrm3lights" + friendly_name: "Bedroom 3 Lightswitch (2)" + description_comment: "Bedroom 3 Main Lightswitch using a Zemismart KS-811 Double Push Button. Main Lights (1-Virtual), All Lights Off (2-Virtual)" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Zemismart Technologies.KS-811 Double" # Project Details + project_version: "v3.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-bedrm3lights_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: "bedroom3-lightswitch" + #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + mqtt_remote_device_name: "bedroom3-ceilingfan" + mqtt_remote_device_command_topic1: "${mqtt_local_command_main_topic}/${mqtt_remote_device_name}/light/set" + mqtt_remote_status_topic1: "${mqtt_local_status_main_topic}/${mqtt_remote_device_name}/light/state" # Topic we will use to view status of remote without HA + mqtt_remote_device_command_ON: "ON" + mqtt_remote_device_command_OFF: "OFF" + mqtt_remote_device_command_topic2: "${mqtt_local_command_main_topic}/${mqtt_remote_device_name}/speed/set" + #mqtt_remote_device_command1: "+" + #mqtt_remote_device_command2: "-" + mqtt_remote_device_command_0: "0" + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_remote_device_name}/speed/state" # Topic we will use to view status locally without HA + + # Button Naming & Icons + + # Switch Naming + switch_1_name: "Main Lights" # Nothing physically connected to this output. Lights are physically on IFan02 light output + switch_2_name: "All Lights Off" # Nothing physically connected to this output + +######################################################################################### +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + common_sntp: !include + file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +######################################################################################### +# 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 + +#GLobals + +globals: + - id: btn1_last_ms + type: uint32_t + restore_value: no + initial_value: '0' + +######################################################################################### +# 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 + id: button_1 + pin: + number: GPIO16 + mode: + input: true + pullup: false # set to true if you need an internal pull-up + inverted: true + name: "Button 1: ${switch_1_name}" + filters: + - delayed_on: 30ms + - delayed_off: 30ms + on_press: + # cooldown: 250 ms between publishes + - if: + condition: + lambda: |- + return (millis() - id(btn1_last_ms)) > 250; + then: + - lambda: |- + id(btn1_last_ms) = millis(); + - if: + condition: + switch.is_on: Relay_1 + then: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic1}" + payload: "${mqtt_remote_device_command_OFF}" + qos: 0 + retain: false + else: + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic1}" + payload: "${mqtt_remote_device_command_ON}" + qos: 0 + retain: false + + - platform: gpio + pin: + number: GPIO05 + mode: INPUT + inverted: True + name: "Button 2: ${switch_2_name}" + on_press: + - switch.turn_off: Relay_2 + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic1}" + payload: "${mqtt_remote_device_command_OFF}" + qos: 0 + retain: false + - mqtt.publish: + topic: "${mqtt_remote_device_command_topic2}" + payload: "${mqtt_remote_device_command_0}" + qos: 0 + retain: false + +######################################################################################### +# 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 + + +########################################################################################## +# MQTT COMMANDS +# This adds device-specific MQTT command triggers to the common MQTT configuration. +########################################################################################## +mqtt: + on_message: + # Switch control. Turn on/off relay if remote device switched on/off + - topic: "${mqtt_remote_status_topic1}" + payload: "${mqtt_remote_device_command_ON}" + then: + - switch.turn_on: Relay_1 + - topic: "${mqtt_remote_status_topic1}" + payload: "${mqtt_remote_device_command_OFF}" + then: + - switch.turn_off: Relay_1 diff --git a/esphome/esp-downstairskitchleds.yaml b/esphome/esp-downstairskitchleds.yaml new file mode 100644 index 0000000..8b82bb1 --- /dev/null +++ b/esphome/esp-downstairskitchleds.yaml @@ -0,0 +1,701 @@ +########################################################################################## +########################################################################################## +# DOWNSTAIRS KITCHEN - OVER PANTRY LEDS +# +# Controlled by a Sinilink Mosfet Board (ESP8266) +# +# V1.1 - 2025-08-18 Full tidyup as general purpose LED strip controller +# V1.0 - 2025-08-17 First Setup (and replacement of Tasmota) +# +# DEVICE GPIO +# ------------------------------------------ +# Sinilink Board +# https://devices.esphome.io/devices/Sinilink-XY-VFMS +# GPIO02 Blue LED (We'll use this for ESPHome status) +# GPIO04 Mosfet Output (0V when switched) and Red LED +# GPIO12 Toggle Button +# GPIO13 Green LED (We'll use this to display fading status) +# +# OPERATION (as at V1.1) +# 1. General Purpuse LED controller +# 2. Designed for a Sinilink XY-VFMS board that has a mosfet output and supposedly will handle +# 5A and a DC input of 5V-36V. +# 3. Has global setting for MAX % PWM output for the LEDs so you can give them a longer life. +# 4. Has a min setting for the LEDs and it will switch off if it goes below that to stop any +# flicker at very low PWM outputs. +# 5. PWM freq is set to 2kHz, but you could potentially ramp it up. I was getting resets at +# higher values with this device, but other devices may be better. Obviously if yoou use +# an esp32 you can set it much higher (40kHz I think is the max?) +# 6. Min and Max output settings aren't set in Home assistant/MQTT, but you could do this if +# needed. With a 1MB flash, it is starting to get tight. I have done minimal optimising +# at this stage though. +# 7. There are PACKAGES included for a bunch of things such as the common network +# items, diagnostic entities, MQTT and SNTP (if needed) +# +########################################################################################### +########################################################################################## + +########################################################################################## +# 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-downstairskitchleds" + friendly_name: "Downstairs Kitchen LEDs" + description_comment: "Downstairs Kitchen Over Pantry LEDs :: Sinilink XY-WFMS" + device_area: "Downstairs Kitchen" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Sinilink.XY-WFMS" # Project Details + project_version: "v1.0" # Project V denotes release of yaml file, allowing checking of deployed vs latest version + + # Passwords & Secrets + api_key: !secret esp-api_key + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-downstairskitchleds_ip # unfortunately you can't use substitutions inside secrets names + mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic + mqtt_local_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: "10s" # update time for for general sensors etc + + # MQTT LOCAL Controls + #mqtt_device_name: "bedroom2-ceilingfan" + #mqtt_local_command_topic: "${mqtt_local_command_main_topic}/${mqtt_device_name}" # Topic we will use to command this locally without HA + #mqtt_local_status_topic: "${mqtt_local_status_main_topic}/${mqtt_device_name}" # Topic we will use to view status locally without HA + + # MQTT REMOTE Controls + + # Button Naming & Icons + + # Switch/Relay Naming & Icons + + +########################################################################################## +# 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.yaml + vars: + local_api_key: "${api_key}" + #common_webportal: !include + # file: common/webportal_common.yaml + common_mqtt: !include + file: common/mqtt_common.yaml + vars: + local_device_name: "${device_name}" + #common_sntp: !include + # file: common/sntp_common.yaml + common_general_sensors: !include + file: common/sensors_common.yaml + vars: + local_friendly_name: "${friendly_name}" + local_update_interval: "${update_interval}" + +########################################################################################## +# 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}" + on_boot: + priority: -200 + then: + - lambda: |- + ESP_LOGI("boot", "Last reset reason: %s", ESP.getResetReason().c_str()); + // Keep the HA dropdown in sync with the stored mode + 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; + } + + # Mode 0: Fade up to full (respect min/max & ramp time) + - if: + condition: + lambda: 'return id(restart_mode) == 0;' + then: + - lambda: 'id(ramp_switch_target_on) = true;' + - script.execute: ramp_on_script + + # Mode 1: Restore Brightness quickly + - if: + condition: + lambda: 'return id(restart_mode) == 1;' + then: + - lambda: |- + // Clamp the remembered brightness to valid bounds + float target = id(last_brightness_pct); + if (target < 0.0f) target = 0.0f; + if (target > 100.0f) target = 100.0f; + float minp = (float) id(min_brightness_pct); + float maxp = (float) id(max_brightness_pct); + if (target > 0.0f) { + if (target < minp) target = minp; + if (target > maxp) target = maxp; + } + id(suppress_slider_sync) = true; + if (target <= 0.0f) { + auto call = id(mosfet_leds).make_call(); + call.set_state(false); + call.set_transition_length(0); + call.perform(); + id(ramp_switch_target_on) = false; + } else { + auto call = id(mosfet_leds).make_call(); + call.set_state(true); + call.set_brightness(target / 100.0f); + call.set_transition_length(150); + call.perform(); + id(ramp_switch_target_on) = true; + } + - delay: 300ms + - lambda: 'id(suppress_slider_sync) = false;' + + # Mode 2: Remain Off + - if: + condition: + lambda: 'return id(restart_mode) == 2;' + then: + - script.stop: ramp_on_script + - script.stop: ramp_off_script + - light.turn_off: + id: mosfet_leds + transition_length: 0s + - lambda: 'id(ramp_switch_target_on) = false;' + +########################################################################################## +# ESP Platform and Framework +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp01_1m # The original sonoff basic + restore_from_flash: true # restore some values on reboot + +preferences: + flash_write_interval: 5min + +mdns: + disabled: false # Disabling will make the build file smaller (and it is still available via static IP) + +########################################################################################## +# 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, Serial control) + +########################################################################################## +# GLOBALS: ramp times (milliseconds) +########################################################################################## +globals: + - id: min_brightness_pct + type: int + restore_value: true + initial_value: '3' # start/finish at X% + - id: max_brightness_pct + type: int + restore_value: false + initial_value: '90' # hard cap; never exceed this + - id: ramp_up_ms # fade-in when turned ON + type: int + restore_value: true + initial_value: '5000' # 5 s + - id: ramp_down_ms # fade-out when turned OFF + type: int + restore_value: true + initial_value: '10000' # 10 s + - id: ramp_switch_target_on + type: bool + restore_value: true + initial_value: 'false' + - id: suppress_slider_sync + type: bool + restore_value: false + initial_value: 'false' + - id: restart_mode # 0=Fade full, 1=Restore brightness, 2=Remain off + type: int + restore_value: true + initial_value: '0' # default = Ramp to full (so can be deployed with no other setup) + - id: last_brightness_pct # actual 0..100 seen last time + type: float + restore_value: true + initial_value: '0.0' + +######################################################################################### +# STATUS LED +# https://esphome.io/components/status_led.html +######################################################################################### +# SINILINK: Status LED Blue LED on GPIO2, active-low +######################################################################################### +status_led: + pin: + number: GPIO2 + inverted: true + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +switch: + # Ramp-aware ON/OFF for HA (asymmetric, eased; no bounce) + - platform: template + id: mosfet_ramp_switch + name: "${friendly_name} Fade Up/Down" + icon: mdi:led-strip-variant + lambda: |- + return id(ramp_switch_target_on); + turn_on_action: + - lambda: 'id(ramp_switch_target_on) = true;' + - script.stop: ramp_off_script + - script.execute: ramp_on_script + turn_off_action: + - lambda: 'id(ramp_switch_target_on) = false;' + - script.stop: ramp_on_script + - script.execute: ramp_off_script + +################################################################################################# +# BUTTON COMPONENT +# https://esphome.io/components/button/index.html +################################################################################################# +button: + # Start ramping UP (from current level) + - platform: template + id: fade_up_button + name: "${friendly_name} Fade Up" + icon: mdi:arrow-up-bold + on_press: + - lambda: |- + id(ramp_switch_target_on) = true; + id(mosfet_ramp_switch).publish_state(true); // reflect in HA immediately + - script.stop: ramp_off_script + - script.execute: ramp_on_script + + # Start ramping DOWN (from current level) + - platform: template + id: fade_down_button + name: "${friendly_name} Fade Down" + icon: mdi:arrow-down-bold + on_press: + - lambda: |- + id(ramp_switch_target_on) = false; + id(mosfet_ramp_switch).publish_state(false); // reflect in HA immediately + - script.stop: ramp_on_script + - script.execute: ramp_off_script + + # STOP any ramping (hold current brightness) + - platform: template + id: fade_stop_button + name: "${friendly_name} Fade Stop" + icon: mdi:pause + on_press: + # Stop any pending scripts (and their delayed turn_off) + - 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 + # Cancel the light's transition by commanding the current level with 0 ms, + # but DO NOT change the ramp switch state/flag. + - lambda: |- + const auto &cv = id(mosfet_leds).current_values; + if (cv.is_on()) { + auto call = id(mosfet_leds).make_call(); + call.set_state(true); + call.set_brightness(cv.get_brightness()); + call.set_transition_length(0); + call.perform(); + } + +######################################################################################### +# SELECT SENSORS +# +######################################################################################### +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; + } + +######################################################################################### +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +######################################################################################### +binary_sensor: + - platform: gpio + id: btn_gpio12 + name: "${friendly_name} Button" + pin: + number: GPIO12 + mode: + input: true + pullup: true + inverted: true + filters: + - delayed_on: 20ms + - delayed_off: 20ms + on_press: + - if: + condition: + lambda: 'return id(ramp_switch_target_on);' + then: + # Target is currently ON → press should go OFF (start ramp-down) + - lambda: |- + id(ramp_switch_target_on) = false; + id(mosfet_ramp_switch).publish_state(false); // reflect in HA immediately + - script.stop: ramp_on_script + - script.execute: ramp_off_script + else: + # Target is currently OFF → press should go ON (start ramp-up) + - lambda: |- + id(ramp_switch_target_on) = true; + id(mosfet_ramp_switch).publish_state(true); // reflect in HA immediately + - script.stop: ramp_off_script + - script.execute: ramp_on_script + +########################################################################################## +# SENSOR: LED / PWM output percentage (0–100 %) +########################################################################################## +sensor: + - platform: template + id: mosfet_output_pct + name: "${friendly_name} Output (%)" + unit_of_measurement: "%" + icon: mdi:percent + accuracy_decimals: 0 + update_interval: 100ms + lambda: |- + const auto &cv = id(mosfet_leds).current_values; + if (cv.is_on()) { + return cv.get_brightness() * 100.0f; // actual 0..100 + } else { + return 0.0f; + } + on_value: + then: + - lambda: |- + // Remember latest actual output (0..100) for "Restore Brightness" + id(last_brightness_pct) = x; + - if: + condition: + lambda: 'return !id(suppress_slider_sync);' + then: + - lambda: |- + float actual = x; // actual % + float minp = (float) id(min_brightness_pct); + float maxp = (float) id(max_brightness_pct); + 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; + id(led_output_set_pct).publish_state((int) floorf(pos + 0.5f)); + +################################################################################ +# TEMPLATE OUTPUTS: drive the real relays when the states change +################################################################################ +output: + - platform: esp8266_pwm + id: mosfet_pwm + pin: GPIO4 + frequency: 2000 Hz # high frequency to avoid audible/visible artifacts + - platform: gpio + id: green_led_out # Green LED + pin: + number: GPIO13 + inverted: false + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/ +########################################################################################## +light: + - platform: monochromatic + id: mosfet_leds + name: "${friendly_name}" + output: mosfet_pwm + restore_mode: RESTORE_DEFAULT_OFF + default_transition_length: 2s + icon: mdi:led-strip-variant + gamma_correct: 1.2 + on_turn_on: + - lambda: 'id(ramp_switch_target_on) = true;' + on_turn_off: + - lambda: 'id(ramp_switch_target_on) = false;' + on_state: + - lambda: |- + const float cap = id(max_brightness_pct) / 100.0f; + const auto &cv = id(mosfet_leds).current_values; + if (cv.is_on() && cv.get_brightness() > cap + 0.001f) { + auto call = id(mosfet_leds).make_call(); + call.set_state(true); + call.set_brightness(cap); // clamp to max + call.set_transition_length(0); // snap to cap + call.perform(); + } + +########################################################################################## +# NUMBERS: adjust ramp/smoothing from Home Assistant (seconds) +########################################################################################## +########################################################################################## +# NUMBERS: adjust ramp times and direct output set (0..100 mapped to min..max) +########################################################################################## +number: + - platform: template + id: cfg_ramp_up_s + name: "${friendly_name} 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) / 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) = secs * 1000; + id(cfg_ramp_up_s).publish_state((float) secs); + + - platform: template + id: cfg_ramp_down_s + name: "${friendly_name} 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) / 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) = secs * 1000; + id(cfg_ramp_down_s).publish_state((float) secs); + + - platform: template + id: led_output_set_pct + name: "${friendly_name} Output Set (0-100)" + icon: mdi:tune + mode: slider + min_value: 0 + max_value: 100 + step: 1 + # Show current position mapped into 0..100 across [min..max] + lambda: |- + const auto &cv = id(mosfet_leds).current_values; + float actual = cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f; // 0..100 actual + float minp = (float) id(min_brightness_pct); + float maxp = (float) id(max_brightness_pct); + 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); // integer + set_action: + - if: + condition: + lambda: 'return x <= 0.0f;' + then: + # 0 means OFF + - lambda: 'id(suppress_slider_sync) = true;' + - script.stop: ramp_on_script + - script.stop: ramp_off_script + - light.turn_off: + id: mosfet_leds + transition_length: 200ms + - lambda: |- + id(ramp_switch_target_on) = false; + id(led_output_set_pct).publish_state(0); + - delay: 400ms + - lambda: 'id(suppress_slider_sync) = false;' + else: + # Map 1..100 → [min..max] and set ON + - lambda: |- + id(suppress_slider_sync) = 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).publish_state((int) floorf(pos + 0.5f)); + - script.stop: ramp_off_script + - script.stop: ramp_on_script + - light.turn_on: + id: mosfet_leds + brightness: !lambda |- + float pos = id(led_output_set_pct).state; // 1..100 + float minp = (float) id(min_brightness_pct); + float maxp = (float) id(max_brightness_pct); + 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) = true;' + - delay: 400ms + - lambda: 'id(suppress_slider_sync) = false;' + +################################################################################################# +# SCRIPT COMPONENT +# https://esphome.io/components/script.html +################################################################################################# +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 + + - id: ramp_on_script + mode: restart + then: + - script.stop: ramp_off_script + - script.stop: led_flash_down + - script.execute: led_flash_up + - if: + condition: + lambda: |- + const auto &cv = id(mosfet_leds).current_values; + const float floor = id(min_brightness_pct) / 100.0f; + return (!cv.is_on()) || (cv.get_brightness() < floor); + then: + - light.turn_on: + id: mosfet_leds + brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' + transition_length: 0s + - light.turn_on: + id: mosfet_leds + brightness: !lambda 'return id(max_brightness_pct) / 100.0f;' + transition_length: !lambda |- + const auto &cv = id(mosfet_leds).current_values; + const float floor = id(min_brightness_pct) / 100.0f; + const float cap = id(max_brightness_pct) / 100.0f; + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr < floor) curr = floor; + if (curr > cap) curr = cap; + float frac = (cap - curr) / (cap - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + return (uint32_t)(id(ramp_up_ms) * frac); + - delay: !lambda |- + const auto &cv = id(mosfet_leds).current_values; + const float floor = id(min_brightness_pct) / 100.0f; + const float cap = id(max_brightness_pct) / 100.0f; + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr < floor) curr = floor; + if (curr > cap) curr = cap; + float frac = (cap - curr) / (cap - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + return (uint32_t)(id(ramp_up_ms) * frac); + - script.stop: led_flash_up + - output.turn_off: green_led_out + + + # Script: ramp down from current level to floor, then cleanly cut to OFF + - id: ramp_off_script + mode: restart + then: + - script.stop: ramp_on_script + - script.stop: led_flash_up + - script.execute: led_flash_down + # Ramp from current to floor; time scales with distance + - light.turn_on: + id: mosfet_leds + brightness: !lambda 'return id(min_brightness_pct) / 100.0f;' + transition_length: !lambda |- + const auto &cv = id(mosfet_leds).current_values; + const float floor = id(min_brightness_pct) / 100.0f; + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr < floor) curr = floor; + float frac = (curr - floor) / (1.0f - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + return (uint32_t)(id(ramp_down_ms) * frac); + # Keep LED blinking for that duration + - delay: !lambda |- + const auto &cv = id(mosfet_leds).current_values; + const float floor = id(min_brightness_pct) / 100.0f; + float curr = cv.is_on() ? cv.get_brightness() : 0.0f; + if (curr < floor) curr = floor; + float frac = (curr - floor) / (1.0f - floor); + if (frac < 0.0f) frac = 0.0f; + if (frac > 1.0f) frac = 1.0f; + return (uint32_t)(id(ramp_down_ms) * frac); + # Finish with a short fade to black + - light.turn_off: + id: mosfet_leds + transition_length: 150ms + - delay: 150ms + - script.stop: led_flash_down + - output.turn_off: green_led_out + # Prepare the "next-on" brightness so the plain light entity doesn't come back at 5% + - lambda: |- + auto call = id(mosfet_leds).make_call(); + call.set_state(false); // remain OFF + call.set_brightness(id(max_brightness_pct) / 100.0f); // remember cap for next ON + call.perform(); diff --git a/esphome/esp-downstbedrm1lights.yaml b/esphome/esp-downstmasterbedrmlights.yaml similarity index 89% rename from esphome/esp-downstbedrm1lights.yaml rename to esphome/esp-downstmasterbedrmlights.yaml index 289385e..c9ac794 100644 --- a/esphome/esp-downstbedrm1lights.yaml +++ b/esphome/esp-downstmasterbedrmlights.yaml @@ -1,6 +1,6 @@ ########################################################################################## ########################################################################################## -# DOWNSTAIRS BEDROOM 1 LIGHTS +# DOWNSTAIRS MASTER BEDROOM 1 LIGHTS # V3.5 2025-07-24 YAML tidyups ########################################################################################## # Zemismart KS-811 Triple push button @@ -18,19 +18,19 @@ ########################################################################################## substitutions: # Device Naming - device_name: "esp-downstbedrm1lights" - friendly_name: "Downstairs Bedroom 1 Lightswitch (3)" - description_comment: "Downstairs Bedroom 1 Main Lightswitch using a Zemismart KS-811 Triple Push Button. Main Lights (1), Wardrobe Lights (2), Spare (3)" + device_name: "esp-downstmasterbedrmlights" + friendly_name: "Downstairs Master Bedroom 1 Lightswitch (2)" + description_comment: "Downstairs Master Bedroom 1 Main Lightswitch using a Zemismart KS-811 Triple Push Button. Main Lights (1), Wardrobe Lights (2), Spare (3)" device_area: "Downstairs Flat" # 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_name: "Zemismart Technologies.KS-811 Double" # 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-downstbedrm1lights_ip + static_ip_address: !secret esp-downstmasterbedrmlights_ip #mqtt_local_command_main_topic: !secret mqtt_local_command_main_topic #mqtt_local_status_main_topic: !secret mqtt_local_status_main_topic @@ -49,7 +49,7 @@ substitutions: #relay_icon: "mdi:lightbulb-group" switch_1_name: "Main Lights" switch_2_name: "Wardrobe Lights" - switch_3_name: "Spare" + #switch_3_name: "Spare" ######################################################################################### # PACKAGES: Included Common Packages @@ -151,14 +151,14 @@ binary_sensor: - switch.toggle: Relay_2 # 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_press: - - switch.toggle: Relay_3 +# - platform: gpio +# pin: +# number: GPIO4 +# mode: INPUT +# inverted: True +# name: "Button 3: ${switch_3_name}" +# on_press: +# - switch.toggle: Relay_3 ######################################################################################### # SWITCH COMPONENT @@ -178,9 +178,9 @@ switch: id: Relay_2 # GPIO14 for third relay (only for KS-811-3 Triple) - - platform: gpio - name: "Relay 3: ${switch_3_name}" - pin: GPIO14 - id: Relay_3 +# - platform: gpio +# name: "Relay 3: ${switch_3_name}" +# pin: GPIO14 +# id: Relay_3 diff --git a/esphome/esp-occupancystair.yaml b/esphome/esp-occupancystair.yaml index 0a8621a..0ee3144 100644 --- a/esphome/esp-occupancystair.yaml +++ b/esphome/esp-occupancystair.yaml @@ -23,7 +23,7 @@ substitutions: device_name: "esp-occupancystair" friendly_name: "Stair Occupancy and Underhouse Environment" description_comment: "D1 Mini ESP32 with LD2410 mmWave for internal stairwell and environment sensors for under house" - device_area: "Outside" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + device_area: "Underhouse" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming project_name: "Generic.ESP32" # Project Details @@ -46,16 +46,19 @@ 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 vars: local_api_key: "${api_key}" -# common_webportal: !include -# file: common/webportal_common.yaml + #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 diff --git a/esphome/esp-poollightpower.yaml b/esphome/esp-poollightpower.yaml index a28e3d9..b88c45a 100644 --- a/esphome/esp-poollightpower.yaml +++ b/esphome/esp-poollightpower.yaml @@ -70,7 +70,7 @@ substitutions: static_ip_address: !secret esp-poollightpower_ip # Device Settings - log_level: "INFO" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE + log_level: "NONE" # Define logging level: NONE, ERROR, WARN, INFO, DEBUG (Default), VERBOSE, VERY_VERBOSE update_interval: "10s" # update time for for general sensors etc # Device Settings @@ -133,6 +133,16 @@ esphome: project: name: "${project_name}" version: "${project_version}" + #platformio_options: + # build_unflags: + # - -std=gnu++20 + # - -std=gnu++2a + # build_flags: + # - -std=gnu++11 + # - -Os + # - -Wl,--gc-sections + # - -fno-exceptions + # - -fno-rtti ########################################################################################## # ESP Platform and Framework @@ -141,12 +151,14 @@ esphome: esp8266: board: esp8285 restore_from_flash: true # mainly for calculating cumulative energy, but not that important here + #framework: + # version: 2.7.4 preferences: flash_write_interval: 10min mdns: - disabled: false + disabled: True # binary size saving ########################################################################################## # ESPHome Logging Enable diff --git a/group/foxhole_lights.yaml b/group/downstairs_flat_lights.yaml similarity index 86% rename from group/foxhole_lights.yaml rename to group/downstairs_flat_lights.yaml index 35664c3..88ef543 100644 --- a/group/foxhole_lights.yaml +++ b/group/downstairs_flat_lights.yaml @@ -1,11 +1,11 @@ -foxhole_lights: +downstairs_flat_lights: name: Downstairs Flat Lights # All the lights in the Downstairs flat # Doesn't include the outdoor switch lights, or bedroom wardrobe light entities: - switch.esp_downstloungemain_relay_1_main_lights # Lounge Main Lights - switch.esp_downstloungemain_relay_2_back_wall_lights # Lounge Back Wall Lights - - switch.esp_downstbedrm1lights_relay_1_main_lights # Main Bedroom, Main Lights + - switch.esp_downstmasterbedrmlights_relay_1_main_lights # Main Bedroom, Main Lights - switch.esp_downstbedrm2lights_relay_1_main_lights # Small Bedroom Room Lights - switch.esp_downstkitchlights_relay_2_kitchen_light # Kitchen Lights - switch.esp_downstkitchlights_relay_1_dining_light # Dining Lights diff --git a/packages/simulation_lights.yaml b/packages/simulation_lights.yaml index bb1c3ba..ec39329 100644 --- a/packages/simulation_lights.yaml +++ b/packages/simulation_lights.yaml @@ -1,23 +1,14 @@ -switch: - - platform: group - name: Simulation Lights - # Lights included in 'away from home' random pattern +group: + simulation_lights_all: + name: Simulation Lights (All) entities: - - switch.tasmo_ks811d_1242_entrance_a # Entranceway Main Lights - - switch.tasmo_ks811d_0302_entrybath_a # Entranceway Guest Bathroom Lights - - switch.tasmo_ks811d_6110_kitchen_a # Main Kitchen, Main Lights - - switch.tasmo_ks811d_6110_kitchen_b # Main Kitchen, Bench Lights - - switch.main_hallway_lightswitch_tasmo_ks811s_2940_hallway_1a # Hallway Main Lights - - switch.tasmo_ks811d_1701_stairs_2a # Stairs, Lower ceiling lights - - switch.tasmo_ks811t_0702_lounge_3a # Lounge Main, South - - switch.tasmo_ks811t_0702_lounge_3b # Lounge Main, Middle - - switch.tasmo_ks811t_0702_lounge_3c # Lounge Main, North (above stairs) - - switch.tasmo_ks811t_0707_downstloun_2a # Foxhole Lounge Main Lights - - switch.tasmo_ks811t_0707_downstloun_2b # Foxhole Lounge Wall Lights - - switch.tasmo_ks811s_3136_downstbed2_1a # Foxhole Craft Room Lights - - switch.tasmo_ks811t_3642_downstbed1_1a # Foxhole Main Bedroom, Main Lights - - switch.tasmo_s4chan_4231_underhouselights_b # Underhouse Main Lights - - switch.esp_downstkitchlights_relay_1_dining_light - - switch.esp_downstkitchlights_relay_2_kitchen_light - - switch.esp_downstbathswitch_relay_1_main_lights - - switch.esp_downstbathswitch_relay_2_cabinet_light + - switch.tasmo_ks811d_1242_entrance_a + - switch.tasmo_ks811d_0302_entrybath_a + - switch.tasmo_ks811d_6110_kitchen_a + - switch.tasmo_ks811d_6110_kitchen_b + - switch.main_hallway_lightswitch_tasmo_ks811s_2940_hallway_1a + - switch.tasmo_ks811d_1701_stairs_2a + - switch.tasmo_ks811t_0702_lounge_3a + - switch.tasmo_ks811t_0702_lounge_3b + - switch.tasmo_ks811t_0702_lounge_3c + - group.downstairs_flat_lights # ← now valid here