esphome lounge switches and scene control

This commit is contained in:
root
2025-10-08 19:21:28 +13:00
parent 1e1d0571d9
commit e96344e3ad
62 changed files with 4189 additions and 925 deletions
+31 -89
View File
@@ -106,8 +106,8 @@ packages:
#### HOME ASSISTANT API (choose encryption or no encryption options) ####
common_api: !include
file: common/api_common.yaml
#file: common/api_common_noencryption.yaml
#file: common/api_common.yaml
file: common/api_common_noencryption.yaml
vars:
local_api_key: "${api_key}"
@@ -124,9 +124,9 @@ packages:
#### DIAGNOSTICS Sensors ####
diag_basic: !include common/include_basic_diag_sensors.yaml
diag_more: !include common/include_more_diag_sensors.yaml
diag_debug: !include common/include_debug_diag_sensors.yaml
diag_resetcount: !include common/include_resetcount_diag_sensors.yaml
#diag_more: !include common/include_more_diag_sensors.yaml
#diag_debug: !include common/include_debug_diag_sensors.yaml
#diag_resetcount: !include common/include_resetcount_diag_sensors.yaml
##########################################################################################
# ESPHome CORE CONFIGURATION
@@ -179,6 +179,9 @@ esphome:
# Boot complete: allow OFF handlers again
- lambda: 'id(booting) = false;'
# NEW: force indicator OFF after boot logic
- output.turn_off: green_led_out
# Only if you want to play with build flags...
# platformio_options:
# build_unflags:
@@ -200,10 +203,10 @@ esp8266:
restore_from_flash: true # restore some values on reboot
mdns:
disabled: false # Disabling will make the build file smaller (and device is still available via static IP)
disabled: true # Disabling will make the build file smaller (and device is still available via static IP)
preferences:
flash_write_interval: 5sec # enough time to update values for reboots, but not enough to wear flash
flash_write_interval: 2min # enough time to update values for reboots, but not enough to wear flash
##########################################################################################
# GLOBAL VARIABLES
@@ -269,11 +272,6 @@ globals:
type: int
restore_value: false
initial_value: '0'
# last non-zero actual 0..100 used, for stable "Restore Brightness"
- id: last_nonzero_brightness_pct
type: float
restore_value: true
initial_value: '0.0'
# target for "Restore Brightness" scripted ramp
- id: restore_target_pct
type: float
@@ -284,17 +282,12 @@ globals:
type: bool
restore_value: false
initial_value: 'false'
# volatile (non-persistent) last non-zero brightness during ramps
- id: last_nonzero_tmp
type: float
restore_value: false
initial_value: '0.0'
# guards OFF persistence during startup caused by restore_mode: ALWAYS_OFF
- id: booting
type: bool
restore_value: false
initial_value: 'true'
# true only while we are performing a ramp-down that briefly turns the light ON to hit the floor
# true only while we are performing a ramp-down that briefly turns the light ON to hit the floor
- id: ramping_for_off
type: bool
restore_value: false
@@ -396,8 +389,6 @@ button:
# Stop any pending scripts (and their delayed actions)
- script.stop: ramp_on_script
- script.stop: ramp_off_script
- script.stop: led_flash_up
- script.stop: led_flash_down
- output.turn_off: green_led_out
- lambda: |-
// We are no longer ramping (up or down)
@@ -414,14 +405,14 @@ button:
call.perform();
}
// Persist the exact frozen level so "Restore Brightness" survives a reboot
// Persist the exact frozen level so restore survives a reboot
if (cv.is_on()) {
float pct = cv.get_brightness() * 100.0f;
id(last_brightness_pct) = pct;
if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct;
}
#########################################################################################
# SELECT COMPONENT
# https://esphome.io/components/select/index.html
@@ -462,8 +453,8 @@ binary_sensor:
pullup: true
inverted: true
filters:
- delayed_on: 20ms
- delayed_off: 20ms
- delayed_on: 30ms
- delayed_off: 30ms
on_press:
- if:
condition:
@@ -494,29 +485,16 @@ sensor:
unit_of_measurement: "%"
icon: mdi:percent
accuracy_decimals: 0
update_interval: 250ms # consider 200ms if you want fewer updates
update_interval: 1s # consider 200ms if you want fewer updates
lambda: |-
const auto &cv = id(mosfet_leds).current_values;
return cv.is_on() ? (cv.get_brightness() * 100.0f) : 0.0f;
on_value:
then:
- lambda: |-
const auto &cv_now = id(mosfet_leds).current_values;
// Only persist exact last brightness while actually ON,
// and not during the OFF ramp's brief floor-kick.
if (cv_now.is_on()) {
if (x > 0.5f) {
if (!id(is_ramping)) id(last_nonzero_brightness_pct) = x;
id(last_nonzero_tmp) = x;
}
} else {
if (x > 0.5f) id(last_nonzero_tmp) = x;
}
// If not suppressing sync, update the 0..100 slider only when its INT changes
if (!id(suppress_slider_sync)) {
float actual = x;
float actual = x; // x is current Output (%)
float minp = (float) id(min_brightness_pct);
float maxp = (float) id(max_brightness_pct);
if (maxp <= minp) maxp = minp + 1.0f;
@@ -530,13 +508,14 @@ sensor:
id(led_output_set_pct).publish_state(pos_i);
}
}
- platform: template
id: mosfet_output_pwm_pct
name: "${friendly_name} Output PWM (%)"
unit_of_measurement: "%"
icon: mdi:square-wave
accuracy_decimals: 1
update_interval: 250ms
update_interval: 1s
lambda: |-
const auto &cv = id(mosfet_leds).current_values;
if (!cv.is_on()) return 0.0f;
@@ -547,6 +526,7 @@ sensor:
if (pwm > 1.0f) pwm = 1.0f;
return pwm * 100.0f;
##########################################################################################
# OUTPUT COMPONENT
# https://esphome.io/components/light/index.html
@@ -741,11 +721,7 @@ number:
if (maxp <= minp) maxp = minp + 1.0f;
float out_pct = minp + (pos * (maxp - minp) / 100.0f);
if (out_pct > maxp) out_pct = maxp;
id(last_brightness_pct) = out_pct; // persist exact target now
if (out_pct > 0.5f) {
id(last_nonzero_brightness_pct) = out_pct;
id(last_nonzero_tmp) = out_pct;
}
id(last_brightness_pct) = out_pct; // persist exact target now
- delay: 400ms
- lambda: 'id(suppress_slider_sync) = false;'
@@ -785,43 +761,14 @@ number:
# Scripts can be executed nearly anywhere in your device configuration with a single call.
##########################################################################################
script:
# Blink pattern while ramping UP: quick double-blink, pause, repeat
- id: led_flash_up
mode: restart
then:
- while:
condition:
lambda: 'return true;'
then:
- output.turn_on: green_led_out
- delay: 100ms
- output.turn_off: green_led_out
- delay: 100ms
- output.turn_on: green_led_out
- delay: 100ms
- output.turn_off: green_led_out
- delay: 400ms
# Blink pattern while ramping DOWN: steady slow blink
- id: led_flash_down
mode: restart
then:
- while:
condition:
lambda: 'return true;'
then:
- output.turn_on: green_led_out
- delay: 250ms
- output.turn_off: green_led_out
- delay: 250ms
# Script: ramp up from current level. Obey global max.
# Script: ramp up from current level. Obey global max. (LED ON while ramping)
- id: ramp_on_script
mode: restart
then:
- lambda: 'id(is_ramping) = true;'
- script.stop: ramp_off_script
- script.stop: led_flash_down
- script.execute: led_flash_up
- output.turn_on: green_led_out
# Ensure we start at at least the floor without a visible "pop".
- if:
condition:
@@ -858,25 +805,22 @@ script:
id(last_ramp_ms) = (int) (id(ramp_up_ms) * frac);
return (uint32_t) id(last_ramp_ms);
- delay: !lambda 'return (uint32_t) id(last_ramp_ms);'
- script.stop: led_flash_up
- output.turn_off: green_led_out
- lambda: |-
id(is_ramping) = false;
const auto &cv = id(mosfet_leds).current_values;
if (cv.is_on()) {
float pct = cv.get_brightness() * 100.0f;
id(last_brightness_pct) = pct; // persist final level
if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct;
id(last_brightness_pct) = pct; // persist final level
}
# Script: ramp to a specific target (Restore Brightness path)
# Script: ramp to a specific target (Restore Brightness path). (LED ON while ramping)
- id: ramp_to_target_script
mode: restart
then:
- lambda: 'id(is_ramping) = true;'
- script.stop: ramp_off_script
- script.stop: led_flash_down
- script.execute: led_flash_up
- output.turn_on: green_led_out
# Ensure we start at the floor cleanly.
- if:
condition:
@@ -919,18 +863,17 @@ script:
id(last_ramp_ms) = (int) (id(ramp_up_ms) * frac);
return (uint32_t) id(last_ramp_ms);
- delay: !lambda 'return (uint32_t) id(last_ramp_ms);'
- script.stop: led_flash_up
- output.turn_off: green_led_out
- lambda: |-
id(is_ramping) = false;
const auto &cv = id(mosfet_leds).current_values;
if (cv.is_on()) {
float pct = cv.get_brightness() * 100.0f;
id(last_brightness_pct) = pct; // persist final level
if (pct > 0.5f) id(last_nonzero_brightness_pct) = pct;
id(last_brightness_pct) = pct; // persist final level
}
# Script: ramp down from current level to floor, then cleanly cut to OFF
# Script: ramp down from current level to floor, then cleanly cut to OFF. (LED ON while ramping)
- id: ramp_off_script
mode: restart
then:
@@ -938,8 +881,7 @@ script:
id(is_ramping) = true;
id(ramping_for_off) = true;
- script.stop: ramp_on_script
- script.stop: led_flash_up
- script.execute: led_flash_down
- output.turn_on: green_led_out
- light.turn_on:
id: mosfet_leds
brightness: !lambda 'return id(min_brightness_pct) / 100.0f;'
@@ -960,7 +902,6 @@ script:
id: mosfet_leds
transition_length: 150ms
- delay: 150ms
- script.stop: led_flash_down
- output.turn_off: green_led_out
- lambda: |-
id(is_ramping) = false;
@@ -1021,3 +962,4 @@ script:
- light.turn_off:
id: mosfet_leds
transition_length: 0s
- output.turn_off: green_led_out # make sure LED is off if no ramp