From 4e382bbb876d5976afc48d38da98ad2a0898e5fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Koco=C5=84?= Date: Mon, 23 Feb 2026 23:38:01 +0100 Subject: [PATCH] upload --- README.md | 23 + TRVZB and External sensor.yaml | 89 + dynamic_valve.yaml | 128 + dynamic_valve_test.yaml | 199 + dynamic_valve_test_na_kurwie.yaml | 3680 +++++++++++++ helloworld.yaml | 1 + motion_light.yaml | 62 + smart-light.yaml | 7969 +++++++++++++++++++++++++++++ test.yaml | 75 + 9 files changed, 12226 insertions(+) create mode 100644 README.md create mode 100644 TRVZB and External sensor.yaml create mode 100644 dynamic_valve.yaml create mode 100644 dynamic_valve_test.yaml create mode 100644 dynamic_valve_test_na_kurwie.yaml create mode 100644 helloworld.yaml create mode 100644 motion_light.yaml create mode 100644 smart-light.yaml create mode 100644 test.yaml diff --git a/README.md b/README.md new file mode 100644 index 0000000..d1cf60a --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# HA - Bluerpints + +Home Assistant Blueprints repository for automating smart home tasks. + +## Project Info +- **Repo:** https://gitlab.domowyasystent.com/peakcontroll/ha-bluerpints +- **Created:** January 3, 2026 +- **Auto DevOps:** Enabled + +## Usage +1. Browse the available blueprints in this repository. +2. Import the desired blueprint into your Home Assistant instance. +3. Customize triggers and actions as needed for your devices. + +[![Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.](https://my.home-assistant.io/badges/blueprint_import.svg)](https://my.home-assistant.io/redirect/blueprint_import/?blueprint_url=https%3A%2F%2Fgitlab.domowyasystent.com%2Fpeakcontroll%2Fha-bluerpints%2F-%2Fraw%2Fmain%2FTRVZB+and+External+sensor.yaml?) + +## Contributing +- Fork the repo and create a branch for your changes. +- Submit a merge request with clear description of the new blueprint or improvement. + +## License +Specify your license here (e.g., MIT, Apache 2.0). + diff --git a/TRVZB and External sensor.yaml b/TRVZB and External sensor.yaml new file mode 100644 index 0000000..da1bafc --- /dev/null +++ b/TRVZB and External sensor.yaml @@ -0,0 +1,89 @@ +blueprint: + name: Sonoff TRVZB & Zewnętrzny czujnik temperatury + description: > + + PeakControl Sonoff Głowica - TRVZB & Zewnętrzny czujnik temperatury 👈 + + +
+ The Automation Process: 👈 + + **Automatyzacja synchronizuje temperaturę z wybranego czujnika:** + **z urządzeniem wykorzystującym tryb „external”.** + + + **Działanie:** + + - uruchamia się co 2 minuty ORAZ przy każdej zmianie temperatury czujnika + - sprawdza, czy czujnik zwraca poprawną wartość (nie unknown / unavailable) + - ustawia select.* na opcję „external” + - po 5 sekundach wpisuje aktualną temperaturę z czujnika do number.* + + **Typowe użycie:** + + - głowice / termostaty z trybem external temperature + - przekazywanie temperatury z zewnętrznego sensora do urządzenia + +
+ domain: automation + input: + temperature_sensor: + name: Czujnik temperatury + selector: + entity: + filter: + domain: sensor + device_class: temperature + + target_number: + name: Number (Głowica - nastawienie temperatury) + selector: + entity: + filter: + domain: number + device_class: temperature + + + target_select: + name: Select (Głowica) + selector: + entity: + filter: + domain: + - select + +trigger: + - platform: time_pattern + minutes: "/2" + + - platform: state + entity_id: !input temperature_sensor + +variables: + set_temperature_sensor: !input temperature_sensor + +condition: + - condition: template + value_template: > + {{ states(set_temperature_sensor) not in ['unknown', 'unavailable'] }} + +action: + - service: select.select_option + target: + entity_id: !input target_select + data: + option: external + + - delay: + hours: 0 + minutes: 0 + seconds: 5 + milliseconds: 0 + + - service: number.set_value + target: + entity_id: !input target_number + data: + value: "{{ states(set_temperature_sensor) | float }}" + +mode: single diff --git a/dynamic_valve.yaml b/dynamic_valve.yaml new file mode 100644 index 0000000..262d027 --- /dev/null +++ b/dynamic_valve.yaml @@ -0,0 +1,128 @@ +blueprint: + name: Dynamic Radiator Valve + description: Automatically sets radiator valve closing/opening degree based on temperature difference and window status + domain: automation + + input: + radiator_climate: + name: Radiator (climate) + selector: + entity: + domain: climate + + temperature_sensor: + name: Temperature Sensor + selector: + entity: + domain: sensor + + valve_closing_number: + name: Valve Closing Number + selector: + entity: + domain: number + + valve_opening_number: + name: Valve Opening Number (optional) + default: null + selector: + entity: + domain: number + + window_sensor: + name: Window Sensor / Input Boolean + selector: + entity: + domain: + - binary_sensor + - input_boolean + + difference_text: + name: Temperature Difference (optional) + default: null + selector: + entity: + domain: input_text + +triggers: + + - platform: state + entity_id: !input radiator_climate + + - platform: state + entity_id: !input temperature_sensor + + - platform: state + entity_id: !input window_sensor + + - platform: time_pattern + minutes: "/1" + +#conditions: +# - condition: template +# value_template: > +# {{ states(climate_entity) not in ['unavailable', 'unknown'] }} + +actions: + - variables: + climate_entity: !input radiator_climate + temp_entity: !input temperature_sensor + window_entity: !input window_sensor + closing_entity: !input valve_closing_number + opening_entity: !input valve_opening_number + diff_text_entity: !input difference_text + + - variables: + window_closed: "{{ states(window_entity) in ['off', 'false', 'closed'] }}" + + - choose: + - conditions: + - condition: template + value_template: "{{ window_closed }}" + sequence: + - variables: + target: "{{ state_attr(climate_entity, 'temperature') | float(0) }}" + current: "{{ states(temp_entity) | float(0) }}" + diff: "{{ current - target }}" + closing_degree: > + {% if diff >= 1.0 %} 100 + {% elif diff >= 0.5 %} 80 + {% elif diff >= 0.0 %} 60 + {% elif diff >= -1.0 %} 50 + {% else %} 30 + {% endif %} + + - conditions: + - condition: template + value_template: "{{ not window_closed }}" + sequence: + - variables: + closing_degree: 0 + + - variables: + valve_entities: > + {% if opening_entity %} + {{ [closing_entity, opening_entity] }} + {% else %} + {{ [closing_entity] }} + {% endif %} + + - service: number.set_value + target: + entity_id: "{{ valve_entities }}" + data: + value: "{{ closing_degree }}" + + - choose: + - conditions: + - condition: template + value_template: "{{ diff_text_entity != None }}" + sequence: + - service: input_text.set_value + target: + entity_id: "{{ diff_text_entity }}" + data: + value: "{{ closing_degree }}" + +mode: queued +max: 5 diff --git a/dynamic_valve_test.yaml b/dynamic_valve_test.yaml new file mode 100644 index 0000000..22cd978 --- /dev/null +++ b/dynamic_valve_test.yaml @@ -0,0 +1,199 @@ +blueprint: + name: Dynamic Radiator Valve – Pro Configurator + description: > + Automatyczne sterowanie zaworem grzejnika na podstawie temperatury, + różnicy temperatur oraz statusu okna. + domain: automation + +input: + radiator_climate: + name: Radiator (Climate) + description: Wybierz urządzenie klimatyczne (np. termostat grzejnika) + selector: + entity: + domain: climate + + temperature_sensor: + name: Temperature Sensor + description: Sensor aktualnej temperatury w pomieszczeniu + selector: + entity: + domain: sensor + + window_sensor: + name: Window Sensor / Input Boolean + description: Określ czujnik stanu okna lub pomocniczy input boolean + selector: + entity: + domain: - binary_sensor + - input_boolean + + valve_closing_number: + name: Valve Closing Number + description: Number entity służąca do ustawiania poziomu zamknięcia zaworu + selector: + entity: + domain: number + + valve_opening_number: + name: Valve Opening Number (optional) + description: (opcjonalnie) number entity do otwierania zaworu + default: null + selector: + entity: + domain: number + + difference_text: + name: Temperature Difference (optional) + description: (opcjonalnie) input_text do zapisywania aktualnej różnicy + default: null + selector: + entity: + domain: input_text + + # Advanced Options + min_diff_threshold: + name: Min Difference Threshold + description: Minimalna różnica względem target do otwarcia zaworu + default: 0.0 + selector: + number: + unit_of_measurement: '°C' + min: -5 + max: 5 + step: 0.1 + + max_diff_threshold: + name: Max Difference Threshold + description: Maksymalna różnica do pełnego zamknięcia zaworu + default: 2.0 + selector: + number: + unit_of_measurement: '°C' + min: 0 + max: 10 + step: 0.1 + + window_override: + name: Window Open Override + description: Gdy okno otwarte, czy zawory powinny zostać zamknięte? + default: true + selector: + boolean: {} + + weekdays: + name: Operate on Weekdays + description: Wybierz dni, w których automatyka ma działać + default: ['mon','tue','wed','thu','fri','sat','sun'] + selector: + select: + multiple: true + options: + - label: Monday + value: mon + - label: Tuesday + value: tue + - label: Wednesday + value: wed + - label: Thursday + value: thu + - label: Friday + value: fri + - label: Saturday + value: sat + - label: Sunday + value: sun + + active_time: + name: Active Time Range + description: Określ ramy czasowe działania automatyki (opcjonalne) + selector: + time: + start: true + end: true + +trigger: + - platform: state + entity_id: !input radiator_climate + - platform: state + entity_id: !input temperature_sensor + - platform: state + entity_id: !input window_sensor + - platform: time_pattern + minutes: "/1" + +condition: + - condition: time + weekday: !input weekdays + - condition: template + value_template: > + {{ states(!input radiator_climate) not in ['unavailable','unknown'] }} + +action: + - variables: + climate_entity: !input radiator_climate + temp_entity: !input temperature_sensor + window_entity: !input window_sensor + closing_entity: !input valve_closing_number + opening_entity: !input valve_opening_number + diff_text_entity: !input difference_text + min_diff: !input min_diff_threshold + max_diff: !input max_diff_threshold + override_open: !input window_override + + - variables: + target_temp: "{{ state_attr(climate_entity,'temperature')|float(0) }}" + current_temp: "{{ states(temp_entity)|float(0) }}" + diff: "{{ current_temp - target_temp }}" + + - choose: + - conditions: + - condition: template + value_template: > + {{ override_open and (states(window_entity) in ['on','true','open']) }} + sequence: + - variables: + closing_degree: 0 + + - conditions: + - condition: template + value_template: > + {{ diff >= max_diff }} + sequence: + - variables: + closing_degree: 100 + + - conditions: + - condition: template + value_template: > + {{ diff <= min_diff }} + sequence: + - variables: + closing_degree: 30 + + default: + - variables: + closing_degree: > + {{ ((diff - min_diff) / (max_diff - min_diff) * 100) | round(0) }} + + - service: number.set_value + data: + value: "{{ closing_degree }}" + target: + entity_id: > + {% if opening_entity %} + [{{ closing_entity }}, {{ opening_entity }}] + {% else %} + {{ closing_entity }} + {% endif %} + + - choose: + - conditions: + - condition: template + value_template: "{{ diff_text_entity != None }}" + sequence: + - service: input_text.set_value + data: + value: "{{ diff }}" + target: + entity_id: "{{ diff_text_entity }}" diff --git a/dynamic_valve_test_na_kurwie.yaml b/dynamic_valve_test_na_kurwie.yaml new file mode 100644 index 0000000..9983d85 --- /dev/null +++ b/dynamic_valve_test_na_kurwie.yaml @@ -0,0 +1,3680 @@ +blueprint: + name: 🔥 Advanced Heating Control V5 + author: panhans + homeassistant: + min_version: "2024.10.0" + description: > + 🔥 room based heating / ❄ based on + + + > 👥 people presence + + 🗓️ multiple schedulers + + 🚶 presence sensor + + ↔️ proximity aka geo fencing + + + 🥶 frost protection + + 😡 adjustable aggressive mode + + 🌤️ activation based on weather, temperature or boolean entities + + 🎛️ granular schedule adjustments + + 🪟 multiple window open detection + + 🎈 party mode + + 🤝 guest mode + + ⚔️ liming protection + + 📍 dynamic valve positioning + + 🧭 thermostat calibration for the most common devices (Tado, Aqara, Popp / Danfoss / Hive, Tuya) + + ⚙️ several tweaks for fixing your thermostat issues + + 🎬 custom action + + 🤫 calm & 💪 reliable + + + **Ensure that you have installed the uptime integration:** + + [![Open your Home Assistant instance and show an integration.](https://my.home-assistant.io/badges/integration.svg)](https://my.home-assistant.io/redirect/integration/?domain=uptime) + + + **Version**: 5.4.3 + + **Help & FAQ**: [Advanced Heating Control](https://community.home-assistant.io/t/advanced-heating-control/469873) + + **Documentation:** [panhans.github.io/HomeAssistant/](https://panhans.github.io/HomeAssistant/) + + + [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/Q5Q3QEH52) + source_url: https://github.com/panhans/HomeAssistant/blob/main/blueprints/automation/panhans/advanced_heating_control.yaml + domain: automation + input: + thermostat_section: + name: Thermostats & Sensors + icon: mdi:thermostat + input: + input_trvs: + name: 🔥 Thermostats / Climates + description: > + `thermostats` `climates` + + + [Thermostats / Climates](https://www.home-assistant.io/integrations/climate/) to be controlled. + selector: + entity: + filter: + - domain: + - climate + multiple: true + + input_hvac_mode: + name: 🎛️ Operation / HVAC Mode + description: > + `hvac` + + + Select the hvac mode for your [thermostats](https://www.home-assistant.io/integrations/climate/). Be sure your selected thermostats support the hvac mode you've chosen. + AHC will log a warning if there is a miss match. For radiator [thermostats]((https://www.home-assistant.io/integrations/climate/)) the default is mostly *heat*. + If you own an air conditioner it will support *auto* or *cool*, too. + default: "heat" + selector: + select: + options: + - heat + - cool + - auto + - heat_cool + + input_temperature_sensor: + name: 🌡️ Room Temperature Sensor + description: > + `calibration` `aggressive mode` `optional` + + + For some features an external temperature sensor is reqired, e.g. calibration. + + Temperature calibration for your [thermostats](https://www.home-assistant.io/integrations/climate/). The following is supported: + + * Tado, Aqara, Popp, Danfoss, Hive, Bosch, SONOFF, Tuya + * generic calibration + + Note: This is an additional sensor inside your room usually next to your favourite spot. [Thermostats](https://www.home-assistant.io/integrations/climate/) or its integration (e.g. Z2M or ZHA) except Tado should provide a seperate calibration entity. + default: [] + selector: + entity: + filter: + - domain: + - sensor + device_class: + - temperature + multiple: false + + temperature_section: + name: Temperatures + icon: mdi:thermometer + collapsed: true + input: + input_temperature_comfort_static: + name: 🛋️ Static Comfort Temperature + description: > + `comfort temperature` + + + You can set a static comfort temperature here. + default: 22 + selector: + number: + min: 12.0 + max: 86.0 + step: 0.5 + mode: box + unit_of_measurement: °C / °F + + input_temperature_eco_static: + name: 🌱 Static Eco Temperature + description: > + `eco temperature` + + + The temperature that is set when your heating schedule is not active. + default: 19 + selector: + number: + min: 4.0 + max: 75.0 + step: 0.5 + mode: box + unit_of_measurement: °C / °F + + input_temperature_comfort: + name: 🛋️ Comfort Temperature + description: > + `comfort temperature` `optional` + + + To control your comfort temperature via automations or the UI, you can specify an *[input_number](https://www.home-assistant.io/integrations/input_number/)* entity here. + + + Create your helper [here](https://my.home-assistant.io/redirect/helpers/). + default: [] + selector: + entity: + filter: + - domain: + - input_number + multiple: false + + input_temperature_eco: + name: 🌱 Eco Temperature + description: > + `eco temperature` `optional` + + + To control your eco temperature via automations or the UI, you can specify an *[input_number](https://www.home-assistant.io/integrations/input_number/)* entity here. + + + Create your helper [here](https://my.home-assistant.io/redirect/helpers/). + default: [] + selector: + entity: + filter: + - domain: + - input_number + multiple: false + + adjustment_section: + name: Adjustments / Heating Plan + icon: mdi:sun-clock + collapsed: true + input: + input_adjustments: + name: 🎛️ Heating Schedule Adjustments + description: > + `optional` + + + Here you can setup some adjustments to your heating schedule.

+ *Note*: Here you can set values for eco or comfort temperature. The switch between those target temperatures is controled by schedules, presence sensors, proximity, ect. +
+ +
+ CLICK HERE: Modifiers +
+ + + > 🕔 **time** + + > Timestamp when the adjustment should kick in. (required) + + + > 📆 **days** + + > Select days where this setting shall be enabled. + + > ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'] + + + > 🗓️ **scheduler** + + > Only enable this entry if this string is part of the name of your active scheduler. + + + > 🛋️ **comfort** + + > Adjust comfort temperature + + + > 🌱 **eco** + + > Adjust eco temperature + + + > 🧭 **calibration** + + > Toggle calibration + + > on/off + + + > 🔘 **mode** + + > Overwrite the operation mode + + > comfort/eco/off/auto (auto means no overwrite) + + +
+ +
+ +
+ CLICK HERE: Example +
+ + + ```yaml + + - time: "08:00" + comfort: "20" + calibration: "off" + - time: "16:00" + eco: "19" + calibration: "on" + - time: "20:00" + days: ['Sat','Sun'] + scheduler: 'Holidays' + comfort: "24" + eco: "17" + ``` + +
+ + selector: + object: + default: "[]" + + # modes + mode_section: + name: Force Comfort/Eco Mode + icon: mdi:fire + collapsed: true + input: + input_mode_party: + name: 🎈 Party mode + description: > + `optional` + + + If on, all settings are ignored and heating takes place. You can define multiple [timers](https://www.home-assistant.io/integrations/timer/) or boolean entities. + If you put a number at the end of the friendly name like *Party Timer 20* this number will be taken as the desired comfort temperature for this [timer](https://www.home-assistant.io/integrations/timer/). + + + Create your timer [here](https://my.home-assistant.io/redirect/helpers/). + default: [] + selector: + entity: + filter: + - domain: + - input_boolean + - binary_sensor + - timer + multiple: true + + input_force_max_temperature: + name: 🥵 Force Max Temperature + description: > + `optional` + + + Set the maximum temperature of all [thermostats](https://www.home-assistant.io/integrations/climate/) regardless of any other settings. + + + **HINT:** Implemented by developer for maintenance reasons. Create your helper [here](https://my.home-assistant.io/redirect/helpers/). + default: [] + selector: + entity: + filter: + - domain: + - input_boolean + - binary_sensor + multiple: false + + input_force_eco_temperature: + name: 🌱 Force Eco Temperature + description: > + `optional` + + + If enabled *eco* temperature will be forced. + default: [] + selector: + entity: + filter: + - domain: + - input_boolean + - binary_sensor + multiple: false + + input_party_legacy_restore: + name: 🔄 Legacy Restore + description: > + `party` + + + Enable this if the temperatures after airing (closing windows) or party won't restore properly + default: false + selector: + boolean: + + temperature_tweak_section: + name: Temperature Tweaks + icon: mdi:knob + collapsed: true + input: + input_off_instead_of_eco: + name: 🛑 Off Instead Of Eco + description: > + `optional` `temperature tweak` + + + Turn off your [thermostats](https://www.home-assistant.io/integrations/climate/) instead of lower the target temperature to eco temperature. + default: false + selector: + boolean: + + input_min_instead_of_off: + name: ⬇️ Min Instead Of Off + description: > + `optional` `temperature tweak` + + + Lower the temperature instead of turning them *OFF*, e.g. during airing. + default: false + selector: + boolean: + + input_fahrenheit: + name: 🇫 Fahrenheit + description: > + `optional` `temperature tweak` + + + Enable this if your unit of measurement is Fahrenheit (untested). + default: false + selector: + boolean: + + input_reset_temperature: + name: ↩️ Reset Temperature + description: > + `optional` `temperature tweak` + + + Reset your temperature entities to the values of the static temperatures after [schedule](https://www.home-assistant.io/integrations/schedule/), [proximity](https://www.home-assistant.io/integrations/proximity/), [people](https://www.home-assistant.io/integrations/person/), presence ends. + The comfort entity is reset when eco takes place and vice versa. + default: false + selector: + boolean: + + input_off_if_above_room_temperature: + name: ↕️ Off If Above/Below Room Temperature + description: > + + Turns your [climate](https://www.home-assistant.io/integrations/climate/) entity *off* if the target temperature is below(cooling) / above(heating) the room temperature. + + default: false + selector: + boolean: + + input_off_if_nobody_home: + name: 🏠🚶‍➡️ Off If Nobody Home + description: > + + Turns your [climate](https://www.home-assistant.io/integrations/climate/) entity *off* if persons are set and nobody is home. + + default: false + selector: + boolean: + + input_physical_change: + name: 🧪 Physical Temperature Change / Sync (experimental) + description: > + `optional` `temperature tweak` + + + Enable this if your want to adjust the temperature using your thermostat or thermostat card. Make sure aggressive mode and generic calibration is disabled for this feature. (experimental). + You also need to set entities for eco and comfort temperature for the moment. + default: false + selector: + boolean: + + # persons + person_section: + name: Persons + icon: mdi:account-multiple + collapsed: true + input: + input_persons: + name: 👥 Persons + description: > + `person` `optional` + + + You can specify [persons](https://www.home-assistant.io/integrations/person/) to make your heating plan more dynamic. If you do not use [schedulers](https://www.home-assistant.io/integrations/schedule/) or presence sensors, heating is activated as soon as someone is at home.
+ With [schedulers](https://www.home-assistant.io/integrations/schedule/) or presence sensors, these are only active when someone is at home. + default: [] + selector: + entity: + filter: + - domain: + - person + multiple: true + + input_people_entering_home_duration: + name: 🏠 Enter Home Duration + description: > + `person` + + + Duration for which someone must be at home for heating to be activated. + default: + hours: 0 + minutes: 0 + seconds: 2 + selector: + duration: + + input_people_leaving_home_duration: + name: 💨 Leaving Home Duration + description: > + `person` + + + Duration for which someone must be out of the house for heating to be deactivated. + default: + hours: 0 + minutes: 0 + seconds: 2 + selector: + duration: + + input_mode_guest: + name: 🤝 Guest Mode + description: > + `person` `optional` + + + + If an entity is specified here, it is treated like a [person](https://www.home-assistant.io/integrations/person/). It's usefull when you're leaving your guests alone in your home and you are not using presence detection. + + * entity defined -> [person](https://www.home-assistant.io/integrations/person/) defined + * enitity is *on* -> simulates [person](https://www.home-assistant.io/integrations/person/) is home + * enitity is *off* -> simulates [person](https://www.home-assistant.io/integrations/person/) is away + default: + selector: + entity: + filter: + - domain: + - input_boolean + - binary_sensor + - timer + multiple: false + + # scheduler + scheduling_section: + name: Scheduling + icon: mdi:clock-outline + collapsed: true + input: + input_schedulers: + name: ⏲️ Schedules + description: > + `schedules` `optional` + + + A [schedule](https://www.home-assistant.io/integrations/schedule/) specifies when heating to comfort temperature should take place. You can create it in the helper section of Home Assistant.
+ If you have also specified [people](https://www.home-assistant.io/integrations/person/), someone must also be at home for heating. This is the same behaviour with a [proximity](https://www.home-assistant.io/integrations/proximity/) entity.
+ You can create as many [schedules](https://www.home-assistant.io/integrations/schedule/) as you like. Make sure the names are clear. + default: [] + selector: + entity: + filter: + - domain: + - schedule + multiple: true + + input_scheduler_selector: + name: ☝🏻 Scheduler Selector + description: > + `schedule` `optional` + + + Define an entity to choose from your schedules. If you use one schedule only you can ignore this. If you use more than one schedule you have multiple possibilities to setup your selection.
+ +
+ CLICK HERE: More information +
+ + + + * toggle [input_boolean](https://www.home-assistant.io/integrations/input_boolean/) or [binary_sensor](https://www.home-assistant.io/integrations/binary_sensor/): If *off* the first defined [schedule](https://www.home-assistant.io/integrations/schedule/) is enabled. If *on* the second [schedule](https://www.home-assistant.io/integrations/schedule/) is active. More than two [schedules](https://www.home-assistant.io/integrations/schedule/) cannot be selected with binary inputs. + + * text [input text](https://www.home-assistant.io/integrations/input_text/), drop down [input text](https://www.home-assistant.io/integrations/input_select/) or [sensor](https://www.home-assistant.io/integrations/sensor/): + * The value has to match the friendly name of the selected [schedule](https://www.home-assistant.io/integrations/schedule/) at least partially. Example: If you provide three [schedules](https://www.home-assistant.io/integrations/schedule/) called *work*, *holiday/sick*, *guest* you can select the holiday [schedule](https://www.home-assistant.io/integrations/schedule/) while setting the selection entity to *sick*, *holiday* or *holiday/sick*. This option is case insensitive. + * You also can go with numbers: if you want to choose the first [schedule](https://www.home-assistant.io/integrations/schedule/) the selector entity must return the number *1*. For the 2nd number *2* and so on. + +
+ default: + selector: + entity: + filter: + - domain: + - input_boolean + - binary_sensor + - input_text + - input_number + - input_select + multiple: false + + # presence + presence_section: + name: Presence Detection + icon: mdi:location-enter + collapsed: true + input: + input_presence_sensor: + name: 🚶 Presence Sensor / On/Off-Entity + description: > + `presence detection` `optional` + + + If you specify a presence sensor, heating will take place if it detects presence.
+ If you have specified [persons](https://www.home-assistant.io/integrations/person/), at least one must also be at home. You also can select an [input boolean](https://www.home-assistant.io/integrations/input_boolean/) entity to realise a simple On/Off-Logic. + default: + selector: + entity: + filter: + - domain: + - binary_sensor + - input_boolean + multiple: false + + input_scheduler_presence: + name: ⏲️ Presence Sensor Scheduler + description: > + `presence detection` `optional` + + + The presence [schedule](https://www.home-assistant.io/integrations/schedule/) specifies exactly when the presence sensor should be used during the day. + default: + selector: + entity: + filter: + - domain: + - schedule + multiple: false + + input_presence_reaction_on_time: + name: ⏳ Presence Reaction On Time + description: > + `presence detection` + + + Specify the duration for which the presence sensor must detect any presence so that the comfort temperature is set. + default: + hours: 0 + minutes: 5 + seconds: 0 + selector: + duration: + + input_presence_reaction_off_time: + name: ⌛ Presence Reaction Off Time + description: > + `presence detection` + + + Specify the duration for which the presence sensor must not detect any presence so that the eco temperature is set. + default: + hours: 0 + minutes: 5 + seconds: 0 + selector: + duration: + + # proximity + proximity_section: + name: Proximity + icon: mdi:leak + collapsed: true + input: + input_proximity: + name: ↔️ Proximity + description: > + `proximity` `optional` + + + You can preheat your rooms with help of home assistant's [proximity integration](https://www.home-assistant.io/integrations/proximity/).
+ Just select your proxmity zone and take your adjustments to distance and duration.
+ If you're in range of your distance and towards to your home heating kicks in.
+ + **Note**: The proximity entity is handles like a person. Comfort heating takes place when coming or beeing home. Combinations with [schedules](https://www.home-assistant.io/integrations/schedule/) are also possible. + default: + selector: + device: + filter: + integration: proximity + multiple: false + + input_proximity_duration: + name: ⏰ Proximity Duration + description: > + `proximity` + + + Duration for which someone must be on way home before heating occurs. + default: + hours: 0 + minutes: 2 + seconds: 0 + selector: + duration: + + input_proximity_distance: + name: ↔️ Proximity Distance + description: > + `proximity` + + + The distance when [proximity](https://www.home-assistant.io/integrations/proximity/) sensor gets impact for this automation. Hint: Unit depends on the setup of your integration. + default: 500 + selector: + number: + min: 0 + max: 999999999 + step: 1 + mode: box + + # away mode + away_section: + name: Away Mode + icon: mdi:walk + collapsed: true + input: + # AWAY OFFSET + input_away_offset: + name: 🏃 Away Temperature Offset + description: > + `scheduler` `persons` `presence` `away mode` + + + First: This feature only works for [schedule](https://www.home-assistant.io/integrations/schedule/) and/or presence based heating combined with [persons](https://www.home-assistant.io/integrations/person/). You can define an offset for your comfort temperature that will be subtracted (heating) from or added (cooling) to your comfort temperature. + + If you enable this option for [schedules](https://www.home-assistant.io/integrations/schedule/) the away offset will be substracted from the comfort temperature if your schedule is *on* but nobody is at home. + For presence detection this is the case if you are at home but no presence is detected. For presence detection you can also ignoring [persons](https://www.home-assistant.io/integrations/person/). So the away temperature is set when no presence is detected but the presence [schedule](https://www.home-assistant.io/integrations/schedule/) is *on*. + default: 0 + selector: + number: + min: 0 + max: 10 + step: 0.5 + mode: slider + unit_of_measurement: °C / °F + + input_away_scheduler_mode: + name: ⏲️ Scheduler Away Mode + description: > + `scheduler` `away mode` + + + Enable/Disable the Away Offset for [schedules](https://www.home-assistant.io/integrations/schedule/) based heating/cooling. + default: false + selector: + boolean: + + input_away_presence_mode: + name: 🚶 Presence Away Mode + description: > + `presence` `away mode` + + + Enable/Disable the Away Offset for presence based heating/cooling. + default: false + selector: + boolean: + + input_away_presence_ignor_people: + name: 🚶 Ignore People For Presence Away Mode + description: > + `presence` `away mode` + + + If you want to make away happen if your presence [schedule](https://www.home-assistant.io/integrations/schedule/) is on but no motion is detected regardless if somebody is at home enable this option. + default: false + selector: + boolean: + + # windows + window_section: + name: Window & Door Detection + icon: mdi:door + collapsed: true + input: + input_windows: + name: 🪟 Windows & Doors + description: > + `airing` `optional` + + + If open during airing your [thermostats](https://www.home-assistant.io/integrations/climate/) will be set to *off* at least to their minimum temperature + if they don't support hvac mode *OFF* except you set a custom window open temperature. + default: [] + selector: + entity: + filter: + - domain: + - binary_sensor + - sensor + multiple: true + + input_windows_reaction_time_open: + name: ⏳ Window & Door Reaction Time Open + description: > + `airing` + + + Duration for which a window or door must be open for the [thermostats](https://www.home-assistant.io/integrations/climate/) to close. + default: + hours: 0 + minutes: 0 + seconds: 30 + selector: + duration: + + input_windows_reaction_time_close: + name: ⌛ Window & Door Reaction Time Close + description: > + `airing` + + + Duration for which a window or door must be closed for the [thermostats](https://www.home-assistant.io/integrations/climate/) to open. + default: + hours: 0 + minutes: 0 + seconds: 30 + selector: + duration: + + input_window_open_temperature: + name: Window Open Temperature + description: > + `airing` + + + If 0° your thermostat turns *off* or if not supported it turns to the minimum temperature of your thermostat. + default: 0 + selector: + number: + min: 0 + max: 15 + step: 1 + mode: slider + unit_of_measurement: °C / °F + + input_window_legacy_restore: + name: 🏚️ Legacy Restore + description: > + `airing` + + + Enable this if the temperatures after airing (closing windows) won't restore properly. + default: false + selector: + boolean: + + # calibration + calibration_section: + name: Calibration + icon: mdi:compass + description: "" + collapsed: true + input: + input_calibration_timeout: + name: ⏳ Calibration Timeout + description: > + `calibration` + + + Define a timeout if you want to decrease the amount of calibration calls if temperature changes too much. + At least the temperature of the external sensor or [thermostat](https://www.home-assistant.io/integrations/climate/) must stay for that duration before calibration gets triggered. + + **HINT:** A minimum timeout of 2s is recommended. + default: + hours: 0 + minutes: 1 + seconds: 0 + selector: + duration: + + input_calibration_delta: + name: ↔️ Calibration Delta + description: > + `calibration` + + + If the difference between the [thermostat](https://www.home-assistant.io/integrations/climate/) temperature and the external sensor temperature is greater or less than the calibration delta the [thermostat](https://www.home-assistant.io/integrations/climate/) calibration will be triggered.
+ The lower the delta the often calibration gets triggered. + + **HINT:** If your thermostat supports external temperature sensor values it is recommended to set this to a lower value like 0 - 0.2. + default: 0.5 + selector: + number: + min: 0 + max: 5 + step: 0.1 + mode: slider + unit_of_measurement: °C / °F + + input_calibration_key_word: + name: 🗝️ Calibration Entity Key Word + description: > + `calibration` + + + Keyword for finding the calibration entity. This word must be part of the entity id. + As a rule, the entities with the word *offset*, *calibration* or *external* are marked by the integrations. Just have a look into your device overview, select your thermostat and check the naming of the *entity_ids* for the calibration. + default: "calibration" + selector: + text: + + input_calibration_step_size: + name: 🦶 Step Size + description: > + `calibration` + + + Usually the step size is determined automatically. You can overwrite the step size by selecting another option if you know your thermostat handles the calibration not like the entities are exposed. + default: auto + selector: + select: + mode: dropdown + options: + - label: Auto + value: auto + - label: "0.1" + value: "0.1" + - label: "0.5" + value: "0.5" + - label: "Full Values" + value: "full" + + input_calibration_generic: + name: 🧭 Generic Calibration + description: > + `generic` `calibration` + + + Adds the difference between room and [thermostat](https://www.home-assistant.io/integrations/climate/) temperature to the target temperature. This is useful if your thermostat integration doesn't provide a special entity for calibration. + Keep in mind the set temperatures for your thermostats will differ to the target temperature. + default: false + selector: + boolean: + + input_generic_calibration_offset: + name: ↕️ Generic Calibration Offset + description: > + `generic` `calibration` + + + If the temperature difference between the thermostat and the temperature sensor is very high, + the offset, i.e. the correction temperature, can be limited to this value. + +
+ CLICK HERE: Example + Generic Calibration Offset = 5°
+ Thermostat Temperature = 28°
+ Room Temperature = 18°
+
+ Difference = Thermostat Temperature - Room Temperature = 10°
+ Difference > Generic Calibration Offset -> Corrected Difference = 5°
+ New Target Temperature = Thermostat Temperature + Corrected Difference = 33° +
+ default: 5 + selector: + number: + min: 0 + max: 20 + step: 1 + mode: slider + unit_of_measurement: °C / °F + + # aggressive mode + aggressive_mode_section: + name: Aggressive Mode + icon: mdi:emoticon-angry + collapsed: true + input: + input_aggressive_mode_range: + name: 😡 Aggressive Range + description: > + `aggressive mode` `tweak` + + + Activate this option if your [thermostats](https://www.home-assistant.io/integrations/climate/) react slowly or only start to react at a large temperature difference + between actual and set temperature. + Define a range when your real target temperature shall be set. + +
+ CLICK HERE: More information +
+ + E.g. you target temperature is 20°C and your room temperature is 19.5°C. + If your range is set to 0.5°C the real target temperature (20°C) will be set when room temperature is between 19.5°C and 20.5°C. + If the room temperature is above or lower than range, it gets some offset in order to force your [thermostat](https://www.home-assistant.io/integrations/climate/) to react. + (see Aggressive Mode - Offset) + +
+ + default: 0 + selector: + number: + min: 0 + max: 5 + step: 0.1 + mode: slider + unit_of_measurement: °C / °F + + input_aggressive_mode_offset: + name: ↕ Aggressive Offset + description: > + `aggressive mode` `tweak` + + + Here you can define the offset that will be added to your target temperature if the room temperature is not in range of your target temperature. + If your room temperature is not in the defined range, e.g. 19.5°C - 20.5°C this offset will be added to your target temperature. If range is 0, then offset is always added. + default: 0 + selector: + number: + min: 0 + max: 5 + step: 0.5 + mode: slider + unit_of_measurement: °C / °F + + input_aggressive_mode_calibration: + name: 🌡️ Aggressive Calibration + description: > + `aggressive mode` `tweak` `experimental` + + If you'd setup an temperature sensor and your thermostats allow calibration, you can enable this feature. If enabled the aggressive offset will be add + to the calibration value and not the target temperature. + + *Note*: This feature is marked as experimental since not every calibration method could be tested. If you notice any problems simple open an issue or + post a message in the [AHC-Thread](https://community.home-assistant.io/t/advanced-heating-control/469873). + Enable this only if native calibration does NOT work when using generic calibration. + default: false + selector: + boolean: + + # frost protection + frostprotection_section: + name: Frost Protection + icon: mdi:snowflake + collapsed: true + input: + input_frost_protection_temp: + name: ❄️ Frost Protection Temperature + description: > + `frost protection` + + + You can set the frost protection temperature here. + default: 5 + selector: + number: + min: 5.0 + max: 62.0 + step: 0.5 + mode: box + unit_of_measurement: °C / °F + + input_frost_protection_duration: + name: ❄️ Frost Protection Fallback Duration + description: > + `frost protection` + + + If the defined [persons](https://www.home-assistant.io/integrations/person/) are not at home for a longer period of time or the presence sensor has no longer detected any presence, the frost protection temperature can be lowered after a this duration. + Note: If set to zero frost protection temperature never will be set. + default: + days: 0 + hours: 0 + minutes: 0 + seconds: 0 + selector: + duration: + enable_day: true + + # liming protection + liming_protection_section: + name: Liming Protection + icon: mdi:pipe-valve + collapsed: true + input: + input_liming_protection: + name: 🎚️ Liming Protection + description: > + `liming protection` + + + Most smart thermostats come with that feature out of the box. + If your thermostat doesn't support this or you're using the generic thermostat integration this feature is maybe handy for you in order to prevent your valve against limescale. + The automation will set the thermostat to its max and open the valve for one minute. + + default: off + selector: + boolean: + + input_liming_protection_day: + name: 🗓️ Day + description: > + `liming protection` + + + Select the day of the week for the execution. + default: "Mon" + selector: + select: + options: + - label: Monday + value: Mon + - label: Tuesday + value: Tue + - label: Wednesday + value: Wed + - label: Thursday + value: Thu + - label: Friday + value: Fri + - label: Saturday + value: Sat + - label: Sunday + value: Sun + + input_liming_protection_time: + name: 🕖 Time + description: > + `liming protection` + + + Select the time for the execution. + default: "12:00:00" + selector: + time: + + input_liming_protection_duration: + name: 🕖 Liming Protection Duration + description: > + `liming protection` + + + Duration of liming protection before the thermostat is reset to its initial state. + default: 1 + selector: + number: + min: 1 + max: 30 + step: 1 + mode: slider + unit_of_measurement: min + + input_liming_in_winter: + name: 🌨️ Liming In Winter / Liming If Automation is Disabled + description: > + `liming protection` + + + Enable this if you want liming protection even if the automation is active. + default: false + selector: + boolean: + + # winter mode + toggle_section: + name: "On/Off Automation Options" + icon: mdi:light-switch + collapsed: true + input: + input_mode_winter: + name: ⛄ Winter Mode / Automation Toggle + description: > + `activation` `optional` + + + If *on* the automation is active. If *off* your valves will set to *off* and the automation is going to sleep. + You can set this up with: + + * [input boolean](https://www.home-assistant.io/integrations/input_boolean/) + * [binary sensor](https://www.home-assistant.io/integrations/binary_sensor/) + + + Create your helper [here](https://my.home-assistant.io/redirect/helpers/). + default: + selector: + entity: + filter: + - domain: + - input_boolean + - binary_sensor + multiple: false + + input_invert_winter_mode_value: + name: 🔄 Invert Winter Mode Value + description: > + `activation` + + + If enabled the the value of the binary winter mode entity will be inverted: + + * off -> activates the automation + * on -> disables the automation + default: off + selector: + boolean: + + input_mode_outside_temperature: + name: 🌤️ Outside Temperature Sensor + description: > + `activation` `optional` + + + You can control the switching on and off of your thermostats via the outside temperature. + To do this, select a temperature sensor or a weather entity and adjust the threshold below. + + * [weather entity](https://www.home-assistant.io/integrations/weather/) + * [temperature sensor entity](https://www.home-assistant.io/integrations/sensor/) + + default: + selector: + entity: + filter: + - domain: + - weather + - domain: + - sensor + device_class: temperature + multiple: false + + input_mode_outside_temperature_threshold: + name: 🎚️ Outside Temperature Threshold + description: > + `activation` + + + If you'd select a temperature [sensor](https://www.home-assistant.io/integrations/sensor/) or a [weather entity](https://www.home-assistant.io/integrations/weather/) + for controlling heating you can adjust the temperature threshold here. + If the outside temperature falls below the threshold value, heating is activated. + default: 15 + selector: + number: + min: 5 + max: 68 + step: 0.5 + mode: box + unit_of_measurement: °C / °F + + input_mode_room_temperature: + name: 🔘 Enable Room Temperature Threshold + description: > + `activation` `optional` + + + If you enable this option the value of the defined room temperature sensor and the value of the outside temperautre must be below / above + its threshold. That makes sense if you go with an A/C and the room is still heated up but it has already cooled down outside. + + + **Not recommendend for heating** + + default: false + selector: + boolean: + + input_mode_room_temperature_threshold: + name: 🎚️ Room Temperature Threshold + description: > + `activation` + + + Threshold for your room temperature sensor. + default: 18 + selector: + number: + min: 5 + max: 68 + step: 0.5 + mode: box + unit_of_measurement: °C / °F + + # valve positioning + valve_positioning_section: + name: "Dynamic Valve Positioning" + icon: mdi:valve + collapsed: true + input: + input_valve_positioning_mode: + name: 🦶 Valve Positioning Mode + description: > + `valve positioning` + + + If your thermostat supports valve positioning you can enable this here. Everytime the autmation gets triggered the code checks if there is an adjustment needed. + + + 📈 **regular**: means linear. The valve will open close proportional to the difference of the target and room temperature. + + + 😊 **optimistic**: The valve opening is reduced earlier, as it is assumed that the radiator still has enough residual heat to heat the room. + + + 🙁 **pessimistic**: The valve opening is initially left relatively open and only closes rapidly when the target temperature is almost reached. + default: "off" + selector: + select: + mode: dropdown + options: + - label: "off" + value: "off" + - label: "regular" + value: "regular" + - label: "optimistic" + value: "optimistic" + - label: "pessimistic" + value: "pessimistic" + + input_fully_open_difference: + name: ↔️ Positioning Temperature Difference + description: > + `valve positioning` + + + The difference between target and set temperature when dynamic valve positioninig should happen. + + +
+ CLICK HERE: Example +
+ + + > Positioning Temperature Difference: 1° + + > Target Temperature: 21°
+ + + > Positioning takes place in a range between 21° and 20° (21°-1°) + + + > If the local temperature is 21.5° the valve positioning is calculated and set. + + > If the local temperture is below this range the valve is fully open. + +
+ + default: 1 + selector: + number: + min: 0.5 + max: 20 + step: 0.5 + mode: box + unit_of_measurement: °C / °F + + input_valve_positioning_step_size: + name: 🦶 Valve Positioning Step Size + description: > + `valve positioning` + + + The step size of for opening/closing the valve. + default: "10" + selector: + select: + mode: dropdown + options: + - label: "5%" + value: "5" + - label: "10%" + value: "10" + - label: "20%" + value: "20" + + input_valve_positioning_max_opening: + name: 🎚️ Max Opening Valve Position + description: > + `valve positioning` + + + The maximal opening of the valve. Some thermostats have a maximum valve position of 80-90%. You can adjust the value here. *Force Max Temperature* still sets the value to 100%. + default: 100 + selector: + number: + min: 1 + max: 100 + step: 1 + mode: slider + unit_of_measurement: "%" + + input_valve_positioning_timeout: + name: ⏱️ Valve Positioning Timeout + description: > + `valve positioning` + + + Timeout that must lie between two adjustments before the second is executed. + default: + hours: 0 + minutes: 20 + seconds: 0 + selector: + duration: + + input_valve_opening_keyword: + name: 🗝️ Positioning Entity Keyword + description: > + `valve positioning` + + + The key word for selecting the opening entity of your thermostats. + default: "valve_opening_degree" + selector: + text: + + # tweaks + tweak_section: + name: Custom Settings + icon: mdi:cog-box + collapsed: true + input: + input_action_call_delay: + name: ⚙️ Action Call Delay + description: > + `tweak` + + + Some [thermostats](https://www.home-assistant.io/integrations/climate/) have problems with setting mode and temperature. You can try to increase the + delay between the action calls. This could fix your problems. + default: + hours: 0 + minutes: 0 + seconds: 2 + selector: + duration: + + input_startup_delay: + name: ⏲ Startup Delay + description: > + `tweak` + + + If your AHC automation is triggered directly after a Home Assistant restart, but the required integrations have not yet been loaded or certain sensors + have not yet been initialized, you can set an automation delay here. + + *Note:* Make sure that you have set up the uptime integration for this purpose. + default: + hours: 0 + minutes: 0 + seconds: 0 + selector: + duration: + + # custom action + input_custom_action: + name: 🎬 Custom Action + description: > + `optional` + + + This custom action gets executed with every temperature / mode change except calibration. If you want to control other devices just check states before doing an action call. + Use the variable *is_heating* in your conditions. *True* means heating is active. + default: + selector: + action: + + input_custom_condition: + name: ☑️ Temperature Change Custom Condition + description: > + `optional` + + + Define a custom condition that prevents / allows temperature changes to your thermostats. This has no impact to the rest of logic like calibration. + default: + selector: + condition: + + input_custom_condition_calibration: + name: ☑️ Calibration Custom Condition + description: > + `optional` + + + Define a custom condition that prevents / allows calibration. + default: + selector: + condition: + + input_log_level: + name: ✍️ Log Level + description: "" + default: debug + selector: + select: + mode: dropdown + options: + - info + - warning + - error + - debug + +trigger_variables: + # thermostats / sensors + input_trvs: !input input_trvs + input_temperature_sensor: !input input_temperature_sensor + is_temperature_sensor_defined: "{{ input_temperature_sensor != [] }}" + + # people + input_persons: !input input_persons + input_mode_guest: !input input_mode_guest + input_people_entering_home_duration: !input input_people_entering_home_duration + input_people_leaving_home_duration: !input input_people_leaving_home_duration + + input_person_count: "{{ input_persons | count }}" + is_person_defined: "{{ input_person_count > 0 }}" + is_guest_mode_defined: "{{ input_mode_guest != none }}" + + # scheduler + input_schedulers: !input input_schedulers + input_scheduler_selector: !input input_scheduler_selector + input_scheduler_presence: !input input_scheduler_presence + is_scheduler_presence_defined: "{{ input_scheduler_presence != none }}" + + # temperatures + input_temperature_comfort: !input input_temperature_comfort + input_temperature_eco: !input input_temperature_eco + input_hvac_mode: !input input_hvac_mode + factor: "{{ iif(input_hvac_mode == 'cool', -1, 1) | int }}" + is_heat_only_if_below_real_temp: !input input_off_if_above_room_temperature + + # on/ff + input_mode_winter: !input input_mode_winter + input_mode_outside_temperature: !input input_mode_outside_temperature + input_mode_outside_temperature_threshold: !input input_mode_outside_temperature_threshold + input_mode_room_temperature_threshold: !input input_mode_room_temperature_threshold + input_mode_room_temperature: !input input_mode_room_temperature + input_invert_winter_mode_value: !input input_invert_winter_mode_value + + # party / force max + input_mode_party: !input input_mode_party + + # adjustments / heating plan + input_adjustments: !input input_adjustments + + # calibration + input_calibration_timeout: !input input_calibration_timeout + + # windows + input_windows: !input input_windows + + #presence + input_presence_sensor: !input input_presence_sensor + is_presence_sensor_defined: "{{ input_presence_sensor != none }}" + input_presence_reaction_on_time: !input input_presence_reaction_on_time + input_presence_reaction_off_time: !input input_presence_reaction_off_time + + # proximity + input_proximity: !input input_proximity + input_proximity_duration: !input input_proximity_duration + input_proximity_distance: !input input_proximity_distance + + # frost protection + input_frost_protection_duration: !input input_frost_protection_duration + + # liming protection + input_liming_protection: !input input_liming_protection + input_liming_protection_day: !input input_liming_protection_day + input_liming_protection_time: !input input_liming_protection_time + input_liming_in_winter: !input input_liming_in_winter + input_liming_protection_duration: !input input_liming_protection_duration + +trigger: + # system + - trigger: homeassistant + event: start + id: temperature_change_hastart + + - trigger: event + event_type: automation_reloaded + id: temperature_change_reload + + - trigger: event + event_type: ahc_delay_event + id: delayed_call_temperature_change + event_data: + automation: "{{ this.entity_id }}" + + - trigger: event + event_type: ahc_positioning_event + id: positioning_event + event_data: + automation: "{{ this.entity_id }}" + + # thermostats become available + - trigger: state + entity_id: !input input_trvs + from: + - unknown + - unavailable + for: + seconds: 5 + id: temperature_change_available + + # physical change + - trigger: state + entity_id: !input input_trvs + attribute: temperature + for: + seconds: 5 + id: temperature_change_valve_target + + # eco/comfort change + - trigger: state + entity_id: !input input_temperature_eco + for: !input input_action_call_delay + id: temperature_change_eco + + - trigger: state + entity_id: !input input_temperature_comfort + for: !input input_action_call_delay + id: temperature_change_comfort + + # persons + - trigger: template + value_template: > + {{ input_persons | expand + | selectattr('state', 'eq', 'home') + | list + | count > 0 + + or (is_guest_mode_defined and states(input_mode_guest) in ['on','active'] ) }} + id: temperature_change_person_on + for: !input input_people_entering_home_duration + + - trigger: template + value_template: > + {{ input_persons | expand + | selectattr('state', 'eq', 'home') + | list + | count == 0 + + and (not is_guest_mode_defined or (is_guest_mode_defined and states(input_mode_guest) not in ['on','active'])) }} + id: temperature_change_person_off + for: !input input_people_leaving_home_duration + + # scheduler + - trigger: template + id: temperature_change_scheduler_on + value_template: > + {% set selected_scheduler = none %} + {% set schedules_count = input_schedulers | count %} + + {% if schedules_count == 0 %} + {% set selected_scheduler = none %} + {% elif schedules_count == 1 or input_scheduler_selector == none %} + {% set selected_scheduler = input_schedulers | first %} + {% elif schedules_count > 1 %} + {% set selector_value = states(input_scheduler_selector) %} + + {% if is_number(selector_value) %} + {% set selector_value = iif(selector_value | int > schedules_count, schedules_count, selector_value) %} + {% set selector_value = iif(selector_value | int <= 0, 1, selector_value) %} + {% set selected_scheduler = input_schedulers[selector_value | int - 1] %} + {% elif selector_value in ['on','off'] %} + {% set selected_scheduler = iif(selector_value == 'off', input_schedulers[0], input_schedulers[1]) %} + {% else %} + {% set selected_scheduler = input_schedulers | expand | selectattr('attributes.friendly_name', 'eq', selector_value) | map(attribute='entity_id') | first | default(none) %} + {% if (selected_scheduler == none) %} + {% set selected_scheduler = input_schedulers | expand | selectattr('attributes.friendly_name', 'search', '(?i)' + selector_value) | map(attribute='entity_id') | first | default(none) %} + {% endif %} + {% endif %} + {% endif %} + + {% if selected_scheduler == none %} + {{ false }} + {% else %} + {{ is_state(selected_scheduler, 'on') }} + {% endif %} + + - trigger: template + id: temperature_change_scheduler_off + value_template: > + {% set selected_scheduler = none %} + {% set schedules_count = input_schedulers | count %} + + {% if schedules_count == 0 %} + {% set selected_scheduler = none %} + {% elif schedules_count == 1 or input_scheduler_selector == none %} + {% set selected_scheduler = input_schedulers | first %} + {% elif schedules_count > 1 %} + {% set selector_value = states(input_scheduler_selector) %} + + {% if is_number(selector_value) %} + {% set selector_value = iif(selector_value | int > schedules_count, schedules_count, selector_value) %} + {% set selector_value = iif(selector_value | int <= 0, 1, selector_value) %} + {% set selected_scheduler = input_schedulers[selector_value | int - 1] %} + {% elif selector_value in ['on','off'] %} + {% set selected_scheduler = iif(selector_value == 'off', input_schedulers[0], input_schedulers[1]) %} + {% else %} + {% set selected_scheduler = input_schedulers | expand | selectattr('attributes.friendly_name', 'eq', selector_value) | map(attribute='entity_id') | first | default(none) %} + {% if (selected_scheduler == none) %} + {% set selected_scheduler = input_schedulers | expand | selectattr('attributes.friendly_name', 'search', '(?i)' + selector_value) | map(attribute='entity_id') | first | default(none) %} + {% endif %} + {% endif %} + {% endif %} + + {% if selected_scheduler == none %} + {{ false }} + {% else %} + {{ is_state(selected_scheduler, 'off') }} + {% endif %} + + # presence sensor + - trigger: template + id: temperature_change_presence_on + value_template: "{{ input_presence_sensor != none and is_state(input_presence_sensor, 'on') }}" + for: !input input_presence_reaction_on_time + + - trigger: template + id: temperature_change_presence_off + value_template: "{{ input_presence_sensor != none and is_state(input_presence_sensor, 'off') }}" + for: !input input_presence_reaction_off_time + + # presence scheduler + - trigger: template + id: temperature_change_presence_scheduler_on + value_template: "{{ input_scheduler_presence != none and is_state(input_scheduler_presence, 'on') }}" + for: !input input_action_call_delay + + - trigger: template + id: temperature_change_presence_scheduler_off + value_template: "{{ input_scheduler_presence != none and is_state(input_scheduler_presence, 'off') }}" + for: !input input_action_call_delay + + # proximity + - trigger: template + id: temperature_change_person_proximity_on + value_template: > + {% set proximity_entities = device_entities(input_proximity) %} + + {% set is_arrived = proximity_entities + | select('is_state','arrived') + | expand + | selectattr('attributes.device_class', 'eq', 'enum') + | list | count > 0 %} + + {% set entities_towards = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'enum') + | map(attribute='entity_id') | select('is_state','towards') + | map('regex_replace','_(?=[^_]*$)(.*)', '') + | list %} + + {% set distances = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'distance') + | map(attribute='state') + | reject('eq', 'unknown') + | map('int') + | select('<=', input_proximity_distance | int) + | map('string') + | list %} + + {% set entities_distances = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'distance') + | selectattr('state', 'in', distances) + | map(attribute='entity_id') + | map('regex_replace','_(?=[^_]*$)(.*)', '') + | list %} + + {% set entites_towards_and_in_distance = entities_towards | select('in', entities_distances) | list | count > 0 %} + + {{ entites_towards_and_in_distance or is_arrived }} + for: !input input_proximity_duration + + - trigger: template + id: temperature_change_person_proximity_off + value_template: > + {% set proximity_entities = device_entities(input_proximity) %} + {% set is_arrived = proximity_entities + | select('is_state','arrived') + | expand + | selectattr('attributes.device_class', 'eq', 'enum') + | list | count > 0 %} + + {% set entities_towards = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'enum') + | map(attribute='entity_id') | select('is_state','towards') + | map('regex_replace','_(?=[^_]*$)(.*)', '') + | list %} + + {% set distances = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'distance') + | map(attribute='state') + | reject('eq', 'unknown') + | map('int') + | select('<=', input_proximity_distance | int) + | map('string') + | list %} + + {% set entities_distances = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'distance') + | selectattr('state', 'in', distances) + | map(attribute='entity_id') + | map('regex_replace','_(?=[^_]*$)(.*)', '') + | list %} + + {% set entites_towards_and_in_distance = entities_towards | select('in', entities_distances) | list | count > 0 %} + + {{ entites_towards_and_in_distance == false and is_arrived == false }} + for: !input input_proximity_duration + + # window + - trigger: template + value_template: "{{ expand(input_windows) | selectattr('state', 'in', ['on','open','tilted']) | list | count > 0 }}" + for: !input input_windows_reaction_time_open + id: temperature_change_window_on + + - trigger: template + value_template: "{{ expand(input_windows) | selectattr('state', 'in', ['on','open','tilted']) | list | count == 0 }}" + for: !input input_windows_reaction_time_close + id: temperature_change_window_off + + # on/off winter mode + - trigger: template + id: temperature_change_winter_mode_on + value_template: > + {% if input_mode_winter != none %} + {% set activation_state = iif(input_invert_winter_mode_value, 'off', 'on') %} + {{ is_state(input_mode_winter, activation_state) }} + {% endif %} + for: !input input_action_call_delay + + - trigger: template + id: temperature_change_winter_mode_off + value_template: > + {% if input_mode_winter != none %} + {% set activation_state = iif(input_invert_winter_mode_value, 'off', 'on') %} + {{ not is_state(input_mode_winter, activation_state) }} + {% endif %} + for: !input input_action_call_delay + + # on/off temperature + - trigger: template + id: temperature_change_outside_on + value_template: > + {% if input_mode_outside_temperature == none %} + {{ false }} + {% else %} + {% set outside_state = false %} + {% set use_room_temp = input_mode_room_temperature and is_temperature_sensor_defined %} + {% set room_state = iif(use_room_temp, false, true) %} + + {% set state = states(input_mode_outside_temperature) %} + {% set state = iif(is_number(state) == true, state, state_attr(input_mode_outside_temperature,'temperature'))%} + + {% if is_number(state) %} + {% set outside_state = (state | float - input_mode_outside_temperature_threshold | float) * factor < 0 %} + {% endif %} + + {% if use_room_temp %} + {% set state = states(input_temperature_sensor) %} + + {% if is_number(state) %} + {% set room_state = (state | float - input_mode_room_temperature_threshold | float) * factor < 0 %} + {% endif %} + {% endif %} + + {{ room_state and outside_state }} + {% endif %} + for: !input input_action_call_delay + + - trigger: template + id: temperature_change_outside_off + value_template: > + {% if input_mode_outside_temperature == none %} + {{ false }} + {% else %} + {% set outside_state = false %} + {% set use_room_temp = input_mode_room_temperature and is_temperature_sensor_defined %} + {% set room_state = iif(use_room_temp, false, true) %} + + {% set state = states(input_mode_outside_temperature) %} + {% set state = iif(is_number(state) == true, state, state_attr(input_mode_outside_temperature,'temperature'))%} + + {% if is_number(state) %} + {% set outside_state = (state | float - input_mode_outside_temperature_threshold | float) * factor < 0 %} + {% endif %} + + {% if use_room_temp %} + {% set state = states(input_temperature_sensor) %} + + {% if is_number(state) %} + {% set room_state = (state | float - input_mode_room_temperature_threshold | float) * factor < 0 %} + {% endif %} + {% endif %} + + {{ not (room_state and outside_state) }} + {% endif %} + for: !input input_action_call_delay + + # force max temp + - trigger: state + id: temperature_change_force_max_temperature_on + entity_id: !input input_force_max_temperature + for: !input input_action_call_delay + + # force eco temp + - trigger: state + id: temperature_change_force_eco_temperature_ds + entity_id: !input input_force_eco_temperature + for: !input input_action_call_delay + + # party + - trigger: template + id: temperature_change_party_on + value_template: "{{ input_mode_party | expand | selectattr('state', 'in', ['active','on']) | list | count > 0 }}" + for: !input input_action_call_delay + + - trigger: template + value_template: "{{ input_mode_party | expand | selectattr('state', 'in', ['active','on']) | list | count == 0 }}" + id: temperature_change_party_off + for: !input input_action_call_delay + + # aggressive mode / heating above/below temp + - trigger: state + id: calibration_aggressive_mode_above_temp_thermostat_current_temp_change + entity_id: !input input_trvs + attribute: current_temperature + for: !input input_calibration_timeout + + - trigger: state + id: calibration_aggressive_mode_thermostat_temp_change + entity_id: !input input_trvs + attribute: temperature + for: + seconds: 30 + + - trigger: state + id: aggressive_mode_above_temp_sensor_change + entity_id: !input input_temperature_sensor + for: + seconds: 30 + + # calibration trigger + - trigger: state + id: calibration_sensor_change + entity_id: !input input_temperature_sensor + for: !input input_calibration_timeout + + - trigger: state + id: calibration_popp_change + entity_id: !input input_temperature_sensor + for: + seconds: 2 + + - trigger: template + id: calibration_popp_ping + value_template: > + {% set has_valves_danfoss = input_trvs | select('is_device_attr', 'manufacturer', 'Danfoss') | list %} + {% set has_valves_popp = input_trvs | select('is_device_attr', 'manufacturer', 'Popp') | list %} + {% set valves_hive = input_trvs | select('is_device_attr', 'manufacturer', 'Hive') | list %} + {% set valves_bosch = input_trvs | select('is_device_attr', 'manufacturer', 'Bosch') | list %} + + {% set has_valves = (has_valves_danfoss + has_valves_popp + valves_hive + valves_bosch) | count > 0 %} + + {{ has_valves and is_temperature_sensor_defined and now().strftime('%M') | int % 10 == 0 }} + + # heating adjustments + - trigger: template + id: temperature_change_heating_adjustment + value_template: > + {% set timestamp = now() %} + + {% set current_day = timestamp.strftime('%a') %} + {% set current_time = timestamp.strftime('%H:%M') %} + + {% set plan = input_adjustments | rejectattr('time', 'undefined') + | selectattr('time','eq', current_time | string) + | sort(attribute='time', reverse = true) + | list %} + + {{ plan | count > 0 and now() < now().replace(second=2) }} + + # liming protection + - trigger: template + value_template: > + {% if not input_liming_protection%} + {{ false }} + {% else %} + {% set enable_liming = true %} + {% if input_mode_winter != none %} + {% set enable_liming = is_state(input_mode_winter,'on') or input_liming_in_winter %} + {% endif %} + + {% set current_timestamp = now() %} + + {% set is_liming_day = input_liming_protection_day == as_datetime(current_timestamp).strftime('%a') %} + + {% set start_hour = input_liming_protection_time.split(':')[0] | int %} + {% set start_minute = input_liming_protection_time.split(':')[1] | int %} + + {% set today_start = as_datetime(current_timestamp).replace(second=0,microsecond=0,hour=start_hour,minute=start_minute) %} + {% set today_end = as_datetime(current_timestamp).replace(second=0,microsecond=0,hour=start_hour,minute=start_minute) + timedelta(minutes=input_liming_protection_duration | int) %} + + {% set is_liming_time = as_datetime(current_timestamp) >= today_start and as_datetime(current_timestamp) <= today_end %} + + {{ enable_liming and is_liming_day and is_liming_time }} + {% endif %} + id: temperature_change_liming_protection_on + + - trigger: template + value_template: > + {% if not input_liming_protection%} + {{ false }} + {% else %} + {% set enable_liming = true %} + {% if input_mode_winter != none %} + {% set enable_liming = is_state(input_mode_winter,'on') or input_liming_in_winter %} + {% endif %} + + {% set current_timestamp = now() %} + + {% set current_timestamp = now() %} + + {% set is_liming_day = input_liming_protection_day == as_datetime(current_timestamp).strftime('%a') %} + + {% set start_hour = input_liming_protection_time.split(':')[0] | int %} + {% set start_minute = input_liming_protection_time.split(':')[1] | int %} + + {% set today_start = as_datetime(current_timestamp).replace(second=0,microsecond=0,hour=start_hour,minute=start_minute) %} + {% set today_end = as_datetime(current_timestamp).replace(second=0,microsecond=0,hour=start_hour,minute=start_minute) + timedelta(minutes=input_liming_protection_duration | int) %} + + {% set is_liming_time = as_datetime(current_timestamp) >= today_start and as_datetime(current_timestamp) <= today_end %} + + {{ not (enable_liming and is_liming_day and is_liming_time) }} + {% endif %} + id: temperature_change_liming_protection_off + + # frost protection + - trigger: template + id: temperature_change_frost_protection_on + for: !input input_frost_protection_duration + value_template: > + {% set now_ts = now() %} + {% set frost_protection_timestamp = as_datetime(now_ts) - timedelta(**input_frost_protection_duration) %} + {% if frost_protection_timestamp == now_ts %} + {{ false }} + {% else %} + + {% set relevant_entities = [input_presence_sensor] + [input_mode_guest] + input_persons %} + {% set relevant_entities_count = relevant_entities | reject('eq',none) | list | count %} + + {% if relevant_entities_count > 0 %} + {% set presence_count = [input_presence_sensor] + | reject('eq',none) + | reject('is_state','on') + | list + | count %} + + {% set guest_mode_count = [input_mode_guest] + | reject('eq',none) + | reject('is_state','on') + | list + | count %} + + {% set person_count = input_persons + | reject('is_state','home') + | list + | count %} + + {{ presence_count + guest_mode_count + person_count == relevant_entities_count }} + {% else %} + {{ false }} + {% endif %} + {% endif %} + +variables: + ##################################################################################### + ###################################### INPUTS ####################################### + ##################################################################################### + + # thermostats / sensors + input_trvs: !input input_trvs + input_hvac_mode: !input input_hvac_mode + input_temperature_sensor: !input input_temperature_sensor + + # temperatures + input_temperature_comfort: !input input_temperature_comfort + input_temperature_comfort_entity: "{{ iif(input_temperature_comfort == [], none, input_temperature_comfort) }}" + input_temperature_comfort_static: !input input_temperature_comfort_static + input_temperature_eco: !input input_temperature_eco + input_temperature_eco_entity: "{{ iif(input_temperature_eco == [], none, input_temperature_eco) }}" + input_temperature_eco_static: !input input_temperature_eco_static + + #frost protection + input_frost_protection_temp: !input input_frost_protection_temp + input_frost_protection_duration: !input input_frost_protection_duration + + #liming protection + input_liming_protection: !input input_liming_protection + input_liming_protection_day: !input input_liming_protection_day + input_liming_protection_time: !input input_liming_protection_time + input_liming_in_winter: !input input_liming_in_winter + input_liming_protection_duration: !input input_liming_protection_duration + + # heating scheduler + input_schedulers: !input input_schedulers + input_scheduler_selector: !input input_scheduler_selector + + # presence + input_presence_sensor: !input input_presence_sensor + input_scheduler_presence: !input input_scheduler_presence + input_presence_reaction_off_time: !input input_presence_reaction_off_time + input_presence_reaction_on_time: !input input_presence_reaction_on_time + + # window detection + input_windows: !input input_windows + input_windows_reaction_time_open: !input input_windows_reaction_time_open + input_windows_reaction_time_close: !input input_windows_reaction_time_close + input_window_open_temperature: !input input_window_open_temperature + input_party_legacy_restore: !input input_party_legacy_restore + input_window_legacy_restore: !input input_window_legacy_restore + is_legacy_restore: "{{ input_party_legacy_restore or input_window_legacy_restore }}" + + # wintermode / on/off + input_mode_winter: !input input_mode_winter + input_invert_winter_mode_value: !input input_invert_winter_mode_value + input_mode_outside_temperature: !input input_mode_outside_temperature + input_mode_outside_temperature_threshold: !input input_mode_outside_temperature_threshold + input_mode_room_temperature: !input input_mode_room_temperature + input_mode_room_temperature_threshold: !input input_mode_room_temperature_threshold + + # proximity + input_proximity: !input input_proximity + + # people + input_persons: !input input_persons + input_mode_guest: !input input_mode_guest + input_people_entering_home_duration: !input input_people_entering_home_duration + input_people_leaving_home_duration: !input input_people_leaving_home_duration + + # force comfort + input_mode_party: !input input_mode_party + input_force_max_temperature: !input input_force_max_temperature + input_force_eco_temperature: !input input_force_eco_temperature + + # calibration + input_calibration_delta: !input input_calibration_delta + input_calibration_generic: !input input_calibration_generic + input_calibration_step_size: !input input_calibration_step_size + input_calibration_key_word: !input input_calibration_key_word + input_generic_calibration_offset: !input input_generic_calibration_offset + + # Aggressive Mode + input_aggressive_mode_offset: !input input_aggressive_mode_offset + input_aggressive_mode_range: !input input_aggressive_mode_range + input_aggressive_mode_calibration: !input input_aggressive_mode_calibration + + # away mode + input_away_offset: !input input_away_offset + is_scheduler_away_mode: !input input_away_scheduler_mode + is_presence_away_mode: !input input_away_presence_mode + presence_ignor_people: !input input_away_presence_ignor_people + + # heating adjustments + input_adjustments: !input input_adjustments + + # temperature tweaks + is_reset_temperature: !input input_reset_temperature + is_off_instead_min: !input input_off_instead_of_eco + is_not_off_but_min: !input input_min_instead_of_off + is_fahrenheit: !input input_fahrenheit + is_heat_only_if_below_real_temp: !input input_off_if_above_room_temperature + is_physical_change_enabled: !input input_physical_change + is_off_if_nobody_home: !input input_off_if_nobody_home + + # custom tweaks + input_action_call_delay: !input input_action_call_delay + input_custom_action: !input input_custom_action + input_startup_delay: !input input_startup_delay + + # valve positioning + input_fully_open_difference: !input input_fully_open_difference + input_valve_opening_keyword: !input input_valve_opening_keyword + input_valve_positioning_step_size: !input input_valve_positioning_step_size + input_valve_positioning_mode: !input input_valve_positioning_mode + input_valve_positioning_timeout: !input input_valve_positioning_timeout + input_valve_positioning_max_opening: !input input_valve_positioning_max_opening + + ##################################################################################### + #################################### EVALUATION ##################################### + ##################################################################################### + + # global + is_temperature_sensor_defined: "{{ input_temperature_sensor != [] }}" + invalid_states: > + {{ ['unknown', 'unavailable'] }} + + value_temperature_sensor: > + {% if is_temperature_sensor_defined %} + {{ states(input_temperature_sensor) }} + {% else %} + {{ 'unknown' }} + {% endif %} + + valid_temperature_sensor: > + {{ value_temperature_sensor not in invalid_states }} + + factor: "{{ iif(input_hvac_mode == 'cool', -1, 1) | int }}" + current_time_stamp: "{{ now() }}" + is_metric: "{{ not is_temperature_sensor_defined or (is_temperature_sensor_defined and state_attr(input_temperature_sensor,VAR_UNIT_OF_MEASUREMENT) == '°C') }}" + + # uptime + up_time_sensor: "{{ integration_entities('uptime') | first | default(none) }}" + is_uptime_defined: "{{ up_time_sensor != none }}" + uptime: > + {% if is_uptime_defined %} + {{ states(up_time_sensor) | as_datetime }} + {% else %} + {{ current_time_stamp | as_datetime }} + {% endif %} + + #startup delay + startup_delay: > + {% set start_delay_seconds = timedelta(**input_startup_delay).total_seconds() %} + + {% if not is_uptime_defined or start_delay_seconds == 0 %} + {{ none }} + {% else %} + {% set difference = (current_time_stamp | as_datetime - uptime | as_datetime).total_seconds() %} + {% set real_start_delay = (start_delay_seconds - difference) %} + + {{ iif(real_start_delay > 0, real_start_delay, none) }} + {% endif %} + + # on/off + state_outside_temp: > + {% if input_mode_outside_temperature == none %} + {{ none }} + {% else %} + {% set outside_state = false %} + {% set use_room_temp = input_mode_room_temperature and valid_temperature_sensor %} + {% set room_state = iif(use_room_temp, false, true) %} + + {% set state = states(input_mode_outside_temperature) %} + {% set state = iif(is_number(state) == true, state, state_attr(input_mode_outside_temperature,'temperature'))%} + + {% if is_number(state) %} + {% set outside_state = (state | float - input_mode_outside_temperature_threshold | float) * factor < 0 %} + {% endif %} + + {% if use_room_temp %} + {% set state = states(input_temperature_sensor) %} + + {% if is_number(state) %} + {% set room_state = (state | float - input_mode_room_temperature_threshold | float) * factor < 0 %} + {% endif %} + {% endif %} + + {{ room_state and outside_state }} + {% endif %} + + state_ahc: > + {% set result = true %} + {% if input_mode_winter != none %} + {% set activation_state = iif(input_invert_winter_mode_value, 'off', 'on') %} + {% set result = is_state(input_mode_winter, activation_state) %} + {% endif %} + + {{ iif(state_outside_temp == none, result, result and state_outside_temp) }} + + # proximity + is_proximity_defined: "{{ input_proximity != none }}" + + state_proximity_arrived: > + {% set proximity_entities = device_entities(input_proximity) %} + {% set is_arrived = proximity_entities + | select('is_state','arrived') + | expand + | selectattr('attributes.device_class', 'eq', 'enum') + | list | count > 0 %} + {{ is_arrived }} + + state_proximity_way_home: > + {% set proximity_entities = device_entities(input_proximity) %} + + {% set earliest_timestamp = current_time_stamp | as_datetime - timedelta(**input_proximity_duration) %} + {% set uptime_duration = as_datetime(uptime) + timedelta(**input_proximity_duration) %} + + {% if uptime_duration > earliest_timestamp %} + {% set earliest_timestamp = uptime_duration%} + {% endif %} + + {% set entities_towards = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'enum') + | selectattr('last_changed', '<=', earliest_timestamp) + | map(attribute='entity_id') | select('is_state','towards') + | map('regex_replace','_(?=[^_]*$)(.*)', '') + | list %} + + {% set distances = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'distance') + | map(attribute='state') + | reject('eq', 'unknown') + | map('int') + | select('<=', input_proximity_distance | int) + | map('string') + | list %} + + {% set entities_distances = proximity_entities + | expand + | selectattr('attributes.device_class', 'eq', 'distance') + | selectattr('state', 'in', distances) + | map(attribute='entity_id') + | map('regex_replace','_(?=[^_]*$)(.*)', '') + | list %} + + {% set towards_and_in_distance = entities_towards | select('in', entities_distances) | list | count > 0 %} + + {{ towards_and_in_distance }} + + # persons + is_person_defined: "{{ input_persons | count > 0 or input_mode_guest != none }}" + is_guest_mode: "{{ input_mode_guest != none and is_state(input_mode_guest, 'on') }}" + is_anybody_home: > + {% if is_guest_mode %} + {{ true }} + {% elif not is_person_defined %} + {{ false }} + {% else %} + {% set on_time_delta = current_time_stamp | as_datetime - timedelta(**input_people_entering_home_duration) %} + {% set off_time_delta = current_time_stamp | as_datetime - timedelta(**input_people_leaving_home_duration) %} + + {% set uptime_on = as_datetime(uptime) + timedelta(**input_people_entering_home_duration) %} + {% set uptime_off = as_datetime(uptime) + timedelta(**input_people_leaving_home_duration) %} + + {% set result = false %} + + {% if uptime_on > on_time_delta or uptime_off > off_time_delta %} + {{ input_persons | expand + | selectattr('state', 'eq', 'home') + | list + | count > 0 }} + {% else %} + {% set persons_home = state_attr('zone.home','persons') | select('in', input_persons) | list %} + + {% set somebody_is_home = persons_home | expand + | selectattr('last_changed', '<=', on_time_delta) + | list + | count > 0 %} + + {% set somebody_is_leaving = persons_home | count == 0 and ['zone.home'] | expand | map(attribute='last_changed') | first | default(off_time_delta) > off_time_delta %} + + {{ somebody_is_home or somebody_is_leaving }} + {% endif %} + {% endif %} + + is_anybody_home_or_proximity: "{{ is_anybody_home or state_proximity_way_home or state_proximity_arrived}}" + + # schedules + active_scheduler: > + {% set selected_scheduler = none %} + {% set schedules_count = input_schedulers | count %} + + {% if schedules_count == 0 %} + {% set selected_scheduler = none %} + {% elif schedules_count == 1 or input_scheduler_selector == none %} + {% set selected_scheduler = input_schedulers | first %} + {% elif schedules_count > 1 %} + {% set selector_value = states(input_scheduler_selector) %} + + {% if is_number(selector_value) %} + {% set selector_value = iif(selector_value | int > schedules_count, schedules_count, selector_value) %} + {% set selector_value = iif(selector_value | int <= 0, 1, selector_value) %} + {% set selected_scheduler = input_schedulers[selector_value | int - 1] %} + {% elif selector_value in ['on','off'] %} + {% set selected_scheduler = iif(selector_value == 'off', input_schedulers[0], input_schedulers[1]) %} + {% else %} + {% set selected_scheduler = input_schedulers | expand | selectattr('attributes.friendly_name', 'eq', selector_value) | map(attribute='entity_id') | first | default(none) %} + {% if (selected_scheduler == none) %} + {% set selected_scheduler = input_schedulers | expand | selectattr('attributes.friendly_name', 'search', '(?i)' + selector_value) | map(attribute='entity_id') | first | default(none) %} + {% endif %} + {% endif %} + {% endif %} + + {{ selected_scheduler }} + + is_scheduler_defined: "{{ active_scheduler != none }}" + + state_scheduler: "{{ active_scheduler != none and is_state(active_scheduler,'on') }}" + + # presence + is_presence_sensor_defined: "{{ input_presence_sensor != none }}" + is_presence_scheduler_defined: "{{ input_scheduler_presence != none }}" + state_presence_scheduler: "{{ is_presence_scheduler_defined and is_state(input_scheduler_presence, 'on') }}" + + state_presence_sensor: > + {% if not is_presence_sensor_defined %} + {{ false }} + {% else %} + {% set last_changed = [input_presence_sensor] | expand | map(attribute='last_changed') | first %} + {% set sensor_state = is_state(input_presence_sensor, 'on') %} + {% set reaction_time = iif(sensor_state, input_presence_reaction_on_time, input_presence_reaction_off_time) %} + {% set min_timestamp = last_changed + timedelta(**reaction_time) %} + {% set current_ts = current_time_stamp | as_datetime%} + + {% if is_uptime_defined and as_datetime(uptime) + timedelta(**reaction_time) > current_ts - timedelta(**reaction_time) %} + {{ sensor_state }} + {% else %} + {% set is_limit = min_timestamp <= current_ts %} + + {{ (sensor_state == true and is_limit) or (sensor_state == false and not is_limit) }} + {% endif %} + {% endif %} + + state_presence: > + {{ iif(is_presence_scheduler_defined, state_presence_scheduler and state_presence_sensor, state_presence_sensor) }} + + # force max temperature + is_force_max_temperature: "{{ input_force_max_temperature != [] and is_state(input_force_max_temperature, 'on') }}" + is_force_eco_temperature: "{{ input_force_eco_temperature != [] and is_state(input_force_eco_temperature, 'on') }}" + + # party + active_party_entity: "{{ input_mode_party | expand | selectattr('state', 'in', ['active','on']) | map(attribute='entity_id') | first | default(none) }}" + state_party: "{{ active_party_entity != none }}" + party_temp: > + {% set pos_party_temp = none %} + {% if state_party == true %} + {% set name = state_attr(active_party_entity,'friendly_name') %} + {% set pos_temp = name.split(' ') | last %} + {% if is_number(pos_temp) %} + {% set pos_party_temp = pos_temp | float %} + {% endif %} + {% endif %} + {{ pos_party_temp }} + + # away + is_away: > + {% if is_person_defined and not is_anybody_home_or_proximity %} + {{ (is_scheduler_away_mode and state_scheduler) or (is_presence_away_mode and state_presence_scheduler and not state_presence) }} + {% elif presence_ignor_people and is_presence_away_mode %} + {{ state_presence_scheduler and not state_presence }} + {% elif is_presence_away_mode and is_person_defined and is_anybody_home_or_proximity and not presence_ignor_people %} + {{ not state_presence }} + {% else %} + {{ false }} + {% endif %} + + # windows & doors + state_window: > + {% set current_ts = current_time_stamp | as_datetime %} + {% set on_time_delta = current_ts - timedelta(**input_windows_reaction_time_open) %} + {% set off_time_delta = current_ts - timedelta(**input_windows_reaction_time_close) %} + + {% set has_open_windows = input_windows + | expand + | selectattr('state', 'in', ['on','open','tilted']) + | selectattr('last_changed', '<=', on_time_delta) + | list + | count > 0 %} + + {% set closed_but_not_in_duration = input_windows + | expand + | selectattr('state', 'in', ['off','closed']) + | selectattr('last_changed', '>=', off_time_delta) + | list + | count > 0 %} + + {{ has_open_windows or closed_but_not_in_duration }} + + # aggressive mode + is_aggressive_mode: "{{ input_aggressive_mode_offset > 0 }}" + is_aggressive_mode_calibration: "{{ is_aggressive_mode and input_aggressive_mode_calibration and valid_temperature_sensor }}" + + # frost protection + is_frost_protection: > + {% set frost_protection_timestamp = as_datetime(current_time_stamp) - timedelta(**input_frost_protection_duration) %} + {% if frost_protection_timestamp == as_datetime(current_time_stamp) %} + {{ false }} + {% else %} + {% set relevant_entities = [input_presence_sensor] + [input_mode_guest] + input_persons %} + {% set relevant_entities_count = relevant_entities | reject('eq',none) | list | count %} + + {% if relevant_entities_count > 0 %} + + {% set presence_count = [input_presence_sensor] + | reject('eq',none) + | reject('is_state','on') + | expand + | selectattr('last_changed', '<=', frost_protection_timestamp) + | list | count %} + + {% set persons_count = input_persons + | reject('eq',none) + | reject('is_state','home') + | expand + | selectattr('last_changed', '<=', frost_protection_timestamp) + | list | count %} + + {% set guest_mode_count = [input_mode_guest] + | reject('eq',none) + | reject('is_state','on') + | expand + | selectattr('last_changed', '<=', frost_protection_timestamp) + | list | count %} + + {{ presence_count + guest_mode_count + persons_count == relevant_entities_count }} + {% else %} + {{ false }} + {% endif %} + {% endif %} + + # liming protection + is_liming_protection: > + {% if not input_liming_protection%} + {{ false }} + {% else %} + {% set enable_liming = true %} + {% if input_mode_winter != none %} + {% set enable_liming = is_state(input_mode_winter,'on') or input_liming_in_winter %} + {% endif %} + + {% set current_timestamp = now() %} + + {% set is_liming_day = input_liming_protection_day == as_datetime(current_timestamp).strftime('%a') %} + + {% set start_hour = input_liming_protection_time.split(':')[0] | int %} + {% set start_minute = input_liming_protection_time.split(':')[1] | int %} + + {% set today_start = as_datetime(current_timestamp).replace(second=0,microsecond=0,hour=start_hour,minute=start_minute) %} + {% set today_end = as_datetime(current_timestamp).replace(second=0,microsecond=0,hour=start_hour,minute=start_minute) + timedelta(minutes=input_liming_protection_duration | int) %} + + {% set is_liming_time = as_datetime(current_timestamp) >= today_start and as_datetime(current_timestamp) <= today_end %} + + {{ enable_liming and is_liming_day and is_liming_time }} + {% endif %} + + # thermostat groups + valves: > + {{ input_trvs | expand + | selectattr('attributes.hvac_modes','search','(?i)'+input_hvac_mode) + | map(attribute='entity_id') + | list }} + + valves_unsupported: > + {{ input_trvs | reject('in',valves) | list }} + + valves_off_mode: > + {{ valves | expand | selectattr('attributes.hvac_modes','search','(?i)off') + | map(attribute='entity_id') + | list }} + + valves_without_off_mode: > + {{ valves | reject('in',valves_off_mode) | list }} + + # tado + valves_tado: "{{ valves | select('is_device_attr', 'manufacturer', 'Tado') | list }}" + + # valves external thermometer support + valves_external: > + {% set result = namespace(r=[]) %} + {% for valve in valves %} + {% set select = device_entities(device_id(valve)) + | expand + | selectattr('domain','in','select') + | selectattr('attributes.options', 'contains', 'external') + | map(attribute='entity_id') | list | first | default(none) %} + {% if select != none %} + {% set result.r = result.r + [valve] %} + {% endif %} + {% endfor %} + {{ result.r }} + + # danfoss / popp / hive / Bosch + valves_danfoss: "{{ valves | select('is_device_attr', 'manufacturer', 'Danfoss') | list }}" + valves_popp: "{{ valves | select('is_device_attr', 'manufacturer', 'Popp') | list }}" + valves_hive: "{{ valves | select('is_device_attr', 'manufacturer', 'Hive') | list }}" + valves_bosch: "{{ valves | select('is_device_attr', 'manufacturer', 'Bosch') | list }}" + valves_dph: "{{ valves_danfoss + valves_popp + valves_hive + valves_bosch }}" + + valves_calibration_common: "{{ valves | reject('in', valves_tado + valves_dph + valves_external) | list }}" + + # global + last_comfort_entity_change: "{{ [input_temperature_comfort_entity] | expand | map(attribute='last_changed') | list | first | default(none) }}" + last_eco_entity_change: "{{ [input_temperature_eco_entity] | expand | map(attribute='last_changed') | list | first | default(none) }}" + + ##################################################################################### + ################################## ADJUSTMENTS ###################################### + ##################################################################################### + + latest_entry_today: > + {% set scheduler_name = none %} + {% if active_scheduler != none %} + {% set scheduler_name = state_attr(active_scheduler,'friendly_name') %} + {% endif %} + + {% set current_ts = current_time_stamp | as_datetime %} + + {% set current_day = current_ts.strftime('%a') %} + {% set current_time = current_ts.strftime('%H:%M') %} + + {% set plan = input_adjustments | rejectattr('time', 'undefined') + | selectattr('time','<=', current_time| string) + | list %} + + {% set selected_entries_days_and_schedule = plan | rejectattr('days','==',Undefined) | selectattr('days','search',current_day) + | rejectattr('scheduler','==',Undefined) | selectattr('scheduler','in',scheduler_name) + | list %} + + {% set selected_entries_days = plan | rejectattr('days','==',Undefined) | selectattr('days','search',current_day) + | selectattr('scheduler','in',[Undefined]) + | list %} + + {% set selected_entries_schedule = plan | rejectattr('scheduler','==',Undefined) | selectattr('scheduler','in',scheduler_name) + | selectattr('days','in',[Undefined]) + | list %} + + {% set selected_entries_time_only = plan | selectattr('days','in',[Undefined]) + | selectattr('scheduler','in',[Undefined]) + | list %} + + {% set selected_entries = selected_entries_days_and_schedule + selected_entries_days + selected_entries_schedule + selected_entries_time_only %} + + {% if selected_entries | count > 0%} + {{ selected_entries | sort(attribute='time', reverse = true) | first }} + {% else %} + {{ none }} + {% endif %} + + latest_entry_day_before: > + {% set timestamp = as_datetime(current_time_stamp).replace(hour=23,minute=59) + timedelta(days=-1) %} + + {% set scheduler_name = none %} + {% if active_scheduler != none %} + {% set scheduler_name = state_attr(active_scheduler,'friendly_name') %} + {% endif %} + + {% set current_day = timestamp.strftime('%a') %} + {% set current_time = timestamp.strftime('%H:%M') %} + + {% set plan = input_adjustments | rejectattr('time', 'undefined') + | selectattr('time','<=', current_time| string) + | list %} + + {% set selected_entries_days_and_schedule = plan | rejectattr('days','==',Undefined) | selectattr('days','search',current_day) + | rejectattr('scheduler','==',Undefined) | selectattr('scheduler','in',scheduler_name) + | list %} + + {% set selected_entries_days = plan | rejectattr('days','==',Undefined) | selectattr('days','search',current_day) + | selectattr('scheduler','in',[Undefined]) + | list %} + + {% set selected_entries_schedule = plan | rejectattr('scheduler','==',Undefined) | selectattr('scheduler','in',scheduler_name) + | selectattr('days','in',[Undefined]) + | list %} + + {% set selected_entries_time_only = plan | selectattr('days','in',[Undefined]) + | selectattr('scheduler','in',[Undefined]) + | list %} + + {% set selected_entries = selected_entries_days_and_schedule + selected_entries_days + selected_entries_schedule + selected_entries_time_only %} + + {% if selected_entries | count > 0%} + {{ selected_entries | sort(attribute='time', reverse = true) | first }} + {% else %} + {{ none }} + {% endif %} + + entry: "{{ iif(latest_entry_today != none, latest_entry_today, latest_entry_day_before) }}" + + entry_time: > + {% if entry != none %} + {% set entry_hour = entry['time'].split(':')[0] | int %} + {% set entry_minute = entry['time'].split(':')[1] | int %} + {{ as_datetime(current_time_stamp).replace(hour=entry_hour, minute=entry_minute, second=0, microsecond=0) + timedelta(days=iif(latest_entry_today == none,-1,0)) }} + {% endif %} + + entry_comfort_temp: > + {% if entry != none and 'comfort' in entry.keys() and (last_comfort_entity_change == none or as_datetime(entry_time) > as_datetime(last_comfort_entity_change)) %} + {% set entry_temp = entry['comfort']%} + {% if is_number(entry_temp) %} + {{ entry_temp }} + {% elif states[entry_temp] != none %} + {{ states(entry_temp) }} + {% endif %} + {% else %} + {{ none }} + {% endif %} + + entry_eco_temp: > + {% if entry != none and 'eco' in entry.keys() and (last_eco_entity_change == none or as_datetime(entry_time) > as_datetime(last_eco_entity_change)) %} + {% set entry_temp = entry['eco']%} + {% if is_number(entry_temp) %} + {{ entry_temp }} + {% elif states[entry_temp] != none %} + {{ states(entry_temp) }} + {% endif %} + {% else %} + {{ none }} + {% endif %} + + entry_calibration: > + {% if entry != none and 'calibration' in entry.keys() %} + {{ entry['calibration'] == 'on' }} + {% else %} + {{ true }} + {% endif %} + + entry_mode: > + {% if entry != none and 'mode' in entry.keys() %} + {{ entry['mode'] }} + {% else %} + {{ 'auto' }} + {% endif %} + + + ##################################################################################### + ############################### TRIGGER EVALUATION ################################## + ##################################################################################### + + trigger_id_defined: "{{ trigger.id is defined }}" + + # calibration + is_calibration_trigger: > + {% if valves_dph | count > 0 and trigger_id_defined and trigger.id in ['calibration_popp_ping','calibration_popp_change'] %} + {{ true }} + {% elif is_aggressive_mode_calibration and trigger_id_defined and 'aggressive_mode' in trigger.id %} + {{ true }} + {% else %} + {{ trigger_id_defined and 'calibration' in trigger.id and not trigger.id == 'calibration_aggressive_mode_thermostat_temp_change' }} + {% endif %} + + # changes + is_generic_calibration_trigger: "{{ is_calibration_trigger and input_calibration_generic }}" + is_generic_calibration: "{{ is_generic_calibration_trigger and entry_calibration and valid_temperature_sensor }}" + + is_aggressive_mode_trigger: "{{ is_aggressive_mode and trigger_id_defined and 'aggressive_mode' in trigger.id }}" + + is_change_trigger: > + {{ trigger_id_defined and + 'temperature_change' in trigger.id and + ('presence' in trigger.id or + 'scheduler' in trigger.id or + 'proximity' in trigger.id or + 'person' in trigger.id or + '_ds' in trigger.id) + and not trigger.id == 'temperature_change_valve_target' }} + + set_max_temperature: "{{ is_force_max_temperature or is_liming_protection }}" + + is_pysical_change: > + {{ trigger_id_defined + and trigger.id == 'temperature_change_valve_target' + and is_physical_change_enabled + and not state_window + and not set_max_temperature + and not is_away }} + + is_adjustment_trigger: + "{{ trigger_id_defined and trigger.id == 'temperature_change_heating_adjustment' and + (entry_comfort_temp != none or entry_eco_temp != none) }}" + + is_reset: > + {{ (is_reset_temperature and is_change_trigger) or + is_pysical_change or is_adjustment_trigger }} + + is_changes_trigger: > + {% if state_window %} + {% if trigger_id_defined and 'temperature_change_window_on' in trigger.id %} + {{ true }} + {% elif trigger_id_defined and 'temperature_change_window_off' not in trigger.id %} + {{ false }} + {% endif %} + {% elif trigger.platform == none %} + {{ true }} + {% elif trigger_id_defined and trigger.id == 'temperature_change_valve_target' %} + {{ false }} + {% elif is_heat_only_if_below_real_temp and trigger_id_defined and 'above_temp' in trigger.id %} + {{ true }} + {% elif is_aggressive_mode_calibration and is_aggressive_mode_trigger %} + {{ false }} + {% elif is_aggressive_mode_trigger %} + {{ true }} + {% elif is_generic_calibration %} + {{ true }} + {% else %} + {{ trigger_id_defined and 'temperature_change' in trigger.id}} + {% endif %} + + is_scene_create_trigger: > + {{ trigger_id_defined and (("window_on" in trigger.id and not state_party) or ("party_on" in trigger.id and not state_window)) }} + + is_scene_apply_trigger: > + {{ trigger_id_defined and ("window_off" in trigger.id or "party_off" in trigger.id) and not is_legacy_restore and not (state_window or state_party) }} + + is_scene_destroy_trigger: > + {{ (is_change_trigger or trigger.id == 'temperature_change_heating_adjustment') and (state_window or state_party) }} + + # scene management + scene_entities: "{{ valves }}" + scene_window_id: "{{ 'scene.' + this.entity_id | replace('automation.','') | replace('.','_') + '_window' }}" + scene_party_id: "{{ 'scene.' + this.entity_id | replace('automation.','') | replace('.','_') + '_party' }}" + scenes_all: "{{ [scene_window_id, scene_party_id] }}" + + scene_to_apply: > + {% if is_scene_apply_trigger and "window_off" in trigger.id %} + {{ scene_window_id }} + {% elif is_scene_apply_trigger and "party_off" in trigger.id %} + {{ scene_party_id }} + {% else %} + {{ none }} + {% endif %} + + scenes_to_destroy: > + {% set scenes = [] %} + {% if is_scene_destroy_trigger %} + {% set scenes = iif(state_window, scenes + [scene_window_id], scenes) %} + {% set scenes = iif(state_party, scenes + [scene_party_id], scenes) %} + {% endif %} + {{ scenes }} + + scene_to_create: > + {{ iif(is_scene_create_trigger and "window_on" in trigger.id, scene_window_id, scene_party_id) }} + + ##################################################################################### + #################################### CHANGES ######################################## + ##################################################################################### + + set_comfort: > + {% if is_force_max_temperature %} + {{ true }} + {% elif entry_mode == 'eco' %} + {{ false }} + {% elif entry_mode == 'comfort' %} + {{ true }} + {% elif state_party %} + {{ true }} + {% elif is_force_eco_temperature %} + {{ false }} + {% elif is_away %} + {{ true }} + {% elif not is_scheduler_defined and not is_presence_sensor_defined %} + {{ is_anybody_home_or_proximity }} + {% else %} + {% set comfort_state = state_scheduler or state_presence %} + + {% if is_person_defined or is_proximity_defined %} + {{ is_anybody_home_or_proximity and comfort_state }} + {% else %} + {{ comfort_state }} + {% endif %} + {% endif %} + + mode: > + {% if not state_ahc %} + {{ 'off' }} + {% elif state_window and input_window_open_temperature | int == 0 and not set_max_temperature %} + {{ 'off' }} + {% elif entry_mode == 'off' %} + {{ 'off' }} + {% elif is_off_instead_min and not set_comfort %} + {{ 'off' }} + {% elif is_off_if_nobody_home and is_person_defined and not is_anybody_home_or_proximity and not set_comfort %} + {{ 'off' }} + {% else %} + {{ input_hvac_mode }} + {% endif %} + + temperature_comfort_of_entity: > + {% if(input_temperature_comfort_entity != none) %} + {{ states(input_temperature_comfort_entity) | float }} + {% else %} + {{ none }} + {% endif %} + + temperature_eco_of_entity: > + {% if(input_temperature_eco_entity != none) %} + {{ states(input_temperature_eco_entity) | float }} + {% else %} + {{ none }} + {% endif %} + + temperature_comfort: "{{ [entry_comfort_temp, temperature_comfort_of_entity, input_temperature_comfort_static] | reject('==', none) | first }}" + temperature_away: "{{ temperature_comfort | float - input_away_offset }}" + temperature_eco: "{{ [entry_eco_temp, temperature_eco_of_entity, input_temperature_eco_static] | reject('==', none) | first }}" + target_temperature: > + {% if state_window and input_window_open_temperature > 0 %} + {{ input_window_open_temperature }} + {% elif state_party %} + {{ iif(party_temp != none, party_temp, temperature_comfort) }} + {% elif is_frost_protection %} + {{ input_frost_protection_temp }} + {% else %} + {{ iif(set_comfort, iif(is_away, temperature_away, temperature_comfort), temperature_eco) }} + {% endif %} + + changes: > + {% set n = namespace(dict=[]) %} + + {% set original_mode = mode %} + + {% if not is_changes_trigger %} + {{ n.dict }} + {% else %} + {% for valve in input_trvs %} + + {% set current_valve_temp = state_attr(valve, 'current_temperature') | float(20) %} + {% set current_valve_target_temp = state_attr(valve, 'temperature') | float(temperature) %} + {% set current_valve_mode = states(valve) %} + {% set min_temp = state_attr(valve, 'min_temp') | float(5) %} + {% set max_temp = state_attr(valve, 'max_temp') | float(30) %} + + {% set valve_temp = target_temperature %} + + {% set dont_turn_off = + valve in valves_without_off_mode or + is_not_off_but_min or + (state_window and input_window_open_temperature > 0) or + set_max_temperature %} + + {% set ref_temp = current_valve_temp %} + {% if valid_temperature_sensor %} + {% set ref_temp = value_temperature_sensor | float(current_valve_temp) %} + {% endif %} + + {% if is_heat_only_if_below_real_temp and iif(factor == 1, target_temperature <= ref_temp, target_temperature >= ref_temp) %} + {% set mode = 'off' %} + {% endif %} + + {% set valve_mode = iif(mode == 'off' and dont_turn_off, current_valve_mode, mode) %} + + {% if mode != 'off' %} + + {% if is_aggressive_mode and not is_aggressive_mode_calibration %} + + {% set temp_diff = valve_temp - ref_temp %} + + {% if temp_diff * factor < input_aggressive_mode_range * -1 %} + {% set valve_temp = valve_temp - input_aggressive_mode_offset * factor %} + {% elif temp_diff * factor > input_aggressive_mode_range %} + {% set valve_temp = valve_temp + input_aggressive_mode_offset * factor %} + {% endif %} + + {% endif %} + + {% if input_calibration_generic %} + + {% if current_valve_temp != ref_temp %} + {% set offset = current_valve_temp - ref_temp %} + + {% set offset = iif(offset > float(input_generic_calibration_offset), input_generic_calibration_offset, offset) %} + {% set offset = iif(offset < float(input_generic_calibration_offset) * -1, input_generic_calibration_offset * -1, offset) %} + + {% set temp_with_offset = float(valve_temp) + float(offset) %} + {% set step = state_attr(valve, 'target_temp_step') | float(0.5) %} + + {% set temp_with_offset = (temp_with_offset | float(0) / float(step)) | round(0) * float(step) %} + + {% set valve_temp = iif(input_calibration_step_size == 'full', float(temp_with_offset) | round(), temp_with_offset | round(1)) %} + + {% endif %} + {% endif %} + + {% endif %} + + {% if mode == 'off' and dont_turn_off %} + {% set valve_temp = min_temp %} + {% endif %} + + {% set valve_temp = iif(set_max_temperature, max_temp, valve_temp) %} + {% set valve_temp = iif(valve_temp > max_temp, max_temp, valve_temp) %} + {% set valve_temp = iif(valve_temp < min_temp, min_temp, valve_temp) %} + + {% if current_valve_mode != valve_mode or current_valve_target_temp != valve_temp %} + {% set n.dict = n.dict + [(valve, [{'mode': valve_mode , 'temp': valve_temp}])] %} + {% endif %} + + {% endfor %} + + {% set mode = original_mode %} + + {{ dict.from_keys(n.dict) }} + {% endif %} + + positioning: > + {% set n = namespace(dict=[]) %} + + {% if input_valve_positioning_mode == 'off' %} + {{ n.dict }} + {% else %} + {% for valve in input_trvs %} + + {% set current_temp = state_attr(valve, 'current_temperature') | float(none) %} + {% if valid_temperature_sensor %} + {% set current_temp = value_temperature_sensor | float(none) %} + {% endif %} + + {% set target_temp = state_attr(valve, 'temperature') | float(none) %} + + {% set open_valve_entity = device_entities(device_id(valve)) | expand + | selectattr('domain','in','number') + | selectattr('entity_id', 'search', input_valve_opening_keyword) + | map(attribute='entity_id') + | list | first | default(none) %} + + {% if open_valve_entity != none and current_temp != none and target_temp != none and + ( + (trigger_id_defined and trigger.id == 'positioning_event') or + ([open_valve_entity] | expand | map(attribute='last_changed') | first) + timedelta(**input_valve_positioning_timeout) <= now() + ) + %} + + {% set opening = 100 %} + {% set difference = target_temp - current_temp %} + {% set step_size = input_valve_positioning_step_size | int %} + + {% if input_fully_open_difference > 0 and not is_force_max_temperature %} + + {% set opening_regular = (100 / input_fully_open_difference) * difference %} + {% set opening_pessimistic = sqrt(((100 / input_fully_open_difference) * difference) | abs) * 10 %} + {% set opening_optimistic = ((100 / input_fully_open_difference) * difference)**2 / 100 %} + + {% set opening = opening_regular %} + {% set opening = iif(input_valve_positioning_mode == 'pessimistic', opening_pessimistic, opening) %} + {% set opening = iif(input_valve_positioning_mode == 'optimistic', opening_optimistic, opening) %} + + {% set opening = iif(difference >= input_fully_open_difference, 100, opening) %} + {% set opening = iif(difference < 0, 0, opening) %} + + {% set opening = opening / 100 * input_valve_positioning_max_opening %} + + {% set opening = ((opening + step_size / 2) // step_size * step_size) | int %} + {% endif %} + + {% set open_valve_entity_value = states(open_valve_entity) | int %} + + {% if open_valve_entity_value != opening %} + {% set n.dict = n.dict + [(valve, [{'entity': open_valve_entity , 'value': opening, 'current_temp': current_temp, 'target_temp': target_temp, 'difference': difference}])] %} + {% endif %} + + {% endif %} + {% endfor %} + + {{ dict.from_keys(n.dict) }} + {% endif %} + + # reset temperature + reset_data: > + {% set result = [] %} + {% if is_adjustment_trigger %} + {% if entry_comfort_temp != none and input_temperature_comfort_entity != none %} + {% set result = result + [{'entity': input_temperature_comfort_entity, 'temp': entry_comfort_temp}] %} + {% endif %} + {% if entry_eco_temp != none and input_temperature_eco_entity != none %} + {% set result = result + [{'entity': input_temperature_eco_entity, 'temp': entry_eco_temp}] %} + {% endif %} + {% else %} + {% set entity = none %} + {% if is_reset and set_comfort %} + {% set entity = iif(is_pysical_change, input_temperature_comfort_entity, input_temperature_eco_entity) %} + {% elif is_reset and not set_comfort %} + {% set entity = iif(is_pysical_change, input_temperature_eco_entity, input_temperature_comfort_entity) %} + {% endif %} + + {% set temp_r = none %} + {% if is_pysical_change %} + {% set temp_r = state_attr(trigger.to_state.entity_id,'temperature') %} + {% else %} + {% set temp_r = iif(is_reset and entity == input_temperature_eco_entity, + input_temperature_eco_static, input_temperature_comfort_static) %} + {% endif %} + + {% if entity != none and temp_r != none %} + {% set result = result + [{'entity': entity, 'temp': temp_r}] %} + {% endif %} + {% endif %} + + {{ result }} + + is_reset_trigger: "{{ is_reset and reset_data | count > 0 }}" + + ##################################################################################### + ################################## CALIBRATION ###################################### + ##################################################################################### + + is_native_calibration: "{{ not input_calibration_generic and entry_calibration and valid_temperature_sensor }}" + is_native_calibration_trigger: "{{ is_calibration_trigger and is_native_calibration }}" + + rounding_mode: > + {% if is_number(input_calibration_step_size) or input_calibration_step_size == 'full' %} + {{ 'manual' }} + {% else %} + {{ 'auto' }} + {% endif %} + + # TADO + calibration_tado: > + {% set n = namespace(dict=[]) %} + + {% if is_native_calibration_trigger %} + {% for valve in valves_tado %} + + {% set offset_old = state_attr(valve, 'offset_celsius') | float(0) %} + {% set local_temperature = state_attr(valve, 'current_temperature') | float %} + {% set calibration_sensor_temperature = value_temperature_sensor | float %} + + {% set offset_new = (-(local_temperature - calibration_sensor_temperature) + offset_old) %} + + {% if is_aggressive_mode_calibration %} + {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - calibration_sensor_temperature %} + + {% if temp_diff * factor < input_aggressive_mode_range * -1 %} + {% set offset_new = offset_new + input_aggressive_mode_offset * factor %} + {% elif temp_diff * factor > input_aggressive_mode_range %} + {% set offset_new = offset_new - input_aggressive_mode_offset * factor %} + {% endif %} + {% endif %} + + {% set t_min = -10.9 %} + {% set t_max = 10.9 %} + + {% set offset_new = iif(offset_new > t_max, t_max, offset_new) %} + {% set offset_new = iif(offset_new < t_min, t_min, offset_new) %} + + {% set offset_new = offset_new | round(1) %} + + {% if (float(offset_old) - float(offset_new)) | abs >= float(input_calibration_delta) %} + {% set n.dict = n.dict + [(valve, [{'value': offset_new }])] %} + {% endif %} + + {% endfor %} + {% endif %} + + {{ dict.from_keys(n.dict) }} + + # XIAOMI / AQARA / SONOFF + calibration_external: > + {% set n = namespace(dict=[]) %} + + {% if is_native_calibration_trigger %} + {% for valve in valves_external %} + + {% set calibration_entities = device_entities(device_id(valve)) | + expand | selectattr('domain','in','number') | + selectattr('entity_id', 'search', input_calibration_key_word) | + map(attribute='entity_id') | list %} + + {% if calibration_entities | count > 0 %} + + {% set calibration_entity = calibration_entities | first %} + {% set offset_old = states(calibration_entity) | float(0) %} + {% set offset_new = value_temperature_sensor | float %} + + {% set step = state_attr(calibration_entity, 'step') | float(1) %} + {% if rounding_mode == 'manual' %} + {% set step = input_calibration_step_size | float(1) %} + {% endif %} + + {% set min_val = state_attr(calibration_entity,'min') | float(0) %} + {% set max_val = state_attr(calibration_entity,'max') | float(55) %} + + {% if is_aggressive_mode_calibration %} + {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - value_temperature_sensor | float %} + + {% if temp_diff * factor < input_aggressive_mode_range * -1 %} + {% set offset_new = offset_new + input_aggressive_mode_offset * factor %} + {% elif temp_diff * factor > input_aggressive_mode_range %} + {% set offset_new = offset_new - input_aggressive_mode_offset * factor %} + {% endif %} + {% endif %} + + {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %} + {% set offset_new = ((offset_new | float(0) / step) | round(0) * step) | round(round_size) | float %} + + {% set offset_new = iif(offset_new > max_val, max_val, offset_new) %} + {% set offset_new = iif(offset_new < min_val, min_val, offset_new) %} + + {% if (float(offset_old) - float(offset_new)) | abs >= float(input_calibration_delta) %} + {% set n.dict = n.dict + [(calibration_entity, [{'value': offset_new, 'valve': valve}])] %} + {% endif %} + {% endif %} + + {% endfor %} + {% endif %} + + {{ dict.from_keys(n.dict) }} + + # DANFOSS, POPP, HIVE, BOSCH + calibration_dph: > + {% set n = namespace(dict=[]) %} + {% if is_native_calibration_trigger %} + + {% for valve in valves_dph %} + + {% set calibration_entities = device_entities(device_id(valve)) | + expand | selectattr('domain','in','number') | + selectattr('entity_id', 'search', input_calibration_key_word) | + map(attribute='entity_id') | list %} + + {% if calibration_entities | count > 0 %} + + {% set calibration_entity = calibration_entities | first %} + + {% set min_val = state_attr(calibration_entity,'min')%} + {% set max_val = state_attr(calibration_entity,'max')%} + + {% set step = state_attr(calibration_entity, 'step') | float(1) %} + {% if rounding_mode == 'manual' %} + {% set step = input_calibration_step_size | float(1) %} + {% endif %} + + {% set current_temp = state_attr(valve,'current_temperature') | float(20) %} + + {% set new_state = value_temperature_sensor | float(current_temp) %} + {% set old_state = states(calibration_entity) | float %} + + {% if is_aggressive_mode_calibration %} + {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - value_temperature_sensor | float %} + + {% if temp_diff * factor < input_aggressive_mode_range * -1 %} + {% set new_state = new_state + input_aggressive_mode_offset * factor %} + {% elif temp_diff * factor > input_aggressive_mode_range %} + {% set new_state = new_state - input_aggressive_mode_offset * factor %} + {% endif %} + {% endif %} + + {% if step <= 1 and max_val | float < 1000 %} + {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %} + {% set new_state = ((new_state | float(0) / step) | round(0) * step) | round(round_size) | float %} + {% else %} + {% set new_state = new_state * 100 | int %} + {% set old_state = old_state | int %} + {% endif %} + + {% set update_calibration = old_state != new_state %} + + {% if is_calibration_trigger and not update_calibration %} + {% set last_updated = [calibration_entity] | expand | map(attribute='last_updated') | first %} + {% set update_calibration = as_datetime(current_time_stamp) - timedelta(minutes=20) >= last_updated %} + {% endif %} + + {% if update_calibration %} + {% set n.dict = n.dict + [(calibration_entity, [{'value': new_state, 'valve': valve}])] %} + {% endif%} + + {% endif %} + + {% endfor %} + {% endif %} + + {{ dict.from_keys(n.dict) }} + + # COMMON CALIBRATION e.g. TUYA + calibration_common: > + {% set n = namespace(dict=[]) %} + + {% if is_native_calibration_trigger %} + + {% for valve in valves_calibration_common %} + + {% set calibration_entities = device_entities(device_id(valve)) | + expand | selectattr('domain','in','number') | + selectattr('entity_id', 'search', input_calibration_key_word) | + map(attribute='entity_id') | list %} + + {% if calibration_entities | count > 0%} + + {% set calibration_entity = calibration_entities | first %} + + {% set step = state_attr(calibration_entity, 'step') | float(1) %} + {% if rounding_mode == 'manual' %} + {% set step = input_calibration_step_size | float(1) %} + {% endif %} + + {% set min_calibration_value = state_attr(calibration_entity,'min') | float %} + {% set max_calibration_value = state_attr(calibration_entity,'max') | float %} + {% set thermostat_temperature = state_attr(valve, 'current_temperature') | float %} + {% set offset_old = states(calibration_entity) | float(0) %} + + {% set new_calibration_value = (-(thermostat_temperature - value_temperature_sensor) + offset_old) %} + + {% if is_aggressive_mode_calibration %} + {% set temp_diff = state_attr(valve,'temperature') | float(target_temperature) - value_temperature_sensor %} + + {% if temp_diff * factor < input_aggressive_mode_range * -1 %} + {% set new_calibration_value = new_calibration_value + input_aggressive_mode_offset * factor %} + {% elif temp_diff * factor > input_aggressive_mode_range %} + {% set new_calibration_value = new_calibration_value - input_aggressive_mode_offset * factor %} + {% endif %} + {% endif %} + + {% set new_calibration_value = iif(new_calibration_value > max_calibration_value, max_calibration_value, new_calibration_value) %} + {% set new_calibration_value = iif(new_calibration_value < min_calibration_value, min_calibration_value, new_calibration_value) %} + + {% set round_size = iif('.' in (step | string), (step | string).split('.')[1] | length, 0) %} + + {% set offset_new = ((new_calibration_value | float(0) / step) | round(0) * step) | round(round_size) | float %} + + {% if (float(offset_old) - float(offset_new)) | abs >= float(input_calibration_delta) %} + {% set n.dict = n.dict + [(calibration_entity, [{'value': offset_new, 'valve': valve}])] %} + {% endif %} + + {% endif %} + + {% endfor %} + {% endif %} + + {{ dict.from_keys(n.dict) }} + + calibration_value_set: "{{ dict(dict(calibration_external, **calibration_dph),**calibration_common) }}" + + ############################################################################################## + ################################## CONDITIONS / BLOCKER ###################################### + ############################################################################################## + + no_changes: > + {{ + (input_persons | count == 0 and + input_mode_guest == none and + input_schedulers | count == 0 and + input_presence_sensor == none and + input_proximity == none) or + (is_temperature_sensor_defined and not valid_temperature_sensor) + }} + + # conditions + scene_trigger: "{{ is_scene_create_trigger or is_scene_apply_trigger or is_scene_destroy_trigger }}" + change_trigger: "{{ is_changes_trigger and not scene_trigger and changes | count > 0 and not no_changes}}" + reset_trigger: "{{ is_reset_trigger and not no_changes }}" + calibration_trigger: "{{ is_calibration_trigger and not input_calibration_generic and (calibration_value_set | count > 0 or calibration_tado | count > 0) }}" + positioning_trigger: "{{ positioning | count > 0 }}" + + # warnings + automation_name: "{{ state_attr(this.entity_id,'friendly_name') }}" + warnings: > + {% set messages = [] %} + {% if not is_uptime_defined %} + {% set messages = messages + ['To make Advance Heating Control work properly just setup the uptime integration (https://www.home-assistant.io/integrations/uptime/)'] %} + {% elif is_aggressive_mode and not input_aggressive_mode_calibration and is_physical_change_enabled %} + {% set messages = messages + ['Aggressive Mode in combination with physical change / sync feature is not recommended. Expect unwanted side effects.'] %} + {% elif is_generic_calibration and is_physical_change_enabled %} + {% set messages = messages + ['Generic Calibration in combination with physical change / sync feature is not recommended. Expect unwanted side effects.'] %} + {% elif valves_unsupported | count > 0 %} + {% set messages = messages + ['Unsupported climate entities: ' + valves_unsupported | join(',') | string ] %} + {% elif is_temperature_sensor_defined and not valid_temperature_sensor %} + {% set messages = messages + ['The temperature sensor' + input_temperature_sensor + ' has an invalid state: ' + states(input_temperature_sensor) ] %} + {% endif %} + + {{ messages }} + + climates_information: > + {% set n = namespace(dict=[]) %} + + {% for valve in input_trvs %} + {% set temperature = state_attr(valve,'temperature') %} + {% set current_temperature = state_attr(valve,'current_temperature') %} + {% set state = states(valve) %} + {% set n.dict = n.dict + [{'entity_id': valve, 'state': state, 'temperature': temperature, 'current_temperature': current_temperature}] %} + {% endfor %} + + {{ n.dict }} + +conditions: + - condition: or + conditions: + - condition: template + value_template: "{{ calibration_trigger }}" + - condition: template + value_template: "{{ scene_trigger }}" + - condition: template + value_template: "{{ change_trigger }}" + - condition: template + value_template: "{{ reset_trigger }}" + - condition: template + value_template: "{{ positioning_trigger }}" + +actions: + - variables: + is_delayed: "{{ not (not is_uptime_defined or (now() | as_datetime - states(up_time_sensor) | as_datetime) > timedelta(**input_startup_delay)) }}" + - action: system_log.write + data: + message: > + {{ 'AHC - ' + automation_name | string + ' \n ' + + 'automation delayed: ' + is_delayed | string }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + - wait_template: > + {{ not is_uptime_defined or (now() | as_datetime - states(up_time_sensor) | as_datetime) > timedelta(**input_startup_delay) }} + - choose: + - conditions: "{{ is_delayed }}" + sequence: + - event: ahc_delay_event + event_data: + automation: "{{ this.entity_id }}" + + default: + - if: + - condition: template + value_template: "{{ warnings | count > 0 }}" + then: + - action: system_log.write + data: + level: warning + logger: blueprints.panhans.heatingcontrol + message: > + {{ 'AHC-Warnings - ' + automation_name + ':\n' + warnings | join('\n') }} + + - event: ahc_event + event_data: + state: "{{ state_ahc }}" + mode: "{{ iif(set_comfort == true, 'comfort', 'eco') }}" + automation: "{{ this.entity_id }}" + is_person_defined: "{{ is_person_defined }}" + is_anybody_home: "{{ is_anybody_home }}" + is_proximity_defined: "{{ is_proximity_defined }}" + is_anybody_home_or_proximity: "{{ is_anybody_home_or_proximity }}" + is_guest_mode: "{{ is_guest_mode }}" + active_scheduler: "{{ active_scheduler }}" + state_scheduler: "{{ state_scheduler }}" + state_presence_sensor: "{{ state_presence_sensor }}" + state_presence_scheduler: "{{ state_presence_scheduler }}" + state_presence: "{{ state_presence }}" + state_proximity_arrived: "{{ state_proximity_arrived }}" + state_proximity_way_home: "{{ state_proximity_way_home }}" + is_force_max_temperature: "{{ is_force_max_temperature }}" + is_force_eco_temperature: "{{ is_force_eco_temperature }}" + active_party_entity: "{{ active_party_entity }}" + party_temp: "{{ party_temp }}" + is_away: "{{ is_away }}" + state_window: "{{ state_window }}" + is_aggressive_mode: "{{ is_aggressive_mode }}" + is_frost_protection: "{{ is_frost_protection }}" + is_liming_protection: "{{ is_liming_protection }}" + state_outside_temp: "{{ state_outside_temp }}" + entry_time: "{{ entry_time }}" + thermostats: "{{ input_trvs }}" + hvac_mode: "{{ mode }}" + temperature_comfort: "{{ temperature_comfort }}" + temperature_eco: "{{ temperature_eco }}" + target_temperature: "{{ target_temperature }}" + set_max_temperature: "{{ set_max_temperature }}" + last_trigger_id: "{{ iif(trigger_id_defined, trigger.id, '') }}" + calibration_trigger: "{{ is_generic_calibration_trigger or calibration_trigger }}" + change_trigger: "{{ change_trigger }}" + warnings: "{{ warnings | count > 0 }}" + + # calibration + - if: + - condition: template + value_template: "{{ calibration_trigger }}" + - condition: and + conditions: !input input_custom_condition_calibration + then: + - action: system_log.write + data: + message: > + {{ 'AHC - Calibration - ' + automation_name | string + ' \n ' + + 'calibration data set: ' + calibration_value_set | string }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + - repeat: + count: "{{ calibration_value_set | count | int }}" + sequence: + - variables: + index: "{{ repeat.index-1 }}" + calibration_entity: "{{ (calibration_value_set.keys() | list) [index] }}" + thermostat: "{{ (((calibration_value_set.values() | list) [index]) | first) ['valve'] }}" + offset: "{{ (((calibration_value_set.values() | list) [index]) | first) ['value'] }}" + select_entity: "{{ device_entities(device_id(thermostat)) | + expand | selectattr('domain','in','select') | + selectattr('attributes.options', 'contains', 'external') | + map(attribute='entity_id') | list | first | default(none) }}" + is_external: "{{ select_entity != none and not is_state(select_entity, 'external') }}" + + - action: system_log.write + data: + message: > + {{ 'AHC - Calibration - ' + automation_name | string + ' \n ' + + 'calibration entity: ' + calibration_entity | string + ' \n ' + + 'offset: ' + offset | string }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + + - if: + - condition: template + value_template: "{{ is_external }}" + then: + - action: select.select_option + target: + entity_id: "{{ select_entity }}" + data: + option: external + - delay: !input input_action_call_delay + + - action: number.set_value + data: + value: "{{ float(offset) }}" + target: + entity_id: "{{ calibration_entity }}" + - delay: !input input_action_call_delay + + # TADO CALIBRATION + - repeat: + count: "{{ calibration_tado | count | int }}" + sequence: + - variables: + index: "{{ repeat.index-1 }}" + thermostat: "{{ (calibration_tado.keys() | list) [index] }}" + offset: "{{ (((calibration_tado.values() | list) [index]) | first) ['value'] }}" + - action: "{{ 'tado.set_climate_temperature_offset' }}" + data: + offset: "{{ offset }}" + entity_id: "{{ thermostat }}" + - delay: !input input_action_call_delay + + # valve opening + - if: + - condition: template + value_template: "{{ positioning_trigger }}" + then: + - repeat: + count: "{{ positioning | count | int }}" + sequence: + - variables: + index: "{{ repeat.index-1 }}" + thermostat: "{{ (positioning.keys() | list) [index] }}" + positioning_value: "{{ (((positioning.values() | list) [index]) | first) ['value'] }}" + positioning_entity: "{{ (((positioning.values() | list) [index]) | first) ['entity'] }}" + + - action: system_log.write + data: + message: > + {{ 'AHC - Positioning - ' + automation_name | string + ' \n ' + + 'entity: ' + positioning_entity | string + ' \n ' + + 'value: ' + positioning_value | string }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + + - action: number.set_value + data: + value: "{{ positioning_value | int }}" + target: + entity_id: "{{ positioning_entity }}" + - delay: !input input_action_call_delay + + # scenes + # scene create + - if: + - condition: template + value_template: "{{ is_scene_create_trigger }}" + - condition: template + value_template: "{{ states[scene_to_create] == none }}" + then: + - action: scene.create + data: + snapshot_entities: "{{ scene_entities }}" + scene_id: "{{ scene_to_create.split('.')[1] }}" + + # scene destroy + - if: + - condition: template + value_template: "{{ is_scene_destroy_trigger }}" + - condition: template + value_template: "{{ scenes_to_destroy | count > 0 }}" + then: + - repeat: + count: "{{ scenes_to_destroy | count | int }}" + sequence: + - variables: + scene_to_destroy: "{{ scenes_to_destroy[repeat.index-1] }}" + - if: + - condition: template + value_template: "{{ states[scene_to_destroy] != none }}" + then: + - action: scene.delete + target: + entity_id: "{{ scene_to_destroy }}" + + # scene apply + - variables: + scene_to_apply_tmp: > + {% if scene_to_apply != none and states[scene_to_apply] != none %} + {{ scene_to_apply }} + {% else %} + {{ scenes_all | expand | reject('==',none) | map(attribute="entity_id") | list | first | default(none) }} + {% endif %} + - if: + - condition: template + value_template: "{{ is_scene_apply_trigger }}" + - condition: template + value_template: "{{ scene_to_apply_tmp != none and states[scene_to_apply_tmp] != none }}" + then: + - action: system_log.write + data: + message: > + {{ 'AHC - Calibration - ' + automation_name | string + ' \n ' + + 'apply scene: ' + scene_to_apply_tmp | string + ' state: ' + states[scene_to_apply_tmp] | string }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + - action: scene.turn_on + target: + entity_id: "{{ scene_to_apply_tmp }}" + - action: scene.delete + target: + entity_id: "{{ scene_to_apply_tmp }}" + - condition: template + value_template: "{{ false }}" + else: + # reset + - if: + - condition: template + value_template: "{{ is_reset_trigger }}" + then: + - repeat: + count: "{{ reset_data | count | int }}" + sequence: + - action: system_log.write + data: + message: > + {{ 'AHC - Calibration - ' + automation_name | string + ' \n ' + + 'reset data: ' + reset_data | string }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + - variables: + index: "{{ repeat.index-1 }}" + reset_entity: "{{ reset_data[index]['entity'] }}" + reset_temp: > + {% set temp_r = reset_data[index]['temp'] %} + {% set t_min = state_attr(reset_entity,'min') %} + {% set t_max = state_attr(reset_entity,'max') %} + {% set step = state_attr(reset_entity,'step') %} + + {% set temp_r = ((temp_r | float(0) / step) | round(0) * step) | float %} + {% set temp_r = iif(temp_r > t_max, t_max, temp_r) %} + {% set temp_r = iif(temp_r < t_min, t_min, temp_r) %} + {{ temp_r }} + - action: input_number.set_value + data: + value: "{{ reset_temp }}" + target: + entity_id: "{{ reset_entity }}" + + - if: + - condition: and + conditions: !input input_custom_condition + - condition: template + value_template: "{{ changes | count | int > 0 and (not no_changes or (no_changes and state_window)) }}" + then: + - repeat: + count: "{{ changes | count | int }}" + sequence: + - variables: + index: "{{ repeat.index-1 }}" + thermostat: "{{ (changes.keys() | list) [index] }}" + mode: "{{ (((changes.values() | list) [index]) | first) ['mode'] }}" + temp_target: "{{ (((changes.values() | list) [index]) | first) ['temp'] }}" + - action: system_log.write + data: + message: > + AHC - Change - {{ automation_name }} {{" \n "}} + Trigger ID: {{ iif(trigger_id_defined, trigger.id, '') }} + Thermostat: {{ thermostat }} {{" \n "}} + Mode: {{ mode }} {{" \n "}} + New Target Temp: {{ temp_target }} {{" \n "}} + Current Target Temp: {{ state_attr(thermostat,'temperature') }} + level: !input input_log_level + logger: blueprints.panhans.heatingcontrol + + - if: + - condition: template + value_template: "{{ states(thermostat) | lower != mode | lower }}" + then: + - action: climate.set_hvac_mode + data: + entity_id: "{{ thermostat }}" + hvac_mode: "{{ mode }}" + - delay: !input input_action_call_delay + + - if: + - condition: template + value_template: "{{ state_attr(thermostat, 'temperature') != temp_target and mode != 'off' }}" + then: + - action: climate.set_temperature + data: + entity_id: "{{ thermostat }}" + temperature: "{{ temp_target | float }}" + - delay: !input input_action_call_delay + + - if: + - condition: template + value_template: "{{ input_valve_positioning_mode != 'off' }}" + - condition: template + value_template: "{{ changes | count | int > 0 or is_scene_apply_trigger }}" + then: + - delay: + seconds: 10 + - event: ahc_positioning_event + event_data: + automation: "{{ this.entity_id }}" + - delay: !input input_action_call_delay + + # custom action + - if: + - condition: template + value_template: "{{ input_custom_action != none }}" + then: !input "input_custom_action" + +mode: queued \ No newline at end of file diff --git a/helloworld.yaml b/helloworld.yaml new file mode 100644 index 0000000..e4ed89e --- /dev/null +++ b/helloworld.yaml @@ -0,0 +1 @@ +temperature_sensorddddddssssdsadsa \ No newline at end of file diff --git a/motion_light.yaml b/motion_light.yaml new file mode 100644 index 0000000..6983e0f --- /dev/null +++ b/motion_light.yaml @@ -0,0 +1,62 @@ +blueprint: + name: Motion-activated Light + description: Turn on a light when motion is detected. + domain: automation + source_url: https://github.com/home-assistant/core/blob/dev/homeassistant/components/automation/blueprints/motion_light.yaml + author: Home Assistant + input: + motion_entity: + name: Motion Sensor + selector: + entity: + filter: + - device_class: + - occupancy + domain: + - binary_sensor + - device_class: + - motion + domain: + - binary_sensor + multiple: false + reorder: false + light_target: + name: Light + selector: + target: + entity: + - domain: + - light + no_motion_wait: + name: Wait time + description: Time to leave the light on after last motion is detected. + default: 120 + selector: + number: + min: 0.0 + max: 3600.0 + unit_of_measurement: seconds + step: 1.0 + mode: slider +mode: restart +max_exceeded: silent +triggers: + trigger: state + entity_id: !input motion_entity + from: 'off' + to: 'on' +actions: +- alias: Turn on the light + action: light.turn_on + target: !input light_target +- alias: Wait until there is no motion from device + wait_for_trigger: + trigger: state + entity_id: !input motion_entity + from: 'on' + to: 'off' +- alias: Wait the number of seconds that has been set + delay: !input no_motion_wait +- alias: Turn off the light + action: light.turn_off + target: !input light_target diff --git a/smart-light.yaml b/smart-light.yaml new file mode 100644 index 0000000..041c25b --- /dev/null +++ b/smart-light.yaml @@ -0,0 +1,7969 @@ +blueprint: + name: Smart Light + description: > + # 🔆 Smart Light + + **Version: 3.3** + + + Smart Lighting: Your Lights, Your Way - Take Control and Customize it to Perfection!💡✨ + + + **If you like my blueprints, and would like to show your support or just say thank you?** [Click Here](https://www.paypal.com/donate/?hosted_button_id=WAZS3QSDTPGA8) 🙂 + + +
+ The Automation Process: 👈 + + + - **Trigger Options:** + + Activate lights, switches, scenes, and scripts when the automation is triggered. + + - **Entity State:** + - Turn lights ON when an entity changes from OFF to ON. + - Turn lights OFF when an entity changes from ON to OFF. + + - **Press Button:** + - Turn lights ON when you press a button. + - Turn lights OFF when you press a button. + + - **Sun Elevation:** + - Turn lights ON when the sun's elevation falls below a set value. + - Turn lights OFF when the sun's elevation rises above a set value. + + - **Ambient Light:** + - Turn lights ON when ambient light falls below a set LUX value. + - Turn lights OFF when ambient light rises above a set LUX value. + + - **Time-Based Option:** + - Define start and end times to turn lights ON and OFF. + + - **Light Control Options:** + - Utilize "Light Control" to adjust brightness, colour temperature, colour, and transition times. + + - **Dynamic Lighting Options:** + - Opt for 'Dynamic Lighting' to automatically adjust brightness based on lux values, and/or adjust brightness and colour temperature according to the sun's position or the time of day. + - Opt to use the 'State Control Option,' allowing you to toggle between dynamic lighting and normal lighting based on the entity's activation state. + + - **Night Lights Mode:** + - Enable 'Night Lights' for softer illumination during night time activities, automatically enabled based on conditions. + + - **Manual Override:** + - Use "Bypass Options" for manual bypassing of trigger sensors, providing manual control and additional customization. + + - **Weekdays Condition Option:** + - Specify the weekday selections to define when the automation can run. +
+ + + Need help? + + - FAQ: [Click Here](https://community.home-assistant.io/t/527354/2) + + - Community Support Including Updates: [Click Here](https://community.home-assistant.io/t/527354) + + + Required = * + domain: automation + input: + trigger_entity: + name: "Trigger - Entity State" + icon: mdi:cog-outline + collapsed: true + input: + include_entity_state: + name: Use The Entity State Option (Optional) + description: > + This option adds triggers that activate when the specified entity changes its state. + When the entity changes its state from OFF to ON, it will turn your lights ON. + When the entity changes its state from ON to OFF, it will turn your lights OFF. + + + You can choose the ON trigger, the OFF trigger, or both. + For more information about triggers and how they can be used, [Click Here](https://community.home-assistant.io/t/527354/110) + + + If you would like to use a motion sensor, please consider using my 💡Sensor Light Blueprint [Click Here](https://community.home-assistant.io/t/481048) + default: [] + selector: + select: + multiple: true + options: + - label: ON State + value: "entity_on" + - label: OFF State + value: "entity_off" + entity_input: + name: Input Entity + description: > + Please select an entity with an ON/OFF state. + default: [] + selector: + entity: + trigger_button: + name: "Trigger - Push Button" + icon: mdi:gesture-tap-button + collapsed: true + input: + include_button: + name: Use The Push Button Option (Optional) + description: > + Adds triggers that activate when the selected button is pressed. + Each time you press the button, choose whether to trigger the lights ON, OFF, or both. + default: [] + selector: + select: + multiple: true + options: + - label: Push Button ON + value: "button_on" + - label: Push Button OFF + value: "button_off" + button_input: + name: Input Button Entity + description: > + Choose the physical or virtual button entity that will trigger this automation. + default: [] + selector: + entity: + trigger_sun: + name: "Trigger - Sun Elevation" + icon: mdi:weather-sunny + collapsed: true + input: + include_sun: + name: Use The Sun Option (Optional) + description: > + This option adds triggers that activate when the sun's elevation value crosses its set threshold. + When it goes below the **Sun Elevation Falling** value, it will turn your lights ON. + When it goes above the **Sun Elevation Rising** value, it will turn your lights OFF. + + + You can choose the ON trigger, the OFF trigger, or both. + For more information about triggers and how they can be used, [Click Here](https://community.home-assistant.io/t/527354/110) + + + For more information on sun settings [Click Here](https://community.home-assistant.io/t/527354/83) + default: [] + selector: + select: + multiple: true + options: + - label: Sun Elevation Falling - ON + value: "sun_falling" + - label: Sun Elevation Rising - OFF + value: "sun_rising" + sun_elevation: + name: Sun Elevation Falling + description: > + The sun elevation falling refers to the angle between the sun and the horizon when the sun is setting. + A negative value indicates that the sun is BELOW the horizon. For example, a setting guide of -1.5 corresponds to dusk + default: -1.5 + selector: + number: + min: -10 + max: 5 + step: 0.5 + unit_of_measurement: degrees + sun_elevation_rising: + name: Sun Elevation Rising + description: > + The sun elevation rising refers to the angle between the sun and the horizon during sunrise. + A negative value indicates that the sun is BELOW the horizon. For example, a setting guide of -4.0 corresponds to dawn. + default: -4.0 + selector: + number: + min: -10 + max: 5 + step: 0.5 + unit_of_measurement: degrees + trigger_ambient: + name: "Trigger - Ambient" + icon: mdi:theme-light-dark + collapsed: true + input: + include_ambient: + name: Use The Ambient Option (Optional) + description: > + This option adds triggers that activate when the ambient light LUX value crosses its set threshold. + When it goes below the **Low LUX Value**, it will turn your lights ON. + When it goes above the **High LUX Value**, it will turn your lights OFF. + + + You can choose the ON trigger, the OFF trigger, or both. + For more information about triggers and how they can be used, [Click Here](https://community.home-assistant.io/t/527354/110) + default: [] + selector: + select: + multiple: true + options: + - label: Low Lux Value - ON + value: "ambient_low" + - label: High Lux Value - OFF + value: "ambient_high" + ambient_light_sensor: + name: Ambient Light Sensor + description: > + Select the ambient light sensor. + default: [] + selector: + entity: + filter: + domain: sensor + device_class: illuminance + ambient_light_value: + name: Ambient Light - Low Lux Value + description: > + Set the Ambient Light Low Lux Value. The light will turn ON when the lux level is below the set value. + This value must be equal or lower than the "High Lux Value" below. Guide is 20 lux (dusk). + default: 20 + selector: + number: + min: 0 + max: 500 + step: 10 + unit_of_measurement: lux + ambient_light_value_off: + name: Ambient Light - High Lux Value + description: > + Set the Ambient Light High Lux Value. The light will turn OFF when the lux level is above the set value. + This value must be equal or higher than the "Low Lux Value" above. + Setting a value higher than the low value allows for an offset. Guide is 80 lux (dawn). + default: 80 + selector: + number: + min: 0 + max: 1000 + step: 10 + unit_of_measurement: lux + trigger_time: + name: "Trigger - Time" + icon: mdi:clock-outline + collapsed: true + input: + include_time: + name: Use The Time Options (Optional) + description: > + This option adds triggers that activate when the specified time value crosses its set threshold. + When the time is below the **ON Time** setting, it will turn your lights ON. + When the time is above the **OFF Time** setting, it will turn your lights OFF. + + + You can choose the ON trigger, the OFF trigger, or both. + For more information about triggers and how they can be used, [Click Here](https://community.home-assistant.io/t/527354/110) + default: [] + selector: + select: + multiple: true + options: + - label: ON Time + value: "time_on" + - label: OFF Time + value: "time_off" + after_time: + name: ON Time + description: > + Set the on time. + default: 00:00:00 + selector: + time: + before_time: + name: OFF Time + description: > + Set the off time. + default: 00:00:00 + selector: + time: + lights: + name: "Lights *" + icon: mdi:lightbulb-outline + collapsed: true + input: + light_switch: + name: Lights - Switches - Scenes - Scripts * + description: > + The lights, switches, scenes, and scripts that will be activated by the trigger. + If adding a scene or script, please refer to the 'Scenes & Scripts - Toggle Helper' section and the 'Scenes & Scripts - Turn OFF' section below. + + + **NOTE** - You can only use entities. Areas, devices and labels are not supported. + default: [] + selector: + target: + entity: + domain: + - light + - switch + - scene + - script + boolean_scenes_scripts: + name: Scenes & Scripts - Toggle Helper + description: > + To ensure the smooth operation of the automation, it's recommended to create an independent toggle helper + when selecting a scene or script in "Lights - Switches - Scenes - Scripts" above and then enter it here. + default: [] + selector: + entity: + filter: + domain: + - input_boolean + end_scenes: + name: Scenes - Scripts To Turn OFF + description: > + If you have selected a scene or a script to be turned ON above in "Lights - Switches - Scenes - Scripts" + and you would like it to be turned OFF after the time delay, then you must create a scene + or a script with everything OFF and enter it here. + default: [] + selector: + entity: + multiple: true + filter: + domain: + - scene + - script + lights_settings: + name: "Light Control" + icon: mdi:lightbulb-on-outline + collapsed: true + input: + include_light_control: + name: Use The Light Control Options (Optional) + description: > + Select if you would like to use brightness or transition. + These settings will only affect a 'light' entity that supports each selected option. + The settings for brightness and transition are provided below. + default: [] + selector: + select: + multiple: true + options: + - label: Use Brightness + value: "use_brightness" + - label: Use Transition + value: "use_transition" + light_brightness: + name: Brightness + description: > + The brightness setting for the lights when they are turned ON. + default: 100 + selector: + number: + min: 1 + max: 100 + mode: slider + step: 1 + unit_of_measurement: '%' + light_transition_on: + name: Transition - ON + description: > + The transition setting for the lights when they are turned ON. + default: 1 + selector: + number: + min: 0 + max: 5 + mode: slider + step: 0.5 + unit_of_measurement: seconds + light_transition_off: + name: Transition - OFF + description: > + The transition setting for the lights when they are turned OFF. + default: 1 + selector: + number: + min: 0 + max: 30 + mode: slider + step: 1 + unit_of_measurement: seconds + include_light_colour_control: + name: Use The Light Colour Control Options (Optional) + description: > + Select if you would like to use colour temperature, RGB, RGBW or RGBWW colour. + These settings will only affect a 'light' entity that supports each selected option. + The settings for colour temperature, RGB, RGBW and RGBWW colour are provided below. + default: disable_colour_control + selector: + select: + options: + - label: Use Colour Temperature + value: "use_colour_temperature" + - label: Use RGB Colour + value: "use_rgb_colour" + - label: Use RGBW Colour + value: "use_rgbw_colour" + - label: Use RGBWW Colour + value: "use_rgbww_colour" + - label: Disable Colour Control + value: "disable_colour_control" + light_colour_temperature: + name: Colour Temperature + description: > + The colour temperature setting for the lights when they are turned ON. + default: 5000 + selector: + number: + min: 2000 + max: 8000 + mode: slider + step: 100 + unit_of_measurement: 'kelvin' + light_rgb_colour: + name: RGB Colour + description: > + The RGB colour setting for the lights when they are turned ON. + default: [255, 255, 255] + selector: + color_rgb: + light_rgbw_colour: + name: RGBW Colour + description: > + The RGBW colour setting for the lights when they are turned ON. + Enter four integers between 0 and 255 to define the values for Red, Green, Blue, and White. + default: [255, 255, 255, 255] + selector: + object: + light_rgbww_colour: + name: RGBWW Colour + description: > + The RGBWW colour setting for the lights when they are turned ON. + Enter five integers between 0 and 255 to define the values for Red, Green, Blue, Cold White and Warm White. + default: [255, 255, 255, 255, 255] + selector: + object: + dynamic_lighting_settings: + name: "Dynamic Lighting" + icon: mdi:creation-outline + collapsed: true + input: + include_dynamic_lighting: + name: Use The Dynamic Lighting Options (Optional) + description: > + This option makes continual adjustments to your normal lighting setup by modulating brightness based on floating lux values, or adapting both colour temperature and brightness according to the sun's changing elevation or the time of day. + Choose from thirteen preset options available in the dropdown menu. + + + 1 - Lux Controlled Brightness + + 2 - Lux Controlled Brightness Inverted + + 3 - Sun Elevation Lighting - Colour Temp + + 4 - Sun Elevation Lighting - Brightness + + 5 - Sun Elevation Lighting - Brightness Inverted + + 6 - Sun Elevation Lighting - Colour Temp + Brightness + + 7 - Sun Elevation Lighting - Colour Temp + Brightness Inverted + + 8 - Sun Elevation Lighting - Colour Temp + Lux Controlled Brightness + + 9 - Sun Elevation Lighting - Colour Temp + Lux Controlled Brightness Inverted + + 10 - Time Controlled - Colour Temp + + 11 - Time Controlled - Brightness + + 12 - Time Controlled - Brightness Inverted + + 13 - Time Controlled - Colour Temp + Brightness + + + A numbering system has been implemented to facilitate navigation within the dropdown selections. Each number corresponds to a specific configuration, + aiding users in identifying and adjusting the settings used within each selection. For instance, when selecting "3 - Sun Elevation Lighting - Colour Temp" + as a dropdown option, settings marked "Used in options 3, 6, 7, 8, 9, 10 or 13" are required for that respective selection because number 3 is included in those options. + + + For more information on dynamic lighting settings [Click Here](https://community.home-assistant.io/t/481048/837) + default: disable_dynamic_lighting + selector: + select: + mode: dropdown + options: + - label: Disable Dynamic Lighting + value: "disable_dynamic_lighting" + - label: 1 - Lux Controlled Brightness + value: "enable_lux_controled_brightness" + - label: 2 - Lux Controlled Brightness Inverted + value: "enable_lux_controled_brightness_inv" + - label: 3 - Sun Elevation Lighting - Colour Temp + value: "enable_sun_elevation_colour" + - label: 4 - Sun Elevation Lighting - Brightness + value: "enable_sun_elevation_brightness" + - label: 5 - Sun Elevation Lighting - Brightness Inverted + value: "enable_sun_elevation_brightness_inv" + - label: 6 - Sun Elevation Lighting - Colour Temp + Brightness + value: "enable_sun_elevation_colour_brightness" + - label: 7 - Sun Elevation Lighting - Colour Temp + Brightness Inverted + value: "enable_sun_elevation_colour_brightness_inv" + - label: 8 - Sun Elevation Lighting - Colour Temp + Lux Controlled Brightness + value: "enable_sun_elevation_colour_lux_brightness" + - label: 9 - Sun Elevation Lighting - Colour Temp + Lux Controlled Brightness Inverted + value: "enable_sun_elevation_colour_lux_brightness_inv" + - label: 10 - Time Controlled - Colour Temp + value: "enable_time_controled_colour" + - label: 11 - Time Controlled - Brightness + value: "enable_time_controled_brightness" + - label: 12 - Time Controlled - Brightness Inverted + value: "enable_time_controled_brightness_inv" + - label: 13 - Time Controlled - Colour Temp + Brightness + value: "enable_time_controled_colour_brightness" + dynamic_lighting_lux_sensor: + name: Dynamic Lighting - Ambient Light Sensor + description: > + **Used in options 1, 2, 8 or 9** - Enter the specific ambient light sensor to be used, based on your selected Dynamic Lighting option. + default: [] + selector: + entity: + filter: + domain: sensor + device_class: illuminance + dynamic_lighting_max_lux: + name: Dynamic Lighting - Max Lux Value + description: > + **Used in options 1, 2, 8 or 9** - Specify the maximum lux value. Once the lux level meets or surpasses this set point, your lights will adjust to either their maximum or minimum brightness, depending on your chosen option. + This value indicates when you prefer your lights to start turning on or off. + default: 400 + selector: + number: + min: 10 + max: 900 + step: 10 + unit_of_measurement: lux + dynamic_lighting_min_lux: + name: Dynamic Lighting - Min Lux Value + description: > + **Used in options 1, 2, 8 or 9** - Specify the minimum lux value. Once the lux level meets or surpasses this set point, your lights will adjust to either their maximum or minimum brightness, depending on your chosen option. + This value indicates when you prefer your lights to start turning on or off. + default: 40 + selector: + number: + min: 0 + max: 600 + step: 10 + unit_of_measurement: lux + dynamic_lighting_max_brightness: + name: Dynamic Lighting - Max Brightness Value + description: > + **Used in options 1, 2, 4, 5, 6, 7, 8, 9, 11, 12 or 13** - Define the maximum brightness value, determines the peak brightness level for your lights. + default: 100 + selector: + number: + min: 10 + max: 100 + step: 1 + unit_of_measurement: '%' + dynamic_lighting_min_brightness: + name: Dynamic Lighting - Min Brightness Value + description: > + **Used in options 1, 2, 4, 5, 6, 7, 8, 9, 11, 12 or 13** - Specify the minimum brightness value, establishing the lowest brightness level for your lights. + When setting the brightness to 0%, the light will be turned off. + default: 0 + selector: + number: + min: 0 + max: 100 + step: 1 + unit_of_measurement: '%' + dynamic_lighting_boolean: + name: Dynamic Lighting - Toggle Helper (Optional) + description: > + **Used in options 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12 or 13** - If you have chosen a brightness level of 0%, + then it's essential to create an independent toggle helper and enter it here. + This toggle helper can also address issues if the automation doesn't behave as expected due to the occasional unavailability of light entities. + While it may not always be necessary, if you're open to creating toggle helpers, it's highly recommended to utilize this option to ensure proper functionality of the automation. + default: [] + selector: + entity: + filter: + domain: + - input_boolean + dynamic_lighting_max_colour_temp: + name: Dynamic Lighting - Max Colour Temperature + description: > + **Used in options 3, 6, 7, 8, 9, 10 or 13** - Specify the highest colour temperature value, determining the coolest colour setting for your lights. + default: 5000 + selector: + number: + min: 2500 + max: 8000 + mode: slider + step: 100 + unit_of_measurement: 'kelvin' + dynamic_lighting_min_colour_temp: + name: Dynamic Lighting - Min Colour Temperature + description: > + **Used in options 3, 6, 7, 8, 9, 10 or 13** - Set the lowest colour temperature value, defining the warmest colour setting for your lights. + default: 3000 + selector: + number: + min: 2000 + max: 7500 + mode: slider + step: 100 + unit_of_measurement: 'kelvin' + dynamic_lighting_sun_elevation_start_rising: + name: Dynamic Lighting - Sun Elevation Rising - Start Point + description: > + **Used in options 3, 4, 5, 6, 7, 8 or 9** - When the sun rises above the sensor's starting point, both the colour temperature and brightness + percentage will transition linearly from their minimum to maximum values until they reach the rising endpoint, based on your selected Dynamic Lighting option. + default: -1.5 + selector: + number: + min: -10 + max: 30 + step: 0.5 + unit_of_measurement: degrees + dynamic_lighting_sun_elevation_end_rising: + name: Dynamic Lighting - Sun Elevation Rising - End Point + description: > + **Used in options 3, 4, 5, 6, 7, 8 or 9** - When the sun rises above the sensor's endpoint, the maximum colour temperature and maximum brightness value will + be established, based on your selected Dynamic Lighting option. + default: 15 + selector: + number: + min: 0 + max: 90 + step: 0.5 + unit_of_measurement: degrees + dynamic_lighting_sun_elevation_start_falling: + name: Dynamic Lighting - Sun Elevation Descending - Start Point + description: > + **Used in options 3, 4, 5, 6, 7, 8 or 9** - When the sun descends below the sensor's starting point, both the colour temperature and brightness percentage will + transition linearly from their maximum to minimum values until they reach the descending endpoint, based on your selected Dynamic Lighting option. + default: 15 + selector: + number: + min: 0 + max: 90 + step: 0.5 + unit_of_measurement: degrees + dynamic_lighting_sun_elevation_end_falling: + name: Dynamic Lighting - Sun Elevation Descending - End Point + description: > + **Used in options 3, 4, 5, 6, 7, 8 or 9** - When the sun descends below the sensor's endpoint, the minimum colour temperature and minimum brightness value will + be established, based on your selected Dynamic Lighting option. + default: -4.0 + selector: + number: + min: -10 + max: 30 + step: 0.5 + unit_of_measurement: degrees + dynamic_lighting_time_start_morning: + name: Dynamic Lighting - Time Morning - Start Point + description: > + **Used in options 10, 11, 12 or 13** - When the time passes over the start point, both the colour temperature and brightness + percentage will transition linearly from their minimum to maximum values until they reach the rising endpoint, based on your selected Dynamic Lighting option. + default: "06:00:00" + selector: + time: + dynamic_lighting_time_end_morning: + name: Dynamic Lighting - Time Morning - End Point + description: > + **Used in options 10, 11, 12 or 13** - When the time passes over the end point, the maximum colour temperature and maximum brightness value will + be established, based on your selected Dynamic Lighting option. + default: "09:00:00" + selector: + time: + dynamic_lighting_time_start_evening: + name: Dynamic Lighting - Time Evening - Start Point + description: > + **Used in options 10, 11, 12 or 13** - When the time passes over the start point, both the colour temperature and brightness percentage will + transition linearly from their maximum to minimum values until they reach the descending endpoint, based on your selected Dynamic Lighting option. + default: "17:00:00" + selector: + time: + dynamic_lighting_time_end_evening: + name: Dynamic Lighting - Time Evening - End Point + description: > + **Used in options 10, 11, 12 or 13** - When the time passes over the end point, the minimum colour temperature and minimum brightness value will + be established, based on your selected Dynamic Lighting option. + default: "19:00:00" + selector: + time: + dynamic_lighting_heartbeat: + name: Dynamic Lighting - Heartbeat + description: > + **Used in options 1, 2, 8, 9, 10, 11, 12 or 13** - Define the heartbeat rate to set the operational speed. + During each heartbeat, it may evaluate the lux value, light brightness, colour temperature, target colour temperature, and target brightness, adjusting the colour temperature or brightness based on your selected Dynamic Lighting option. + + + **Note** - When using a **Time Controlled** option (10, 11, 12, or 13), the minimum heartbeat should be set to no lower than 1 minute, with adjustments made in 1-minute increments (e.g., 1, 2, 3, 4, 5, and so on), as setting it lower will not provide any benefit and may slow down your system's performance. + Depending on the duration between the start and end points of the light transition, adjusting this value will determine the size of the step value. A longer heartbeat generally improves performance, but it may also result in larger step values that could be bothersome to the eye. Take the time to determine the correct heartbeat value for your needs. + The heartbeat is only active between the start and end points. + default: 1 + selector: + number: + min: 0.25 + max: 10 + step: 0.25 + unit_of_measurement: minutes + dynamic_lighting_step_value: + name: Dynamic Lighting - Step Value + description: > + **Used in options 1, 2, 8, or 9** - With every heartbeat, the system evaluates the lux value, light brightness, and targeted brightness. + If the targeted brightness exceeds the predefined step value, the system applies the set step value to gradually moderate the rate of change, ensuring a smoother transition in light brightness. + default: 4 + selector: + number: + min: 1 + max: 100 + step: 1 + unit_of_measurement: '%' + dynamic_lighting_dead_zone: + name: Dynamic Lighting - Dead Zone (±) + description: > + **Used in options 1, 2, 8, or 9** - With every heartbeat, the system evaluates the current light brightness and the targeted brightness. + If the targeted brightness falls within the defined dead zone, the system maintains the current light brightness. + This prevents minor fluctuations in light intensity that could be bothersome to the eye. + default: 7 + selector: + number: + min: 0 + max: 15 + step: 1 + unit_of_measurement: '%' + dynamic_lighting_state_control: + name: Dynamic Lighting - State Control Option (Optional) + description: > + Enable or disable dynamic lighting based on the state of a specified entity. + When the entity is in the selected activation state below, dynamic lighting will function as configured. + When the entity is not in the activation state below, dynamic lighting will be disabled. + This allows you to toggle between normal lighting and dynamic lighting based on the entity's state. + default: disable_state_control + selector: + select: + options: + - label: Enable State Control Option + value: "enable_state_control" + - label: Disable State Control Option + value: "disable_state_control" + dynamic_lighting_state_control_activation_state: + name: Dynamic Lighting - State Control Activation State + description: > + Select the state the entity must be in to activate dynamic lighting. + When the entity is in the selected state (ON or OFF), dynamic lighting will be enabled. + This option defines the activation condition for dynamic lighting. + default: "on" + selector: + select: + options: + - label: ON State + value: "on" + - label: OFF State + value: "off" + dynamic_lighting_state_control_entity: + name: Dynamic Lighting - State Control Entity + description: > + If the state control option above is enabled, select the entity that will toggle dynamic lighting based on its activation state above. + default: [] + selector: + entity: + bypass_settings: + name: "Bypass" + icon: mdi:cog-pause-outline + collapsed: true + input: + include_bypass: + name: Use The Bypass Options (Optional) + description: > + Select if you would like to enable an option. + Each option determines how your lights will behave when the bypass switch is turned ON: + + 1 - Turns the lights ON + 2 - Turns the lights OFF + 3 - Keeps the lights current state + + If you enable an option, make sure to enter the corresponding bypass switch in the input below. + default: [] + selector: + select: + options: + - label: 1 - Enable the Bypass - Turn the Lights ON + value: "bypass_enabled_turn_on" + - label: 2 - Enable the Bypass - Turn the Lights OFF + value: "bypass_enabled_turn_off" + - label: 3 - Enable the Bypass - Keep the Lights Current State + value: "bypass_enabled_stop" + multiple: true + bypass_lights_on: + name: Bypass Switch - Turn the Lights ON + description: > + Select the switches that will turn your lights ON, bypass the trigger sensor, and allow your lights to function as normal. + Please note that the entity cannot be included in the 'Lights - Switches - Scenes - Scripts' or 'Night Lights' selections. + default: [] + selector: + entity: + multiple: true + bypass_lights_off: + name: Bypass Switch - Turn the Lights OFF + description: > + Select the switches that will turn your lights OFF, bypass the trigger sensor, and allow your lights to function as normal. + Please note that the entity cannot be included in the 'Lights - Switches - Scenes - Scripts' or 'Night Lights' selections. + default: [] + selector: + entity: + multiple: true + bypass_lights_stop: + name: Bypass Switch - Keep the Lights Current State + description: > + Select the switches that will keep your lights current state, bypass the trigger sensor, and allow your lights to function as normal. + Please note that the entity cannot be included in the 'Lights - Switches - Scenes - Scripts' or 'Night Lights' selections. + default: [] + selector: + entity: + multiple: true + bypass_time_delay: + name: Bypass - Time Delay + description: > + This is only used in two specific bypass scenarios when your lights are ON: + + 1. When you have selected option 2 above to "Enable the Bypass - Turn the Lights OFF" and you turn the bypass ON. + 2. When the bypass is turned OFF, the trigger sensor is OFF, and your lights are still ON. + + In both cases, the automation will turn your lights OFF after the set time delay. + default: 0 + selector: + number: + min: 0 + max: 10 + step: 0.25 + unit_of_measurement: minutes + include_bypass_auto_off: + name: Use The Bypass Auto OFF Option (Optional) + description: > + Enable this option if you want the bypass to automatically turn OFF after a set time delay. + You can choose which bypass option the auto OFF will apply to: + + 1 - Turns the lights ON + 2 - Turns the lights OFF + 3 - Keeps the lights current state + + Each option corresponds to one of the bypass options above. + default: [] + selector: + select: + options: + - label: A - Enable Auto OFF for Bypass Option 1 - Turn the Lights ON + value: "bypass_auto_off_enabled_on" + - label: B - Enable Auto OFF for Bypass Option 2 - Turn the Lights OFF + value: "bypass_auto_off_enabled_off" + - label: C - Enable Auto OFF for Bypass Option 3 - Keep the Lights Current State + value: "bypass_auto_off_enabled_stop" + multiple: true + bypass_auto_off_delay: + name: Bypass Auto OFF - Time Delay + description: > + Set the bypass auto OFF time delay. + The time delay starts from the last bypass that was turned ON. + default: 60 + selector: + number: + min: 1 + max: 240 + step: 1 + unit_of_measurement: minutes + weekdays: + name: "Weekdays" + icon: mdi:calendar-week + collapsed: true + input: + include_weekdays: + name: Use The Weekdays Option (Optional) + description: > + This option adds a condition to operate only on specified weekdays. It applies globally to all triggers. + default: weekday_disabled + selector: + select: + options: + - label: Enable the weekday option + value: "weekday_enabled" + - label: Disable the weekday option + value: "weekday_disabled" + weekday_options: + name: Weekdays + description: > + Select the days of the week on which you want the automation to run. + default: + - mon + - tue + - wed + - thu + - fri + - sat + - sun + selector: + select: + multiple: true + mode: list + options: + - label: Monday + value: "mon" + - label: Tuesday + value: "tue" + - label: Wednesday + value: "wed" + - label: Thursday + value: "thu" + - label: Friday + value: "fri" + - label: Saturday + value: "sat" + - label: Sunday + value: "sun" + night_lights_trigger_settings: + name: "Night Lights Settings" + icon: mdi:weather-night + collapsed: true + input: + include_night_lights: + name: Use The Night Lights Options (Optional) + description: > + Enabling the night lights option allows for separate and customizable lighting control when night light conditions are met. + Night light condition options include entity state, time, or sun elevation. + Please choose the condition option you would like to use below. + + + This feature is particularly beneficial for creating a soothing ambiance with softer lighting at night. + The flexibility of these options allows for personalized adjustments, enhancing your nighttime ambiance and comfort, especially when moving around during the night. + default: night_lights_disabled + selector: + select: + options: + - label: Enable the night lights options + value: "night_lights_enabled" + - label: Disable the night lights options + value: "night_lights_disabled" + night_lights_conditions: + name: Night Lights Conditions (Required For Night Lights) + description: > + Select any night light condition from the options provided. + Ensure you've enabled **Use the night lights options** in the section above and choose at least one **Night Lights Condition** for night lights to operate. + + + Settings for each option are provided below. + default: [] + selector: + select: + multiple: true + options: + - label: Enable entity state option + value: "entity_state_enabled" + - label: Enable time option + value: "time_enabled" + - label: Enable sun elevation option + value: "sun_enabled" + night_lights_entity_state: + name: Night Lights - Entity State + description: > + Select an entity that will trigger the activation of night lights when turned ON. + This could be your phone on **Do Not Disturb**, a helper, a bed sensor, etc. + Please note that the selected entity cannot be included in the **Lights - Switches - Scenes - Scripts** or **Night Lights** selections. + default: [] + selector: + entity: + multiple: true + night_lights_after_time: + name: Night Lights - Start Time + description: > + Set the start time. + default: 00:00:00 + selector: + time: + night_lights_before_time: + name: Night Lights - End Time + description: > + Set the end time. + default: 00:00:00 + selector: + time: + night_lights_sun_elevation: + name: Night Lights - Sun Elevation Falling + description: > + The sun elevation falling refers to the angle between the sun and the horizon when the sun is setting. + A negative value indicates that the sun is BELOW the horizon. For example, a setting guide of -1.5 corresponds to dusk. + default: -1.5 + selector: + number: + min: -10 + max: 5 + step: 0.5 + unit_of_measurement: degrees + night_lights_sun_elevation_rising: + name: Night Lights - Sun Elevation Rising + description: > + The sun elevation rising refers to the angle between the sun and the horizon during sunrise. + A negative value indicates that the sun is BELOW the horizon. For example, a setting guide of -4.0 corresponds to dawn. + default: -4.0 + selector: + number: + min: -10 + max: 5 + step: 0.5 + unit_of_measurement: degrees + night_lights_settings: + name: "Night Lights" + icon: mdi:lightbulb-night-outline + collapsed: true + input: + night_lights: + name: Night Lights + description: > + The lights, switches, scenes, and scripts that will be activated by the trigger sensor/s. + If adding a scene or script, please refer to the 'Night Lights - Scenes & Scripts - Toggle Helper' section below and the 'Scenes - Scripts To Turn OFF' section above. + + + **NOTE** - You can only use entities. Areas, devices and labels are not supported. + default: {} + selector: + target: + entity: + domain: + - light + - switch + - scene + - script + night_boolean_scenes_scripts: + name: Night Lights - Scenes & Scripts - Toggle Helper + description: > + To ensure the smooth operation of the automation, it's recommended to create an independent toggle helper + when selecting a scene or script in "Night Lights" above and then enter it here. + default: [] + selector: + entity: + filter: + domain: + - input_boolean + night_lights_light_control_settings: + name: "Night Light Control" + icon: mdi:lightbulb-on-80 + collapsed: true + input: + include_night_light_control: + name: Night Lights - Use The Light Control Options (Optional) + description: > + Select if you would like to use brightness or transition. + These settings will only affect a 'light' entity that supports each selected option. + The settings for brightness and transition are provided below. + + + Selecting **If lights are ON, adjust the lights when crossing over** option ensures that the light control settings will be applied to any lights that are already ON during the transition from normal lights to night lights and vice versa. + + + Selecting **Yes - Manage OFF script when crossing over** is beneficial for scripts containing if-then-else actions that toggle various functions on and off during the transition from normal lights to night lights and vice versa. + + + Selecting **Use cross over time delay from night lights to normal lights** applies to the night lights conditions. + This delay is especially useful when using the night lights state condition with a motion sensor, as it adds a buffer period after the motion sensor clears before switching to normal lighting. + default: [] + selector: + select: + multiple: true + options: + - label: Use brightness + value: "use_brightness" + - label: Use transition + value: "use_transition" + - label: If lights are ON, adjust the lights when crossing over + value: "if_lights_are_on_adjust_when_crossing_over" + - label: Yes - Manage OFF script when crossing over + value: "manage_scripts_crossing_over" + - label: Use cross over time delay from night lights to normal lights + value: "use_delay" + night_light_brightness: + name: Night Lights - Brightness + description: > + The brightness setting of the night lights when they are turned ON. + default: 20 + selector: + number: + min: 1 + max: 100 + mode: slider + step: 1 + unit_of_measurement: '%' + night_light_transition_on: + name: Night Lights - Transition - ON + description: > + The transition of the night lights when they are turned ON. + default: 1 + selector: + number: + min: 0 + max: 5 + mode: slider + step: 0.5 + unit_of_measurement: seconds + night_light_transition_off: + name: Night Lights - Transition - OFF + description: > + The transition of the night lights when they are turned OFF. + default: 1 + selector: + number: + min: 0 + max: 30 + mode: slider + step: 1 + unit_of_measurement: seconds + cross_over_time_delay: + name: Cross Over - Time Delay + description: > + The time delay sets the duration the night lights stay active after the night light condition is deactivated, before transitioning to normal lighting. + default: 5 + selector: + number: + min: 0 + max: 30 + step: 0.5 + unit_of_measurement: minutes + include_night_light_colour_control: + name: Use The Night Light Colour Control Options (Optional) + description: > + Select if you would like to use colour temperature, RGB, RGBW or RGBWW colour. + These settings will only affect a 'light' entity that supports each selected option. + The settings for colour temperature, RGB, RGBW and RGBWW colour are provided below + default: disable_colour_control + selector: + select: + options: + - label: Use Colour Temperature + value: "use_colour_temperature" + - label: Use RGB Colour + value: "use_rgb_colour" + - label: Use RGBW Colour + value: "use_rgbw_colour" + - label: Use RGBWW Colour + value: "use_rgbww_colour" + - label: Disable Colour Control + value: "disable_colour_control" + night_light_colour_temperature: + name: Night Lights - Colour Temperature + description: > + The colour temperature setting for the night lights when they are turned ON. + default: 5000 + selector: + number: + min: 2000 + max: 8000 + mode: slider + step: 100 + unit_of_measurement: 'kelvin' + night_light_rgb_colour: + name: Night Lights - RGB Colour + description: > + The RGB colour setting for the lights when they are turned ON. + default: [255, 255, 255] + selector: + color_rgb: + night_light_rgbw_colour: + name: Night Lights - RGBW Colour + description: > + The RGBW colour setting for the lights when they are turned ON. + Enter four integers between 0 and 255 to define the values for Red, Green, Blue, and White. + default: [255, 255, 255, 255] + selector: + object: + night_light_rgbww_colour: + name: Night Lights - RGBWW Colour + description: > + The RGBWW colour setting for the lights when they are turned ON. + Enter five integers between 0 and 255 to define the values for Red, Green, Blue, Cold White and Warm White. + default: [255, 255, 255, 255, 255] + selector: + object: + ha_restart: + name: "HA Restart" + icon: mdi:restart + collapsed: true + input: + include_ha_restart: + name: Use The HA Restart Option (Optional) + description: > + Because this automation supports many scenarios, the HA Restart safeguard option may not always behave as expected. + In most cases it works fine, so it’s enabled by default. However, if you find it causes issues in your setup, you can disable this option. + In most cases, when HA restarts, the automation will not land on an ON or OFF state, so disabling this option gives you a higher chance that nothing goes wrong. + default: enable_ha_restart + selector: + select: + options: + - label: Enable the HA Restart option + value: "enable_ha_restart" + - label: Disable the HA Restart + value: "disable_ha_restart" + +mode: restart +max_exceeded: silent + +variables: + + include_entity_state: !input include_entity_state + entity_input: !input entity_input + include_button: !input include_button + button_input: !input button_input + include_sun: !input include_sun + sun_elevation: !input sun_elevation + sun_elevation_rising: !input sun_elevation_rising + include_ambient: !input include_ambient + ambient_light_sensor: !input ambient_light_sensor + ambient_light_value: !input ambient_light_value + ambient_light_value_off: !input ambient_light_value_off + include_time: !input include_time + after_time: !input after_time + before_time: !input before_time + light_switch: !input light_switch + boolean_scenes_scripts: !input boolean_scenes_scripts + end_scenes: !input end_scenes + include_light_control: !input include_light_control + light_brightness: !input light_brightness + light_transition_on: !input light_transition_on + light_transition_off: !input light_transition_off + include_light_colour_control: !input include_light_colour_control + light_colour_temperature: !input light_colour_temperature + light_rgb_colour: !input light_rgb_colour + light_rgbw_colour: !input light_rgbw_colour + light_rgbww_colour: !input light_rgbww_colour + include_dynamic_lighting: !input include_dynamic_lighting + dynamic_lighting_lux_sensor: !input dynamic_lighting_lux_sensor + dynamic_lighting_max_lux: !input dynamic_lighting_max_lux + dynamic_lighting_min_lux: !input dynamic_lighting_min_lux + dynamic_lighting_max_brightness: !input dynamic_lighting_max_brightness + dynamic_lighting_min_brightness: !input dynamic_lighting_min_brightness + dynamic_lighting_boolean: !input dynamic_lighting_boolean + dynamic_lighting_max_colour_temp: !input dynamic_lighting_max_colour_temp + dynamic_lighting_min_colour_temp: !input dynamic_lighting_min_colour_temp + dynamic_lighting_sun_elevation_start_rising: !input dynamic_lighting_sun_elevation_start_rising + dynamic_lighting_sun_elevation_end_rising: !input dynamic_lighting_sun_elevation_end_rising + dynamic_lighting_sun_elevation_start_falling: !input dynamic_lighting_sun_elevation_start_falling + dynamic_lighting_sun_elevation_end_falling: !input dynamic_lighting_sun_elevation_end_falling + dynamic_lighting_time_start_morning: !input dynamic_lighting_time_start_morning + dynamic_lighting_time_end_morning: !input dynamic_lighting_time_end_morning + dynamic_lighting_time_start_evening: !input dynamic_lighting_time_start_evening + dynamic_lighting_time_end_evening: !input dynamic_lighting_time_end_evening + dynamic_lighting_heartbeat: !input dynamic_lighting_heartbeat + dynamic_lighting_step_value: !input dynamic_lighting_step_value + dynamic_lighting_dead_zone: !input dynamic_lighting_dead_zone + dynamic_lighting_state_control: !input dynamic_lighting_state_control + dynamic_lighting_state_control_activation_state: !input dynamic_lighting_state_control_activation_state + dynamic_lighting_state_control_entity: !input dynamic_lighting_state_control_entity + include_bypass: !input include_bypass + bypass_lights_on: !input bypass_lights_on + bypass_lights_off: !input bypass_lights_off + bypass_lights_stop: !input bypass_lights_stop + bypass_time_delay: !input bypass_time_delay + include_bypass_auto_off: !input include_bypass_auto_off + bypass_auto_off_delay: !input bypass_auto_off_delay + include_weekdays: !input include_weekdays + weekday_options: !input weekday_options + include_night_lights: !input include_night_lights + night_lights_conditions: !input night_lights_conditions + night_lights_entity_state: !input night_lights_entity_state + night_lights_after_time: !input night_lights_after_time + night_lights_before_time: !input night_lights_before_time + night_lights_sun_elevation: !input night_lights_sun_elevation + night_lights_sun_elevation_rising: !input night_lights_sun_elevation_rising + night_lights: !input night_lights + night_boolean_scenes_scripts: !input night_boolean_scenes_scripts + include_night_light_control: !input include_night_light_control + night_light_brightness: !input night_light_brightness + night_light_transition_on: !input night_light_transition_on + night_light_transition_off: !input night_light_transition_off + cross_over_time_delay: !input cross_over_time_delay + include_night_light_colour_control: !input include_night_light_colour_control + night_light_colour_temperature: !input night_light_colour_temperature + night_light_rgb_colour: !input night_light_rgb_colour + night_light_rgbw_colour: !input night_light_rgbw_colour + night_light_rgbww_colour: !input night_light_rgbww_colour + include_ha_restart: !input include_ha_restart + +# Split domains for light switch targets and check the entities are OFF - exclude scenes and scripts as they have no off state + + light_entities_off: "{{ expand(light_switch.entity_id) | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'off') | map(attribute='entity_id') | list }}" + switch_entities_off: "{{ expand(light_switch.entity_id) | selectattr('domain', 'eq', 'switch') | selectattr('state', 'eq', 'off') | map(attribute='entity_id') | list }}" + +# For light control - Light data + + light_data: >- + {% set light = namespace(data={}) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if 'use_brightness' in include_light_control %} + {% set light.data = dict(light.data, **{ 'brightness_pct': light_brightness }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + +# Split domains for light switch targets + + light_entities: "{{ expand(light_switch.entity_id) | selectattr('domain', 'eq', 'light') | map(attribute='entity_id') | list }}" + switch_entities: "{{ expand(light_switch.entity_id) | selectattr('domain', 'eq', 'switch') | map(attribute='entity_id') | list }}" + scene_entities: >- + {% set a = light_switch.entity_id %} + {% if boolean_scenes_scripts == [] %} + {{ expand(a) | selectattr('domain', 'eq', 'scene') | map(attribute='entity_id') | list }} + {% elif is_state(boolean_scenes_scripts, 'off') %} + {{ expand(a) | selectattr('domain', 'eq', 'scene') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + script_entities: >- + {% set a = light_switch.entity_id %} + {% if boolean_scenes_scripts == [] %} + {{ expand(a) | selectattr('domain', 'eq', 'script') | map(attribute='entity_id') | list }} + {% elif is_state(boolean_scenes_scripts, 'off') %} + {{ expand(a) | selectattr('domain', 'eq', 'script') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + boolean_scenes_scripts_helper: >- + {% if boolean_scenes_scripts | length > 0 and states(boolean_scenes_scripts) == 'off' %} + {{ boolean_scenes_scripts }} + {% else %} + [] + {% endif %} + +# Split domains for end scenes and scripts + + end_scene_entities: "{{ end_scenes | select('match', '^scene\\..*') | list }}" + end_script_entities: "{{ end_scenes | select('match', '^script\\..*') | list }}" + +# Split domains for night lights target and check the entities are OFF - Exclude scenes and scripts as they have no off state + + night_light_entities_off: >- + {% set b = night_lights and night_lights.entity_id %} + {% if b %} + {{ expand(b) | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'off') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + night_switch_entities_off: >- + {% set b = night_lights and night_lights.entity_id %} + {% if b %} + {{ expand(b) | selectattr('domain', 'eq', 'switch') | selectattr('state', 'eq', 'off') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + +# For night light control - Light data + + night_light_data: >- + {% set light = namespace(data={}) %} + {% if 'use_transition' in include_night_light_control %} + {% set light.data = dict(light.data, **{ 'transition': night_light_transition_on }) %} + {% endif %} + {% if 'use_brightness' in include_night_light_control %} + {% set light.data = dict(light.data, **{ 'brightness_pct': night_light_brightness }) %} + {% endif %} + {% if include_night_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': night_light_colour_temperature }) %} + {% endif %} + {% if include_night_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': night_light_rgb_colour }) %} + {% endif %} + {% if include_night_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': night_light_rgbw_colour }) %} + {% endif %} + {% if include_night_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': night_light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + +# Split domains for night lights target + + night_light_entities: >- + {% set b = night_lights and night_lights.entity_id %} + {% if b %} + {{ expand(b) | selectattr('domain', 'eq', 'light') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + night_switch_entities: >- + {% set b = night_lights and night_lights.entity_id %} + {% if b %} + {{ expand(b) | selectattr('domain', 'eq', 'switch') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + night_scene_entities: >- + {% set b = night_lights and night_lights.entity_id %} + {% if night_boolean_scenes_scripts == [] %} + {{ expand(b) | selectattr('domain', 'eq', 'scene') | map(attribute='entity_id') | list }} + {% elif is_state(night_boolean_scenes_scripts, 'off') %} + {{ expand(b) | selectattr('domain', 'eq', 'scene') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + night_script_entities: >- + {% set b = night_lights and night_lights.entity_id %} + {% if night_boolean_scenes_scripts == [] %} + {{ expand(b) | selectattr('domain', 'eq', 'script') | map(attribute='entity_id') | list }} + {% elif is_state(night_boolean_scenes_scripts, 'off') %} + {{ expand(b) | selectattr('domain', 'eq', 'script') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + night_boolean_scenes_scripts_helper: >- + {% if night_boolean_scenes_scripts | length > 0 and states(night_boolean_scenes_scripts) == 'off' %} + {{ night_boolean_scenes_scripts }} + {% else %} + [] + {% endif %} + +# Set up crossover lights for t10, t11 & t12 trigger. Also used in bypass t9 on, off & stop. + + crossover_lights_light: >- + {% set a = light_switch.entity_id %} + {% set b = night_lights and night_lights.entity_id %} + {% if a and b %} + {{ expand(a) | reject('in', expand(b)) | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + crossover_lights_switch: >- + {% set a = light_switch.entity_id %} + {% set b = night_lights and night_lights.entity_id %} + {% if a and b %} + {{ expand(a) | reject('in', expand(b)) | selectattr('domain', 'eq', 'switch') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + crossover_night_lights_light_on: >- + {% set b = night_lights and night_lights.entity_id %} + {% if b %} + {{ expand(b) | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + +# Set up crossover lights for t13, t14 & t15 trigger. Also used in bypass t9 on, off & stop. + + crossover_night_lights_light: >- + {% set a = light_switch.entity_id %} + {% set b = night_lights and night_lights.entity_id %} + {% if a and b %} + {{ expand(b) | reject('in', expand(a)) | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + crossover_night_lights_switch: >- + {% set a = light_switch.entity_id %} + {% set b = night_lights and night_lights.entity_id %} + {% if a and b %} + {{ expand(b) | reject('in', expand(a)) | selectattr('domain', 'eq', 'switch') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + crossover_lights_light_on: >- + {% set a = light_switch.entity_id %} + {% if a %} + {{ expand(a) | selectattr('domain', 'eq', 'light') | selectattr('state', 'eq', 'on') | map(attribute='entity_id') | list }} + {% else %} + [] + {% endif %} + +# Set up conditions for the bypass and HA restart + + trigger_options_on: > + {% set result = true %} + {% if 'entity_on' in include_entity_state %} + {% set result = result and (states[entity_input].state == 'on') %} + {% endif %} + {% if 'entity_off' in include_entity_state %} + {% set result = result and (states[entity_input].state == 'on') %} + {% endif %} + {% if 'sun_falling' in include_sun and 'sun_rising' in include_sun %} + {% set sun_falling_condition = (is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun', 'elevation') <= sun_elevation | float(90)) %} + {% set sun_rising_condition = (is_state_attr('sun.sun', 'rising', true)) and (state_attr('sun.sun', 'elevation') <= sun_elevation_rising | float(90)) %} + {% set result = result and (sun_falling_condition or sun_rising_condition) %} + {% endif %} + {% if 'sun_falling' in include_sun and is_state_attr('sun.sun', 'rising', false) and not 'sun_rising' in include_sun and not 'time_off' in include_time %} + {% set sun_falling_condition = (state_attr('sun.sun', 'elevation') <= sun_elevation | float(90)) %} + {% set result = result and sun_falling_condition %} + {% endif %} + {% if 'sun_rising' in include_sun and is_state_attr('sun.sun', 'rising', true) and not 'sun_falling' in include_sun %} + {% set sun_rising_condition = (state_attr('sun.sun', 'elevation') <= sun_elevation_rising | float(90)) %} + {% set result = result and sun_rising_condition %} + {% endif %} + {% if 'sun_falling' in include_sun and 'time_off' in include_time and not 'sun_rising' in include_sun and not 'time_on' in include_time %} + {% set sun_falling_condition = (is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun', 'elevation') <= sun_elevation | float(90)) %} + {% set time_off_condition = result and (now().time() <= strptime(before_time, '%H:%M:%S').time()) %} + {% if sun_falling_condition and time_off_condition %} + {% set result = true %} + {% else %} + {% set result = false %} + {% endif %} + {% endif %} + {% if 'ambient_high' in include_ambient and 'ambient_low' in include_ambient %} + {% set result = result and (states[ambient_light_sensor].state | float < ambient_light_value_off | float) %} + {% endif %} + {% if 'ambient_low' in include_ambient and not 'ambient_high' in include_ambient %} + {% set result = result and (states[ambient_light_sensor].state | float < ambient_light_value | float(90)) %} + {% endif %} + {% if 'ambient_high' in include_ambient and not 'ambient_low' in include_ambient%} + {% set result = result and (states[ambient_light_sensor].state | float < ambient_light_value_off | float) %} + {% endif %} + {% if 'time_on' in include_time and 'time_off' in include_time %} + {% set time_condition = (strptime(after_time, '%H:%M:%S').time() <= now().time() <= strptime(before_time, '%H:%M:%S').time()) %} + {% set result = result and time_condition %} + {% endif %} + {% if 'time_on' in include_time and not 'time_off' in include_time %} + {% set result = result and (now().time() >= strptime(after_time, '%H:%M:%S').time()) %} + {% endif %} + {% if 'time_off' in include_time and not 'time_on' in include_time and not 'sun_falling' in include_sun %} + {% set result = result and (now().time() <= strptime(before_time, '%H:%M:%S').time()) %} + {% endif %} + {{ result }} + trigger_options_off: > + {% set result = true %} + {% if 'entity_on' in include_entity_state %} + {% set result = result and (states[entity_input].state == 'on') %} + {% endif %} + {% if 'entity_off' in include_entity_state %} + {% set result = result and (states[entity_input].state == 'on') %} + {% endif %} + {% if 'sun_falling' in include_sun and 'sun_rising' in include_sun %} + {% set sun_falling_condition = (is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun', 'elevation') <= sun_elevation | float(90)) %} + {% set sun_rising_condition = (is_state_attr('sun.sun', 'rising', true)) and (state_attr('sun.sun', 'elevation') <= sun_elevation_rising | float(90)) %} + {% set result = result and (sun_falling_condition or sun_rising_condition) %} + {% endif %} + {% if 'sun_falling' in include_sun and is_state_attr('sun.sun', 'rising', false) and not 'sun_rising' in include_sun and not 'time_off' in include_time %} + {% set sun_falling_condition = (state_attr('sun.sun', 'elevation') <= sun_elevation | float(90)) %} + {% set result = result and sun_falling_condition %} + {% endif %} + {% if 'sun_rising' in include_sun and is_state_attr('sun.sun', 'rising', true) and not 'sun_falling' in include_sun %} + {% set sun_rising_condition = (state_attr('sun.sun', 'elevation') <= sun_elevation_rising | float(90)) %} + {% set result = result and sun_rising_condition %} + {% endif %} + {% if 'sun_falling' in include_sun and 'time_off' in include_time and not 'sun_rising' in include_sun and not 'time_on' in include_time %} + {% set sun_falling_condition = (is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun', 'elevation') <= sun_elevation | float(90)) %} + {% set time_off_condition = result and (now().time() <= strptime(before_time, '%H:%M:%S').time()) %} + {% if sun_falling_condition and time_off_condition %} + {% set result = true %} + {% else %} + {% set result = false %} + {% endif %} + {% endif %} + {% if 'ambient_high' in include_ambient and 'ambient_low' in include_ambient %} + {% set result = result and (states[ambient_light_sensor].state | float < ambient_light_value_off | float) %} + {% endif %} + {% if 'ambient_low' in include_ambient and not 'ambient_high' in include_ambient %} + {% set result = result and (states[ambient_light_sensor].state | float < ambient_light_value | float(90)) %} + {% endif %} + {% if 'ambient_high' in include_ambient and not 'ambient_low' in include_ambient%} + {% set result = result and (states[ambient_light_sensor].state | float < ambient_light_value_off | float) %} + {% endif %} + {% if 'time_on' in include_time and 'time_off' in include_time %} + {% set time_condition = (strptime(after_time, '%H:%M:%S').time() <= now().time() <= strptime(before_time, '%H:%M:%S').time()) %} + {% set result = result and time_condition %} + {% endif %} + {% if 'time_on' in include_time and not 'time_off' in include_time %} + {% set result = result and (now().time() >= strptime(after_time, '%H:%M:%S').time()) %} + {% endif %} + {% if 'time_off' in include_time and not 'time_on' in include_time and not 'sun_falling' in include_sun %} + {% set result = result and (now().time() <= strptime(before_time, '%H:%M:%S').time()) %} + {% endif %} + {{ not result }} + +# For dynamic lighting state control option + + dynamic_lighting_state_control_activation_state_inv: > + {% if dynamic_lighting_state_control_activation_state == 'on' %} + off + {% else %} + on + {% endif %} + +triggers: + - trigger: state + id: "t0" + entity_id: !input entity_input + from: "off" + to: "on" + - trigger: state + id: "t1" + entity_id: !input entity_input + from: "on" + to: "off" + - trigger: numeric_state + id: "t2" + entity_id: sun.sun + attribute: elevation + below: !input sun_elevation + - trigger: numeric_state + id: "t3" + entity_id: sun.sun + attribute: elevation + above: !input sun_elevation_rising + - trigger: numeric_state + id: "t4" + entity_id: !input ambient_light_sensor + below: !input ambient_light_value + - trigger: numeric_state + id: "t5" + entity_id: !input ambient_light_sensor + above: !input ambient_light_value_off + - trigger: time + id: "t6" + at: !input after_time + - trigger: time + id: "t7" + at: !input before_time + - trigger: state + id: "t8_on" + entity_id: !input bypass_lights_on + from: "off" + to: "on" + - trigger: state + id: "t8_off" + entity_id: !input bypass_lights_off + from: "off" + to: "on" + - trigger: state + id: "t8_stop" + entity_id: !input bypass_lights_stop + from: "off" + to: "on" + - trigger: state + id: "t9_on" + entity_id: !input bypass_lights_on + from: "on" + to: "off" + - trigger: state + id: "t9_off" + entity_id: !input bypass_lights_off + from: "on" + to: "off" + - trigger: state + id: "t9_stop" + entity_id: !input bypass_lights_stop + from: "on" + to: "off" + - trigger: state + id: "t10" + entity_id: !input night_lights_entity_state + from: "off" + to: "on" + - trigger: time + id: "t11" + at: !input night_lights_after_time + - trigger: numeric_state + id: "t12" + entity_id: sun.sun + attribute: elevation + below: !input night_lights_sun_elevation + - trigger: state + id: "t13" + entity_id: !input night_lights_entity_state + from: "on" + to: "off" + - trigger: time + id: "t14" + at: !input night_lights_before_time + - trigger: numeric_state + id: "t15" + entity_id: sun.sun + attribute: elevation + above: !input night_lights_sun_elevation_rising + - trigger: state + id: "t16" + entity_id: !input dynamic_lighting_state_control_entity + to: !input dynamic_lighting_state_control_activation_state + - trigger: state + id: "t17" + entity_id: !input dynamic_lighting_state_control_entity + from: !input dynamic_lighting_state_control_activation_state + - trigger: state + id: "t18" + entity_id: !input button_input + - trigger: state + id: "t19" + entity_id: !input button_input + - trigger: homeassistant + id: "t20" + event: start + +# All Conditions +condition: +#Trigger conditions + - condition: or + conditions: + - condition: and # trigger by entity on state + conditions: + - "{{ 'entity_on' in include_entity_state }}" + - condition: trigger + id: 't0' + - condition: state + entity_id: !input entity_input + match: any + state: 'on' + - condition: and # trigger by entity off state + conditions: + - "{{ 'entity_off' in include_entity_state }}" + - condition: trigger + id: 't1' + - condition: state + entity_id: !input entity_input + match: any + state: 'off' + - condition: and # trigger by sun falling + conditions: + - "{{ 'sun_falling' in include_sun }}" + - condition: trigger + id: 't2' + - condition: and # trigger by sun rising + conditions: + - "{{ 'sun_rising' in include_sun }}" + - condition: trigger + id: 't3' + - condition: and # trigger by ambient low LUX - ON + conditions: + - "{{ 'ambient_low' in include_ambient }}" + - condition: trigger + id: 't4' + - condition: and # trigger by ambient high LUX - OFF + conditions: + - "{{ 'ambient_high' in include_ambient }}" + - condition: trigger + id: 't5' + - condition: and # trigger by time ON + conditions: + - "{{ 'time_on' in include_time }}" + - condition: trigger + id: 't6' + - condition: and # trigger by time OFF + conditions: + - "{{ 'time_off' in include_time }}" + - condition: trigger + id: 't7' + - condition: and # trigger by by-pass turning on + conditions: + - condition: trigger + id: 't8_on' + - "{{ 'bypass_enabled_turn_on' in include_bypass }}" + - condition: and # trigger by by-pass turning off + conditions: + - condition: trigger + id: 't8_off' + - "{{ 'bypass_enabled_turn_off' in include_bypass }}" + - condition: and # trigger by by-pass stop + conditions: + - condition: trigger + id: 't8_stop' + - "{{ 'bypass_enabled_stop' in include_bypass }}" + - condition: and # trigger by by-pass turning on + conditions: + - condition: trigger + id: 't9_on' + - "{{ 'bypass_enabled_turn_on' in include_bypass }}" + - condition: and # trigger by by-pass turning off + conditions: + - condition: trigger + id: 't9_off' + - "{{ 'bypass_enabled_turn_off' in include_bypass }}" + - condition: and # trigger by by-pass stop + conditions: + - condition: trigger + id: 't9_stop' + - "{{ 'bypass_enabled_stop' in include_bypass }}" + - condition: and # trigger by the start of night light entity state & check if any lights are on + conditions: + - condition: trigger + id: 't10' + - "{{ include_night_lights == 'night_lights_enabled' }}" + - "{{ 'entity_state_enabled' in night_lights_conditions }}" + - condition: state + entity_id: !input night_lights_entity_state + match: any + state: 'on' + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by the start of night lights time & check if any lights are on + conditions: + - condition: trigger + id: 't11' + - "{{ include_night_lights == 'night_lights_enabled' }}" + - "{{ 'time_enabled' in night_lights_conditions }}" + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by the start of night lights sun elevation & check if any lights are on + conditions: + - condition: trigger + id: 't12' + - "{{ include_night_lights == 'night_lights_enabled' }}" + - "{{ 'sun_enabled' in night_lights_conditions }}" + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by the end of night lights entity state & check if any lights are on + conditions: + - condition: trigger + id: 't13' + - "{{ include_night_lights == 'night_lights_enabled' }}" + - "{{ 'entity_state_enabled' in night_lights_conditions }}" + - condition: state + entity_id: !input night_lights_entity_state + state: 'off' + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by the end of night lights time & check if any lights are on + conditions: + - condition: trigger + id: 't14' + - "{{ include_night_lights == 'night_lights_enabled' }}" + - "{{ 'time_enabled' in night_lights_conditions }}" + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by the end of night lights sun elevation & check if any lights are on + conditions: + - condition: trigger + id: 't15' + - "{{ include_night_lights == 'night_lights_enabled' }}" + - "{{ 'sun_enabled' in night_lights_conditions }}" + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by dynamic lighting state control and check in any normal lights are on + conditions: + - condition: trigger + id: + - 't16' + - 't17' + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: "{{ dynamic_lighting_state_control == 'enable_state_control' }}" + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by push button + conditions: + - condition: template + value_template: "{{ 'button_on' in include_button }}" + - condition: trigger + id: 't18' + - condition: or + conditions: + - condition: and # Normal Lights + conditions: + - condition: template + value_template: > + {% if (expand(light_switch.entity_id) | selectattr('domain', 'in', ['light','switch']) | list | count > 0) %} + {{ expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count == 0 }} + {% else %} + true + {% endif %} + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'off') }} + {% else %} + true + {% endif %} + - condition: template + value_template: > + {% set entity_ok = ('entity_state_enabled' in night_lights_conditions) and + (expand(night_lights_entity_state) | selectattr('state','equalto','on') | list | count > 0) %} + {% set time_ok = ('time_enabled' in night_lights_conditions) and + (now().strftime('%H:%M:%S') >= night_lights_after_time and now().strftime('%H:%M:%S') <= night_lights_before_time) %} + {% set sun_ok = ('sun_enabled' in night_lights_conditions) and ( + (not is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation | float(90)) or + (is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation_rising | float(90)) + ) %} + {% if include_night_lights == 'night_lights_enabled' %} + {{ not (entity_ok or time_ok or sun_ok) }} + {% else %} + true + {% endif %} + - condition: and # Dynamic Lighting + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'off') }} + {% else %} + true + {% endif %} + - condition: and # Night Lights + conditions: + - alias: "Check if night lights is enabled" + condition: template + value_template: "{{ include_night_lights == 'night_lights_enabled' }}" + - condition: template + value_template: > + {% if (expand(night_lights.entity_id) | selectattr('domain', 'in', ['light','switch']) | list | count > 0) %} + {{ expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count == 0 }} + {% else %} + true + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'off') }} + {% else %} + true + {% endif %} + - condition: template + value_template: > + {% set entity_ok = ('entity_state_enabled' in night_lights_conditions) and + (expand(night_lights_entity_state) | selectattr('state','equalto','on') | list | count > 0) %} + {% set time_ok = ('time_enabled' in night_lights_conditions) and + (now().strftime('%H:%M:%S') >= night_lights_after_time and now().strftime('%H:%M:%S') <= night_lights_before_time) %} + {% set sun_ok = ('sun_enabled' in night_lights_conditions) and ( + (not is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation | float(90)) or + (is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation_rising | float(90)) + ) %} + {% if include_night_lights == 'night_lights_enabled' %} + {{ (entity_ok or time_ok or sun_ok) }} + {% else %} + false + {% endif %} + - condition: and # trigger by push button + conditions: + - condition: template + value_template: "{{ 'button_off' in include_button }}" + - condition: trigger + id: 't19' + - condition: or + conditions: + - condition: and # Normal Lights + conditions: + - condition: template + value_template: > + {% if (expand(light_switch.entity_id) | selectattr('domain', 'in', ['light','switch']) | list | count > 0) %} + {{ expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0 }} + {% else %} + true + {% endif %} + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% else %} + true + {% endif %} + - condition: template + value_template: > + {% set entity_ok = ('entity_state_enabled' in night_lights_conditions) and + (expand(night_lights_entity_state) | selectattr('state','equalto','on') | list | count > 0) %} + {% set time_ok = ('time_enabled' in night_lights_conditions) and + (now().strftime('%H:%M:%S') >= night_lights_after_time and now().strftime('%H:%M:%S') <= night_lights_before_time) %} + {% set sun_ok = ('sun_enabled' in night_lights_conditions) and ( + (not is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation | float(90)) or + (is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation_rising | float(90)) + ) %} + {% if include_night_lights == 'night_lights_enabled' %} + {{ not (entity_ok or time_ok or sun_ok) }} + {% else %} + true + {% endif %} + - condition: and # Dynamic Lighting + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% else %} + true + {% endif %} + - condition: and # Night Lights + conditions: + - alias: "Check if night lights is enabled" + condition: template + value_template: "{{ include_night_lights == 'night_lights_enabled' }}" + - condition: template + value_template: > + {% if (expand(night_lights.entity_id) | selectattr('domain', 'in', ['light','switch']) | list | count > 0) %} + {{ expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0 }} + {% else %} + true + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% else %} + true + {% endif %} + - condition: template + value_template: > + {% set entity_ok = ('entity_state_enabled' in night_lights_conditions) and + (expand(night_lights_entity_state) | selectattr('state','equalto','on') | list | count > 0) %} + {% set time_ok = ('time_enabled' in night_lights_conditions) and + (now().strftime('%H:%M:%S') >= night_lights_after_time and now().strftime('%H:%M:%S') <= night_lights_before_time) %} + {% set sun_ok = ('sun_enabled' in night_lights_conditions) and ( + (not is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation | float(90)) or + (is_state_attr('sun.sun','rising', true) and state_attr('sun.sun','elevation') <= night_lights_sun_elevation_rising | float(90)) + ) %} + {% if include_night_lights == 'night_lights_enabled' %} + {{ (entity_ok or time_ok or sun_ok) }} + {% else %} + false + {% endif %} + - condition: and # trigger by HA Restart & check if any triggers are on + conditions: + - condition: trigger + id: 't20' + - condition: template + value_template: "{{ include_ha_restart == 'enable_ha_restart' }}" + - condition: template + value_template: "{{ trigger_options_on }}" + - condition: and # trigger by HA Restart & check if any lights are on + conditions: + - condition: trigger + id: 't20' + - condition: template + value_template: "{{ include_ha_restart == 'enable_ha_restart' }}" + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + - condition: and # trigger by HA Restart & check if by-pass auto off is enabled and any by-passes are on + conditions: + - "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + - condition: trigger + id: 't20' + - condition: template + value_template: "{{ include_ha_restart == 'enable_ha_restart' }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + +# Check Motion Sensor Manual By-pass + - condition: or + conditions: + - "{{ include_bypass == [] }}" + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: trigger + id: + - 't8_on' + - 't8_off' + - 't8_stop' + - 't9_on' + - 't9_off' + - 't9_stop' + - 't20' + +# Check The Weekday Option + - condition: or + conditions: + - "{{ include_weekdays == 'weekday_disabled' }}" + - condition: and + conditions: + - condition: time + weekday: !input weekday_options + - "{{ include_weekdays == 'weekday_enabled' }}" + - condition: trigger + id: + - 't8_on' + - 't8_off' + - 't8_stop' + - 't9_on' + - 't9_off' + - 't9_stop' + +action: + - choose: + - alias: "Check if night lights are enabled and within conditions" + conditions: + - condition: and + conditions: + - alias: "Check if night lights is enabled" + condition: template + value_template: "{{ include_night_lights == 'night_lights_enabled' }}" + - alias: "Check if night lights entity state is enabled" + condition: or + conditions: + - "{{ ('time_enabled' in night_lights_conditions) and not ('entity_state_enabled' in night_lights_conditions) }}" + - "{{ ('sun_enabled' in night_lights_conditions) and not ('entity_state_enabled' in night_lights_conditions) }}" + - condition: and + conditions: + - "{{ 'entity_state_enabled' in night_lights_conditions }}" + - condition: state + entity_id: !input night_lights_entity_state + state: 'on' + match: any + - alias: "Check if night lights time is enabled" + condition: or + conditions: + - "{{ ('entity_state_enabled' in night_lights_conditions) and not ('time_enabled' in night_lights_conditions) }}" + - "{{ ('sun_enabled' in night_lights_conditions) and not ('time_enabled' in night_lights_conditions) }}" + - condition: and + conditions: + - "{{ 'time_enabled' in night_lights_conditions }}" + - condition: time + after: !input night_lights_after_time + before: !input night_lights_before_time + - alias: "Check if night lights sun is enabled" + condition: or + conditions: + - "{{ ('entity_state_enabled' in night_lights_conditions) and not ('sun_enabled' in night_lights_conditions) }}" + - "{{ ('time_enabled' in night_lights_conditions) and not ('sun_enabled' in night_lights_conditions) }}" + - "{{ ('sun_enabled' in night_lights_conditions) and (((is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun','elevation') <= night_lights_sun_elevation | float(90))) or ((is_state_attr('sun.sun', 'rising', true)) and (state_attr('sun.sun','elevation') <= night_lights_sun_elevation_rising | float(90)))) }}" + sequence: + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - choose: + - alias: "By-pass is turned on & check by-pass option - Turn lights off" + conditions: + - condition: trigger + id: 't8_off' + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + else: + - stop: "Stop the automation" + - alias: "By-pass is turned on & check by-pass option - Keep the current lights state" + conditions: + - condition: trigger + id: 't8_stop' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + else: + - stop: "Stop the automation" + - choose: + - alias: "By-pass is turned off & check if the trigger is off" + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - choose: + - alias: "Check all by-pass are off" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - stop: "Stop the automation" + - alias: "Trigger is off and check if any by-passes are on" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + - alias: "By-pass is turned off & check if the trigger is on" + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + - alias: "Check if any triggers are ON" + condition: template + value_template: "{{ trigger_options_on }}" + sequence: + - choose: + - alias: "Check weekdays" + conditions: + - condition: and + conditions: + - "{{ include_weekdays == 'weekday_enabled' }}" + - condition: not + conditions: + - condition: time + weekday: !input weekday_options + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - stop: "Stop the automation" + - alias: "Check all by-pass are off and check conditions if enabled" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - stop: "Stop the automation" + - alias: "Motion trigger is on and check if any by-passes are on" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + - alias: "By-pass is turned off & reset lights to the site conditions" + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_lights_light }}" + data: + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_lights_light }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ crossover_lights_switch }}" + - choose: + - alias: "Check if normal lights Scenes & Scripts - Toggle Helper is on" + conditions: + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the input boolean normal lights" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn ON lights" + action: light.turn_on + target: + entity_id: "{{ crossover_night_lights_light_on }}" + data: "{{ night_light_data }}" + - choose: + - alias: "Turn off normal lights when trigger by start night lights conditions" + conditions: + - condition: trigger + id: + - 't10' + - 't11' + - 't12' + sequence: + - choose: + - alias: "light - switch - scene - script is ON" + conditions: + - condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_lights_light }}" + data: + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_lights_light }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ crossover_lights_switch }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - choose: + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the input boolean normal lights" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn ON lights" + action: light.turn_on + target: + entity_id: "{{ crossover_night_lights_light_on }}" + data: "{{ night_light_data }}" + - alias: "light - switch - scene - script is ON" + conditions: + - "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'off') | list | count > 0) or (expand(night_lights.entity_id) | selectattr('state', '==', 'off') | list | count > 0) or (is_state(boolean_scenes_scripts, 'off')) }}" + sequence: + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - stop: "Stop the automation" + - alias: "Safe Guard when HA restarts" + conditions: + - condition: trigger + id: 't20' + sequence: + - choose: + - alias: "Check all by-pass are off and check conditions if enabled" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + sequence: + - choose: + - alias: "Check if any light are ON and all triggers are OFF" + conditions: + - alias: "Check if any lights are ON" + condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the normal switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the night switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for normal lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for night lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - stop: "Stop the automation" + - alias: "Check if any by-passes are on" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + sequence: + - alias: "Check by-pass auto off is enabled and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + - alias: "Check if any lights are ON and any trigger is OFF" + conditions: + - alias: "Check if any lights are ON" + condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the normal switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the night switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for normal lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for night lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - stop: "Stop the automation" + - choose: + - conditions: + - condition: or + conditions: + - condition: trigger + id: + - 't0' + - 't2' + - 't4' + - 't6' + - 't8_on' + - 't10' + - 't11' + - 't12' + - 't18' + - 't20' + - condition: and + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: or + conditions: + - "{{ ('entity_on' in include_entity_state ) and (states[entity_input].state == 'on') }}" + - "{{ ('sun_falling' in include_sun) and (is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun','elevation') <= sun_elevation | float(90)) }}" + - "{{ ('sun_rising' in include_sun) and (is_state_attr('sun.sun', 'rising', true)) and (state_attr('sun.sun','elevation') <= sun_elevation_rising | float(90)) }}" + - "{{ ('ambient_low' in include_ambient) and (states[ambient_light_sensor].state | int < ambient_light_value | int) }}" + - "{{ ('ambient_high' in include_ambient) and (states[ambient_light_sensor].state | int < ambient_light_value_off | int) and (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: and + conditions: + - condition: template + value_template: "{{ ('time_on' in include_time) and ('time_off' in include_time) }}" + - condition: time + after: !input after_time + before: !input before_time + sequence: + - alias: "Turn ON lights" + action: light.turn_on + target: + entity_id: "{{ night_light_entities_off }}" + data: "{{ night_light_data }}" + - choose: + - alias: "Check if normal lights scenes or scripts helper is on - This is for scenes only when crossing over" + conditions: + - condition: template + value_template: >- + {% if boolean_scenes_scripts == [] %} + false + {% elif is_state(boolean_scenes_scripts, 'on') %} + true + {% else %} + false + {% endif %} + sequence: + - delay: 0 + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn on the night scenes" + action: scene.turn_on + target: + entity_id: "{{ night_scene_entities }}" + data: + transition: "{{ night_light_transition_on }}" + - alias: "Turn on the boolean for scenes and scripts" + action: input_boolean.turn_on + data: + entity_id: "{{ night_boolean_scenes_scripts_helper }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn on the night scenes" + action: scene.turn_on + target: + entity_id: "{{ night_scene_entities }}" + - alias: "Turn on the boolean for scenes and scripts" + action: input_boolean.turn_on + data: + entity_id: "{{ night_boolean_scenes_scripts_helper }}" + - alias: "Turn on the night switches" + action: switch.turn_on + target: + entity_id: "{{ night_switch_entities_off }}" + - alias: "Turn on the night scripts" + action: script.turn_on + target: + entity_id: "{{ night_script_entities }}" + - choose: + - alias: "By-pass is enabled & check by-pass option - Turn lights on" + conditions: + - condition: trigger + id: 't8_on' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + else: + - stop: "Stop the automation" + - conditions: + - condition: trigger + id: + - 't1' + - 't3' + - 't5' + - 't7' + - 't19' + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + default: + - choose: + - alias: "By-pass is turned on & check by-pass option - Turn lights off" + conditions: + - condition: trigger + id: 't8_off' + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + else: + - stop: "Stop the automation" + - alias: "By-pass is turned on & check by-pass option - Keep the current lights state" + conditions: + - condition: trigger + id: 't8_stop' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + else: + - stop: "Stop the automation" + - choose: + - alias: "By-pass is turned off & check if the trigger is off" + conditions: + - condition: and + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - choose: + - alias: "Check all by-pass are off" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - stop: "Stop the automation" + - alias: "Trigger is off and check if any by-passes are on" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + - alias: "By-pass is turned off & check if the trigger is on" + conditions: + - condition: and + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + - alias: "Check if any triggers are ON" + condition: template + value_template: "{{ trigger_options_on }}" + sequence: + - choose: + - alias: "Check weekdays" + conditions: + - condition: and + conditions: + - "{{ include_weekdays == 'weekday_enabled' }}" + - condition: not + conditions: + - condition: time + weekday: !input weekday_options + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - stop: "Stop the automation" + - alias: "Check all by-pass are off and check conditions if enabled" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - stop: "Stop the automation" + - alias: "Trigger is on and check if any by-passes are on" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + - alias: "By-pass is turned off & reset lights to the site conditions" + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_night_lights_light }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_night_lights_light }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ crossover_night_lights_switch }}" + - choose: + - alias: "Check if night lights scenes & scripts - toggle helper is on" + conditions: + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the input boolean night lights" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - choose: + - alias: "Turn ON lights" + conditions: + - alias: "Check the dynamic lighting options" + condition: or + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'disable_dynamic_lighting' }}" + - alias: "Check that dynamic lighting is active and the state control option is enabled" + condition: and + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: "{{ dynamic_lighting_state_control == 'enable_state_control' }}" + - condition: template + value_template: "{{ states(dynamic_lighting_state_control_entity) == dynamic_lighting_state_control_activation_state_inv }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ crossover_lights_light_on }}" + data: "{{ light_data }}" + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - choose: + - alias: "Turn off night lights when trigger by end night lights conditions" + conditions: + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - choose: + - alias: "If delay is selected in night lights" + conditions: + - "{{ 'use_delay' in include_night_light_control }}" + sequence: + delay: + minutes: !input cross_over_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) or (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) or (is_state(night_boolean_scenes_scripts, 'on')) }}" + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_night_lights_light }}" + data: + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ crossover_night_lights_light }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ crossover_night_lights_switch }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - choose: + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + sequence: + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_night_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ night_light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_night_light_control }}" + sequence: + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the input boolean night lights" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - choose: + - alias: "Turn ON lights" + conditions: + - alias: "Check the dynamic lighting options" + condition: or + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'disable_dynamic_lighting' }}" + - alias: "Check that dynamic lighting is active and the state control option is enabled" + condition: and + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: "{{ dynamic_lighting_state_control == 'enable_state_control' }}" + - condition: template + value_template: "{{ states(dynamic_lighting_state_control_entity) == dynamic_lighting_state_control_activation_state_inv }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ crossover_lights_light_on }}" + data: "{{ light_data }}" + - alias: "If transition is selected" + conditions: + - "{{ 'manage_scripts_crossing_over' in include_night_light_control }}" + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'off') | list | count > 0) or (expand(night_lights.entity_id) | selectattr('state', '==', 'off') | list | count > 0) or (is_state(night_boolean_scenes_scripts, 'off')) }}" + sequence: + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - stop: "Stop the automation" + - alias: "Safe Guard when HA restarts" + conditions: + - condition: trigger + id: 't20' + sequence: + - choose: + - alias: "Check all by-pass are off and check conditions if enabled" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + state: 'off' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + state: 'off' + sequence: + - choose: + - alias: "Check if any light are ON and all triggers are OFF" + conditions: + - alias: "Check if any lights are ON" + condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the normal switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the night switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for normal lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for night lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - stop: "Stop the automation" + - alias: "Check if any by-passes are on" + conditions: + - condition: or + conditions: + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: or + conditions: + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_on + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' in include_bypass) and ('bypass_enabled_stop' not in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_off + match: any + state: 'on' + - condition: and + conditions: + - "{{ ('bypass_enabled_turn_on' not in include_bypass) and ('bypass_enabled_turn_off' not in include_bypass) and ('bypass_enabled_stop' in include_bypass) }}" + - condition: state + entity_id: !input bypass_lights_stop + match: any + state: 'on' + sequence: + - alias: "Check by-pass auto off is enabled and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + - alias: "Check if any lights are ON and any trigger is OFF" + conditions: + - alias: "Check if any lights are ON" + condition: or + conditions: + - "{{ (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - "{{ (include_night_lights == 'night_lights_enabled') and (expand(night_lights.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: template + value_template: >- + {% if boolean_scenes_scripts != [] %} + {{ is_state(boolean_scenes_scripts, 'on') }} + {% endif %} + - condition: template + value_template: >- + {% if night_boolean_scenes_scripts != [] %} + {{ is_state(night_boolean_scenes_scripts, 'on') }} + {% endif %} + - alias: "Check if all triggers are OFF" + condition: template + value_template: "{{ trigger_options_off }}" + sequence: + - alias: "Wait the number of minutes set in the by-pass time delay" + delay: + minutes: !input bypass_time_delay + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the normal lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the night lights" + action: light.turn_off + target: + entity_id: "{{ night_light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the normal switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the night switches" + action: switch.turn_off + target: + entity_id: "{{ night_switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for normal lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts + - alias: "Turn off the boolean for night lights scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input night_boolean_scenes_scripts + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - stop: "Stop the automation" + - choose: + - conditions: + - condition: or + conditions: + - condition: trigger + id: + - 't0' + - 't2' + - 't4' + - 't6' + - 't8_on' + - 't13' + - 't14' + - 't15' + - 't16' + - 't17' + - 't18' + - 't20' + - condition: and + conditions: + - condition: trigger + id: + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: or + conditions: + - "{{ ('entity_on' in include_entity_state ) and (states[entity_input].state == 'on') }}" + - "{{ ('sun_falling' in include_sun) and (is_state_attr('sun.sun', 'rising', false)) and (state_attr('sun.sun','elevation') <= sun_elevation | float(90)) }}" + - "{{ ('sun_rising' in include_sun) and (is_state_attr('sun.sun', 'rising', true)) and (state_attr('sun.sun','elevation') <= sun_elevation_rising | float(90)) }}" + - "{{ ('ambient_low' in include_ambient) and (states[ambient_light_sensor].state | int < ambient_light_value | int) }}" + - "{{ ('ambient_high' in include_ambient) and (states[ambient_light_sensor].state | int < ambient_light_value_off | int) and (expand(light_switch.entity_id) | selectattr('state', '==', 'on') | list | count > 0) }}" + - condition: and + conditions: + - condition: template + value_template: "{{ ('time_on' in include_time) and ('time_off' in include_time) }}" + - condition: time + after: !input after_time + before: !input before_time + sequence: + - alias: "Parallel actions for dynamic lighting and normal lights" + parallel: + - sequence: + - alias: "Check if the dynamic lighting is enabled" + condition: and + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - alias: "Check the dynamic lighting state control option" + condition: or + conditions: + - condition: template + value_template: "{{ dynamic_lighting_state_control == 'disable_state_control' }}" + - alias: "Check if the dynamic lighting state control option is enabled" + condition: and + conditions: + - condition: template + value_template: "{{ dynamic_lighting_state_control == 'enable_state_control' }}" + - condition: state + entity_id: !input dynamic_lighting_state_control_entity + state: !input dynamic_lighting_state_control_activation_state + - choose: + - alias: "Dynamic Lighting - Input Boolean Helper" + conditions: + - condition: template + value_template: "{{ dynamic_lighting_boolean != [] }}" + sequence: + - alias: "Turn on the boolean for dynamic lighting" + action: input_boolean.turn_on + data: + entity_id: !input dynamic_lighting_boolean + - choose: + - alias: "1 - Dynamic Lighting - Lux Controlled Brightness" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_lux_controled_brightness'}}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_brightness_pct: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_max_lux - dynamic_lighting_min_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_max_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if lp <= 0 %} + {% set bv = bv %} + {% elif (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif (bv > lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif (lp > bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif bv > (lp + dynamic_lighting_step_value) %} + {% set bv = lp + dynamic_lighting_step_value %} + {% elif bv < (lp - dynamic_lighting_step_value) %} + {% set bv = lp - dynamic_lighting_step_value %} + {% endif %} + {{ bv | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + in_dead_zone: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_max_lux - dynamic_lighting_min_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_max_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + false + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + false + {% elif (bv >= lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + true + {% elif (lp >= bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + true + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If dynamic lighting brightness is in the dead zone" + conditions: + - condition: template + value_template: "{{ in_dead_zone }}" + - condition: template + value_template: "{{ repeat.index != 1 }}" + sequence: + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Set the dynamic lighting brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_lux_controled_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - choose: + - alias: "2 - Dynamic Lighting - Lux Controlled Brightness - Inverted" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_lux_controled_brightness_inv'}}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_brightness_pct: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_min_lux - dynamic_lighting_max_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_min_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if lp <= 0 %} + {% set bv = bv %} + {% elif (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif (bv > lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif (lp > bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif bv > (lp + dynamic_lighting_step_value) %} + {% set bv = lp + dynamic_lighting_step_value %} + {% elif bv < (lp - dynamic_lighting_step_value) %} + {% set bv = lp - dynamic_lighting_step_value %} + {% endif %} + {{ bv | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + in_dead_zone: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_min_lux - dynamic_lighting_max_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_min_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + true + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + false + {% elif (bv >= lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + true + {% elif (lp >= bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + true + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If dynamic lighting brightness is in the dead zone" + conditions: + - condition: template + value_template: "{{ in_dead_zone }}" + - condition: template + value_template: "{{ repeat.index != 1 }}" + sequence: + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Set dynamic lighting brightness inverted for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_lux_controled_brightness_inv' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - choose: + - alias: "3 - Dynamic Lighting - Sun Elevation Lighting - Colour Temp" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_kelvin: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if 'use_brightness' in include_light_control %} + {% set light.data = dict(light.data, **{ 'brightness_pct': light_brightness }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if elevation >= (dynamic_lighting_sun_elevation_start_rising - 2) and elevation <= (dynamic_lighting_sun_elevation_end_rising + 2) and is_state_attr('sun.sun', 'rising', true) %} + false + {% elif elevation <= (dynamic_lighting_sun_elevation_start_falling + 2) and elevation >= (dynamic_lighting_sun_elevation_end_falling - 2) and is_state_attr('sun.sun', 'rising', false) %} + false + {% elif elevation >= (dynamic_lighting_sun_elevation_end_rising + 2) and elevation >= (dynamic_lighting_sun_elevation_start_falling - 2) %} + true + {% elif elevation <= (dynamic_lighting_sun_elevation_start_rising - 2) and is_state_attr('sun.sun', 'rising', true) %} + true + {% elif elevation <= (dynamic_lighting_sun_elevation_end_falling - 2) and is_state_attr('sun.sun', 'rising', false) %} + true + {% else %} + true + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If sun elevation is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set dynamic sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "4 - Dynamic Lighting - Sun Elevation Lighting - Brightness" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_brightness' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_brightness_pct: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_brightness %} + {% set end_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_brightness %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_brightness %} + {% set end_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_brightness %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if (brightness_value >= (lp * 0.99) and brightness_value <= (lp * 1.01)) %} + true + {% else %} + false + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If lights are ON and the lights are within 1% of the actual brightness" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set dynamic sun elevation lighting brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "5 - Dynamic Lighting - Sun Elevation Lighting - Brightness Inverted" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_brightness_inv' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_brightness_pct: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_min_brightness %} + {% set end_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_max_brightness %} + {% if elevation > dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_min_brightness %} + {% set end_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_max_brightness %} + {% if elevation > dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if (brightness_value >= (lp * 0.99) and brightness_value <= (lp * 1.01)) %} + true + {% else %} + false + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If lights are ON and the lights are within 1% of the actual brightness" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set dynamic sun elevation lighting brightness inverted for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_brightness_inv' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "6 - Dynamic Lighting - Sun Elevation Lighting - Colour Temp + Brightness" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_brightness' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_kelvin: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_brightness_pct: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_brightness %} + {% set end_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_brightness %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_brightness %} + {% set end_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_brightness %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if (brightness_value >= (lp * 0.99) and brightness_value <= (lp * 1.01)) %} + true + {% else %} + false + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If lights are ON and the lights are within 1% of the actual brightness" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set dynamic sun elevation lighting brightness and dynamic sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "7 - Dynamic Lighting - Sun Elevation Lighting - Colour Temp + Brightness Inverted" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_brightness_inv' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_kelvin: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_brightness_pct: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_min_brightness %} + {% set end_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_max_brightness %} + {% if elevation > dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_min_brightness %} + {% set end_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_max_brightness %} + {% if elevation > dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if (brightness_value >= (lp * 0.99) and brightness_value <= (lp * 1.01)) %} + true + {% else %} + false + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If lights are ON and the lights are within 1% of the actual brightness" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set dynamic sun elevation lighting brightness and dynamic sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_brightness_inv' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "8 - Dynamic Lighting - Sun Elevation Lighting - Colour Temp + Lux Controlled Brightness" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness' }}" + sequence: + - alias: "Parallel actions for dynamic lighting" + parallel: + - sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_brightness_pct: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_max_lux - dynamic_lighting_min_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_max_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if lp <= 0 %} + {% set bv = bv %} + {% elif (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif (bv > lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif (lp > bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif bv > (lp + dynamic_lighting_step_value) %} + {% set bv = lp + dynamic_lighting_step_value %} + {% elif bv < (lp - dynamic_lighting_step_value) %} + {% set bv = lp - dynamic_lighting_step_value %} + {% endif %} + {{ bv | round(0) }} + dynamic_kelvin: > + {% if expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 %} + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + {% endif %} + dynamic_light_off_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + in_dead_zone: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_max_lux - dynamic_lighting_min_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_max_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + false + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + false + {% elif (bv >= lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + true + {% elif (lp >= bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + true + {% else %} + false + {% endif %} + - choose: + - alias: "Check if the light is off" + conditions: "{{ expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 }}" + sequence: + - alias: "Delay for parallel actions needed for when the light is off" + delay: + milliseconds: 100 + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - alias: "Delay for parallel actions needed for when the light is on" + delay: + milliseconds: 100 + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - alias: "Delay for parallel actions needed for when the light is on" + delay: + milliseconds: 100 + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If dynamic lighting brightness is in the dead zone" + conditions: + - condition: template + value_template: "{{ in_dead_zone }}" + - condition: template + value_template: "{{ repeat.index != 1 }}" + sequence: + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Set dynamic lighting lux brightness and dynamic sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness' }}" + - "{{ expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_off_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Set dynamic lighting lux brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_kelvin: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if elevation >= (dynamic_lighting_sun_elevation_start_rising - 2) and elevation <= (dynamic_lighting_sun_elevation_end_rising + 2) and is_state_attr('sun.sun', 'rising', true) %} + false + {% elif elevation <= (dynamic_lighting_sun_elevation_start_falling + 2) and elevation >= (dynamic_lighting_sun_elevation_end_falling - 2) and is_state_attr('sun.sun', 'rising', false) %} + false + {% elif elevation >= (dynamic_lighting_sun_elevation_end_rising + 2) and elevation >= (dynamic_lighting_sun_elevation_start_falling - 2) %} + true + {% elif elevation <= (dynamic_lighting_sun_elevation_start_rising - 2) and is_state_attr('sun.sun', 'rising', true) %} + true + {% elif elevation <= (dynamic_lighting_sun_elevation_end_falling - 2) and is_state_attr('sun.sun', 'rising', false) %} + true + {% else %} + true + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If sun elevation is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If the lights are OFF" + conditions: "{{ expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "9 - Dynamic Lighting - Sun Elevation Lighting - Colour Temp + Lux Controlled Brightness Inverted" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness_inv' }}" + sequence: + - alias: "Parallel actions for dynamic lighting" + parallel: + - sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_brightness_pct: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_min_lux - dynamic_lighting_max_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_min_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if lp <= 0 %} + {% set bv = bv %} + {% elif (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_max_brightness %} + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif (bv > lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif (lp > bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + {% set bv = lp %} + {% elif bv > (lp + dynamic_lighting_step_value) %} + {% set bv = lp + dynamic_lighting_step_value %} + {% elif bv < (lp - dynamic_lighting_step_value) %} + {% set bv = lp - dynamic_lighting_step_value %} + {% endif %} + {{ bv | round(0) }} + dynamic_kelvin: > + {% if expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 %} + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + {% endif %} + dynamic_light_off_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + in_dead_zone: > + {% set lux = states(dynamic_lighting_lux_sensor) | float %} + {% set slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (dynamic_lighting_min_lux - dynamic_lighting_max_lux) %} + {% set ak = (( slope * dynamic_lighting_min_lux) * -1) + dynamic_lighting_min_brightness %} + {% set le = light_entities %} + {% set lec = expand(le) | map(attribute='entity_id') | list | length %} + {% set lp = (expand(le) | map(attribute='attributes.brightness') | reject('equalto', None) | sum | float(default=255) / 255 * 100 / lec) | round(0) %} + {% if lux <= dynamic_lighting_min_lux %} + {% set bv = dynamic_lighting_min_brightness %} + {% elif lux >= dynamic_lighting_max_lux %} + {% set bv = dynamic_lighting_max_brightness %} + {% else %} + {% set bv = ((slope * lux) + ak) | round(1) %} + {% endif %} + {% if (bv > lp) and (dynamic_lighting_max_brightness - lp) <= dynamic_lighting_dead_zone %} + true + {% elif (lp > bv) and (lp - dynamic_lighting_min_brightness) <= dynamic_lighting_dead_zone %} + false + {% elif (bv >= lp) and (bv - lp) <= dynamic_lighting_dead_zone %} + true + {% elif (lp >= bv) and (lp - bv) <= dynamic_lighting_dead_zone %} + true + {% else %} + false + {% endif %} + - choose: + - alias: "Check if the light is off" + conditions: "{{ expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 }}" + sequence: + - alias: "Delay for parallel actions needed for when the light is off" + delay: + milliseconds: 100 + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - alias: "Delay for parallel actions needed for when the light is on" + delay: + milliseconds: 100 + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - alias: "Delay for parallel actions needed for when the light is on" + delay: + milliseconds: 100 + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If dynamic lighting brightness is in the dead zone" + conditions: + - condition: template + value_template: "{{ in_dead_zone }}" + - condition: template + value_template: "{{ repeat.index != 1 }}" + sequence: + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Set dynamic lighting lux brightness and dynamic sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness_inv' }}" + - "{{ expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_off_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Set dynamic lighting lux brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness_inv' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_elevation_cutoff: > + {% if is_state_attr('sun.sun', 'rising', true) %} + {{ dynamic_lighting_sun_elevation_start_rising }} + {% else %} + {{ dynamic_lighting_sun_elevation_end_falling }} + {% endif %} + dynamic_kelvin: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_start_rising - dynamic_lighting_sun_elevation_end_rising) %} + {% set start_ak = (( start_slope * dynamic_lighting_sun_elevation_end_rising) * -1) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (dynamic_lighting_sun_elevation_end_falling - dynamic_lighting_sun_elevation_start_falling) %} + {% set end_ak = (( end_slope * dynamic_lighting_sun_elevation_end_falling) * -1) + dynamic_lighting_min_colour_temp %} + {% if elevation >= dynamic_elevation_cutoff %} + {% if elevation >= dynamic_lighting_sun_elevation_start_rising and elevation <= dynamic_lighting_sun_elevation_end_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = ((start_slope * elevation) + start_ak) | round(1) %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_falling and elevation >= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = ((end_slope * elevation) + end_ak) | round(1) %} + {% elif elevation >= dynamic_lighting_sun_elevation_end_rising and elevation >= dynamic_lighting_sun_elevation_start_falling %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_start_rising and is_state_attr('sun.sun', 'rising', true) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif elevation <= dynamic_lighting_sun_elevation_end_falling and is_state_attr('sun.sun', 'rising', false) %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {% else %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set elevation = state_attr('sun.sun', 'elevation') | float %} + {% if expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% if elevation >= (dynamic_lighting_sun_elevation_start_rising - 2) and elevation <= (dynamic_lighting_sun_elevation_end_rising + 2) and is_state_attr('sun.sun', 'rising', true) %} + false + {% elif elevation <= (dynamic_lighting_sun_elevation_start_falling + 2) and elevation >= (dynamic_lighting_sun_elevation_end_falling - 2) and is_state_attr('sun.sun', 'rising', false) %} + false + {% elif elevation >= (dynamic_lighting_sun_elevation_end_rising + 2) and elevation >= (dynamic_lighting_sun_elevation_start_falling - 2) %} + true + {% elif elevation <= (dynamic_lighting_sun_elevation_start_rising - 2) and is_state_attr('sun.sun', 'rising', true) %} + true + {% elif elevation <= (dynamic_lighting_sun_elevation_end_falling - 2) and is_state_attr('sun.sun', 'rising', false) %} + true + {% else %} + true + {% endif %} + {% else %} + false + {% endif %} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If sun elevation is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "If the lights are OFF" + conditions: "{{ expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0 }}" + sequence: + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - alias: "Set sun elevation colour temperature for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_sun_elevation_colour_lux_brightness_inv' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Wait for sun elevation to change" + wait_for_trigger: + - trigger: state + entity_id: sun.sun + attribute: elevation + - choose: + - alias: "10 - Dynamic Lighting - Time Controlled - Colour Temp" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_colour' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_kelvin: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (start_time_morning - end_time_morning) %} + {% set start_ak = (start_slope * (-end_time_morning)) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (end_time_evening - start_time_evening) %} + {% set end_ak = (end_slope * (-end_time_evening)) + dynamic_lighting_min_colour_temp %} + {% if current_time >= start_time_morning and current_time <= end_time_morning %} + {% set colour_temp_value = (start_slope * current_time + start_ak) | round(1) %} + {% elif current_time >= start_time_evening and current_time <= end_time_evening %} + {% set colour_temp_value = (end_slope * current_time + end_ak) | round(1) %} + {% elif current_time > end_time_morning and current_time < start_time_evening %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif current_time < start_time_morning %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif current_time > end_time_evening %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if 'use_brightness' in include_light_control %} + {% set light.data = dict(light.data, **{ 'brightness_pct': light_brightness }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set lights_on = expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% set in_morning = start_time_morning <= current_time <= end_time_morning %} + {% set in_evening = start_time_evening <= current_time <= end_time_evening %} + {{ lights_on and not (in_morning or in_evening) }} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If time is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - choose: + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_morning + before: !input dynamic_lighting_time_start_evening + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_evening + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_evening + before: !input dynamic_lighting_time_start_morning + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_morning + - alias: "Set the dynamic lighting brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_colour' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - choose: + - alias: "11 - Dynamic Lighting - Time Controlled - Brightness" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_brightness' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_brightness_pct: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set start_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (start_time_morning - end_time_morning) %} + {% set start_ak = (start_slope * (-end_time_morning)) + dynamic_lighting_max_brightness %} + {% set end_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (end_time_evening - start_time_evening) %} + {% set end_ak = (end_slope * (-end_time_evening)) + dynamic_lighting_min_brightness %} + {% if current_time >= start_time_morning and current_time <= end_time_morning %} + {% set brightness_value = (start_slope * current_time + start_ak) | round(1) %} + {% elif current_time >= start_time_evening and current_time <= end_time_evening %} + {% set brightness_value = (end_slope * current_time + end_ak) | round(1) %} + {% elif current_time > end_time_morning and current_time < start_time_evening %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif current_time < start_time_morning %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif current_time > end_time_evening %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set lights_on = expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% set in_morning = start_time_morning <= current_time <= end_time_morning %} + {% set in_evening = start_time_evening <= current_time <= end_time_evening %} + {{ lights_on and not (in_morning or in_evening) }} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If time is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - choose: + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_morning + before: !input dynamic_lighting_time_start_evening + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_evening + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_evening + before: !input dynamic_lighting_time_start_morning + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_morning + - alias: "Set the dynamic lighting brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - choose: + - alias: "12 - Dynamic Lighting - Time Controlled - Brightness Inverted" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_brightness_inv' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_brightness_pct: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set start_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (start_time_morning - end_time_morning) %} + {% set start_ak = (start_slope * (-end_time_morning)) + dynamic_lighting_min_brightness %} + {% set end_slope = (dynamic_lighting_max_brightness - dynamic_lighting_min_brightness) / (end_time_evening - start_time_evening) %} + {% set end_ak = (end_slope * (-end_time_evening)) + dynamic_lighting_max_brightness %} + {% if current_time >= start_time_morning and current_time <= end_time_morning %} + {% set brightness_value = (start_slope * current_time + start_ak) | round(1) %} + {% elif current_time >= start_time_evening and current_time <= end_time_evening %} + {% set brightness_value = (end_slope * current_time + end_ak) | round(1) %} + {% elif current_time > end_time_morning and current_time < start_time_evening %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif current_time < start_time_morning %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif current_time > end_time_evening %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {% if include_light_colour_control == 'use_colour_temperature' %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': light_colour_temperature }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgb_colour' %} + {% set light.data = dict(light.data, **{ 'rgb_color': light_rgb_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbw_colour' %} + {% set light.data = dict(light.data, **{ 'rgbw_color': light_rgbw_colour }) %} + {% endif %} + {% if include_light_colour_control == 'use_rgbww_colour' %} + {% set light.data = dict(light.data, **{ 'rgbww_color': light_rgbww_colour }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set lights_on = expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% set in_morning = start_time_morning <= current_time <= end_time_morning %} + {% set in_evening = start_time_evening <= current_time <= end_time_evening %} + {{ lights_on and not (in_morning or in_evening) }} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If time is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - choose: + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_morning + before: !input dynamic_lighting_time_start_evening + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_evening + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_evening + before: !input dynamic_lighting_time_start_morning + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_morning + - alias: "Set the dynamic lighting brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_brightness_inv' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - choose: + - alias: "13 - Dynamic Lighting - Time Controlled - Colour Temp & Brightness" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_colour_brightness' }}" + sequence: + - alias: "Dynamic Lighting Control" + repeat: + until: "{{ ((dynamic_lighting_boolean == []) and (expand(light_entities) | selectattr('state', '==', 'off') | list | count > 0)) or ((dynamic_lighting_boolean != []) and (is_state(dynamic_lighting_boolean, 'off'))) }}" + sequence: + - variables: + dynamic_brightness_pct: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set start_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (start_time_morning - end_time_morning) %} + {% set start_ak = (start_slope * (-end_time_morning)) + dynamic_lighting_max_brightness %} + {% set end_slope = (dynamic_lighting_min_brightness - dynamic_lighting_max_brightness) / (end_time_evening - start_time_evening) %} + {% set end_ak = (end_slope * (-end_time_evening)) + dynamic_lighting_min_brightness %} + {% if current_time >= start_time_morning and current_time <= end_time_morning %} + {% set brightness_value = (start_slope * current_time + start_ak) | round(1) %} + {% elif current_time >= start_time_evening and current_time <= end_time_evening %} + {% set brightness_value = (end_slope * current_time + end_ak) | round(1) %} + {% elif current_time > end_time_morning and current_time < start_time_evening %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% elif current_time < start_time_morning %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% elif current_time > end_time_evening %} + {% set brightness_value = dynamic_lighting_min_brightness %} + {% else %} + {% set brightness_value = dynamic_lighting_max_brightness %} + {% endif %} + {{ brightness_value | round(0) }} + dynamic_kelvin: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set start_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (start_time_morning - end_time_morning) %} + {% set start_ak = (start_slope * (-end_time_morning)) + dynamic_lighting_max_colour_temp %} + {% set end_slope = (dynamic_lighting_min_colour_temp - dynamic_lighting_max_colour_temp) / (end_time_evening - start_time_evening) %} + {% set end_ak = (end_slope * (-end_time_evening)) + dynamic_lighting_min_colour_temp %} + {% if current_time >= start_time_morning and current_time <= end_time_morning %} + {% set colour_temp_value = (start_slope * current_time + start_ak) | round(1) %} + {% elif current_time >= start_time_evening and current_time <= end_time_evening %} + {% set colour_temp_value = (end_slope * current_time + end_ak) | round(1) %} + {% elif current_time > end_time_morning and current_time < start_time_evening %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% elif current_time < start_time_morning %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% elif current_time > end_time_evening %} + {% set colour_temp_value = dynamic_lighting_min_colour_temp %} + {% else %} + {% set colour_temp_value = dynamic_lighting_max_colour_temp %} + {% endif %} + {{ colour_temp_value | round(0) }} + dynamic_light_data: > + {% set light = namespace(data={}) %} + {% set light.data = dict(light.data, **{ 'color_temp_kelvin': dynamic_kelvin }) %} + {% set light.data = dict(light.data, **{ 'brightness_pct': dynamic_brightness_pct }) %} + {% if 'use_transition' in include_light_control %} + {% set light.data = dict(light.data, **{ 'transition': light_transition_on }) %} + {% endif %} + {{ light.data }} + should_wait: > + {% set current_time = now().hour + (now().minute / 60) %} + {% set start_time_morning = dynamic_lighting_time_start_morning.split(':')[0] | int + (dynamic_lighting_time_start_morning.split(':')[1] | int / 60) %} + {% set end_time_morning = dynamic_lighting_time_end_morning.split(':')[0] | int + (dynamic_lighting_time_end_morning.split(':')[1] | int / 60) %} + {% set start_time_evening = dynamic_lighting_time_start_evening.split(':')[0] | int + (dynamic_lighting_time_start_evening.split(':')[1] | int / 60) %} + {% set end_time_evening = dynamic_lighting_time_end_evening.split(':')[0] | int + (dynamic_lighting_time_end_evening.split(':')[1] | int / 60) %} + {% if end_time_morning < start_time_morning %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_morning = end_time_morning + 24 %} + {% set start_time_evening = start_time_evening + 24 %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% if end_time_evening < start_time_evening %} + {% if current_time < end_time_evening %} + {% set current_time = current_time + 24 %} + {% endif %} + {% set end_time_evening = end_time_evening + 24 %} + {% endif %} + {% set lights_on = expand(light_entities) | selectattr('state', '==', 'on') | list | count > 0 %} + {% set in_morning = start_time_morning <= current_time <= end_time_morning %} + {% set in_evening = start_time_evening <= current_time <= end_time_evening %} + {{ lights_on and not (in_morning or in_evening) }} + - choose: + - alias: "Stop when crossing over" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' not in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - stop: "Stop the automation" + - alias: "Adjust the lights settings when crossing over if lights are ON is selected in night light control" + conditions: + - condition: template + value_template: "{{ 'if_lights_are_on_adjust_when_crossing_over' in include_night_light_control }}" + - condition: trigger + id: + - 't13' + - 't14' + - 't15' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "Adjust the light settings when all bypasses are off or state control is enabled, and the entity is turned ON" + conditions: + - condition: trigger + id: + - 't16' + - 't9_on' + - 't9_off' + - 't9_stop' + - condition: template + value_template: "{{ repeat.index == 1 }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - alias: "If time is outside the adjustment zone and the lights are ON" + conditions: "{{ should_wait }}" + sequence: + - choose: + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_morning + before: !input dynamic_lighting_time_start_evening + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_evening + - conditions: + - condition: time + after: !input dynamic_lighting_time_end_evening + before: !input dynamic_lighting_time_start_morning + sequence: + - wait_for_trigger: + - trigger: time + at: !input dynamic_lighting_time_start_morning + - alias: "Set the dynamic lighting brightness for the normal lights" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'enable_time_controled_colour_brightness' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ dynamic_light_data }}" + - alias: "Dynamic lighting heartbeat" + delay: + minutes: !input dynamic_lighting_heartbeat + - stop: "Stop the automation" + - sequence: + - choose: + - alias: "Turn ON lights" + conditions: + - alias: "Check the dynamic lighting options" + condition: or + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting == 'disable_dynamic_lighting' }}" + - alias: "Check that dynamic lighting is active and the state control option is enabled" + condition: and + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: "{{ dynamic_lighting_state_control == 'enable_state_control' }}" + - condition: template + value_template: "{{ states(dynamic_lighting_state_control_entity) == dynamic_lighting_state_control_activation_state_inv }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities_off }}" + data: "{{ light_data }}" + - choose: + - alias: "Dynamic Lighting State Control Turning OFF" + conditions: + - condition: trigger + id: 't17' + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + sequence: + - action: light.turn_on + target: + entity_id: "{{ light_entities }}" + data: "{{ light_data }}" + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn on the scenes" + action: scene.turn_on + target: + entity_id: "{{ scene_entities }}" + data: + transition: "{{ light_transition_on }}" + - alias: "Turn on the boolean for scenes and scripts" + action: input_boolean.turn_on + data: + entity_id: "{{ boolean_scenes_scripts_helper }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn on the scenes" + action: scene.turn_on + target: + entity_id: "{{ scene_entities }}" + - alias: "Turn on the boolean for scenes and scripts" + action: input_boolean.turn_on + data: + entity_id: "{{ boolean_scenes_scripts_helper }}" + - alias: "Turn on the switches" + action: switch.turn_on + target: + entity_id: "{{ switch_entities_off }}" + - alias: "Turn on the scripts" + action: script.turn_on + target: + entity_id: "{{ script_entities }}" + - choose: + - alias: "By-pass is enabled & check by-pass option - Turn lights on" + conditions: + - condition: trigger + id: 't8_on' + sequence: + - alias: "Check by-pass settings and preform the correct action" + if: + - alias: "Check if the by-pass auto off is enabled" + condition: template + value_template: "{{ ('bypass_auto_off_enabled_on' in include_bypass_auto_off) or ('bypass_auto_off_enabled_off' in include_bypass_auto_off) or ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + then: + - alias: "Wait the number of minutes set in the by-pass auto off time delay" + delay: + minutes: !input bypass_auto_off_delay + - alias: "Parallel Actions for the by-pass auto off" + parallel: + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_on' in include_bypass) and ('bypass_auto_off_enabled_on' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_on + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_turn_off' in include_bypass) and ('bypass_auto_off_enabled_off' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_off + - sequence: + - choose: + - conditions: + - condition: template + value_template: "{{ ('bypass_enabled_stop' in include_bypass) and ('bypass_auto_off_enabled_stop' in include_bypass_auto_off) }}" + sequence: + - alias: "Turn off the by-pass" + action: homeassistant.turn_off + entity_id: !input bypass_lights_stop + - stop: "Stop the automation" + else: + - stop: "Stop the automation" + - conditions: + - condition: trigger + id: + - 't1' + - 't3' + - 't5' + - 't7' + - 't19' + sequence: + - choose: + - alias: "Dynamic Lighting - Check if Input Boolean Helper is ON" + conditions: + - condition: template + value_template: "{{ include_dynamic_lighting != 'disable_dynamic_lighting' }}" + - condition: template + value_template: >- + {% if dynamic_lighting_boolean != [] %} + {{ is_state(dynamic_lighting_boolean, 'on') }} + {% endif %} + sequence: + - alias: "Turn off the boolean for dynamic lighting" + action: input_boolean.turn_off + data: + entity_id: !input dynamic_lighting_boolean + - choose: + - alias: "If transition is selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + data: + transition: "{{ light_transition_off }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + transition: "{{ light_transition_off }}" + - alias: "If transition is not selected" + conditions: + - condition: template + value_template: "{{ 'use_transition' not in include_light_control }}" + sequence: + - alias: "Turn off the lights" + action: light.turn_off + target: + entity_id: "{{ light_entities }}" + - alias: "Turn off the scenes" + action: scene.turn_on + data: + entity_id: "{{ end_scene_entities }}" + - alias: "Turn off the switches" + action: switch.turn_off + target: + entity_id: "{{ switch_entities }}" + - alias: "Turn off the script" + action: script.turn_on + data: + entity_id: "{{ end_script_entities }}" + - alias: "Turn off the boolean for scenes and scripts" + action: input_boolean.turn_off + data: + entity_id: !input boolean_scenes_scripts \ No newline at end of file diff --git a/test.yaml b/test.yaml new file mode 100644 index 0000000..4bb9ab4 --- /dev/null +++ b/test.yaml @@ -0,0 +1,75 @@ +blueprint: + name: Sonoff TRVZB + External Temp AUTO + description: Auto sync external temperature for all Sonoff TRVZB devices + domain: automation + +trigger: + + - platform: time_pattern + minutes: "/2" + + - platform: homeassistant + event: start + + +variables: + + sensors: > + {{ states.sensor + | map(attribute='entity_id') + | select('match','sensor\\..*_temperature.*') + | list }} + + +action: + + - repeat: + + for_each: "{{ sensors }}" + + sequence: + + - variables: + + sensor_entity: "{{ repeat.item }}" + + prefix: > + {{ sensor_entity.split('.')[1] + | regex_replace('_temperature.*','') }} + + number_entity: "number.{{ prefix }}_temperature_input" + + select_entity: "select.{{ prefix }}_temperature_sensor_select" + + + # sprawdź czy encje istnieją + - condition: template + value_template: > + {{ number_entity in states + and select_entity in states + and states(sensor_entity) not in ['unknown','unavailable'] }} + + + # ustaw external tylko gdy potrzeba + - if: + - condition: template + value_template: "{{ states(select_entity) != 'external' }}" + then: + - service: select.select_option + target: + entity_id: "{{ select_entity }}" + data: + option: external + + + - delay: "00:00:05" + + + - service: number.set_value + target: + entity_id: "{{ number_entity }}" + data: + value: "{{ states(sensor_entity) | float }}" + + +mode: single