Skip to content

Instantly share code, notes, and snippets.

@jmerifjKriwe
Last active February 2, 2024 14:56
Show Gist options
  • Save jmerifjKriwe/bffbc7424dd04f4a31d6a71f7012cd1f to your computer and use it in GitHub Desktop.
Save jmerifjKriwe/bffbc7424dd04f4a31d6a71f7012cd1f to your computer and use it in GitHub Desktop.
automatic_blinds_shading.yaml
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