Start Roborock Routine / Room / Zone Cleaning with Press on Button Card

I looked for a good way to allow for easy room cleaning. I did not like the hardcoded rooms most solutions called for. Unfortunately, the action to get the room numbers is not easily suited to find a segment based on the room name.

So I created a sensor that calls the action to get the map and reverses the loopup so you can find segment numbers. I also created a select entity that allows you to pick a room on the current floor. Then I created a script to use these.

Note that the room select entity does not survive a restart. It does have a default list: if it can find the default for a floor it will set that. I did that because normally my robot only does my bedroom. When you adjust the defaults, always make sure you have an “All” selection at the end of the defaults list.

The sensors (goes in template.yaml):

- trigger:
    - trigger: homeassistant
      event: start
    - trigger: state
      entity_id: select.dusty_selected_map
      from:
        - unavailable
        - unknown
      not_to:
        - unavailable
        - unknown
  action:
    - action: roborock.get_maps
      target:
        entity_id: vacuum.dusty
      data: {}
      response_variable: maps
  sensor:
    - name: "dusty roomnumbers"
      unique_id: sensor.dusty_roomnumbers
      icon: mdi:floor-plan
      state: "{{ 'OK' if maps else 'unavailable' }}"
      attributes:
        rooms: |
          {%- set ns = namespace(floors='{')-%}
          {%- for floor in maps['vacuum.dusty'].maps -%}
            {% set ns.rooms = '{ "flag":' + floor.flag | string %}
            {%- for room in floor.rooms %}
              {%- set ns.rooms = ns.rooms + ', ' + '"' + floor.rooms[room] + '": ' + room | string -%}
            {%-endfor-%}
            {%- set ns.floors = ns.floors + ('' if ns.floors=='{' else ',') + 
                                '"' + floor.name + '": ' + ns.rooms + '}' -%}
          {%-endfor%}
          {{ (ns.floors + '}') | from_json }}
- trigger:
    - trigger: state
      id: state
      entity_id: 
        - sensor.dusty_roomnumbers
        - select.dusty_selected_map
    - trigger: event
      id: pick
      event_type: dusty_room_picked
    - trigger: event
      id: "reload"
      event_type: event_template_reloaded
  action:
    variables:
      defaults: ['Bedroom', 'All']
  select:
    - name: "dusty room"
      icon: mdi:location-enter
      unique_id: sensor.dusty_room
      options: |
        {%- if has_value('select.dusty_selected_map') and has_value('sensor.dusty_roomnumbers') -%}
          {%- set rooms = state_attr('sensor.dusty_roomnumbers','rooms') | default([]) -%}
          {%- set selected = states('select.dusty_selected_map') | default('') -%}
          {{ [defaults | last] + rooms.get(selected,[]) | reject('eq','flag') | list }}
        {%- else -%}
          {{ [defaults | last] }}
        {%- endif -%}
      state: |
        {%- if trigger is defined and trigger and trigger.id == 'pick' -%}
          {%- set cur = trigger.event.data.option -%}
        {%- elif trigger is defined and trigger and trigger.id == 'state' and 
                  trigger.entity_id == 'select.dusty_selected_map' -%}
          {%- set cur = None -%}
        {%- else -%}
          {%- set cur = states('select.dusty_room') -%}
        {%- endif -%}
        {%- if has_value('select.dusty_selected_map') and has_value('sensor.dusty_roomnumbers') -%}
          {%- set rooms = state_attr('sensor.dusty_roomnumbers','rooms') | default([]) -%}
          {%- set selected = states('select.dusty_selected_map') | default('') -%}
          {%- if selected in rooms -%}
            {%- set options = [defaults | last] + rooms.get(selected,[]) | reject('eq','flag') | list -%}
          {%- else -%}
            {%- set options = [defaults | last] -%}
          {%- endif -%}
          {%- set cur = cur if cur in options else defaults | select("in", options) | first() -%}
          {{ cur if cur in options else defaults | last }}
        {%- else -%}
          {{ defaults | last if cur in ['unavailable','unknown'] else cur }}
        {%- endif -%}
      select_option: 
        - event: dusty_room_picked
          event_data: 
            option: "{{ option }}"
      optimistic: true

The script (goes in scripts.yaml):

alias: Start dusty
variables:
  rooms: "{{ state_attr('sensor.dusty_roomnumbers','rooms') }}"
  floor: "{{states('select.dusty_selected_map') }}"
  room: "{{ states('select.dusty_room') }}"
  segments: "{{ [rooms[floor][room]] | reject('eq', Undefined) | list }}"
sequence:
  - if:
      - condition: template
        value_template: "{{ segments | length == 0 }}"
    then:
      - action: vacuum.start
        metadata: {}
        data: {}
        target:
          entity_id: vacuum.dusty
    else:
      - action: vacuum.send_command
        data:
          command: app_segment_clean
          params:
            - segments: "{{ segments }}"
              repeat: 1
        target:
          entity_id: vacuum.dusty
mode: single
icon: mdi:robot-vacuum-variant
1 Like