Last active
February 2, 2024 14:56
-
-
Save jmerifjKriwe/bffbc7424dd04f4a31d6a71f7012cd1f to your computer and use it in GitHub Desktop.
automatic_blinds_shading.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
blueprint: | |
name: "New Shading - automatic driving for sun protection" | |
description: >- | |
**Version: 2024020202** <br /> | |
This is an largely complete automation for roller shutters. | |
Two major areas are covered: a) daily raising and lowering, b) shading against too much sunlight. | |
For more information open: | |
<details> | |
In order to have extensive flexibility here, different sensors are used. But there is also the possibility to define an occupant of the room, so that e.g. the roller shutter does not go up in the morning, although the occupant is still sleeping.<br /> | |
As a bonus, there is also an overwrite option for closing (aka Christmas mode). This can be used to prevent a roller shutter from going down during the Christmas season - for example, because you want to display the illuminated Christmas decorations for longer.<br /> | |
**NOTE** - if multiple criteria (e.g. temperature sensors and/or azimuth and/or elevation) are defined, shading will not occur until ALL criteria are met.<br /> | |
**NOTE** - it's NOT possible to execute this automation manually! | |
**NOTE** - if you want to use sun elevation and/or azimuth it's strongly advised to use sun.sun - and make sure your sun.sun entity is enabled! | |
</details> | |
Credits to <br /> | |
- Herr.Vorragend and NickNol for ideas and additional features (code)<br /> | |
- Gifford47 for idea to handle cover groups as well<br /> | |
- kreuzundkwer for implementation of tilt position for shading<br /> | |
**The automation only moves the roller shutter if it is positioned at one of the defined positions (ventilate position, shading position, open position or closed position). Otherwise, the roller shutter has been moved manually. After a manual movement, it is unclear what is intended to be achieved, so the automation no longer takes action. To automate the movement of the roller shutter again, it must be moved to one of the defined positions beforehand. | |
Dont forget that a lot of options are `Optional` | |
source_url: https://gist.github.com/jmerifjKriwe/bffbc7424dd04f4a31d6a71f7012cd1f#file-automatic_blinds_shading-yaml | |
domain: automation | |
homeassistant: | |
min_version: '2023.12.0' | |
input: | |
# inputs we need for everything | |
blind: | |
name: "Blind" | |
description: "Which roller shutter should be automated?" | |
selector: | |
entity: | |
filter: | |
- domain: | |
- cover | |
# inputs only for shading | |
auto_shading: | |
name: "🕶️ Auto Shading" | |
description: "Enable the auto shading function?\n\n`Shading`" | |
default: true | |
selector: | |
boolean: {} | |
shading_blinds_position: | |
name: "🕶️ Shading position" | |
description: "To which position should the shutter be moved for shading?\n\n`Shading`" | |
default: 25 | |
selector: | |
number: | |
min: 0.0 | |
max: 100.0 | |
unit_of_measurement: "%" | |
shading_tilt_position: | |
name: "🕶️Shading tilt position" | |
description: "To which tilt position should the cover be moved for shading?\n\n`Shading`" | |
default: 50 | |
selector: | |
number: | |
min: 0 | |
max: 100 | |
unit_of_measurement: "%" | |
shading_sun_sensor: | |
name: "🕶️ Shading sun sensor" | |
description: "which sensors provides attributes with current azimuth and elevation of sun. I strongly suggest to use sun.sun\n\n`Shading`" | |
default: "sun.sun" | |
selector: | |
entity: | |
filter: | |
- domain: | |
- sun | |
shading_azimuth_in: | |
name: "🕶️ Shading azimuth in" | |
description: "What is the minimum azimuth at which the sun hits the window? (Shading will start)\nAzimuth attribute of Shading sun sensor is used.\n\n`Shading`" | |
default: 95 | |
selector: | |
number: | |
min: 0 | |
max: 365 | |
unit_of_measurement: "°" | |
shading_azimuth_out: | |
name: "🕶️ Shading azimuth out" | |
description: "What is the maximum azimuth at which the sun hits the window? (Shading will stop)\nAzimuth attribute of Shading sun sensor is used.\n\n`Shading`" | |
default: 265 | |
selector: | |
number: | |
min: 0 | |
max: 365 | |
unit_of_measurement: "°" | |
shading_elevation_min: | |
name: "🕶️ Shading elevation min" | |
description: "Starting from which elevation of the sun should the window be shaded? (Here it makes sense to consider surrounding buildings, trees, etc.).\nElevation attribute of Shading sun sensor is used.\n\n`Shading`" | |
default: 25 | |
selector: | |
number: | |
min: 0.0 | |
max: 90.0 | |
unit_of_measurement: "°" | |
shading_elevation_max: | |
name: "🕶️ Shading elevation max" | |
description: "What is the maximal elevation for elevation? (In most cases, 90 degrees is probably the most reasonable value. However, this can also be different due to surrounding buildings, etc.)\nElevation attribute of Shading sun sensor is used.\n\n`Shading`" | |
default: 90 | |
selector: | |
number: | |
min: 0.0 | |
max: 90.0 | |
unit_of_measurement: "°" | |
shading_outdoor_temperatur_sensor: | |
name: "🕶️ Shading temperature sensor1" | |
description: "This is the main temperature sensor. (Here, for example, the current outdoor or indoor temperature can be used as a criterion).\nThis sensor does not have to be defined if the shading is to take place independently of it. \n\n`Optional`\n\n`Shading`" | |
selector: | |
entity: | |
filter: | |
- domain: | |
- sensor | |
default: [] | |
shading_min_temperatur: | |
name: "🕶️ Shading temperature sensor1 min" | |
description: "Minimum temperature for sensor 1 above which shading should occur. \n\n`Optional`\n\n`Shading`" | |
default: 18 | |
selector: | |
number: | |
min: 0.0 | |
max: 50.0 | |
unit_of_measurement: "°C" | |
shading_outdoor_temperatur_sensor2: | |
name: "🕶️ Shading temperature sensor2" | |
description: "This is a secondary temperature sensor. (Here, for example, a temperature difference sensor can be used as a criterion. Or, if Sensor1 is outdoor temperature, you can use indoor temperature).\nThis sensor does not have to be defined. \n\n`Optional`\n\n`Shading`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- sensor | |
shading_min_temperatur2: | |
name: "🕶️ Shading temperature sensor2 min" | |
description: "Minimum temperature for sensor 1 above which shading should occur. \n\n`Optional`\n\n`Shading`" | |
default: 18 | |
selector: | |
number: | |
min: 0.0 | |
max: 50.0 | |
unit_of_measurement: "°C" | |
brightness_sensor: | |
name: "🕶️ Brightness sensor for shading" | |
description: "If a brightness sensor is to be used for shading, it can be defined here. \n\n`Optional`\n\n`Shading`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- sensor | |
shading_sun_brightness_in: | |
name: "🕶️ Shading brightness in" | |
description: "The minimum brightness value from which shading should start. (Must be above the value of brightness out!) \n\n`Optional`\n\n`Shading`" | |
default: 35000 | |
selector: | |
number: | |
min: 0.0 | |
max: 100000.0 | |
unit_of_measurement: lx | |
step: 10.0 | |
shading_sun_brightness_out: | |
name: "🕶️ Shading brightness out" | |
description: "The brightness value from which shading is no longer necessary. (Must be BELOW the value of brightness in!). \n\n`Optional`\n\n`Shading`" | |
default: 25000 | |
selector: | |
number: | |
min: 0.0 | |
max: 100000.0 | |
unit_of_measurement: lx | |
step: 10.0 | |
forecast_sensor: | |
name: "🕶️ Forecast temperatur" | |
description: "Another temperature sensor. In this case, however, explicitly for use with a forecast.\nThe idea is that it can happen, especially in spring, that the value for the temperature sensor1 is exceeded by strong solar radiation and the shading would be started. However, in spring you may not want shading, but the solar radiation as a welcome, free heating is desired.\nSo you can define via the forecast sensor that shading is only started at an expected daily maximum temperature.\n**NOTE** - sensor must support weather.get_forecasts which has been introduced with HA 2023.9 \n\n`Optional`\n\n`Shading`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- weather | |
forecast_temp: | |
name: "🕶️ Forecast temperatur" | |
description: "Minimum temperature for forecast sensor above which shading should occur.\n**NOTE** - if temperature sensor1 is also defined and its temperature rises above the value defined here, this condition is considered to be TRUE. \n\n`Optional`\n\n`Shading`" | |
default: 20 | |
selector: | |
number: | |
min: 0.0 | |
max: 50.0 | |
unit_of_measurement: "°C" | |
weather_conditions: | |
name: "🕶️ Weather conditions" | |
description: "Check the following weather conditions when activating the shading.\n**NOTE** - Forecast sensor needs to be defined \n\n`Optional`\n\n`Shading`" | |
default: | |
- sunny | |
- partlycloudy | |
- cloudy | |
- clear | |
selector: | |
select: | |
multiple: true | |
options: | |
- "clear-night" | |
- "clear" | |
- "cloudy" | |
- "fog" | |
- "hail" | |
- "lightning" | |
- "lightning-rainy" | |
- "partlycloudy" | |
- "pouring" | |
- "rainy" | |
- "snowy" | |
- "snowy-rainy" | |
- "sunny" | |
- "windy" | |
- "windy-variant" | |
- "exceptional" | |
shading_waitingtime: | |
name: "🕶️ Shading waiting time for shading IN (in seconds)" | |
description: "To prevent excessive stress on the motor, a waiting time for starting shading can be defined here. Shading then only STARTs when the conditions are fulfilled over the entire waiting time IN.\n\n`Shading`" | |
default: 300 | |
selector: | |
number: | |
min: 0 | |
max: 3600 | |
unit_of_measurement: s | |
shading_waitingtime_out: | |
name: "🕶️ Shading waiting time for shading OUT (in seconds)" | |
description: "To prevent excessive stress on the motor, a waiting time can be defined here. Shading then ENDs when ONE of the conditions is NOT fulfilled over the entire waiting time OUT.\n\n`Shading`" | |
default: 900 | |
selector: | |
number: | |
min: 0 | |
max: 3600 | |
unit_of_measurement: s | |
temporary_disable_shading: | |
name: "🕶️ Temporary de-activation of shading" | |
description: "Sensor (input_boolean or binary_sensor) can be defined to temporarily disable(TRUE/ON) shading. This can be useful if you want to temporarily disable automation (e.g. because of control by other automations). \n\n`Optional`\n\n`Shading`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- input_boolean | |
- binary_sensor | |
# inputs for opening and closing in the morning and evening | |
auto_up: | |
name: "🌅 Auto Up" | |
description: "Enable automation for driving blind up?" | |
default: true | |
selector: | |
boolean: {} | |
auto_down: | |
name: "🌆 Auto Down" | |
description: "Enable automation for driving blind down?" | |
default: true | |
selector: | |
boolean: {} | |
open_position: | |
name: "🌅 Open Position" | |
description: "To which position should the shutter be moved to be open?" | |
default: 100 | |
selector: | |
number: | |
min: 0.0 | |
max: 100.0 | |
unit_of_measurement: "%" | |
closed_position: | |
name: "🌆 Closed Position" | |
description: "To which position should the shutter be moved to be closed?" | |
default: 0 | |
selector: | |
number: | |
min: 0.0 | |
max: 100.0 | |
unit_of_measurement: "%" | |
position_tolerance: | |
name: "Position Tolerance" | |
description: "Tolerance to be applied when comparing the current position with the to be position" | |
default: 0 | |
selector: | |
number: | |
min: 0.0 | |
max: 3.0 | |
unit_of_measurement: "%" | |
window_sensor: | |
name: "Window or door sensor" | |
description: "This can be used to define whether the roller shutter belongs to a window or an (outer) door with a window opening sensor. If this is the case, a Ventilate function can be used. This means that the Ventilate position is approached when the window is opened/tilted.\nThis sensor can be defined here. \n\n`Optional`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- binary_sensor | |
auto_ventilate: | |
name: "Auto Ventilate" | |
description: "Enable automation for ventilation?" | |
default: true | |
selector: | |
boolean: {} | |
ventilate_position: | |
name: "Ventilate position" | |
description: "What position should the shutter move to when opening the window/door and the shutter is closed to allow ventilation? If closing is triggered and the window_sensor is 'on' the shutter will move to this position instead of closing completly\n\nShould not be 100. In this case please use 99 \n\n`Optional`" | |
default: 30 | |
selector: | |
number: | |
min: 0.0 | |
max: 100.0 | |
unit_of_measurement: "%" | |
door: | |
name: "Door or window" | |
description: "Does the shutter belong to a window (FALSE) or a door (TRUE)? In the case of a door, an attempt is made to prevent the shutter from being lowered when the door is open in order to prevent it from being locked out. (without guarantee!) \n\n`Optional`" | |
default: "false" | |
selector: | |
select: | |
options: | |
- label: Window | |
value: "false" | |
- label: Door | |
value: "true" | |
brightness_sensor2: | |
name: "Brightness sensor for Up and Down" | |
description: "An additional brightness sensor can be defined here, which is only used for daily up and down. (Leave free if the same as for shading is to be used). \n\n`Optional`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- sensor | |
brightness_up: | |
name: "🌅 Brightness up" | |
description: "The brightness value from which the shutter should be opened. \n\n`Optional`" | |
default: 70 | |
selector: | |
number: | |
min: 0 | |
max: 1000 | |
unit_of_measurement: lx | |
step: 10.0 | |
brightness_down: | |
name: "🌆 Brightness down" | |
description: "The brightness value from which the shutter should be closed. (Sollte unter dem Wert zum Öffnen liegen.) \n\n`Optional`" | |
default: 10 | |
selector: | |
number: | |
min: 0 | |
max: 1000 | |
unit_of_measurement: lx | |
step: 10.0 | |
workday_sensor: | |
name: "Sensor for workday/non-workday" | |
description: "It may be desired to open a shutter at a different time on work days than on non-work days. The corresponding binary sensor can be defined here. If not set, shutter will open every time at time_up_early. \n\n`Optional`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- binary_sensor | |
time_up_early: | |
name: "🌅 Time for drive up - early" | |
description: "The earliest time at which roller shutters may be opened. The shutter will be opened if AFTER this time the defined brightness value is high enough.\n**NOTE** - if an occupant is defined, he must also be awake." | |
default: '06:00:00' | |
selector: | |
time: {} | |
time_up_early_non_workday: | |
name: "🌅 Time for drive up - early on non-workdays" | |
description: "As directly above, but for non-workdays." | |
default: '07:00:00' | |
selector: | |
time: {} | |
time_up_late: | |
name: "🌅 Time for drive up - late" | |
description: "The latest time at which the shutter should be opened. If the required brightness value has NOT yet been reached by this time, the shutter will still be opened.\n**NOTE** - if an occupant is defined and he is still asleep, the shutter will NOT be opened. It will only be opened when the occupant has woken up." | |
default: '08:00:00' | |
selector: | |
time: {} | |
time_down_early: | |
name: "🌆 Time for drive down - early" | |
description: "The earliest time at which roller shutters may be closed. The shutter will be closed if AFTER this time the defined brightness value is low enough." | |
default: '16:30:00' | |
selector: | |
time: {} | |
time_down_late: | |
name: "🌆 Time for drive down - late" | |
description: "The latest time at which the shutter should be closed. If the required brightness value has NOT yet been reached by this time, the shutter will still be closed." | |
default: '22:00:00' | |
selector: | |
time: {} | |
resident: | |
name: "🌅 Overwrite mode for opening and for unplannend closing (aka Resident mode)" | |
description: "This switch can be used to override the automatic opening of the shutter. If this sensor (input_boolean or binary_sensor) is set to ON, the shutter will not open automatically.\nThis can be used e.g. to define a resident for the room. In this case, the roller shutter only opens when the occupant is no longer asleep.\nFor this it is necessary to use a Boolean sensor that returns TRUE/ON for sleeping and FALSE for non-sleeping. | |
\nThe blind will also close (without checking the defined times) if this sensor switches to TRUE/ON (because the resident is sleeping). \n\n`Optional`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- input_boolean | |
- binary_sensor | |
adv_blind: | |
name: "🌆 Overwrite mode for closing (aka Christmas mode)" | |
description: "This switch can be used to override the automatic closing of the shutter. If this Sensor (input_boolean or binary_sensor) is set to TRUE/ON, the shutter will not close automatically.\nThis can be used e.g. for the Christmas time. But it can also be used e.g. to not close a shutter if it has been too hot during the day and therefore the cooler air should circulate at night.\n**NOTE** - the shutter will not be closed afterwards. There is no function (yet) that does this at a defined later time. If desired, the later closing must be done outside of this blueprint. \n\n`Optional`" | |
default: [] | |
selector: | |
entity: | |
filter: | |
- domain: | |
- input_boolean | |
- binary_sensor | |
check_config: | |
name: "Check configuration" | |
description: "With this boolean, you can enable or disable the basic plausibility check for the configuration." | |
default: false | |
selector: | |
boolean: {} | |
check_config_debuglevel: | |
name: "Check configuration - Debug level" | |
description: "Choose the debug level for Syslog messages in case of configuration issues\nPlease make sure that it suits your Home Assistant logger default level." | |
default: "info" | |
selector: | |
select: | |
multiple: false | |
options: | |
- "critical" | |
- "debug" | |
- "error" | |
- "info" | |
- "warning" | |
mode: restart | |
max_exceeded: silent | |
variables: | |
blind: !input blind | |
blind_entities: "{{ expand(blind) | map(attribute='entity_id') | list }}" | |
brightness_sensor: !input brightness_sensor | |
shading_sun_sensor: !input shading_sun_sensor | |
shading_outdoor_temperatur_sensor: !input shading_outdoor_temperatur_sensor | |
shading_outdoor_temperatur_sensor2: !input shading_outdoor_temperatur_sensor2 | |
shading_azimuth_in: !input shading_azimuth_in | |
shading_azimuth_out: !input shading_azimuth_out | |
shading_elevation_min: !input shading_elevation_min | |
shading_elevation_max: !input shading_elevation_max | |
shading_min_temperatur: !input shading_min_temperatur | |
shading_min_temperatur2: !input shading_min_temperatur2 | |
shading_blinds_position: !input shading_blinds_position | |
shading_tilt_position: !input shading_tilt_position | |
shading_sun_brightness_in: !input shading_sun_brightness_in | |
shading_sun_brightness_out: !input shading_sun_brightness_out | |
shading_waitingtime: !input shading_waitingtime | |
shading_waitingtime_out: !input shading_waitingtime_out | |
auto_shading: !input auto_shading | |
forecast_sensor: !input forecast_sensor | |
forecast_temp: !input forecast_temp | |
weather_conditions: !input weather_conditions | |
temporary_disable_shading: !input temporary_disable_shading | |
door: !input door | |
resident: !input resident | |
window_sensor: !input window_sensor | |
brightness_sensor2: !input brightness_sensor2 | |
brightness_up: !input brightness_up | |
brightness_down: !input brightness_down | |
open_position: !input open_position | |
closed_position: !input closed_position | |
position_tolerance: !input position_tolerance | |
ventilate_position: !input ventilate_position | |
adv_blind: !input adv_blind | |
auto_up: !input auto_up | |
auto_down: !input auto_down | |
auto_ventilate: !input auto_ventilate | |
time_up_early: !input time_up_early | |
time_up_late: !input time_up_late | |
time_up_early_non_workday: !input time_up_early_non_workday | |
time_down_early: !input time_down_early | |
time_down_late: !input time_down_late | |
workday_sensor: !input workday_sensor | |
check_config: !input check_config | |
check_config_debuglevel: !input check_config_debuglevel | |
trigger: | |
# triggers for shading in | |
- platform: numeric_state | |
entity_id: !input shading_outdoor_temperatur_sensor | |
above: !input shading_min_temperatur | |
id: "t_si_1" | |
- platform: numeric_state | |
entity_id: !input shading_outdoor_temperatur_sensor2 | |
above: !input shading_min_temperatur2 | |
id: "t_si_2" | |
- platform: numeric_state | |
entity_id: !input brightness_sensor | |
above: !input shading_sun_brightness_in | |
id: "t_si_3" | |
- platform: numeric_state | |
entity_id: !input shading_sun_sensor | |
attribute: elevation | |
above: !input shading_elevation_min | |
id: "t_si_4" | |
- platform: numeric_state | |
entity_id: !input shading_sun_sensor | |
attribute: azimuth | |
above: !input shading_azimuth_in | |
below: !input shading_azimuth_out | |
id: "t_si_5" | |
- platform: numeric_state | |
entity_id: !input shading_outdoor_temperatur_sensor | |
above: !input forecast_temp | |
id: "t_si_6" | |
- platform: state | |
entity_id: !input temporary_disable_shading | |
from: "on" | |
to: "off" | |
for: "00:00:05" # we need a small delay cause temporary_disable_shading also triggers shading out | |
id: "t_si_7" | |
# triggers for shading out | |
- platform: numeric_state | |
entity_id: !input shading_outdoor_temperatur_sensor | |
below: !input shading_min_temperatur | |
id: "t_so_1" | |
- platform: numeric_state | |
entity_id: !input shading_outdoor_temperatur_sensor2 | |
below: !input shading_min_temperatur2 | |
id: "t_so_2" | |
- platform: numeric_state | |
entity_id: !input brightness_sensor | |
below: !input shading_sun_brightness_out | |
id: "t_so_3" | |
- platform: numeric_state | |
entity_id: !input shading_sun_sensor | |
attribute: elevation | |
above: !input shading_elevation_max | |
id: "t_so_4" | |
- platform: numeric_state | |
entity_id: !input shading_sun_sensor | |
attribute: azimuth | |
above: !input shading_azimuth_out | |
id: "t_so_5" | |
- platform: numeric_state | |
entity_id: !input shading_sun_sensor | |
attribute: elevation | |
below: !input shading_elevation_min | |
id: "t_so_6" | |
- platform: state | |
entity_id: !input temporary_disable_shading | |
from: "on" | |
to: "off" | |
for: "00:00:02" # we need a small delay cause temporary_disable_shading also triggers shading in | |
id: "t_so_7" | |
## it's a duplicate of t_si_7 but we need both as a kind of workaround as all other triggers for shading in/out could already have fired | |
# trigger for opening blind | |
- platform: numeric_state | |
entity_id: !input brightness_sensor2 | |
above: !input brightness_up | |
for: "00:00:03" | |
id: "t_bo_1" | |
- platform: time | |
at: !input time_up_late | |
id: "t_bo_2" | |
- platform: time | |
at: !input time_up_early | |
id: "t_bo_3" | |
- platform: time | |
at: !input time_up_early_non_workday | |
id: "t_bo_4" | |
- platform: state | |
entity_id: !input resident | |
from: "on" | |
to: "off" | |
id: "t_bo_5" | |
- platform: numeric_state | |
entity_id: !input brightness_sensor | |
above: !input brightness_up | |
for: "00:00:05" | |
id: "t_bo_6" | |
# trigger for closing blind | |
- platform: numeric_state | |
entity_id: !input brightness_sensor2 | |
below: !input brightness_down | |
id: "t_bc_1" | |
- platform: time | |
at: !input time_down_early | |
id: "t_bc_2" | |
- platform: time | |
at: !input time_down_late | |
id: "t_bc_3" | |
- platform: state | |
entity_id: !input window_sensor | |
from: "on" | |
to: "off" | |
id: "t_bc_4" | |
- platform: state | |
entity_id: !input resident | |
from: "off" | |
to: "on" | |
id: "t_bc_5" | |
- platform: numeric_state | |
entity_id: !input brightness_sensor | |
below: !input brightness_down | |
id: "t_bc_6" | |
# trigger for ventilate | |
- platform: state | |
entity_id: !input window_sensor | |
from: "off" | |
to: "on" | |
id: "t_bv_1" | |
condition: | |
- or: | |
- "{{ auto_shading }}" | |
- "{{ auto_up }}" | |
- "{{ auto_down }}" | |
action: | |
## we have to call a service for forecast due to HA changes | |
- if: | |
- "{{ (forecast_sensor != [] ) }}" | |
then: | |
- service: weather.get_forecasts | |
target: | |
entity_id: !input forecast_sensor | |
data: | |
type: daily | |
response_variable: forecast | |
- choose: | |
- alias: "Check and perform shading in or blinds up" | |
conditions: | |
- or: | |
- "{{ auto_shading }}" | |
- "{{ auto_up }}" | |
- or: | |
# Check if we have a trigger for shading in | |
- condition: trigger | |
id: "t_si_1" | |
- condition: trigger | |
id: "t_si_2" | |
- condition: trigger | |
id: "t_si_3" | |
- condition: trigger | |
id: "t_si_4" | |
- condition: trigger | |
id: "t_si_5" | |
- condition: trigger | |
id: "t_si_6" | |
- condition: trigger | |
id: "t_si_7" | |
# Check if we have a trigger for blinds up | |
- condition: trigger | |
id: "t_bo_1" | |
- condition: trigger | |
id: "t_bo_2" | |
- condition: trigger | |
id: "t_bo_3" | |
- condition: trigger | |
id: "t_bo_4" | |
- condition: trigger | |
id: "t_bo_5" | |
- condition: trigger | |
id: "t_bo_6" | |
sequence: | |
- choose: | |
- alias: "Checking for shading in" | |
conditions: | |
- and: # Check if we want to perform shading in | |
- "{{ auto_shading }}" | |
- "{{ ( (temporary_disable_shading == [] ) or (is_state(temporary_disable_shading, ['false', 'off'])) ) }}" | |
- "{{ now() >= today_at(time_up_early) }}" | |
- "{{ now() <= today_at(time_down_late) + timedelta(seconds = 5) }}" | |
- "{{ ( (shading_outdoor_temperatur_sensor == [] ) or (states(shading_outdoor_temperatur_sensor) | int(default=shading_min_temperatur) >= shading_min_temperatur) ) }}" | |
- "{{ ( (shading_outdoor_temperatur_sensor2 == [] ) or (states(shading_outdoor_temperatur_sensor2) | int(default=shading_min_temperatur2) >= shading_min_temperatur2) ) }}" | |
- "{{ ( (brightness_sensor == [] ) or (states(brightness_sensor) | int(default=shading_sun_brightness_in) >= shading_sun_brightness_in) ) }}" | |
- "{{ state_attr(shading_sun_sensor, 'azimuth') >= shading_azimuth_in and state_attr(shading_sun_sensor, 'azimuth') <= shading_azimuth_out }}" | |
- "{{ state_attr(shading_sun_sensor, 'elevation') >= shading_elevation_min and state_attr(shading_sun_sensor, 'elevation') <= shading_elevation_max }}" | |
- "{{ state_attr(blind, 'current_position') | int(default=101) > shading_blinds_position }}" | |
- "{{ ( (resident == [] ) or (is_state(resident, ['false', 'off'])) ) }}" | |
- or: | |
- "{{ ( forecast_sensor == [] ) and (shading_outdoor_temperatur_sensor == [] ) }}" | |
- "{{ ( forecast_sensor != [] ) and ( forecast.forecast[0].temperature | int(default=forecast_temp) >= forecast_temp ) }}" | |
- "{{ (shading_outdoor_temperatur_sensor != [] ) and (states(shading_outdoor_temperatur_sensor) | int(default=forecast_temp) >= forecast_temp) }}" | |
- "{{ ( forecast_sensor == [] ) or (states(forecast_sensor) in weather_conditions) }}" | |
sequence: | |
# we are ready for shading in | |
- if: # check if blind is higher than ventilate position. In this case we consider blind position like open and therefor we want to use the delay timer | |
- "{{ state_attr(blind, 'current_position') | int(default=101) > ventilate_position }}" | |
- not: | |
- condition: trigger | |
id: "t_si_7" | |
then: | |
- alias: "Wait the number of seconds set in shading_waitingtime" | |
delay: | |
seconds: !input shading_waitingtime | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
- alias: "Moving the blind to shading position" | |
service: cover.set_cover_position | |
data: | |
position: !input shading_blinds_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- if: | |
- "{{ state_attr(repeat.item, 'current_tilt_position') != 'None' }}" | |
then: | |
- alias: "Moving the blind to tilt position" | |
service: cover.set_cover_tilt_position | |
data: | |
tilt_position: !input shading_tilt_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- stop: "Stop the automation" | |
- alias: "Check for opening" | |
conditions: | |
- "{{ auto_up }}" | |
- or: # Check if the trigger is for normal blind opening | |
- condition: trigger | |
id: "t_bo_1" | |
- condition: trigger | |
id: "t_bo_2" | |
- condition: trigger | |
id: "t_bo_3" | |
- condition: trigger | |
id: "t_bo_4" | |
- condition: trigger | |
id: "t_bo_5" | |
- condition: trigger | |
id: "t_bo_6" | |
- or: | |
- "{{ state_attr(blind, 'current_position') | int(default=101) == ventilate_position }}" | |
- "{{ (state_attr(blind, 'current_position') | int(default=110) <= closed_position + position_tolerance) and (state_attr(blind, 'current_position') | int(default=110) >= closed_position - position_tolerance)}}" | |
- "{{ ( (resident == [] ) or (is_state(resident, ['false', 'off'])) ) }}" | |
# Now we have to check different opening scenarios | |
- or: | |
## "Blinds - opening - up late reached" | |
- and: | |
- "{{ now() >= today_at(time_up_late) }}" | |
- or: | |
- "{{ now() <= today_at(time_down_early) + timedelta(seconds = 5) }}" | |
- "{{ now() <= today_at(time_down_late) + timedelta(seconds = 5) }}" | |
## Blinds - opening - up early reached and brightness above minimum" | |
- and: | |
- or: | |
- and: | |
- "{{ (workday_sensor == [] or (is_state(workday_sensor, 'on')) ) }}" | |
- "{{ now() >= today_at(time_up_early) }}" | |
- and: | |
- "{{ (workday_sensor == [] ) or (is_state(workday_sensor, 'off')) }}" | |
- "{{ now() >= today_at(time_up_early_non_workday) }}" | |
- "{{ now() <= today_at(time_up_late) + timedelta(seconds = 5) }}" | |
- or: | |
- "{{ ( (brightness_sensor2 == []) and (brightness_sensor == []) ) }}" | |
- "{{ ( (brightness_sensor2 != []) and (states(brightness_sensor2) | int(default=brightness_up) >= brightness_up) ) }}" | |
- "{{ ( (brightness_sensor2 == [] and brightness_sensor != []) and (states(brightness_sensor) | int(default=brightness_up) >= brightness_up) ) }}" | |
sequence: | |
# ok, we can open the blind | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
- if: | |
- "{{ open_position == 100 }}" | |
then: | |
- alias: "Moving the blind to open position" | |
service: cover.open_cover | |
data: {} | |
target: | |
entity_id: "{{ repeat.item }}" | |
else: | |
- alias: "Moving the blind to open position" | |
service: cover.set_cover_position | |
data: | |
position: !input open_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- stop: "Stop the automation" | |
default: | |
- stop: "Stop the automation" | |
- alias: "Check and perform shading out" | |
conditions: | |
- "{{ auto_shading }}" | |
- "{{ ( (temporary_disable_shading == [] ) or (is_state(temporary_disable_shading, ['false', 'off'])) ) }}" | |
- "{{ now() >= today_at(time_up_early) }}" | |
- "{{ now() <= today_at(time_down_late) + timedelta(seconds = 5) }}" | |
- or: | |
- condition: trigger | |
id: "t_so_1" | |
- condition: trigger | |
id: "t_so_2" | |
- condition: trigger | |
id: "t_so_3" | |
- condition: trigger | |
id: "t_so_4" | |
- condition: trigger | |
id: "t_so_5" | |
- condition: trigger | |
id: "t_so_6" | |
- condition: trigger | |
id: "t_so_7" | |
- "{{ state_attr(blind, 'current_position') | int(default=101) == shading_blinds_position }}" | |
sequence: | |
- if: | |
# if sun is outside of shading window (azimuth or elevation) we immedately stop shading | |
- and: | |
- "{{ state_attr(shading_sun_sensor, 'azimuth') >= shading_azimuth_in and state_attr(shading_sun_sensor, 'azimuth') <= shading_azimuth_out }}" | |
- "{{ state_attr(shading_sun_sensor, 'elevation') >= shading_elevation_min and state_attr(shading_sun_sensor, 'elevation') <= shading_elevation_max }}" | |
- not: | |
- condition: trigger | |
id: "t_so_7" | |
then: | |
- alias: "Wait the number of seconds set in shading_waitingtime_out" | |
delay: | |
seconds: !input shading_waitingtime_out | |
- if: | |
- "{{ ( (window_sensor != []) and (is_state(window_sensor, 'on') ) ) }}" | |
- "{{ auto_ventilate }}" | |
then: | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- alias: "Moving the blind to ventilate position" | |
service: cover.set_cover_position | |
data: | |
position: !input ventilate_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
else: | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
- if: | |
- "{{ open_position == 100 }}" | |
then: | |
- alias: "Moving the blind to open position" | |
service: cover.open_cover | |
data: {} | |
target: | |
entity_id: "{{ repeat.item }}" | |
else: | |
- alias: "Moving the blind to open position" | |
service: cover.set_cover_position | |
data: | |
position: !input open_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
- stop: "Stop the automation" | |
- alias: "Check for closing blind" | |
conditions: | |
- or: | |
- "{{ auto_down }}" | |
- "{{ auto_ventilate }}" | |
- or: | |
- "{{ ( (adv_blind == []) or (is_state(adv_blind, ['false', 'off'])) ) }}" | |
- condition: trigger | |
id: "t_bc_5" | |
- or: | |
# Check if we have a trigger for blind down | |
- condition: trigger | |
id: "t_bc_1" | |
- condition: trigger | |
id: "t_bc_2" | |
- condition: trigger | |
id: "t_bc_3" | |
- condition: trigger | |
id: "t_bc_4" | |
- condition: trigger | |
id: "t_bc_5" | |
- condition: trigger | |
id: "t_bc_6" | |
## check to allow a window but a door only if window_sensor not open - we want protection | |
- "{{ ( ( door == 'false' ) or ( (door == 'true') and (window_sensor == []) ) or ( (door == 'true') and (window_sensor != []) and (is_state(window_sensor, 'off') ) ) ) }}" | |
- or: | |
- "{{ (state_attr(blind, 'current_position') | int(default=110) <= open_position + position_tolerance) and (state_attr(blind, 'current_position') | int(default=110) >= open_position - position_tolerance)}}" | |
- "{{ state_attr(blind, 'current_position') | int(default=101) == ventilate_position }}" | |
- or: | |
## Blinds - closing - down late reached | |
- and: | |
- "{{ now() >= today_at(time_down_late) }}" | |
- "{{ auto_down }}" | |
## Blinds - closing - down early reached and brightness below minimum | |
- and: | |
- "{{ auto_down }}" | |
- "{{ now() >= today_at(time_down_early) }}" | |
- "{{ now() <= today_at(time_down_late) + timedelta(seconds = 5) }}" | |
- or: | |
- "{{ ( (brightness_sensor == [] ) and (brightness_sensor2 == [] ) ) }}" | |
- "{{ ( (brightness_sensor != [] ) and (states(brightness_sensor) | int(default=brightness_down) <= brightness_down) ) }}" | |
- "{{ ( (brightness_sensor2 != [] ) and (states(brightness_sensor2) | int(default=brightness_down) <= brightness_down) ) }}" | |
## Blinds - closing - due to resident goes sleeping | |
- and: | |
- "{{ auto_down }}" | |
- "{{ ( (resident != [] ) and (is_state(resident, ['true', 'on'])) ) }}" | |
- condition: trigger | |
id: t_bc_5 | |
## Blinds - closing after ventilate | |
- and: | |
- condition: trigger | |
id: "t_bc_4" | |
- "{{ auto_ventilate }}" | |
- "{{ state_attr(blind, 'current_position') | int(default=101) == ventilate_position }}" | |
- "{{ ( (window_sensor != []) and (is_state(window_sensor, 'off') ) ) }}" | |
sequence: | |
- if: | |
- not: | |
- condition: trigger | |
id: "t_bc_4" | |
then: | |
- delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
- if: | |
- "{{ ( (window_sensor != []) and (is_state(window_sensor, 'on') ) ) }}" | |
- "{{ auto_ventilate }}" | |
then: | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- alias: "Moving the blind to ventilate position" | |
service: cover.set_cover_position | |
data: | |
position: !input ventilate_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
else: | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- if: | |
- "{{ closed_position == 0 }}" | |
then: | |
- alias: "Moving the blind to close position" | |
service: cover.close_cover | |
data: {} | |
target: | |
entity_id: "{{ repeat.item }}" | |
else: | |
- alias: "Moving the blind to close position" | |
service: cover.set_cover_position | |
data: | |
position: !input closed_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
- stop: "Stop the automation" | |
- alias: Window sensor - opened | |
conditions: | |
- condition: trigger | |
id: "t_bv_1" | |
- "{{ auto_ventilate }}" | |
- "{{ (state_attr(blind, 'current_position') | int(default=110) <= closed_position + position_tolerance) and (state_attr(blind, 'current_position') | int(default=110) >= closed_position - position_tolerance)}}" | |
- "{{ ( (window_sensor != []) and (is_state(window_sensor, 'on')) ) }}" | |
sequence: | |
- repeat: | |
for_each: "{{ blind_entities|list }}" | |
sequence: | |
- alias: "Moving the blind to ventilate position" | |
service: cover.set_cover_position | |
data: | |
position: !input ventilate_position | |
target: | |
entity_id: "{{ repeat.item }}" | |
- alias: "Wait 1-5 random seconds to prevent sending to many commands to blinds at same time" | |
delay: "00:00:{{ (range(1, 3)|random|int) }}" | |
default: | |
- if: | |
- "{{ check_config }}" | |
then: | |
## checking time slots | |
- if: | |
- "{{ today_at(time_up_early) >= today_at(time_up_late) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: time_up_early should be earlier than time_up_late - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ today_at(time_up_early_non_workday) >= today_at(time_up_late) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: time_up_early_non_workday should be earlier than time_up_late - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ today_at(time_down_early) >= today_at(time_down_late) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: time_down_early should be earlier than time_down_late - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
## checking shading | |
- if: | |
- "{{ shading_azimuth_in >= shading_azimuth_out }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: shading_azimuth_in should be lower than shading_azimuth_out - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ shading_elevation_min >= shading_elevation_max }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: shading_elevation_min should be lower than - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ shading_sun_brightness_in <= shading_sun_brightness_out }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: shading_sun_brightness_in should be higher than shading_sun_brightness_out - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
## checking positions | |
- if: | |
- "{{ (open_position - position_tolerance) <= (closed_position + position_tolerance) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: open_position should be higher than closed_position - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ (open_position - position_tolerance) <= (ventilate_position + position_tolerance) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: open_position should be higher than ventilate_position - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ (closed_position + position_tolerance) >= (ventilate_position - position_tolerance) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: closed_position should be lower than ventilate_position - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ (shading_blinds_position - position_tolerance) <= (closed_position + position_tolerance)}}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: shading_blinds_position should be higher than closed_position - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ (shading_blinds_position + position_tolerance) >= (open_position - position_tolerance) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: shading_blinds_position should be lower than open_position - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
## checking resident/adv_blind/temporary_disable_shading | |
- if: | |
- "{{ ( (resident != [] ) and (not is_state(resident, ['false', 'off','true', 'on'])) ) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: resident is only allowed to be on/off/true/false - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ ( (adv_blind != [] ) and (not is_state(adv_blind, ['false', 'off','true', 'on'])) ) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: adv_blind is only allowed to be on/off/true/false - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
- if: | |
- "{{ ( (temporary_disable_shading != [] ) and (not is_state(temporary_disable_shading, ['false', 'off','true', 'on'])) ) }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: temporary_disable_shading is only allowed to be on/off/true/false - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
## checking if sensors have the right attributes | |
- if: | |
- "{{ state_attr(blind, 'current_position') is none }}" | |
then: | |
- service: system_log.write | |
data: | |
level: "{{ check_config_debuglevel }}" | |
message: "New shading - config issue: blind is missing attribute current_position - {{this.entity_id}}" | |
logger: "blueprints.jmerifjKriwe1.new_shading" | |
# - service: persistent_notification.create | |
# data: | |
# notification_id: "jmerifjKriwe1" | |
# title: "Pausiblity check" | |
# message: "Found an issue" | |
- stop: "Stopping the automation - reset" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment