Roborock S4 Lovelace Dashboard
Note: this post was written about the Roborock S4 but it should also work with the S5, S5 Max, S6 and S6 Pure.
This is part 3 of a 3 part post on the vacuum.
- Part 1 - Integrating the Roborock S4 in Home Assistant
- Part 2 - Roborock S4 Automations and Scripts in Home Assistant
- Part 3 - Roborock S4 Lovelace Dashboard (Reading Now!)
In this final post I will document the cards I’ve created for my roborock lovelace dashboard. I will briefly go over what each card does, any setup required and finally the lovelace yaml to reproduce the card in your own dashboard.
Vacuum State/Control Card
The vacuum state/control card provides some stats about the vacuum, information about it’s state, and a few common controls. The bottom of the card contains the following (from left to right):
- Current status (clicking opens up more details)
- Battery Icon based on current state
- Battery Percent (clicking opens up battery history)
- Locate Vacuum (clicking will call the vacuum locate service)
- Return to Dock (clicking will call the return_to_base service)
- Clean First Floor (clicking will initiate the script to clean the first floor)
Before I detail the yaml necessary to create the card we will first need to create
a few custom template sensors to extract some device state attributes that will
be added in our picture-elements
card.
The yaml below is for Home Assistant < 2021.11.0. If you are using >= 2021.11.0, look at the next section.
- platform: template
sensors:
roborock_s4_battery:
friendly_name: 'Roborock S4 Battery'
value_template: "{{state_attr('vacuum.roborock_s4', 'battery_level')}}"
unit_of_measurement: '%'
device_class: battery
roborock_s4_lifetime_cleaned_area:
friendly_name: 'Lifetime Cleaned Area'
value_template: "{{state_attr('vacuum.roborock_s4', 'total_cleaned_area')}}"
unit_of_measurement: ㎡
roborock_s4_lifetime_cleaning_time:
friendly_name: 'Lifetime Cleaning Time'
value_template: "{{(state_attr('vacuum.roborock_s4', 'total_cleaning_time') / 60)|round(1, 'floor')}}"
# NOTE: This date is converted to be timezone aware so that it plays nice
# with some other templating functions and filters.
roborock_s4_last_cleaned:
friendly_name: Relative time since last cleaning ended
value_template: "{{relative_time(strptime(as_timestamp(state_attr('vacuum.roborock_s4', 'clean_stop'))|timestamp_custom('%Y-%m-%d %H:%M:%S%z'), '%Y-%m-%d %H:%M:%S%z'))}}"
roborock_s4_lifetime_cleaning_count:
friendly_name: 'Lifetime Cleaning Count'
value_template: "{{state_attr('vacuum.roborock_s4', 'cleaning_count')}}"
The yaml below is for Home Assistant >= 2021.11.0. First you will need to enable 3 sensors from the configuration page. sensor.roborock_s4_total_clean_area
, sensor.roborock_s4_total_duration
and sensor.roborock_s4_total_clean_count
- platform: template
sensors:
# Sensors for roborock card.
roborock_s4_battery:
friendly_name: "Roborock S4 Battery"
value_template: "{{state_attr('vacuum.roborock_s4', 'battery_level')}}"
unit_of_measurement: "%"
device_class: battery
roborock_s4_lifetime_cleaned_area:
friendly_name: "Lifetime Cleaned Area"
value_template: "{{ states('sensor.roborock_s4_total_clean_area')|round(0, 'floor') }}"
unit_of_measurement: ㎡
roborock_s4_lifetime_cleaning_time:
friendly_name: "Lifetime Cleaning Time"
entity_id: sensor.roborock_s4_total_duration
value_template: >
{% set seconds = states('sensor.roborock_s4_total_duration') %}
{% set hours = int(seconds) / (60 * 60) %}
{{ hours|round(1, 'floor') }}
## NOTE: This date is converted to be timezone aware in PDT so that it plays nice
## with some other templating functions and filters.
roborock_s4_last_cleaned:
friendly_name: Last Cleaned Date/Time
value_template: >
{{ relative_time(strptime(as_timestamp(states('sensor.roborock_s4_last_clean_end'))|timestamp_custom('%Y-%m-%d %H:%M:%S%z'), '%Y-%m-%d %H:%M:%S%z')) }}
After the above template sensors are added to your configuration.yaml
and
Home Assistant is restarted you will see these in the States tab in the developer
tools.
This card also uses one custom card, lovelace-card-templater. This can be installed manually or via HACS.
type: 'custom:card-templater'
entities:
- vacuum.roborock_s4
card:
type: picture-elements
image: "/local/roborock_s4.jpg"
elements:
- type: state-label
entity: vacuum.roborock_s4
style:
left: 0
right: 0
bottom: 0
background-color: "rgba(0, 0, 0, 0.3)"
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
title: Battery
icon_template: '{{ state_attr("vacuum.roborock_s4", "battery_icon") }}'
style:
right: 171px
bottom: 0
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: state-label
title: Battery Level
entity: sensor.roborock_s4_battery
style:
right: 120px
bottom: 0px
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
title: Locate Vacuum
icon: 'mdi:map-marker'
style:
right: 90px
bottom: 0
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
title: Clean First Floor
icon: 'mdi:broom'
tap_action:
action: call-service
service: mqtt.publish
service_data:
payload: 1
topic: /nodered/vacuum_first_floor
style:
right: 0
bottom: 0
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
title: Return To Base
icon: 'mdi:home-map-marker'
tap_action:
action: call-service
service: vacuum.return_to_base
service_data:
entity_id: vacuum.roborock_s4
style:
right: 45px
bottom: 0
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: state-label
entity: sensor.roborock_s4_last_cleaned
prefix: 'Last ran '
suffix: ' ago'
style:
background-color: "rgba(0, 0, 0, 0.3)"
bottom: 85%
padding: 8px
font-size: 16px
line-height: 2px
color: white
transform: translate(0%,0%)
- type: state-label
prefix: "Ran "
suffix: "x"
entity: sensor.roborock_s4_lifetime_cleaning_count
style:
background-color: "rgba(0, 0, 0, 0.3)"
bottom: 85%
right: 0px
padding: 8px
font-size: 16px
line-height: 2px
color: white
transform: translate(0%,0%)
width: 25%
- type: state-label
prefix: "Ran for "
suffix: " hrs"
entity: sensor.roborock_s4_lifetime_cleaning_time
style:
background-color: "rgba(0, 0, 0, 0.3)"
bottom: 72%
right: 0px
padding: 8px
font-size: 16px
line-height: 2px
color: white
transform: translate(0%,0%)
width: 25%
- type: state-label
entity: sensor.roborock_s4_lifetime_cleaned_area
prefix: "Cleaned "
style:
background-color: "rgba(0, 0, 0, 0.3)"
bottom: 59%
right: 0px
padding: 8px
font-size: 16px
line-height: 2px
color: white
transform: translate(0%,0%)
width: 25%
If you are using Home Assistant >= 2021.11.0 change sensor.roborock_s4_lifetime_cleaning_count
to sensor.roborock_s4_total_clean_count
.
The asset image for the card can be downloaded here.
Vacuum Room Card
The vacuum room card allows you to specify a particular room along with the number of times to clean it. In order to use this card you will first have to obtain the coordinates for each of your rooms. You can read how I obtained these values in this post, the Home Assistant documentation also contains alternative instructions.
This card also requires 2 input_select
’s to be created before it can be used.
You will need to add these to your configuration.yaml
and restart Home Assistant (
or if you have the latest version of Home Assistant you can call the input_select.reload
service).
input_select:
vacuum_room_select:
name: Choose a room to clean
options:
- Bathroom
- Dining Room
- Guest Bedroom
- Hallway
- Kitchen
- Living Room
vacuum_room_repeat:
name: Number of times to clean the room
options:
- 1
- 2
- 3
initial: 1
icon: mdi:numeric
This card also uses one custom card, lovelace-card-templater. This can be installed manually or via HACS.
type: "custom:card-templater"
card:
type: entities
title: Vacuum a Room
show_header_toggle: false
entities:
- input_select.vacuum_room_select
- input_select.vacuum_room_repeat
- type: call-service
service: mqtt.publish
service_data:
topic: /nodered/vacuum_room
payload_template: >-
{
"room": "{{ states.input_select.vacuum_room_select.state }}",
"repeat": {{ states.input_select.vacuum_room_repeat.state }}
}
name: " "
icon: " "
entities:
- input_select.vacuum_room_select
- input_select.vacuum_room_repeat
When the Run
button is clicked it will publish an mqtt message to the /nodered/vacuum_room
topic. This will be read by the Vacuum Room Node-RED flow, which will properly create
the parameters and make the service call.
Maintenance Cards
The maintenance cards highlight the part of the vacuum, how many hours are left until it needs to be cleaned or replaced, and provides a way to reset the counter after you’ve done the maintenance.
Before we can use any of these cards we will need to create 2 custom template sensors for each card. The first will create a sensor for the percentage remaining and the second will create a sensor for the number of hours remaining.
The yaml below is for Home Assistant < 2021.11.0. If you are using >= 2021.11.0, look at the next section.
- platform: template
sensors:
# Used for the Filter maintenance card
roborock_s4_filter_remaining:
friendly_name: '% Filter Remaining'
unit_of_measurement: '%'
value_template: "{{((state_attr('vacuum.roborock_s4', 'filter_left') / 150) * 100) | round | int}}"
# Used for the Filter maintenance card
roborock_s4_filter_hrs_remaining:
friendly_name: 'Filter Remaining Hours'
unit_of_measurement: 'hrs'
value_template: "{{state_attr('vacuum.roborock_s4', 'filter_left')}}"
# Used for the Side Brush maintenance card
roborock_s4_side_brush_remaining:
friendly_name: '% Side Brush Remaining'
unit_of_measurement: '%'
value_template: "{{((state_attr('vacuum.roborock_s4', 'side_brush_left') / 200) * 100) | round | int}}"
# Used for the Side Brush maintenance card
roborock_s4_side_brush_hrs_remaining:
friendly_name: 'Side Brush Remaining Hours'
unit_of_measurement: 'hrs'
value_template: "{{state_attr('vacuum.roborock_s4', 'side_brush_left')}}"
# Used for the Main Brush maintenance card
roborock_s4_main_brush_remaining:
friendly_name: '% Main Brush Remaining'
unit_of_measurement: '%'
value_template: "{{((state_attr('vacuum.roborock_s4', 'main_brush_left') / 300) * 100) | round | int}}"
# Used for the Main Brush maintenance card
roborock_s4_main_brush_hrs_remaining:
friendly_name: 'Main Brush Remaining Hours'
unit_of_measurement: 'hrs'
value_template: "{{state_attr('vacuum.roborock_s4', 'main_brush_left')}}"
# Used for the Sensors maintenance card
roborock_s4_sensors_remaining:
friendly_name: '% Sensors Remaining'
unit_of_measurement: '%'
value_template: "{{((state_attr('vacuum.roborock_s4', 'sensor_dirty_left') / 30) * 100) | round | int}}"
# Used for the Sensors maintenance card
roborock_s4_sensors_hrs_remaining:
friendly_name: 'Sensors Remaining Hours'
unit_of_measurement: 'hrs'
value_template: "{{state_attr('vacuum.roborock_s4', 'sensor_dirty_left')}}"
The yaml below is for Home Assistant >= 2021.11.0. First you will need to enable 4 sensors from the configuration page. sensor.roborock_s4_filter_left
, sensor.roborock_s4_side_brush_left
, sensor.roborock_s4_sensor_dirty_left
and sensor.roborock_s4_main_brush_left
.
- platform: template
sensors:
# Used for the Filter maintenance card
roborock_s4_filter_remaining:
friendly_name: "% Filter Remaining"
unit_of_measurement: "%"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_filter_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ ((hours / 150) * 100) | round | int }}
# Used for the Filter maintenance card
roborock_s4_filter_hrs_remaining:
friendly_name: "Filter Remaining Hours"
unit_of_measurement: "hrs"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_filter_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ hours | round | int }}
# Used for the Side Brush maintenance card
roborock_s4_side_brush_remaining:
friendly_name: "% Side Brush Remaining"
unit_of_measurement: "%"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_side_brush_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ ((hours / 200) * 100) | round | int }}
# Used for the Side Brush maintenance card
roborock_s4_side_brush_hrs_remaining:
friendly_name: "Side Brush Remaining Hours"
unit_of_measurement: "hrs"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_side_brush_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ hours | round | int }}
# Used for the Main Brush maintenance card
roborock_s4_main_brush_remaining:
friendly_name: "% Main Brush Remaining"
unit_of_measurement: "%"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_main_brush_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ ((hours / 300) * 100) | round | int }}
# Used for the Main Brush maintenance card
roborock_s4_main_brush_hrs_remaining:
friendly_name: "Main Brush Remaining Hours"
unit_of_measurement: "hrs"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_main_brush_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ hours | round | int }}
# Used for the Sensors maintenance card
roborock_s4_sensors_remaining:
friendly_name: "% Sensors Remaining"
unit_of_measurement: "%"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_sensor_dirty_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ ((hours / 30) * 100) | round | int }}
# Used for the Sensors maintenance card
roborock_s4_sensors_hrs_remaining:
friendly_name: "Sensors Remaining Hours"
unit_of_measurement: "hrs"
value_template: >
{% set seconds = int(states('sensor.roborock_s4_sensor_dirty_left')) %}
{% set hours = seconds / (60 * 60) %}
{{ hours | round | int }}
After these are added to your configuration.yaml
and you have restarted Home
Assistant you can then add the following picture-elements
cards to your lovelace
configuration.
- type: horizontal-stack
cards:
- type: picture-elements
image: /local/side_brush.png
elements:
- type: state-label
entity: sensor.roborock_s4_side_brush_remaining
title: "% Remaining Until Side Brush Should Be Replaced"
style:
font-size: 30px
color: orange
left: 0px
right: 0px
bottom: 0px
background-color: "rgba(0, 0, 0, 0.3)"
transform: translate(0%,0%)
- type: state-label
title: Hours Remaining Until Side Brush Should Be Replaced
entity: sensor.roborock_s4_side_brush_hrs_remaining
suffix: " left"
style:
right: 0px
bottom: 0px
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
icon: mdi:restart
title: Reset Hours
tap_action:
action: call-service
service: vacuum.send_command
service_data:
entity_id: vacuum.roborock_s4
command: reset_consumable
params: ["side_brush_work_time"]
confirmation:
text: Are you sure you want to reset the hours remaining counter for replacing the side brush?
style:
top: 0px
right: 0px
padding: 7px
transform: translate(0%,0%)
- type: picture-elements
image: /local/sensors.png
elements:
- type: state-label
entity: sensor.roborock_s4_sensors_remaining
title: "% Remaining Until Sensors Should Be Cleaned"
style:
font-size: 30px
color: orange
left: 0px
right: 0px
bottom: 0px
background-color: "rgba(0, 0, 0, 0.3)"
transform: translate(0%,0%)
- type: state-label
title: "Hours Remaining Until Sensors Should Be Cleaned"
entity: sensor.roborock_s4_sensors_hrs_remaining
suffix: " left"
style:
right: 0px
bottom: 0px
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
icon: mdi:restart
title: Reset Hours
tap_action:
action: call-service
service: vacuum.send_command
service_data:
entity_id: vacuum.roborock_s4
command: reset_consumable
params: ["sensor_dirty_time"]
confirmation:
text: Are you sure you want to reset the hours remaining counter for cleaning the sensors?
style:
top: 0px
right: 0px
padding: 7px
transform: translate(0%,0%)
- type: horizontal-stack
cards:
- type: picture-elements
image: /local/filter.png
elements:
- type: state-label
title: "% Remaining Until Filter Should Be Replaced"
entity: sensor.roborock_s4_filter_remaining
style:
font-size: 30px
color: orange
left: 0px
right: 0px
bottom: 0px
background-color: "rgba(0, 0, 0, 0.3)"
transform: translate(0%,0%)
- type: state-label
title: "Hours Remaining Until Filter Should Be Replaced"
entity: sensor.roborock_s4_filter_hrs_remaining
suffix: " left"
style:
right: 0px
bottom: 0px
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
icon: mdi:restart
title: Reset Hours
tap_action:
action: call-service
service: vacuum.send_command
service_data:
entity_id: vacuum.roborock_s4
command: reset_consumable
params: ["filter_work_time"]
confirmation:
text: Are you sure you want to reset the hours remaining counter for replacing the filter?
style:
top: 0px
right: 0px
padding: 7px
transform: translate(0%,0%)
- type: picture-elements
image: /local/main_brush.png
elements:
- type: state-label
title: "% Remaining Until Main Brush Should Be Replaced"
entity: sensor.roborock_s4_main_brush_remaining
style:
font-size: 30px
color: orange
left: 0px
right: 0px
bottom: 0px
background-color: "rgba(0, 0, 0, 0.3)"
transform: translate(0%,0%)
- type: state-label
title: "Hours Remaining Until Main Brush Should Be Replaced"
entity: sensor.roborock_s4_main_brush_hrs_remaining
suffix: " left"
style:
right: 0px
bottom: 0px
padding: 10px
font-size: 16px
line-height: 16px
color: white
transform: translate(0%,0%)
- type: icon
icon: mdi:restart
title: Reset Hours
tap_action:
action: call-service
service: vacuum.send_command
service_data:
entity_id: vacuum.roborock_s4
command: reset_consumable
params: ["main_brush_work_time"]
confirmation:
text: Are you sure you want to reset the hours remaining counter for replacing the main brush?
style:
top: 0px
right: 0px
padding: 7px
transform: translate(0%,0%)
Clicking on the reset icon will pop up a confirmation alert that you will have to click on to continue with the action. This was added to prevent an accidental click on the card from resetting the counter.
The assets for the above cards can be found below: