Skip to content

Instantly share code, notes, and snippets.

@lukasvice
Last active June 27, 2024 11:54
Show Gist options
  • Save lukasvice/b364724d84c3ac4e160f7a7d8fa37066 to your computer and use it in GitHub Desktop.
Save lukasvice/b364724d84c3ac4e160f7a7d8fa37066 to your computer and use it in GitHub Desktop.
Home Assistant script to control venetian blinds with Shelly
# Have a look at the blog post about this script:
# https://medium.com/@lukasvice/a-utility-script-for-controlling-venetian-blinds-with-shelly-in-home-assistant-2e5cbf2d8d5f
script:
cover_position_tilt:
mode: parallel
fields:
entity_id:
description: "The cover entity"
example: "cover.X"
position:
description: "Position of the cover"
example: 100
tilt_position:
description: "Tilt position (optional)"
example: 100
sequence:
- alias: "Set variables"
variables:
# Time in ms for a full tilt
tilt_time_ms: 1800
# Time between blinds move commands
cmd_wait_time_ms: 500
_original_position: "{{ state_attr(entity_id, 'current_position') }}"
- alias: "Open/Close tilt depending on current position"
choose:
# When closing
- conditions: "{{ state_attr(entity_id, 'current_position') > position|int }}"
sequence:
# Move to the desired position
- service: cover.set_cover_position
data_template:
entity_id: "{{ entity_id }}"
position: "{{ position|int }}"
# Blinds have to be tilted, if tilt_position is set and tilt_position is not fully closed
- alias: "Check if blinds should be tilted"
condition: template
value_template: "{{ tilt_position is defined and tilt_position != none and tilt_position|int > 0 }}"
# Wait for the blinds to stop (Shelly updates current_position on start/stop)
# Cancel the script if the position was not received after 100 seconds
- wait_for_trigger:
- platform: template
value_template: "{% if state_attr(entity_id, 'current_position') != _original_position %}true{% endif %}"
timeout: 100
continue_on_timeout: false
# If it's not the desired position, the blinds were stopped manually (in this case cancel the script)
- alias: "Check if blinds have reached desired position"
condition: template
value_template: "{% if is_state_attr(entity_id, 'current_position', position|int) %}true{% endif %}"
- delay:
milliseconds: "{{ cmd_wait_time_ms }}"
# Move the blinds the required time for tilting in the original direction
- service: cover.close_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_time_ms / 100 * tilt_position|int }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ cmd_wait_time_ms }}"
# Move the blinds the required time for tilting in the opposite direction
- service: cover.open_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_time_ms / 100 * tilt_position|int }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
# When opening
- conditions: "{{ state_attr(entity_id, 'current_position') < position|int }}"
sequence:
# Move to the desired position
- service: cover.set_cover_position
data_template:
entity_id: "{{ entity_id }}"
position: "{{ position|int }}"
# Blinds have to be tilted, if tilt_position is set and tilt_position is not fully open
- alias: "Check if blinds should be tilted"
condition: template
value_template: "{{ tilt_position is defined and tilt_position != none and tilt_position|int < 100 }}"
# Wait for the blinds to stop (Shelly updates current_position on start/stop)
# Cancel the script if the position was not received after 100 seconds
- wait_for_trigger:
- platform: template
value_template: "{% if state_attr(entity_id, 'current_position') != _original_position %}true{% endif %}"
timeout: 100
continue_on_timeout: false
# If it's not the desired position, the blinds were stopped manually (in this case cancel the script)
- alias: "Check if blinds have reached desired position"
condition: template
value_template: "{% if is_state_attr(entity_id, 'current_position', position|int) %}true{% endif %}"
- delay:
milliseconds: "{{ cmd_wait_time_ms }}"
# Move the blinds the required time for tilting in the original direction
- service: cover.open_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_time_ms / 100 * (100 - tilt_position|int) }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ cmd_wait_time_ms }}"
# Move the blinds the required time for tilting in the opposite direction
- service: cover.close_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_time_ms / 100 * (100 - tilt_position|int) }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
# Special case: the blinds are already in the desired position
default:
- alias: "Continue only if blinds are not fully opened or closed"
condition: template
value_template: "{{ state_attr(entity_id, 'current_position') > 0 and state_attr(entity_id, 'current_position') < 100 }}"
- choose:
# When the blinds are almost closed, move up for the tilt time
- conditions: "{{ state_attr(entity_id, 'current_position') < 10 }}"
sequence:
- service: cover.open_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_time_ms }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
# When the blinds are open, move down for the tilt time
default:
- service: cover.close_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_time_ms }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ cmd_wait_time_ms }}"
# Trigger event to restart the script with the original parameters
- event: start_cover_position_tilt
event_data:
entity_id: "{{ entity_id }}"
position: "{{ position }}"
tilt_position: "{{ tilt_position }}"
automation:
# Automation triggered by a custom event to restart the script
- id: start_cover_position_tilt
alias: "Start Cover Position Tilt"
mode: parallel
trigger:
- platform: event
event_type: "start_cover_position_tilt"
action:
- service: script.cover_position_tilt
data_template:
entity_id: "{{ trigger.event.data.entity_id }}"
position: "{{ trigger.event.data.position }}"
tilt_position: "{{ trigger.event.data.tilt_position }}"
service: script.cover_position_tilt
data:
entity_id: cover.shelly_XXX
position: 70
tilt_position: 50
@u20p17
Copy link

u20p17 commented Apr 10, 2024

danke, hatte es tatsächlich falsch^^ jetzt funktionierts (Y)

@u20p17
Copy link

u20p17 commented Apr 17, 2024

today i had some time to play with this script, but in my case it is not working as expected. the problem I think is that my venetian blinds do need different times for a full tilt upwards (1400ms) and downwards (1000ms). Do you have the same issue and just took the middle value? if you send tilt position 50 should the blinds stop at around 45deg?

@lukasvice
Copy link
Author

@u20p17 Hmm, my blinds always take the same amount of time regardless of the direction. Maybe you could modify the script so that you have two variables, tilt_time_opening_ms and tilt_time_closing_ms. You can then use these variables in the "opening" or "closing" condition of the script. This might work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment