From a27b79fbd91cacd351ff57143dfd315d64a334d1 Mon Sep 17 00:00:00 2001 From: root Date: Wed, 10 Sep 2025 21:07:31 +1200 Subject: [PATCH] esphome RGB Bulbs and Fly Sprayer --- automations.yaml | 35 -- customize.yaml | 9 - esphome/esp-4chdmxdimmer1.yaml | 16 +- esphome/esp-flysprayer1.yaml | 696 +++++++++++++++++++++++++++++ esphome/esp-rgblampbulb1.yaml | 258 +++++++++++ esphome/esp-rgblampbulb2.yaml | 427 ++++++++++++++++++ packages/alexa_tplink_actions.yaml | 73 +-- packages/pool_controls.yaml | 32 -- packages/robotdyn_dimmers.yaml | 12 + scripts/check_config.yaml | 3 - 10 files changed, 1441 insertions(+), 120 deletions(-) create mode 100644 esphome/esp-flysprayer1.yaml create mode 100644 esphome/esp-rgblampbulb1.yaml create mode 100644 esphome/esp-rgblampbulb2.yaml delete mode 100644 packages/pool_controls.yaml create mode 100644 packages/robotdyn_dimmers.yaml delete mode 100644 scripts/check_config.yaml diff --git a/automations.yaml b/automations.yaml index 082d3e0..e69de29 100644 --- a/automations.yaml +++ b/automations.yaml @@ -1,35 +0,0 @@ -- id: '1693027703299' - alias: Downstairs Kitchen turn ON LEDs on with main lights - description: '' - triggers: - - type: turned_on - device_id: 1a7e2bfdfaa08e2b78bcbd5d5d12d2a7 - entity_id: ef02e93de5fdda30bea18dac1316927a - domain: switch - trigger: device - conditions: [] - actions: - - data: - transition: 20 - brightness_pct: 95 - target: - entity_id: light.controller_dimmable_3c317c - action: light.turn_on - mode: single -- id: '1693027792035' - alias: Downstairs Kitchen turn OFF LEDs with main lights - description: '' - triggers: - - type: turned_off - device_id: 1a7e2bfdfaa08e2b78bcbd5d5d12d2a7 - entity_id: ef02e93de5fdda30bea18dac1316927a - domain: switch - trigger: device - conditions: [] - actions: - - data: - transition: 20 - target: - entity_id: light.controller_dimmable_3c317c - action: light.turn_off - mode: single diff --git a/customize.yaml b/customize.yaml index fa5d031..e69de29 100644 --- a/customize.yaml +++ b/customize.yaml @@ -1,9 +0,0 @@ -sensor.dryer_finished: - icon: mdi:tumble-dryer-alert -sensor.washing_machine_finished: - icon: mdi:washing-machine-alert -sensor.dishwasher_finished: - icon: mdi:dishwasher-alert -sensor.pets_fed: - friendly_name: Pets Fed - icon: mdi:paw diff --git a/esphome/esp-4chdmxdimmer1.yaml b/esphome/esp-4chdmxdimmer1.yaml index 57bc927..17a2a98 100644 --- a/esphome/esp-4chdmxdimmer1.yaml +++ b/esphome/esp-4chdmxdimmer1.yaml @@ -1,8 +1,8 @@ ########################################################################################## ########################################################################################## # 4 Channel DMX Mains Dimmer -# This is using an esp8366 (D1 Mini) sensing DMX512 Serial to a 2 channel -# mains lighting contoller (1.2A/Channel) +# This is using an esp8366 (D1 Mini) sending DMX512 Serial to a pair of 2 channel +# mains lighting contollers (1.2A/Channel) # # Contoller: https://www.aliexpress.com/item/32838426377.html # RS-485 TTL converter: https://www.aliexpress.com/item/1005005737922222.html @@ -18,6 +18,8 @@ # - The dimmer needs to be set to DMX mode, and given an ID of 1-999 (not standalone or dynamic) # - there is no reason you can't run many dimmers off one ESP (limit may be in data speed lags?) # - The dimmer is pretty smooth, and it remembers values even if no data being transmitted. +# - On my system, I am restoring all channels to ON. Power is controlled by a (smart) wallswitch +# so if all networks fail, switching the switch will power these on and restore to full brightness. # # System Settings on Dimmer: (onboard buttons M and < held for 2 secs) # ------ @@ -56,7 +58,7 @@ substitutions: # Device Naming device_name: "esp-4chdmxdimmer1" friendly_name: "4 Channel DMX Dimmer 1" - description_comment: "4 Channel Mains Lighting Dimmer using DMX512 protocol" + description_comment: "Lounge 4 Channel Mains Lighting Dimmer using DMX512 protocol" device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. # Project Naming @@ -186,28 +188,28 @@ light: id: light_test_1 default_transition_length: 5s gamma_correct: 1 - restore_mode: RESTORE_DEFAULT_ON + restore_mode: ALWAYS_ON - platform: monochromatic name: "Test Lights Chan 2" output: dmx_2 id: light_test_2 default_transition_length: 5s gamma_correct: 1 - restore_mode: RESTORE_DEFAULT_ON + restore_mode: ALWAYS_ON - platform: monochromatic name: "Test Lights Chan 3" output: dmx_3 id: light_test_3 default_transition_length: 5s gamma_correct: 1 - restore_mode: RESTORE_DEFAULT_ON + restore_mode: ALWAYS_ON - platform: monochromatic name: "Test Lights Chan 4" output: dmx_4 id: light_test_4 default_transition_length: 5s gamma_correct: 1 - restore_mode: RESTORE_DEFAULT_ON + restore_mode: ALWAYS_ON ########################################################################################## # SENSOR COMPONENT diff --git a/esphome/esp-flysprayer1.yaml b/esphome/esp-flysprayer1.yaml new file mode 100644 index 0000000..cd88ffd --- /dev/null +++ b/esphome/esp-flysprayer1.yaml @@ -0,0 +1,696 @@ +########################################################################################## +########################################################################################## +# FLY SPRAYER – Sinilink XY-WFUSB (ESP8266/ESP8285) – ESPHome +# +# V1.0 2025-05-30 Initial Version +# +# Device: Sinilink XY-WFUSB module https://www.aliexpress.com/item/1005005815472269.html +# GPIO: Tasmota template: Button=GPIO4, Relay=GPIO5, Led_i=GPIO14, LedLink=GPIO16 +# +# Purpose: +# - Pulse a MOSFET/relay with 5 V to trigger a fly spray can at selectable intervals. +# - Sprayer has its own timers, but it fires whenever it is started up, which we utilise here. +# - Enforce a cooldown so it never double-fires too quickly (Sprayer has some memory) +# - Operation window select: Night only / Day only / 24 Hours / On / Off. +# - Randomize each interval by ± a percentage to avoid a perfectly regular pattern. +# - Red LED (GPIO14, inverted) pulses slowly when idle; goes solid ON during spray. +# - Green LED (GPIO16) as standard ESPHome status LED. +# - Has a resettable total spray count, and a daily spray count +# - has a countdown until next spray +# +########################################################################################## +########################################################################################## + +########################################################################################## +# 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-flysprayer1" + friendly_name: "Fly Sprayer" + description_comment: "Control of generic automatic fly sprayer on a configurable interval" + device_area: "Lounge" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Project Naming + project_name: "Generic ESP8266.XY-WFUSB" # 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 # 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-flysprayer1_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 + 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 Controls + #mqtt_device_name: "lounge-flyspray" + #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 + + # Hardware pins (XY-WFUSB per your Tasmota screen) + pin_button: 4 # GPIO4 -> momentary button (optional local trigger) + pin_relay: 5 # GPIO5 -> MOSFET/relay output + pin_led_red: 14 # GPIO14 -> Red LED (inverted) + pin_led_green: 16 # GPIO16 -> Green status LED (WiFi/status) + relay_inverted: false # Set to "true" if your MOSFET stage is active LOW + + # Timing configuration + relay_activation_ms: 5000 # Relay Activation Time (ms). Nominally 5 seconds. + relay_cooldown_ms: 30000 # Relay Cool Down Period (ms). Minimum gap between sprays. + + # Operation windows (local 24h). Night is from night_start_h to night_end_h across midnight. + night_start_h: 21 # 21:00 (9pm) + night_end_h: 7 # 07:00 (7am) + + # Interval jitter (± percent of selected interval) + interval_jitter_pct: 10 # Default ±10% + +######################################################################################### +# 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 CORE CONFIGURATION +# https://esphome.io/components/esphome.html +########################################################################################## +esphome: + name: "${device_name}" + friendly_name: "${friendly_name}" + comment: "${description_comment}" + area: "${device_area}" + project: + name: "${project_name}" + version: "${project_version}" + on_boot: + # Early: make hardware safe/pretty + - priority: -10 + then: + - switch.turn_off: relay_out + - light.turn_on: + id: red_led + brightness: 50% + effect: red_idle_pulse + + # Late: after components & restores are ready, publish real values and start loop + - priority: 800 + then: + - delay: 200ms + - lambda: |- + // Publish restored counts + id(spray_count_sensor).publish_state((float) id(spray_count)); + id(spray_count_today_sensor).publish_state(id(spray_count_today)); + // Reset countdown display + id(next_spray_seconds).publish_state(0); + id(next_spray_in_text).publish_state("Ready"); + - script.execute: spray_loop + + +########################################################################################## +# ESP PLATFORM AND FRAMEWORK +# https://esphome.io/components/esp8266.html +# https://esphome.io/components/esp32.html +########################################################################################## +esp8266: + board: esp8285 + 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 + +preferences: + flash_write_interval: 20s + +########################################################################################## +# GLOBAL VARIABLES +# https://esphome.io/components/globals.html +########################################################################################## +globals: + # millisecond tick when we last fired successfully + - id: last_fire_ms + type: uint32_t + restore_value: no + initial_value: '0' + + - id: last_wait_ms + type: uint32_t + restore_value: no + initial_value: '60000' + + - id: window_allowed + type: bool + restore_value: no + initial_value: 'false' + + # absolute millis() when the next spray countdown ends + - id: next_target_ms + type: uint32_t + restore_value: no + initial_value: '0' + + # total successful sprays (persists across reboots) + - id: spray_count + type: uint32_t + restore_value: yes + initial_value: '0' + + # total sprays since local midnight + - id: spray_count_today + type: uint32_t + restore_value: yes + initial_value: '0' + + # day-of-month snapshot to detect midnight rollover + - id: last_day + type: int + restore_value: yes + initial_value: '-1' + +########################################################################################## +# LOGGER COMPONENT +# https://esphome.io/components/logger.html +# Logs all log messages through the serial port and through MQTT topics. +########################################################################################## +logger: + level: "${log_level}" #INFO Level suggested, or DEBUG for testing + #baud_rate: 0 #set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + #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 to ramp up +# - topic: "${mqtt_local_command_topic}/light/set" +# payload: "${mqtt_local_device_command_ON}" +# then: +# - switch.turn_on: mosfet_ramp_switch +# # Light control to ramp down +# - topic: "${mqtt_local_command_topic}/light/set" +# payload: "${mqtt_local_device_command_OFF}" +# then: +# - switch.turn_off: mosfet_ramp_switch + +######################################################################################### +# STATUS LED +# https://esphome.io/components/status_led.html +######################################################################################### +status_led: + pin: + number: ${pin_led_green} + inverted: false + +########################################################################################## +# SWITCH COMPONENT +# https://esphome.io/components/switch/ +########################################################################################## +switch: + - platform: gpio + id: relay_out + name: "Spray Relay" + icon: mdi:relay + pin: + number: ${pin_relay} + inverted: ${relay_inverted} + restore_mode: RESTORE_DEFAULT_OFF + internal: true + on_turn_on: + # Ensure red LED goes solid during activation (script also enforces) + - light.turn_on: + id: red_led + brightness: 100% + effect: none + on_turn_off: + # Return to idle pulsing when relay is off + - light.turn_on: + id: red_led + brightness: 50% + effect: red_idle_pulse + +################################################################################################# +# BUTTON COMPONENT +# https://esphome.io/components/button/index.html +################################################################################################# +button: + - platform: template + id: spray_now + name: "Spray Now" + icon: mdi:spray + on_press: + then: + - script.execute: try_spray_now + - platform: template + id: reset_spray_count + name: "Reset Spray Count" + icon: mdi:backup-restore + on_press: + then: + - lambda: |- + id(spray_count) = 0; + id(spray_count_sensor).publish_state(0); + +######################################################################################### +# SELECT COMPONENT +# https://esphome.io/components/select/index.html +######################################################################################### +select: + - platform: template + id: spray_interval + name: "${friendly_name} Spray Interval" + icon: mdi:timer + optimistic: true + restore_value: true + initial_option: "20 minutes" + options: + - "5 minutes" + - "10 minutes" + - "20 minutes" + - "30 minutes" + - "1 hour" + - "2 hours" + - "4 hours" + on_value: + then: + - logger.log: + format: "Spray Interval changed to %s — rescheduling" + args: [ 'id(spray_interval).state.c_str()' ] + - script.execute: spray_loop + + - platform: template + id: spray_operation + name: "${friendly_name} Operation" + icon: mdi:toggle-switch + optimistic: true + restore_value: true + initial_option: "On" + options: + - "Off" + - "Night Only" + - "Day Only" + - "24 Hours" + - "On" + on_value: + then: + - logger.log: + format: "Operation changed to %s — rescheduling" + args: [ 'id(spray_operation).state.c_str()' ] + - script.execute: spray_loop + +########################################################################################## +# BINARY SENSORS +# https://esphome.io/components/binary_sensor/ +########################################################################################## +binary_sensor: + # Front panel/local button (GPIO4) – single press triggers a Spray Now (honors cooldown) + - platform: gpio + id: btn_local + pin: + number: ${pin_button} + mode: INPUT_PULLUP + inverted: true + name: "Local Button Press" + icon: mdi:spray + internal: true + on_press: + then: + - button.press: spray_now + +########################################################################################## +# SENSOR COMPONENT +# https://esphome.io/components/sensor/ +########################################################################################## +sensor: + # Next spray remaining time in seconds (updated by the scheduler) + - platform: template + id: next_spray_seconds + name: "Next Spray Seconds to go" + icon: mdi:timer-sand + unit_of_measurement: "s" + accuracy_decimals: 0 + #entity_category: diagnostic + update_interval: never + + # Total sprays counter (persisted; updated on each spray and when reset) + - platform: template + id: spray_count_sensor + name: "Spray Count Total" + icon: mdi:counter + unit_of_measurement: "" + accuracy_decimals: 0 + state_class: total_increasing + update_interval: never + filters: + - round: 0 + + # Sprays since local midnight (auto-resets at midnight) + - platform: template + id: spray_count_today_sensor + name: "${friendly_name} Spray Count Today" + icon: mdi:counter + unit_of_measurement: "" + accuracy_decimals: 0 + state_class: measurement + update_interval: never + filters: + - round: 0 + +########################################################################################## +# TEXT SENSOR COMPONENT +# https://esphome.io/components/text_sensor/ +########################################################################################## +text_sensor: + - platform: template + id: next_spray_in_text + name: "Next Spray In" + icon: mdi:clock-outline + #entity_category: diagnostic + update_interval: never + +########################################################################################## +# OUTPUT COMPONENT +# https://esphome.io/components/light/index.html +########################################################################################## +# An OUTPUT can be binary (0,1) or float, which is any value between 0 and 1. +# PWM Outputs such as "ledc" are float. https://esphome.io/components/output/ledc.html +########################################################################################## +output: + - platform: esp8266_pwm + id: red_led_pwm + pin: + number: ${pin_led_red} + inverted: true # Tasmota showed Led_i on GPIO14 + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/ +########################################################################################## +light: + - platform: monochromatic + id: red_led + name: "${friendly_name} Red LED" + icon: mdi:led-on + output: red_led_pwm + default_transition_length: 300ms + internal: true + effects: + - pulse: + name: red_idle_pulse + transition_length: 1500ms + update_interval: 1500ms + +########################################################################################## +# NUMBER COMPONENT +# https://esphome.io/components/number/ +########################################################################################## + + +########################################################################################## +# SCRIPT COMPONENT +# https://esphome.io/components/script.html +# Scripts can be executed nearly anywhere in your device configuration with a single call. +########################################################################################## +# SCRIPTS – main loop, cooldown-safe trigger, and actual spray action +########################################################################################## +########################################################################################## +# SCRIPT COMPONENT +# https://esphome.io/components/script.html +# Scripts can be executed nearly anywhere in your device configuration with a single call. +########################################################################################## +# SCRIPTS – main loop, cooldown-safe trigger, and actual spray action +########################################################################################## +script: + # Cooldown-checked "Spray Now" + - id: try_spray_now + mode: restart + then: + - if: + condition: + lambda: |- + const uint32_t now = millis(); + return (now - id(last_fire_ms)) >= (uint32_t) ${relay_cooldown_ms}; + then: + - logger.log: "Spray: activating relay (within allowed period)." + - lambda: |- + id(last_fire_ms) = millis(); + - script.execute: do_spray + else: + - logger.log: "Spray request ignored: Fired during cool down period." + + # Actual relay action for the configured activation time + - id: do_spray + mode: restart + then: + - lambda: |- + id(spray_count)++; + id(spray_count_sensor).publish_state((float) id(spray_count)); + id(spray_count_today)++; + id(spray_count_today_sensor).publish_state(id(spray_count_today)); // publish as int + - switch.turn_on: relay_out + - light.turn_on: + id: red_led + brightness: 100% + effect: none + - delay: !lambda "return (uint32_t) ${relay_activation_ms};" + - switch.turn_off: relay_out + - light.turn_on: + id: red_led + brightness: 50% + effect: red_idle_pulse + + # Scheduler loop – waits a randomized interval, updates countdown text, checks window, then tries to spray + - id: spray_loop + mode: restart + then: + - while: + condition: + lambda: "return true;" + then: + # 1) Compute the base interval and randomized wait + - lambda: |- + auto s = id(spray_interval).state; + uint32_t base_sec = 3600; // default 1 hour + if (s == "5 minutes") base_sec = 5 * 60; + else if (s == "10 minutes") base_sec = 10 * 60; + else if (s == "20 minutes") base_sec = 20 * 60; + else if (s == "30 minutes") base_sec = 30 * 60; + else if (s == "1 hour") base_sec = 60 * 60; + else if (s == "2 hours") base_sec = 2 * 60 * 60; + else if (s == "4 hours") base_sec = 4 * 60 * 60; + + // Jitter ±pct + const uint32_t pct = ${interval_jitter_pct}; + const uint32_t jitter = (base_sec * pct) / 100; + const uint32_t span = (jitter * 2u) + 1u; + const uint32_t rnd = random_uint32() % span; // 0..(2*jitter) + const int32_t delta = (int32_t)rnd - (int32_t)jitter; // -jitter..+jitter + int32_t next_sec = (int32_t)base_sec + delta; + if (next_sec < 1) next_sec = 1; + + ESP_LOGI("spray", "Next interval: base=%u s, jitter=%u%%, wait=%ld s", + base_sec, pct, (long) next_sec); + + id(last_wait_ms) = (uint32_t) next_sec * 1000u; + id(next_target_ms) = millis() + id(last_wait_ms); + + // Publish an initial countdown snapshot (minutes only for text; seconds kept for numeric sensor) + uint32_t rem_ms = id(next_target_ms) > millis() ? (id(next_target_ms) - millis()) : 0; + uint32_t sec = (rem_ms + 999u) / 1000u; // seconds, rounded up + id(next_spray_seconds).publish_state(sec); + uint32_t min = (sec + 59u) / 60u; // minutes, ceiling + char buf[16]; + snprintf(buf, sizeof(buf), "%u min", (unsigned)min); + std::string countdown_txt(buf); + + // Override text for specific modes + auto op = id(spray_operation).state; + char await_buf[16]; + + if (op == "Off") { + id(next_spray_in_text).publish_state("Disabled"); + } else if (op == "Night Only") { + bool in_window = false; + if (id(sntp_time).now().is_valid()) { + auto n = id(sntp_time).now(); + int hour = n.hour; + int nh = ${night_start_h}; + int eh = ${night_end_h}; + if (nh > eh) in_window = (hour >= nh) || (hour < eh); + else in_window = (hour >= nh) && (hour < eh); + } + if (!in_window) { + snprintf(await_buf, sizeof(await_buf), "%02d:00", ${night_start_h}); + id(next_spray_in_text).publish_state(std::string("Awaiting ") + await_buf); + } else { + id(next_spray_in_text).publish_state(countdown_txt); + } + } else if (op == "Day Only") { + bool in_window = false; + if (id(sntp_time).now().is_valid()) { + auto n = id(sntp_time).now(); + int hour = n.hour; + int nh = ${night_start_h}; + int eh = ${night_end_h}; + bool is_night; + if (nh > eh) is_night = (hour >= nh) || (hour < eh); + else is_night = (hour >= nh) && (hour < eh); + in_window = !is_night; // day is the opposite of night window + } + if (!in_window) { + snprintf(await_buf, sizeof(await_buf), "%02d:00", ${night_end_h}); + id(next_spray_in_text).publish_state(std::string("Awaiting ") + await_buf); + } else { + id(next_spray_in_text).publish_state(countdown_txt); + } + } else { + id(next_spray_in_text).publish_state(countdown_txt); + } + + # 2) Tick the countdown once per second until the target time + - while: + condition: + lambda: "return millis() < id(next_target_ms);" + then: + - lambda: |- + uint32_t rem_ms = id(next_target_ms) > millis() ? (id(next_target_ms) - millis()) : 0; + uint32_t sec = (rem_ms + 999u) / 1000u; // seconds, rounded up + id(next_spray_seconds).publish_state(sec); + uint32_t min = (sec + 59u) / 60u; // minutes, ceiling + char buf[16]; + snprintf(buf, sizeof(buf), "%u min", (unsigned)min); + std::string countdown_txt(buf); + + // Override text for specific modes + auto op = id(spray_operation).state; + char await_buf[16]; + + if (op == "Off") { + id(next_spray_in_text).publish_state("Disabled"); + } else if (op == "Night Only") { + bool in_window = false; + if (id(sntp_time).now().is_valid()) { + auto n = id(sntp_time).now(); + int hour = n.hour; + int nh = ${night_start_h}; + int eh = ${night_end_h}; + if (nh > eh) in_window = (hour >= nh) || (hour < eh); + else in_window = (hour >= nh) && (hour < eh); + } + if (!in_window) { + snprintf(await_buf, sizeof(await_buf), "%02d:00", ${night_start_h}); + id(next_spray_in_text).publish_state(std::string("Awaiting ") + await_buf); + } else { + id(next_spray_in_text).publish_state(countdown_txt); + } + } else if (op == "Day Only") { + bool in_window = false; + if (id(sntp_time).now().is_valid()) { + auto n = id(sntp_time).now(); + int hour = n.hour; + int nh = ${night_start_h}; + int eh = ${night_end_h}; + bool is_night; + if (nh > eh) is_night = (hour >= nh) || (hour < eh); + else is_night = (hour >= nh) && (hour < eh); + in_window = !is_night; + } + if (!in_window) { + snprintf(await_buf, sizeof(await_buf), "%02d:00", ${night_end_h}); + id(next_spray_in_text).publish_state(std::string("Awaiting ") + await_buf); + } else { + id(next_spray_in_text).publish_state(countdown_txt); + } + } else { + id(next_spray_in_text).publish_state(countdown_txt); + } + + // Midnight rollover check (via sntp_time) + if (id(sntp_time).now().is_valid()) { + auto n = id(sntp_time).now(); + int d = n.day_of_month; + if (id(last_day) == -1) { + // First valid time after boot: initialise without reset + id(last_day) = d; + } else if (id(last_day) != d) { + // New day -> reset today's counter + id(last_day) = d; + id(spray_count_today) = 0; + id(spray_count_today_sensor).publish_state(0); + } + } + - delay: 1s + + # 3) Check operation window; if allowed, attempt spray (cooldown enforced inside) + - lambda: |- + auto op = id(spray_operation).state; + bool allowed = false; + + if (op == "Off") { + allowed = false; + } else if (op == "24 Hours" || op == "On") { + allowed = true; + } else { + if (!id(sntp_time).now().is_valid()) { + allowed = false; // no time yet; be conservative + } else { + auto n = id(sntp_time).now(); + int hour = n.hour; // 0..23 + int nh = ${night_start_h}; + int eh = ${night_end_h}; + + bool is_night; + if (nh > eh) { + // window crosses midnight (e.g., 21:00..07:00) + is_night = (hour >= nh) || (hour < eh); + } else { + is_night = (hour >= nh) && (hour < eh); + } + + if (op == "Night Only") allowed = is_night; + else if (op == "Day Only") allowed = !is_night; + } + } + + if (allowed) ESP_LOGI("spray", "Window OK: attempting spray."); + else ESP_LOGI("spray", "Window blocked: skipping this cycle."); + + id(window_allowed) = allowed; + - if: + condition: + lambda: "return id(window_allowed);" + then: + - script.execute: try_spray_now + + + + + diff --git a/esphome/esp-rgblampbulb1.yaml b/esphome/esp-rgblampbulb1.yaml new file mode 100644 index 0000000..af94a22 --- /dev/null +++ b/esphome/esp-rgblampbulb1.yaml @@ -0,0 +1,258 @@ +########################################################################################## +########################################################################################## +# XCRhom.tech E27 9W RGBWW Smart Bulb +# +# # V1.0 2025-09-09 Initial Version +# +# Device https://www.aliexpress.com/item/1005007226730234.html +# Tasmota name AiYaTo-RGBCW +# +# GPIO Config +# ----- +# - Pin map mirrors original Tasmota config: +# PWM1=GPIO12 (R), PWM2=GPIO14 (G), PWM3=GPIO5 (B), +# PWM4=GPIO4 (CW), PWM5=GPIO13 (WW, inverted). +# +# 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-rgblampbulb1 + friendly_name: "RGBWW 9W E27 Smart Bulb" + description_comment: "RGBWW light bulb in bedroom 3 lamp" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Passwords If NOT using a secrets file, just replace these with the passwords etc (in quotes) + 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-rgblampbulb1_ip + + # Adjust the color temperature here (200 mired is approx 5000k) + white_temp: "3000K" + + # 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 + + # Adjust the ON/OFF times for flashing. + # 600ms on, 400ms off => 60% ON, 40% OFF duty cycle + on_time_ms: "500ms" + off_time_ms: "500ms" + +########################################################################################## +# PACKAGES: Included Common Packages +# https://esphome.io/components/packages.html +########################################################################################## +# Comment some of these out where not needed, eg MQTT, Web portal, SNTP, General Sensors +########################################################################################## +packages: + 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 + on_boot: + priority: 800 + then: + - light.turn_on: + id: my_light + brightness: 80% + color_temperature: ${white_temp} # e.g. "3000K" or "370 mireds" + transition_length: 3s + +######################################################################################### +# 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 + #restore_from_flash: true # restore some values on reboot + +mdns: + disabled: false # Disabling will make the build file smaller (and it is still available via static IP) + +preferences: + flash_write_interval: 20s + +######################################################################################### +# ESPHome Logging Enable +# https://esphome.io/components/logger.html +######################################################################################### +logger: + level: INFO # 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 + +########################################################################################## +# OUTPUT COMPONENT +# https://esphome.io/components/output/esp8266_pwm.html +########################################################################################## +output: + - platform: esp8266_pwm + id: output_red # PWM1 → GPIO12 + pin: GPIO12 + frequency: 1500 Hz + + - platform: esp8266_pwm + id: output_green # PWM2 → GPIO14 + pin: GPIO14 + frequency: 1500 Hz + + - platform: esp8266_pwm + id: output_blue # PWM3 → GPIO05 + pin: GPIO05 + frequency: 1500 Hz + + # Typically one channel is cold white... + - platform: esp8266_pwm + id: output_cold_white # PWM4 → GPIO04 + pin: GPIO04 + frequency: 1500 Hz + + # ...and one channel is warm white (inverted on GPIO13). + - platform: esp8266_pwm + id: output_warm_white # PWM5 → GPIO13 + pin: GPIO13 + frequency: 1500 Hz + inverted: true + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/ +########################################################################################## +light: + - platform: rgbww + name: ${friendly_name} + id: my_light + red: output_red + green: output_green + blue: output_blue + cold_white: output_cold_white + warm_white: output_warm_white + + # Keep total output reasonable on 9W bulbs and avoid mixing RGB with WW simultaneously. + constant_brightness: true + color_interlock: true + + # Typical white temperature mapping for RGBWW + cold_white_color_temperature: 6500 K + warm_white_color_temperature: 2700 K + + # Ensure it always powers on (and with our desired effect). + restore_mode: ALWAYS_ON + + # Optional: small gamma tweak for nicer dimming curves + gamma_correct: 2.4 + + # You can omit this or set it to zero for no fade on effect changes. + default_transition_length: 0s + + ###################################################################################### + # CALM EFFECTS + # - Night Light: steady warm, ~3% brightness + # - Breathe (Soft): slow, gentle brightness wave on current color + # - Amber Glow: very gentle warm amber wave + # - Blue Calm: subtle cool blue drift + # - Warm Dim: static warm preset around 15% + ###################################################################################### + effects: + # Night Light (steady warm ~3%) + - lambda: + name: "Night Light" + update_interval: 2s + lambda: |- + auto call = id(my_light).turn_on(); + call.set_brightness(0.03f); + // 2700K ≈ 370 mireds + call.set_color_temperature(370.0f); + call.set_transition_length(1000); + call.perform(); + + # Breathe (Soft) — gentle pulse on the *current* color + - pulse: + name: "Breathe (Soft)" + transition_length: 3s + update_interval: 3s + min_brightness: 5% + max_brightness: 35% + + # Amber Glow — very gentle warm wave (8–20%) + - lambda: + name: "Amber Glow" + update_interval: 500ms + lambda: |- + static float t = 0.0f; + t += 0.5f; // seconds step (approx) + float phase = (sinf(t * 2.0f * (3.14159f/16.0f)) + 1.0f) / 2.0f; // 16s cycle + float b = 0.08f + phase * 0.12f; // 8%..20% + auto call = id(my_light).turn_on(); + call.set_brightness(b); + // Warm amber tone via WW channel (keep RGB off) + call.set_color_temperature(400.0f); // ≈ 2500K-2800K feel + call.set_transition_length(800); + call.perform(); + + # Blue Calm — soft cool tint, tiny drift (6–14%) + - lambda: + name: "Blue Calm" + update_interval: 1000ms + lambda: |- + static float t = 0.0f; + t += 1.0f; + float phase = (sinf(t * 2.0f * (3.14159f/20.0f)) + 1.0f) / 2.0f; // 20s cycle + float b = 0.06f + phase * 0.08f; // 6%..14% + auto call = id(my_light).turn_on(); + call.set_brightness(b); + // Gentle cool tint using RGB to keep it soft + call.set_rgb(0.45f, 0.55f, 1.00f); + call.set_transition_length(1200); + call.perform(); + + # Warm Dim — static warm preset (~15%) + - lambda: + name: "Warm Dim" + update_interval: 5s + lambda: |- + auto call = id(my_light).turn_on(); + call.set_brightness(0.15f); + call.set_color_temperature(360.0f); // ~2777K + call.set_transition_length(800); + call.perform(); diff --git a/esphome/esp-rgblampbulb2.yaml b/esphome/esp-rgblampbulb2.yaml new file mode 100644 index 0000000..cf215bc --- /dev/null +++ b/esphome/esp-rgblampbulb2.yaml @@ -0,0 +1,427 @@ +########################################################################################## +########################################################################################## +# LB01 Athom 15W RGBCCT Bulb (ESP8266) - ESPHome +# +# V1.0 2025-09-09 Initial Version (Tasmota pinout import) +# +# Based on Tasmota template in screenshot: +# GPIO4 -> PWM 1 +# GPIO5 -> PWM 4 +# GPIO12 -> PWM 2 +# GPIO13 -> PWM_i 5 (inverted) +# GPIO14 -> PWM 3 +# +# Assumed channel roles (adjust if colors are swapped on test): +# PWM1 = Red, PWM2 = Green, PWM3 = Blue, +# PWM4 = Cold White, PWM5 = Warm White (inverted) +########################################################################################## +########################################################################################## + + +########################################################################################## +# 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-rgblampbulb2 + friendly_name: "Athom LB01 15W RGBCCT Bulb" + description_comment: "Athom RGBCCT bulb using Tasmota pin mapping" + device_area: "Bedroom 3" # Allows ESP device to be automatically linked to an 'Area' in Home Assistant. + + # Passwords If NOT using a secrets file, just replace these with the passwords etc (in quotes) + api_key: !secret esp-api_key + ota_pass: !secret esp-ota_pass + static_ip_address: !secret esp-rgblampbulb2_ip + + # Preferred warm color temperature (use K or mireds, e.g. "2700K" or "370 mireds") + white_temp: "3000K" + + # Device Settings + log_level: "INFO" # NONE, ERROR, WARN, INFO, DEBUG, VERBOSE, VERY_VERBOSE + update_interval: "60s" # general sensors update + + # Effect timing defaults + on_time_ms: "500ms" + off_time_ms: "500ms" + + # >>> PWM frequency for all channels (easy to adjust in one place) <<< + pwm_freq: "2000 Hz" + + # >>> ESPHome equivalent of Tasmota DimmerRange 24,100 <<< + # 0.24 = 24% minimum PWM when the light is ON. OFF still goes to 0. + dimmer_min_power: "0.24" + + +########################################################################################## +# PACKAGES: Included Common Packages +# https://esphome.io/components/packages.html +########################################################################################## +# Comment some of these out where not needed, eg MQTT, Web portal, SNTP, General Sensors +########################################################################################## +packages: + 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 + on_boot: + # Run late so it wins over everything (Wi-Fi, light init, restore, etc.) + priority: -10 + then: + - delay: 100ms + - lambda: |- + // Force WHITE mode @ 60% and 3000K (333 mireds) with no fade + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::WHITE); + call.set_brightness(0.60f); + call.set_color_temperature(333.0f); // 3000 K + call.set_transition_length(0); + call.perform(); +# Optional project metadata and 2MB flash map (uncomment if you confirm ESP8285 2MB) + project: + name: "China Athom Technology.Athom RGBCCT Bulb" + version: "v1.1.4" + platformio_options: + board_upload.flash_size: 2MB + board_upload.maximum_size: 2097152 + board_build.ldscript: eagle.flash.2m.ld + +######################################################################################### +# ESP Platform and Framework +# https://esphome.io/components/esp8266.html +######################################################################################### +esp8266: + board: esp8285 + 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 + #restore_from_flash: true # restore some values on reboot + +mdns: + disabled: false # Disabling will make the build file smaller (and it is still available via static IP) + +#preferences: + #flash_write_interval: 2s + + + +######################################################################################### +# ESPHome Logging Enable +# https://esphome.io/components/logger.html +######################################################################################### +logger: + level: ${log_level} + #baud_rate: 0 # set to 0 for no logging via UART, needed if you are using it for other serial things (eg PZEM) + #esp8266_store_log_strings_in_flash: false + #tx_buffer_size: 64 + + +########################################################################################## +# OUTPUT COMPONENT +########################################################################################## +output: + - platform: esp8266_pwm + id: output_red # PWM1 -> GPIO4 + pin: GPIO4 + frequency: ${pwm_freq} + min_power: 0.000499 + max_power: 1 + zero_means_zero: true + + - platform: esp8266_pwm + id: output_green # PWM2 -> GPIO12 + pin: GPIO12 + frequency: ${pwm_freq} + min_power: 0.000499 + max_power: 1 + zero_means_zero: true + + - platform: esp8266_pwm + id: output_blue # PWM3 -> GPIO14 + pin: GPIO14 + frequency: ${pwm_freq} + min_power: 0.000499 + max_power: 1 + zero_means_zero: true + + - platform: esp8266_pwm + id: output_cold_white # PWM4 -> GPIO5 + pin: GPIO5 + frequency: ${pwm_freq} + min_power: 0.01 + max_power: 0.9 + zero_means_zero: true + + - platform: esp8266_pwm + id: output_warm_white # PWM5 -> GPIO13 (inverted) + pin: GPIO13 + frequency: ${pwm_freq} + inverted: true + min_power: 0.01 + max_power: 0.9 + zero_means_zero: true + +########################################################################################## +# DIAGNOSTIC BUTTONS: Force individual channels (bypass light logic) +########################################################################################## +########################################################################################## +# DIAGNOSTIC BUTTONS (use light API, not raw PWMs) +########################################################################################## +button: + - platform: template + name: "Test WW 100%" + on_press: + then: + - light.turn_on: + id: my_light + brightness: 100% + color_temperature: 3000 K + transition_length: 0s + + - platform: template + name: "Test CW 100%" + on_press: + then: + - light.turn_on: + id: my_light + brightness: 100% + color_temperature: 6000 K + transition_length: 0s + + - platform: template + name: "All OFF (light)" + on_press: + then: + - light.turn_off: + id: my_light + transition_length: 0s + + + +########################################################################################## +# LIGHT COMPONENT +# https://esphome.io/components/light/ +########################################################################################## +light: + - platform: rgbct + id: my_light + name: ${friendly_name} + restore_mode: RESTORE_DEFAULT_OFF + red: output_red + green: output_green + blue: output_blue + white_brightness: output_cold_white # GPIO5 + color_temperature: output_warm_white # GPIO13 (inverted) + + # Keep total output reasonable on 15W bulbs and avoid mixing RGB with WW simultaneously. + color_interlock: true + + # Typical white temperature mapping for RGBWW + cold_white_color_temperature: 6000 K + warm_white_color_temperature: 3000 K + + # Do NOT restore last color at boot; on_boot shapes warm 60% only after power loss +# restore_mode: RESTORE_DEFAULT_OFF + + # Optional: small gamma tweak for nicer dimming curves +# gamma_correct: 2.4 + + # Default fade for normal changes; boot uses its own 3s transition above. + default_transition_length: 1s + + ###################################################################################### + # CALM EFFECTS + # - Night Light: steady warm, ~3% brightness + # - Breathe (Soft): slow, gentle brightness wave on current color + # - Amber Glow: very gentle warm amber wave + # - Blue Calm: subtle cool blue drift + # - Warm Dim: static warm preset around 15% + ###################################################################################### + effects: + # Night Light (steady warm ~3%) + - lambda: + name: "Night Light" + update_interval: 2s + lambda: |- + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::WHITE); + call.set_brightness(0.03f); + call.set_color_temperature(333.0f); // ~3000K + call.set_transition_length(1000); + call.perform(); + + # Breathe (Soft) — gentle pulse on the current color + - pulse: + name: "Breathe (Soft)" + transition_length: 3s + update_interval: 3s + min_brightness: 5% + max_brightness: 35% + + # Amber Glow — very gentle warm wave (8–20%) + - lambda: + name: "Amber Glow" + update_interval: 500ms + lambda: |- + static float t = 0.0f; + t += 0.5f; // seconds step (approx) + float phase = (sinf(t * 2.0f * (3.14159f/16.0f)) + 1.0f) / 2.0f; // ~16s cycle + float b = 0.08f + phase * 0.12f; // 8%..20% + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::WHITE); + call.set_brightness(b); + call.set_color_temperature(333.0f); // 3000K + call.set_transition_length(800); + call.perform(); + + # Pastel Cycle — very slow, soft rainbow (~12–20% brightness) + - lambda: + name: "Pastel Cycle" + update_interval: 1000ms + lambda: |- + static float t = 0.0f; + t += 1.0f; // seconds + const float period = 120.0f; // 120s full cycle + float w = 2.0f * 3.14159f / period; + // Three sine waves 120° apart for a pastel rainbow + float r = 0.35f + 0.25f * sinf(w * t + 0.0f); + float g = 0.35f + 0.25f * sinf(w * t + 2.094f); + float b = 0.35f + 0.25f * sinf(w * t + 4.188f); + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::RGB); + call.set_brightness(0.18f); + call.set_rgb(r, g, b); + call.set_transition_length(1200); + call.perform(); + + # Ocean Fade — teal↔blue drift (~10–18% brightness) + - lambda: + name: "Ocean Fade" + update_interval: 1200ms + lambda: |- + static float t = 0.0f; + t += 1.2f; + float phase = (sinf(t * 2.0f * (3.14159f/36.0f)) + 1.0f) / 2.0f; // ~36s cycle + // Lerp between teal (0.0,0.6,0.6) and blue (0.25,0.45,1.0) + float r = (1.0f - phase) * 0.00f + phase * 0.25f; + float g = (1.0f - phase) * 0.60f + phase * 0.45f; + float b = (1.0f - phase) * 0.60f + phase * 1.00f; + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::RGB); + call.set_brightness(0.16f); + call.set_rgb(r, g, b); + call.set_transition_length(1400); + call.perform(); + + # Sunset Drift — peach↔soft amber (~12–22% brightness) + - lambda: + name: "Sunset Drift" + update_interval: 1000ms + lambda: |- + static float t = 0.0f; + t += 1.0f; + float phase = (sinf(t * 2.0f * (3.14159f/40.0f)) + 1.0f) / 2.0f; // ~40s + // Peach (1.0,0.65,0.50) to Amber (1.0,0.75,0.30) + float r = 1.00f; + float g = (1.0f - phase) * 0.65f + phase * 0.75f; + float b = (1.0f - phase) * 0.50f + phase * 0.30f; + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::RGB); + call.set_brightness(0.20f); + call.set_rgb(r, g, b); + call.set_transition_length(1200); + call.perform(); + + # Lavender Breeze — lavender↔rose (~10–18% brightness) + - lambda: + name: "Lavender Breeze" + update_interval: 1200ms + lambda: |- + static float t = 0.0f; + t += 1.2f; + float phase = (sinf(t * 2.0f * (3.14159f/48.0f)) + 1.0f) / 2.0f; // ~48s + // Lavender (0.70,0.55,1.00) to Rose (1.00,0.60,0.85) + float r = (1.0f - phase) * 0.70f + phase * 1.00f; + float g = (1.0f - phase) * 0.55f + phase * 0.60f; + float b = (1.0f - phase) * 1.00f + phase * 0.85f; + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::RGB); + call.set_brightness(0.15f); + call.set_rgb(r, g, b); + call.set_transition_length(1400); + call.perform(); + + # Forest Calm — moss↔mint (~8–16% brightness) + - lambda: + name: "Forest Calm" + update_interval: 1000ms + lambda: |- + static float t = 0.0f; + t += 1.0f; + float phase = (sinf(t * 2.0f * (3.14159f/44.0f)) + 1.0f) / 2.0f; // ~44s + // Moss (0.25,0.55,0.25) to Mint (0.50,0.95,0.65) + float r = (1.0f - phase) * 0.25f + phase * 0.50f; + float g = (1.0f - phase) * 0.55f + phase * 0.95f; + float b = (1.0f - phase) * 0.25f + phase * 0.65f; + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::RGB); + call.set_brightness(0.14f); + call.set_rgb(r, g, b); + call.set_transition_length(1200); + call.perform(); + + # Blue Calm — soft cool tint, tiny drift (6–14%) + - lambda: + name: "Blue Calm" + update_interval: 1000ms + lambda: |- + static float t = 0.0f; + t += 1.0f; + float phase = (sinf(t * 2.0f * (3.14159f/20.0f)) + 1.0f) / 2.0f; // ~20s cycle + float b = 0.06f + phase * 0.08f; // 6%..14% + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::RGB); + call.set_brightness(b); + call.set_rgb(0.45f, 0.55f, 1.00f); // gentle cool bluish tint + call.set_transition_length(1200); + call.perform(); + + # Warm Dim — static warm preset (~15%) + - lambda: + name: "Warm Dim" + update_interval: 5s + lambda: |- + auto call = id(my_light).turn_on(); + call.set_color_mode(ColorMode::WHITE); + call.set_brightness(0.15f); + call.set_color_temperature(333.0f); // ~3000K + call.set_transition_length(800); + call.perform(); diff --git a/packages/alexa_tplink_actions.yaml b/packages/alexa_tplink_actions.yaml index 11cdd2a..d0ac97c 100644 --- a/packages/alexa_tplink_actions.yaml +++ b/packages/alexa_tplink_actions.yaml @@ -1,37 +1,42 @@ automation: - alias: "Turn on the Wifi Guest Network" - trigger: - platform: state - entity_id: input_boolean.wifi_guest_network - to: "on" - action: - service: media_player.play_media - target: - entity_id: media_player.view_rd_kitchen_echo_show - data: - media_content_type: "custom" - media_content_id: "ask t.p.link to enable guest network" - - alias: "Turn off the Wifi Guest Network" - trigger: - platform: state - entity_id: input_boolean.wifi_guest_network - to: "off" - action: - service: media_player.play_media - target: - entity_id: media_player.view_rd_kitchen_echo_show - data: - media_content_type: "custom" - media_content_id: "ask t.p.link to disable guest network" - - alias: "Switch guest network off after time" - trigger: - platform: state - entity_id: input_boolean.wifi_guest_network - from: "off" - to: "on" - for: "02:00:00" - condition: [] - action: - service: input_boolean.turn_off - entity_id: input_boolean.wifi_guest_network mode: single + triggers: + - trigger: state + entity_id: input_boolean.wifi_guest_network + to: "on" + actions: + - action: media_player.play_media + target: + entity_id: media_player.view_rd_kitchen_echo_show + data: + media_content_type: custom + media_content_id: ask t.p.link to enable guest network + + - alias: "Turn off the Wifi Guest Network" + mode: single + triggers: + - trigger: state + entity_id: input_boolean.wifi_guest_network + to: "off" + actions: + - action: media_player.play_media + target: + entity_id: media_player.view_rd_kitchen_echo_show + data: + media_content_type: custom + media_content_id: ask t.p.link to disable guest network + + - alias: "Switch guest network off after time" + mode: single + triggers: + - trigger: state + entity_id: input_boolean.wifi_guest_network + from: "off" + to: "on" + for: "02:00:00" + conditions: [] + actions: + - action: input_boolean.turn_off + target: + entity_id: input_boolean.wifi_guest_network diff --git a/packages/pool_controls.yaml b/packages/pool_controls.yaml deleted file mode 100644 index aeb2610..0000000 --- a/packages/pool_controls.yaml +++ /dev/null @@ -1,32 +0,0 @@ -input_select: - pool_light_colour_select: - icon: mdi:swimming-pool - name: Pool Light Colour - initial: "Off" - options: - - "Off" - - "Dk Blue" - - "Red" - - "Green" - - "Lt Blue" - - "Disco" - - "9" - - "10" - - "11" - - "12" - - "13" - -automation: - - id: set_the_pool_light_colour - alias: Set the Pool Light Colour - trigger: - entity_id: input_select.pool_light_colour_select - platform: state - action: - service: mqtt.publish - data: - topic: viewroad-commands/poolcontrols/poollightcolour - payload: '{% set mapping = { "Off":"0", "Dk Blue":"1", - "Red":"2", "Green":"3", "4":"4" ,"Lt Blue":"5", "6":"6", "7":"7", "Disco":"8", "9":"9", "10":"10", "11":"11", "12":"12", "13":"13" } %} {% set dta = trigger.to_state.state %} - {{ mapping[dta] }} - ' diff --git a/packages/robotdyn_dimmers.yaml b/packages/robotdyn_dimmers.yaml new file mode 100644 index 0000000..41ff2c7 --- /dev/null +++ b/packages/robotdyn_dimmers.yaml @@ -0,0 +1,12 @@ +mqtt: + - light: + schema: json + name: "Lounge Dimmer" + unique_id: lounge_dimmer_1 + state_topic: "livingroom/dimmer" + command_topic: "livingroom/dimmer/set" + availability: + - topic: "livingroom/availability" + brightness: true + supported_color_modes: ["brightness"] + retain: true diff --git a/scripts/check_config.yaml b/scripts/check_config.yaml deleted file mode 100644 index 5e0df46..0000000 --- a/scripts/check_config.yaml +++ /dev/null @@ -1,3 +0,0 @@ -#check_config: -# sequence: [] -# alias: Check Configuration