Custom Component: Cover Time Based

I managed to reimplement the functionality of this custom component using HA core integrations. Assuming you have already learned the RF commands for Open, Close and Stop for the device RF Blind:

  1. Create helpers to record the cover’s state
input_number:
  rf_blind_position:
    name: RF Blind Position
    min: 0
    max: 100
    step: 1

input_select:
  rf_blind_movement:
    name: RF Blind Movement
    options:
      - opening
      - closing
      - stopped
  1. Create a script to send the relevant RF commands and correspondingly set the state of input_select.rf_blind_movement
script:
  rf_blind_set_position:
    alias: RF Blind Set Position
    fields:
      target_position:
        name: Target Position
        description: The position that the cover should move to. 0 is closed, 100 is open.
        required: true
        default: 100
        selector:
          number:
            min: 0
            max: 100
            step: 1
            unit_of_measurement: '%'
    sequence:
    - condition: template
      value_template: '{{ states(''input_number.rf_blind_position'') | int(0) != target_position }}'
    - if:
      - condition: template
        value_template: '{{ states(''input_number.rf_blind_position'') | int(0) < target_position }}'
      then:
      - service: input_select.select_option
        data:
          option: opening
        target:
          entity_id: input_select.rf_blind_movement
      - service: remote.send_command
        data:
          device: RF Blind
          command: Up
        target:
          entity_id: remote.rf_universal_remote
      - wait_template: '{{ states(''input_number.rf_blind_position'') | int(0) >= target_position }}'
        continue_on_timeout: true
        timeout: '15' # set this to the number of seconds it takes your cover to open/close + 1s
      - service: input_select.select_option
        data:
          option: stopped
        target:
          entity_id: input_select.rf_blind_movement
      - service: remote.send_command
        data:
          device: RF Blind
          command: Stop
        target:
          entity_id: remote.rf_universal_remote
      else:
      - service: input_select.select_option
        data:
          option: closing
        target:
          entity_id: input_select.rf_blind_movement
      - service: remote.send_command
        data:
          device: RF Blind
          command: Down
        target:
          entity_id: remote.rf_universal_remote
      - wait_template: '{{ states(''input_number.rf_blind_position'') | int(0) <= target_position }}'
        continue_on_timeout: true
        timeout: '15' # set this to the number of seconds it takes your cover to open/close + 1s
      - service: input_select.select_option
        data:
          option: stopped
        target:
          entity_id: input_select.rf_blind_movement
      - service: remote.send_command
        data:
          device: RF Blind
          command: Stop
        target:
          entity_id: remote.rf_universal_remote
    mode: restart
  1. Create an automation to update input_number.rf_blind_position based on the time that input_select.rf_blind_movement spends in a given state
automation:
- id: '1688177050049'
  alias: RF Blind Position
  description: Set the current position of the RF Blind based on time spent opening,
    closing or stopped.
  trigger:
  - platform: state
    entity_id:
    - input_select.rf_blind_movement
  condition: []
  action:
  - choose:
    - conditions:
      - condition: state
        entity_id: input_select.rf_blind_movement
        state: opening
      sequence:
      - repeat:
          while:
          - condition: state
            entity_id: input_select.rf_blind_movement
            state: opening
          - condition: template
            value_template: '{{ states(''input_number.rf_blind_position'') | int(0) + 1 <= 100 }}'
          sequence:
          - delay:
              hours: 0
              minutes: 0
              seconds: 0
              milliseconds: 141 # set this to the number of seconds your blind takes to open/close divided by 100
          - service: input_number.set_value
            data:
              value: '{{ states(''input_number.rf_blind_position'') | int(0) + 1 }}'
            target:
              entity_id: input_number.rf_blind_position
    - conditions:
      - condition: state
        entity_id: input_select.rf_blind_movement
        state: closing
      sequence:
      - repeat:
          while:
          - condition: state
            entity_id: input_select.rf_blind_movement
            state: closing
          - condition: template
            value_template: '{{ states(''input_number.rf_blind_position'') | int(0) - 1 >= 0 }}'
          sequence:
          - delay:
              hours: 0
              minutes: 0
              seconds: 0
              milliseconds: 141 # set this to the number of seconds your blind takes to open/close divided by 100
          - service: input_number.set_value
            data:
              value: '{{ states(''input_number.rf_blind_position'') | int(0) - 1 }}'
            target:
              entity_id: input_number.rf_blind_position
  mode: single
  1. Create a template cover to bring it all together!
cover:
- platform: template
  covers:
    rf_blind:
      friendly_name: RF Blind
      unique_id: cover.rf_blind
      value_template: >
        {% if states('input_select.rf_blind_movement') in ['opening','closing'] %}
          {{ states('input_select.rf_blind_movement') }}
        {% else %}
          {{ states('input_number.rf_blind_position') | int(0) > 0 }}
        {% endif %}
      position_template: "{{ states('input_number.rf_blind_position') | int(0) }}"
      open_cover:
        service: script.rf_blind_set_position
        data:
          target_position: 100
      close_cover:
        service: script.rf_blind_set_position
        data:
          target_position: 0
      stop_cover:
        service: script.rf_blind_set_position
        data:
          target_position: "{{ states('input_number.rf_blind_position') | int(0) }}"
      set_cover_position:
        service: script.rf_blind_set_position
        data:
          target_position: "{{ position }}"

With the above setup, I was able to remove the custom component safely.

The logic in automation.rf_blind_position can be further extended to set input_number.rf_blind_position to a known value if you have sensors that can give feedback when the blind actually reaches certain positions (eg. contact sensors at the 100 and 0 positions).

4 Likes