RF Blind Position Control Script

I’ve put together a bit of a script to be able to set the position of an RF blind, I’m using a Dooya RF blind with up, down, and stop commands set up as switches using a Broadlink RM Pro.

I tried the ‘timedcover’ mentioned elsewhere in the forum, it works, but the problem I came across is it doesn’t ‘reset’, so the calibration slowly falls out of wack as setting 0 or 100 doesn’t fully open or close the blind. There’s a few mentions of using similar scripts, but I couldn’t find anything quite complete enough to use.

This can probably be fixed more elegantly in a component, but this works for me. It’s a script with a few smarts to track and set the blind position anywhere within 1-99%, setting either 0 or 100% tells it to simply open all the way, or close all the way, regardless of where it thinks the blind is.

The biggest limitation is that it doesn’t handle multiple commands. If you start trying to change the blind position while it’s operating, you’re going to have a bad time.

There’s a few parts to it, first, the template cover (which passes some info to let the script be generic).

cover:
  - platform: template
    covers:
      blind_bedroom:
        friendly_name: 'Bedroom Blind'
        position_template: "{{ states('input_number.blind_bedroom_position') }}"
        open_cover:
          service: switch.turn_on
          entity_id: switch.blind_bedroom
        close_cover:
          service: switch.turn_off
          entity_id: switch.blind_bedroom
        stop_cover:
          service: switch.turn_on
          entity_id: switch.blind_bedroom_stop
        set_cover_position:
          service: script.set_cover_position
          data_template:
            position_set: '{{ position }}'
            position_previous: 'input_number.blind_bedroom_position'
            entity_id: 'cover.blind_bedroom'
            opening_time: 35.6
            closing_time: 35.6

We also need an input_number to track the position of the blind:

input_number:			
  blind_bedroom_position:
    name: Bedroom Blind Position
    unit_of_measurement: '%'
    min: 0
    max: 100
    step: 1

And the script, this has been set up to be generic (and takes some variables from the cover’s data_template).

script:
  set_cover_position:
    sequence:
        
      - service_template: >
          {% if position_set | float  == 0 %}
            cover.close_cover
          {% elif position_set | float == 100 %}
            cover.open_cover
          {% elif position_set | float == states(position_previous) | float %}
            script.dummy
          {% elif position_set | float > states(position_previous) | float %}
            cover.open_cover
          {% elif position_set | float < states(position_previous) | float %}
            cover.close_cover
          {% endif %}
        data_template:
          entity_id: "{{ entity_id }}"
        
      - delay:
          seconds: >
            {% if position_set | float == 0 %}
              {{ ( states(position_previous) | float / 100 * closing_time | round ) | int }}
            {% elif position_set | float == 100 %}
              {{ ( ( 100 - states(position_previous) | float ) / 100 * opening_time | round ) | int }}
            {% elif position_set | float > states(position_previous) | float %}
              {{ (( position_set | float - states(position_previous) | float ) / 100 * opening_time | round ) | int }}
            {% elif position_set | float < states(position_previous) | float %}
              {{ (( states(position_previous) | float - position_set | float ) / 100 * closing_time | round ) | int }}
            {% endif %}
          
      - service_template: >
          {% if position_set | float == 0 %}
            cover.close_cover
          {% elif position_set | float == 100 %}
            cover.open_cover
          {% elif position_set | float > states(position_previous) | float %}
            cover.stop_cover
          {% elif position_set | float < states(position_previous) | float %}
            cover.stop_cover
          {% endif %}
        data_template:
          entity_id: "{{ entity_id }}"
          
      - service: input_number.set_value
        data_template:
          entity_id: "{{ position_previous }}"
          value: "{{ position_set }}"
6 Likes

How would I go about using this for multiple blinds? I can’t seem to get it working with one, is there anything in the script I need to modify to work with my config?

Thanks!