Roborock vacuum routines control with one button

I was always on the run in the morning, so I wanted a simple automation to start my Roborock vacuum cleaning routine without accessing the app.

So, I started working on an automation involving a 3 event button (single, double, long). Set up individual automation per event and it worked for a while.

Then my basic automation got messed up by my partner not using the button, but the dedicated app. So I added the vacuum state to the mix. Of course, the integration’s state machine is more complicated than I needed, so I added a synced helper to synchronize the automation and vacuum state machines.

I ended up with a simple to use yet powerful automation and thought I should share it with the community.

Long story short, my automation provides the following actions:

  1. Single click: Starts a user-defined action if the vacuum is not already cleaning. In my case, it’s a custom “app_segment_clean” routine repeated one time.
  2. Double click: Starts a user-defined action if the vacuum is not already cleaning. In my case, it’s the same custom “app_segment_clean” routine as for single click, but repeated three times.
  3. Long click: Send the vacuum to the docking station, stopping any cleaning activity in progress.
  4. Single click while a cleaning activity is in progress: Pauses the current activity.
  5. Single click while a cleaning activity is paused: Resumes the paused cleaning activity.
  6. If the vacuum is paused for more than a user-defined number of minutes, the automation will send it back to the docking station.
  7. Optional daily custom routine with custom trigger time.
  8. An automation Do Not Disturb mode, in case you want to block the automation at night. I needed this as I had a “curious” guest interacting with the button in the middle of the night and started a whole-house cleaning routine at 2:00 in the morning.

What you’ll need:

  • A Roborock vacuum
  • The Roborock integration
  • An Input Select helper, with the following states: None, Cleaning, Paused

The action commands are similar to the ones you would use in the aforementioned integration.

Disclaimer:

  • I only tested on my setup, so please test it on your setup before officially deploying it “in production”.
  • Since my setup relies on Z2M, it only works for Z2M buttons for now. Sorry, ZHA is on my list, but if I waited until I had added everything I wanted in this automation, I would probably release it in 2036.
  • There are duplications and limitations, mostly caused by my current skill level. I am interested in making this more easy to use and more bulletproof. Please bear with me.

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Github link: Home Assistant Blueprint: Control Roborock vacuum with one button · GitHub

I’m looking forward to feedback and improvements, but please bear with me, I’m still new at it.

blueprint:
  name: Vacuum control via one single button
  description: The one vacuum control automation to rule them all, with the help of
    just one button.
  domain: automation
  homeassistant:
    min_version: 2024.6.0
  input:
    button_device:
      name: Button to control vacuum with
      description: This device will be used to control the vacuum
      selector:
        device: {}
    vacuum_device:
      name: Vacuum to be controlled
      description: This device will be used for all cleaning activities in this automation.
      selector:
        device:
          filter:
          - integration: roborock
          multiple: false
    vacuum_state_entity:
      name: Vacuum state entity
      description: This entity will be used to sync the automation internal state
        with the device state.
      selector:
        entity:
          filter:
          - integration: roborock
          multiple: false
    state_helper:
      name: Vacuum state helper
      description: This helper will be used for storing the current vacuum state.
      selector:
        entity:
          filter:
          - domain:
            - input_select
          multiple: false
    single_click_action:
      name: Single click action
      description: Command to be run on single click
      default: app_start
    single_click_params:
      name: Single click params
      description: String to be provided as arguments for single click action
      default: {}
      selector:
        object: {}
    double_click_action:
      name: Double click action
      description: String to be run on double click
      default: app_start
    double_click_params:
      name: Double click params
      description: String to be provided as arguments for double click action
      default: {}
      selector:
        object: {}
    single_click_while_cleaning_action:
      name: Single click action while cleaning
      description: Command to be run on single click while vacuum is cleaning
      default: app_pause
    single_click_while_cleaning_params:
      name: Single click while cleaning params
      description: String to be provided as argument for single click action while
        the vacuum is cleaning
      default: {}
      selector:
        object: {}
    single_click_while_paused_action:
      name: Single click while paused action
      description: Command to be run on single click while vacuum is paused
      default: app_start
    single_click_while_paused_params:
      name: Single click while paused params
      description: String to be provided as argument for single click action while
        the vacuum is paused
      default: {}
      selector:
        object: {}
    daily_cleanup_enabled:
      name: Enable daily cleanup
      description: Enabling this will launch a specific action + params at the designated
        time
      default: true
      selector:
        boolean: {}
    daily_cleanup_action:
      name: Daily cleanup action
      description: Command to be run every day at the specified time
      default: app_start
    daily_cleanup_params:
      name: Daily cleanup params
      description: String to be provided as argument for daily cleanup action
      default: {}
      selector:
        object: {}
    daily_cleanup_time:
      name: Time to run the daily task
      description: Automatic cleanup is run at configured time
      default: 09:00:00
      selector:
        time: {}
    cleaning_idle_timer:
      name: Cleaning idle timer
      description: Time to wait in paused state until return to dock is initiated
      default: 10
      selector:
        number:
          min: 5.0
          max: 15.0
          mode: slider
          step: 1.0
    automations_stop_time:
      name: Time to start Do Not Distub mode for this automation
      description: Automation will not run after this time
      default: '21:00:00'
      selector:
        time: {}
    automations_start_time:
      name: Time to stop Do Not Distrub mode for this automation
      description: Automation will run only after this time
      default: 08:00:00
      selector:
        time: {}
  source_url: https://gist.github.com/codingPear/53147a53af9d37d7c3b3484f4b47010b/
triggers:
- domain: mqtt
  device_id: !input button_device
  type: action
  subtype: single
  trigger: device
  id: button_single_click
- domain: mqtt
  device_id: !input button_device
  type: action
  subtype: double
  trigger: device
  id: button_double_click
- domain: mqtt
  device_id: !input button_device
  type: action
  subtype: long
  trigger: device
  id: button_long_click
- domain: mqtt
  device_id: !input button_device
  type: action
  subtype: hold
  trigger: device
  id: button_hold_click
- trigger: state
  entity_id:
  - !input vacuum_state_entity
  id: global_state_none
  to: returning
- trigger: state
  entity_id:
  - !input vacuum_state_entity
  to: cleaning
  id: global_state_cleaning
- trigger: state
  entity_id:
  - !input vacuum_state_entity
  to: paused
  id: global_state_paused
- trigger: state
  entity_id:
  - !input vacuum_state_entity
  to: paused
  id: global_state_paused_long_time
  for:
    hours: 0
    minutes: !input cleaning_idle_timer
    seconds: 0
- trigger: time
  at: !input daily_cleanup_time
  id: daily_cleanup_time
conditions:
- condition: time
  after: !input automations_start_time
  before: !input automations_stop_time
  weekday:
  - sat
  - fri
  - thu
  - wed
  - tue
  - mon
  - sun
actions:
- choose:
  - conditions:
    - condition: and
      conditions:
      - condition: trigger
        id:
        - button_single_click
    - condition: state
      entity_id: !input state_helper
      state: None
    sequence:
    - action: vacuum.send_command
      metadata: {}
      data:
        command: !input single_click_action
        params: !input single_click_params
      target:
        device_id: !input vacuum_device
    - action: input_select.select_option
      metadata: {}
      data:
        option: Cleaning
      target:
        entity_id: !input state_helper
    alias: Single press, vacuum docked
  - conditions:
    - condition: and
      conditions:
      - condition: trigger
        id:
        - button_double_click
    - condition: state
      entity_id: !input state_helper
      state: None
    sequence:
    - action: vacuum.send_command
      metadata: {}
      data:
        command: !input double_click_action
        params: !input double_click_params
      target:
        device_id: !input vacuum_device
    - action: input_select.select_option
      metadata: {}
      data:
        option: Cleaning
      target:
        entity_id: !input state_helper
    alias: Double press, vacuum docked
  - conditions:
    - condition: or
      conditions:
      - condition: trigger
        id:
          - button_long_click
      - condition: trigger
        id:
          - button_hold_click
    - condition: not
      conditions:
      - condition: state
        entity_id: !input state_helper
        state: None
    sequence:
    - action: vacuum.return_to_base
      metadata: {}
      data: {}
      target:
        device_id: !input vacuum_device
    - action: input_select.select_option
      metadata: {}
      data:
        option: None
      target:
        entity_id: !input state_helper
    alias: Long press, vacuum not docked
  - conditions:
    - condition: trigger
      id:
      - button_single_click
    - condition: state
      entity_id: !input state_helper
      state: Cleaning
    sequence:
    - action: vacuum.send_command
      metadata: {}
      data:
        command: !input single_click_while_cleaning_action
        params: !input single_click_while_cleaning_params
      target:
        device_id: !input vacuum_device
    - action: input_select.select_option
      metadata: {}
      data:
        option: Paused
      target:
        entity_id: !input state_helper
    alias: Single press, vacuum cleaning
  - conditions:
    - condition: trigger
      id:
      - button_single_click
    - condition: state
      entity_id: !input state_helper
      state: Paused
    sequence:
    - action: vacuum.send_command
      metadata: {}
      data:
        command: !input single_click_while_paused_action
        params: !input single_click_while_paused_action
      target:
        device_id: !input vacuum_device
    - action: input_select.select_option
      metadata: {}
      data:
        option: Cleaning
      target:
        entity_id: !input state_helper
    alias: Single press, vacuum paused
  - conditions:
    - condition: trigger
      id:
      - daily_cleanup_time
    - condition: state
      entity_id: !input state_helper
      state: None
    - condition: template
      value_template: !input daily_cleanup_enabled
    sequence:
    - action: vacuum.send_command
      metadata: {}
      data:
        command: !input daily_cleanup_action
        params: !input daily_cleanup_params
    - action: input_select.select_option
      metadata: {}
      data:
        option: Cleaning
      target:
        entity_id: !input state_helper
    alias: Daily cleanup
  - conditions:
    - condition: trigger
      id:
      - global_state_paused_long_time
    sequence:
    - action: vacuum.return_to_base
      metadata: {}
      data: {}
      target:
        device_id: !input vacuum_device
    - action: input_select.select_option
      metadata: {}
      data:
        option: None
      target:
        entity_id: !input state_helper
    alias: Vacuum idle
  - conditions:
    - condition: trigger
      id:
      - global_state_cleaning
    sequence:
    - action: input_select.select_option
      metadata: {}
      data:
        option: Cleaning
      target:
        entity_id: !input state_helper
    alias: Vacuum state changed from app, cleaning
  - conditions:
    - condition: trigger
      id:
      - global_state_paused
    sequence:
    - action: input_select.select_option
      metadata: {}
      data:
        option: Paused
      target:
        entity_id: !input state_helper
    alias: Vacuum state changed from app, paused
  - conditions:
    - condition: trigger
      id:
      - global_state_none
    sequence:
    - action: input_select.select_option
      metadata: {}
      data:
        option: None
      target:
        entity_id: !input state_helper
    alias: Vacuum state changed from app, none
mode: single


Backlog:

  • Add a switch for enabling or disabling the daily routine.
  • Add a way to select weekdays to run the daily routine.
  • Remove vacuum device and entity duplication. The user should only need to provide one or the other, not both.
  • Add ZHA support.

Changelog:

  • 2024-12-25: Initial release
  • 2024-12-27: Added option to disable scheduled daily cleanup. Added minimum Home Assistant version embedded in the blueprint details.
  • 2025-01-09: Added support for both Long and Hold events. Some buttons (looking and you, Sonoff) have the long event, while others (ex: Aqara, some Tuya ones) use the Hold event.
2 Likes

Hello HA Community,

Can someone please tell me if this blueprint works on other brands as well?

With my current understanding, I suspect it might work, since it’s using the vacuum entity, but cannot say for sure as I haven’t tested it on anything except my Roborock.

Thank you in advance!