-
-
Save lukasvice/b364724d84c3ac4e160f7a7d8fa37066 to your computer and use it in GitHub Desktop.
# 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 |
Nice, I am happy that it is working! Of course I would also be happy about a beer, thank you! :) https://www.buymeacoffee.com/lukasvice
Hi lukasvice,
was hoping you could help me. I still have no solution for the external Venetian blinds. I am looking for someone that could test your code with these blinds and a Shelly pro 2 pm especially the tilt. As I don’t have the blinds yet to test. I am happy to send you this Shelly device and
instead of a beer pay you for your time. I am really struggling with this. 🙂
thanks in advance.
How do you use it in day to day world. Do you use cover template that calls script, or just using some custom cards. Can you share configuration?
I'm using it most of the times manual in my dashboard, here is one example card:
# Raffstore
- view_layout:
grid-area: "cardc"
type: horizontal-stack
cards:
- type: custom:button-card
template: edge
- type: custom:button-card
show_icon: false
show_name: false
show_label: false
styles:
grid:
- grid-template-areas: "'item1 item1' 'item2 item2' 'item3 item3'"
- grid-template-columns: 1fr 1fr
- grid-template-rows: "min-content min-content min-content"
- row-gap: 10px
card:
- border-radius: var(--border-radius)
- box-shadow: var(--box-shadow)
- padding: 10px
custom_fields:
item1:
card:
type: custom:button-card
template: card_cover
variables:
ulm_card_cover_enable_controls: true
ulm_card_cover_enable_slider: true
ulm_card_cover_enable_popup: true
ulm_card_cover_enable_horizontal: true
ulm_card_cover_name: "Büro"
entity: cover.raffstore_buero
item2:
card:
type: custom:button-card
template: list_2_items
custom_fields:
item1:
card:
type: custom:button-card
template: card_script
variables:
ulm_card_script_title: '100'
ulm_card_script_icon: 'mdi:percent-outline'
tap_action:
action: call-service
service: script.cover_position_tilt
service_data:
entity_id: cover.raffstore_buero
position: 0
tilt_position: 50
styles:
card:
- box-shadow: "none"
item2:
card:
type: custom:button-card
template: card_script
variables:
ulm_card_script_title: '75'
ulm_card_script_icon: 'mdi:percent-outline'
tap_action:
action: call-service
service: script.cover_position_tilt
service_data:
entity_id: cover.raffstore_buero
position: 25
tilt_position: 50
styles:
card:
- box-shadow: "none"
item3:
card:
type: custom:button-card
template: list_2_items
custom_fields:
item1:
card:
type: custom:button-card
template: card_script
variables:
ulm_card_script_title: '50'
ulm_card_script_icon: 'mdi:percent-outline'
tap_action:
action: call-service
service: script.cover_position_tilt
service_data:
entity_id: cover.raffstore_buero
position: 50
tilt_position: 50
styles:
card:
- box-shadow: "none"
item2:
card:
type: custom:button-card
template: card_script
variables:
ulm_card_script_title: '25'
ulm_card_script_icon: 'mdi:percent-outline'
tap_action:
action: call-service
service: script.cover_position_tilt
service_data:
entity_id: cover.raffstore_buero
position: 75
tilt_position: 50
styles:
card:
- box-shadow: "none"
In the Dashboard it looks like this:
But it's also part of my automations, here is an example, when it's getting to hot outside, normally all blinds will close completley expect the office one as i'm working from home:
description: Close all Raffstore if Temp is above 23 °C
trigger:
- platform: numeric_state
entity_id: sensor.gw2000a_v2_1_8_outdoor_temperature
for:
hours: 0
minutes: 0
seconds: 0
above: 23
alias: Check Temp > 23C
condition:
- condition: and
conditions:
- condition: time
after: "09:00:00"
before: "20:00:00"
weekday:
- sun
- mon
- tue
- wed
- thu
- fri
- sat
- condition: numeric_state
entity_id: sensor.gw2000a_v2_1_8_wind_speed
alias: Check Windspeed > 16.0 m/s
below: 16
alias: Time & Wind Condition
action:
- parallel:
- choose:
- conditions:
- condition: numeric_state
entity_id: cover.raffstore_buero
attribute: current_position
below: 100
enabled: false
- condition: state
entity_id: cover.raffstore_buero
state: open
sequence:
- service: script.cover_position_tilt
data:
entity_id: cover.raffstore_buero
position: 2
tilt_position: 40
alias: Buero Action
- choose:
- conditions:
- condition: numeric_state
entity_id: cover.raffstore_kinderzimmer
attribute: current_position
below: 100
enabled: false
- condition: state
entity_id: cover.raffstore_kinderzimmer
state: open
sequence:
- service: cover.close_cover
data: {}
target:
entity_id: cover.raffstore_kinderzimmer
alias: Kinderzimmer Action
- choose:
- conditions:
- condition: numeric_state
entity_id: cover.raffstore_schlafzimmer_fenste
attribute: current_position
below: 100
enabled: false
- condition: state
entity_id: cover.raffstore_schlafzimmer_fenste
state: open
sequence:
- service: cover.close_cover
data: {}
target:
entity_id: cover.raffstore_schlafzimmer_fenste
alias: SZ Fenster Action
- choose:
- conditions:
- condition: numeric_state
entity_id: cover.raffstore_schlafzimmer
attribute: current_position
below: 100
enabled: false
- condition: state
entity_id: cover.raffstore_schlafzimmer
state: open
sequence:
- service: cover.close_cover
data: {}
target:
entity_id: cover.raffstore_schlafzimmer
alias: SZ Fenster
mode: single
@xbmcgotham You don't need to send me your Shelly, because it works with every Shelly 2PM. It is not installed on the Shelly itself, but everything runs on Home Assistant. You have to set the tilt time in the script, so you can only test it once you have the blinds and your Shelly is connected to Home Assistant.
Just tried out the script, too.
Similar to a previous comment
My installation had just issues with the first line in your cover_posistion_titlt.yaml.
I'm also having troubles with that line. I simply had to remove it.
Thanks for the script. I think I can understand the code quite well.
However, the special case does not work for me. Are some conditions or cases still missing?
- If current position and current tilt position is the same the scrip shouldn't do anything?
- If the position is the same as the current position, then why are we making the tilt one full move until the
tilt_time_ms
?
After that, the blinds are simply completely closed again. here one would have to approach the current tilt position and/or the new tilt position somehow.
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 }}"
Maybe it doesn't even make sense what I'm saying and you have a little input :)
Hi @MelleD,
I see what you mean, and I think both questions are based on the same problem: it's not possible to know the current tilt position. If the blinds have been moved outside the script, it's impossible to know the tilt position. That's why we always have to move the blinds to get to a known tilt state, before moving the blinds to the desired tilt position. I hope that was understable.
However, last week I tried something to optimise exactly this behaviour: After the script has finished, I persist the current position and tilt position. Then, the next time the script runs, it can check if the blinds are currently in the same position and will not move. If the blinds are moved outside the script, the persisted position is erased for the reason described above. It seems to be quite stable, so I will update the solution here on GitHub with the new version soon.
Let me know if you have any further questions or ideas.
Hey @lukasvice,
That's why we always have to move the blinds to get to a known tilt state, before moving the blinds to the desired tilt position. I hope that was understable.
That's clear to me
If the blinds are moved outside the script, the persisted position is erased for the reason described above.
I would have gone in that direction too and make totally sense. How did you delete persisted till position?
Let me know if you have any further questions or ideas.
I'm trying to organize my thoughts because it's hard to explain :-). Whether I don't know if it is technically feasible with HA. I think you're a lot further than me ;)
Currently I wrapped my shelly cover in my own cover template, so that I already have the current tilt position which is set from the UI.
I have 1 to 1 the same thought, that the current tilt position must be set to 0 whenever cover close, cover open or cover set position is executed. Maybe you have a hint how to do that.
So far so good. What I am currently still unsure whether I would really put position and tilt position together in one script or in two separate actions
For example, if I look at the mushroom cover card, these are 2 different actions, but maybe that doesn't have any effect.
My process (as I said unsure if technically possible with HA).
Let's assume resetting tilt position works.
Action 1 set position:
1a. Go to position
2a. If possible, save in an extra attribute in which direction the roller shutter was last moved (up or down)
3a. The roller shutter is in the correct position
4a. Set current tilt position to zero or -1
Set the tilt position :
1b. Calculate how much time (ms) one tilt step needs based on a full tilt ms duration (First thought full tilt / 100)
2b. Based on the current tilt position, calculate the difference that needs to be moved (e.g if you just change the tilt position without moving the shutter and current tilt position is not zero)
3b. Move the cover from the position in the opposite direction to the saved driving direction from step 2a
4b. Duration of movement is difference from 2b * tilt_step_ms from 1b
I'm pretty sure you've seen my blog post about this script - if not, it's linked here :)
You can split up your scripts, sounds reasonable. With the new Shelly Plus 2 PM firmware version 1.0.0 you can get the last_direction
directly from the device. But even with this information, you can't be sure if it's fully tilted or if it's only moved for 0.2 seconds, so maybe it's half tilted. Maybe I'm missing something, but I haven't found a way how to use this information. Anyone with good ideas is welcome! :)
To store the last position and tilt position, I use a trigger-based template sensor that stores the data of each cover as JSON. This script can be triggered by two events:
- Custom (manual): This event is fired by the end of the
cover_position_tilt
script and theentity_id
,position
, andtilt_position
are passed as arguments - A cover changes to
opening
orclosing
: This resets the stored position in the data tounknown
At the beginning of the cover_position_tilt
script, I read the stored position from the JSON and compare it to the desired position. If it's the same, the script stops, otherwise it continues as normal.
I don't think this is the prettiest approach, but I couldn't think of a better one - and it works :) As I said, I'm open to any ideas and improvements.
Here's the template sensor:
template:
- trigger:
- id: "cover_position_tilt"
platform: event
event_type: "cover_position_tilt"
- platform: state
entity_id:
- cover.shelly_2_5_COVER_ID
- cover.shelly_2_5_COVER_ID
- cover.shelly_2_5_COVER_ID
to:
- "opening"
- "closing"
sensor:
- name: "cover_states"
state: >
{% set current = ('{}' if states('sensor.cover_states') == 'unknown' else states('sensor.cover_states')) | from_json %}
{% if trigger.id == "cover_position_tilt" -%}
{% set new = {
trigger.event.data.entity_id: {
'position': trigger.event.data.position,
'tilt_position': trigger.event.data.tilt_position
}
} %}
{%- else -%}
{% set new = {
trigger.entity_id: 'unknown'
} %}
{%- endif %}
{{ dict(current, **new) | to_json }}
This is how to trigger it manually at the end of the open
and close
movements in the script:
- event: cover_position_tilt
event_data:
entity_id: "{{ entity_id }}"
position: "{{ position }}"
tilt_position: "{{ tilt_position }}"
And this is the comparison at the beginning of the script:
- alias: "Set variables"
variables:
_last_position: >
{% set cover_states = ('{}' if states('sensor.cover_states') == 'unknown' else states('sensor.cover_states')) | from_json %}
{{ cover_states[entity_id].position if entity_id in cover_states and 'position' in cover_states[entity_id] else 'unknown' }}
_last_tilt_position: >
{% set cover_states = ('{}' if states('sensor.cover_states') == 'unknown' else states('sensor.cover_states')) | from_json %}
{{ cover_states[entity_id].tilt_position if entity_id in cover_states and 'tilt_position' in cover_states[entity_id] else 'unknown' }}
- condition: template
value_template: >
{{ _last_position == 'unknown' or _last_tilt_position == 'unknown' or position != _last_position or tilt_position != _last_tilt_position }}
Thanks for all the feedback on the first line that was causing problems - I have removed it from the code!
Exactly I know your links and the problems :-)
I am currently creating the temporary data in a temp sensor because the data was always deleted from the original sensor. Maybe there's a better way. In addition, I create a wrapper cover for the blinds to call the scripts directly.
I can also share my script this week, if you want
I solved it by 6 conditions.
- last_action open & current_tilt_position = 0
- last_action close & current_tilt_position = 0
- last_action open & (current_tilt_position - new_tilt_position) > 0
- last_action close & (current_tilt_position - new_tilt_position) > 0
- last_action open & (current_tilt_position - new_tilt_position) < 0
- last_action close & (current_tilt_position - new_tilt_position) < 0
The only edge case that hasn't been resolved is when someone manually tilts the blinds.
My idea (untested), since I'm already overriding open_cover and stop_cover, I could set the current_tilt_positiona to 50 as soon as the position was offset by just 1%.
@MelleD Sounds promising! Tbh, I didn't fully understand your approach, but I'm very curious to see your solution :)
I do have one question though: Imagine you have the blinds at 70% with a 50% tilt position. Now you move the blinds up to 71%. In reality, this only changes the tilt and not the position. How do you deal with this, or how do you know correct the state?
Here are currently my try:
Like you, you have to play around with the time a bit.
Maybe I need 2 times.
script:
open_cover:
mode: parallel
fields:
entity_id:
description: "The orginal cover entity"
example: "cover.X"
sequence:
- alias: "Set variables"
variables:
temp: "_temp"
entity_id_temp: "{{ entity_id + temp }}"
current_position: "{{ state_attr(entity_id, 'current_position') }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: 0
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: last_action
state: "open_cover"
- service: cover.open_cover
target:
entity_id: "{{entity_id}}"
data: {}
close_cover:
mode: parallel
fields:
entity_id:
description: "The orginal cover entity"
example: "cover.X"
sequence:
- alias: "Set variables"
variables:
temp: "_temp"
entity_id_temp: "{{ entity_id + temp }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: 0
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: last_action
state: "close_cover"
- service: cover.close_cover
target:
entity_id: "{{entity_id}}"
data: {}
set_cover_position_tilt:
mode: parallel
fields:
entity_id:
description: "The cover entity"
example: "cover.X"
tilt_position:
description: "Tilt position"
example: 100
sequence:
- alias: "Set variables"
variables:
tilt_full_time_ms: 1200
temp: "_temp"
entity_id_temp: "{{ entity_id + temp }}"
current_position: "{{ state_attr(entity_id, 'current_position') }}"
current_tilt_position: "{{state_attr(entity_id_temp, 'current_tilt_position')}}"
- alias: "Continue only if blinds are not fully opened and tilt position is changed"
condition: template
value_template: "{{ current_position is not none and (current_position|int) < 100 and current_tilt_position is not none and (tilt_position|int) != current_tilt_position}}"
- alias: "Move the blinds"
choose:
- conditions: "{{ state_attr(entity_id_temp, 'last_action') == 'open_cover' and current_tilt_position == 0}}"
sequence:
- service: cover.close_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_full_time_ms / 100 * tilt_position|int }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: "{{tilt_position|int}}"
- conditions: "{{ state_attr(entity_id_temp, 'last_action') == 'close_cover' and current_tilt_position == 0}}"
sequence:
- service: cover.open_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_full_time_ms / 100 * tilt_position|int }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: "{{tilt_position|int}}"
- conditions: "{{ state_attr(entity_id_temp, 'last_action') == 'open_cover' and current_position != 0 and (tilt_position-current_tilt_position)>0}}"
sequence:
- service: cover.close_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_full_time_ms / 100 * (tilt_position-current_tilt_position) }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: "{{tilt_position|int}}"
- conditions: "{{ state_attr(entity_id_temp, 'last_action') == 'open_cover' and current_position != 0 and (tilt_position-current_tilt_position)<0}}"
sequence:
- service: cover.open_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_full_time_ms / 100 * ((tilt_position-current_tilt_position)*-1) }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- conditions: "{{ state_attr(entity_id_temp, 'last_action') == 'close_cover' and current_position != 0 and (tilt_position-current_tilt_position)>0}}"
sequence:
- service: cover.open_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_full_time_ms / 100 * (tilt_position-current_tilt_position) }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: "{{tilt_position|int}}"
- conditions: "{{ state_attr(entity_id_temp, 'last_action') == 'close_cover' and current_position != 0 and (tilt_position-current_tilt_position)<0}}"
sequence:
- service: cover.close_cover
data_template:
entity_id: "{{ entity_id }}"
- delay:
milliseconds: "{{ tilt_full_time_ms / 100 * ((tilt_position-current_tilt_position)*-1) }}"
- service: cover.stop_cover
data_template:
entity_id: "{{ entity_id }}"
- service: python_script.set_state_attribute
data:
entity_id: "{{entity_id_temp}}"
state_attr: current_tilt_position
state: "{{tilt_position|int}}"
I do have one question though: Imagine you have the blinds at 70% with a 50% tilt position. Now you move the blinds up to 71%. In reality, this only changes the tilt and not the position. How do you deal with this, or how do you know correct the state?
I would like to do the following if the position moves just 1%.
- If the current tilt position is 0 I would set it to 50%
- If the current tilt position != 0 I would subtract or add 50 (depending on the last action)
2a. If the current tilt position is then over 100% I would set it back to 0.
But here my technical knowledge is too weak how and where to find out that the position moved only 1%.
I'm aware that you can't get a 100% accurate solution with this, but I don't have the use case to change the tilt 4 or 5 times either ;).
Most of the time you do it once, maybe a second time to adjust. That works quite well. It would be important to show the manual status.
With the new Shelly Plus 2 PM firmware version 1.0.0 you can get the last_direction directly from the device
With this information, I can remove some settings but I didn't find this information into HA
Can you please help me understand how exactly should I use this? Do you have any tutorial? I am also not familiar much about scripts.
I have several external venetian blinds using Shelly 2PM plus and I need to make tilt control in HA.
If I understand correctly, I have to create "script" in HA for each one, copy in it the content after "-script" and rename entity_id to my id of cover.shelly....
Then create automation with content under "-automation"
What next?
I freshly started with HA and Shellys but after hours of figuring out issues I made it work. Here a summary of my conclusions:
In order to get the position of the covers I had to remove the shellys from HA and Shelly App. Then re-integrate them via the Shelly app and the run the Calibration on the Shelly app (Settings->Calibration). Once completed, re-integrated the Shellys in HA. Based on above replies maybe one additional remark:
The cover_position_tilt.yaml does not need to be modified simply e.g. create a new folder "Packages" via Studio Code Server. Then create a new file in the packages folder with name cover_position_tilt.yaml and copy paste the script content. Next is to add the following in the configuration.yaml
homeassistant:
packages: !include_dir_named packages/
Once done go in Developer Tools and click on Check Configuration. If everything is good restart HA. Testing of the script: In Developer Tools click on Services and paste the below and click on Call Service
service: script.cover_position_tilt
data:
entity_id: cover.replace_with_your_shelly_entity_ID
position: 10
tilt_position: 40
@FlyingDodo86 Thanks for sharing.
Note that in the meantime, I have updated the script to exclude the "package" line to make it easier for new users to use it. I still use it as a package though.
Hi @lukasvice hope your doing great!, I see you have made great progress. I am just wondering, as I am not a developer, can you confirm to me if this script will do what I am expecting for my setup? :-)
I have the blind boxes installed and all wired up, but have not yet the blinds, so I can still adapt to the best situation.
Like shown on the drawing attached, this is the setup I like and have wired up for. A Shelly (Pro series I have now) unit that is controlled by a manual switch on the wall and the HA. I know that in the past the Shelly HA script needs tweaking to make the tilt work, and I am not sure how this currently works with the wall switches in parallel. I am happy to buy additional WAREMA control system if that would allow for easy integration. I do try to stay away from Wifi or RF and like all wired as some blinds are to far away to reach that way.
Hope you can get back to me.
Appreciated, thanks!
@xbmcgotham yes it will work, checking wiring diagram for shelly 2PM
Does work with Shelly 2PM Plus
@FlyingDodo86 Thanks for sharing.
Note that in the meantime, I have updated the script to exclude the "package" line to make it easier for new users to use it. I still use it as a package though.
Hello @lukasvice, I created a package folder and inside this folder I copied the latest cover_position_tilt.yaml. When I add
homeassistant:
packages: !include_dir_named packages/
to the configuration.yaml and then check the configuration I get the following warning:
Konfigurationswarnungen
Setup of package 'script' failed: Integration 'cover_position_tilt' not found.
Setup of package 'automation' failed: Invalid package definition 'automation': expected a dictionary. Package will not be initialized
What's my issue?
Hi @u20p17, your approach seems fine to me. It looks like script
and automation
are somehow being interpreted as package names. Are you sure you're not using !include_dir_merge_named
(That would work a bit differently)?
You can also look at some examples here and try to compare your configurations: https://www.home-assistant.io/examples/#example-configurationyaml
@lukasvice, i indeed did use the !include_dir_merge_named… if i delete this line in the configuration.yaml and restart HA i do not see any error/warning, but i can also not see any new script/automation…
something i am doing wrong 🤗
@u20p17, there's a difference between !include_dir_named
and !include_dir_merge_named
. The merge
one requires the package name at the beginning of the file. Try using the one without merge
, as you wrote in your original comment. See also the documentation on this: https://www.home-assistant.io/docs/configuration/packages/#create-a-packages-folder.
danke, hatte es tatsächlich falsch^^ jetzt funktionierts (Y)
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?
@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.
How do you use it in day to day world. Do you use cover template that calls script, or just using some custom cards.
Can you share configuration?