Trigger something for every X square meters vacuumed

Hi!

I have a Xiaomi Mi RoboRock S6 and I find that the notifications are lacking. I would like to trigger a script that sends a notification telling me to empty the bin based on the area cleaned by the robot. I have set up the xiaomi_miio integration and I have access to the total area cleaned in {{ state_attr('vacuum.robocop', 'total_cleaned_area') }}

How can I set up an automation that is triggered for every 100 square meters cleaned?

Sending a notification I know how to do but it’s the trigger I’m unsure of how to define.

1 Like

You could define an input_number, say:

input_number:
  vacuum_area:
    min: 0
    max: 10000
    step: 100

Then when you start the vacuum, set it to 100:

- service: input_number.set_value
  entity_id: input_number.vacuum_area
  data:
    value: 100
- # START VACUUM

Then have an automation something like this:

- trigger:
  - platform: template
    value_template: >
      {{ state_attr('vacuum.robocop', 'total_cleaned_area') >=
         states('input_number.vacuum_area')|int }}
  action:
  - service: input_number.increment
    entity_id: input_number.vacuum_area
  - # SEND NOTIFICATION

Interesting! I haven’t tried it yet but I’m wondering… when the total_cleaned_area is larger than 100 won’t that trigger always fire whenever the vacuum starts? Since input_number is set to 100 on vacuum start and total_cleaned_area will just keep increasing.

I have no idea. I don’t use any vacuum integrations. I just assumed it would start at zero again each time it was started. If not, then adjust accordingly.

I think I’ve found a solution myself. Basically whenever the vacuum returns to the dock, compare the total cleaned area in the from_state with the to_state and see if it has increased by X square meters.

In the example below, for every 40 square meters the vacuum has finished cleaning I’ll get a notification when it returns to the base with an action to send it to the kitchen so I can easily empty its bin.

automations.yaml

- id: '1234'
  alias: Send notification when vacuum returns to base
  trigger:
  - entity_id: vacuum.robocop
    platform: state
    to: returning
  condition:
  - condition: template
    value_template: '{{ (trigger.to_state.attributes.total_cleaned_area / 40)|int
      > (trigger.from_state.attributes.total_cleaned_area / 40)|int }}'
  action:
  - data:
    service: notify.mobile_app_my_mobile
      data:
        actions:
        - action: send_robocop_to_waste_bin
          title: Go to waste bin
      message: Finished cleaning, returning to base...
      title: Robocop

- id: '1235'
  alias: Send Robocop to waste bin on notification action
  trigger:
  - event_data:
      action: send_robocop_to_waste_bin
    event_type: mobile_app_notification_action
    platform: event
  condition: []
  action:
  - data:
      command: app_goto_target
      params: [25000, 25000]
    entity_id: vacuum.robocop
    service: vacuum.send_command
1 Like

This is in case you clean a big space on that single time.
How would you solve that for multiple cleaning cycles?
I mean, i’d like my roborock to go to the bin when it’s own bin is full.

It might take him 3-4 cleaning cycles (that are being done on different days).
How would you solve that?
At first i thought just count the number of cleaning cycles it makes and every 4 - send it to the bin,
However the amount of coverage it does may also very to where one time he might clean small spaces and other time he might clean big places - so the calculation needs to be according to the square foot he covers.

How do i do that?

No, my solution above is actually for the case you just mentioned (but I can see by how I worded my answer that it might not come across as so).

Basically everytime the robot finishes it compares the “total area covered” from before starting the cleaning with the “total area covered” after completion to see if the number of “50 square meters covered” has increased.

It’s only this part of the code in my answer where all the magic happens:

  condition:
  - condition: template
    value_template: '{{ (trigger.to_state.attributes.total_cleaned_area / 40)|int
      > (trigger.from_state.attributes.total_cleaned_area / 40)|int }}

Example 1:

  • Robot has covered 99m² in total, that’s 1 full 50m²
  • Robot starts cleaning, when complete the total area covered is now 129m²
  • 129m² is two full 50m² so the “number of 50m²” har now increased and therefore HA will send a
    notification where it’s asking me to send it to the bin

Example 2

  • If robot goes from 129m² to 149m² in area total covered between start and end in one (or more) cleaning cycles the “number of 50m² since ever” still won’t change on cleaning complete so no automation triggered

Do note that my solution just sends a notification when this happens but you could probably set it up so that it actually goes to the bin on every cleaning complete where “number of total 50m²” has increased.

Don’t forget to empty it though before the battery runs out :wink:

Thank you, this is a great answer.
I might have not explained myself correctly since this is not what i meant.

I mean that i’d like to get notification (for the purpose of simplify that question) everytime that the bin is full.
Since we don’t have a sensor for that, i’m assuming that every 50sqm that bin will get full (again, just for the sake of it - i don’t know that exact number but that doesn’t meter right now as it’s easily changeable).

What i’d like is to have the ability that every total of 50sqm the vacuum will go next to the trash can.
Meaning that for example, he would do the following:

  • Robot has covered 30m² in total, nothing happens here
  • Robot has covered 30m² in total, he now goes to the trash can (as it’s now the 30sqm from step one, + 30sqm from this step is total of 60sqm which will pass the 50sqm requirement).

So the solution suggest doesn’t cover this case.
I basically need some kind of a way to save the state of the vacuum once as a reference and use that reference to compare with the new state.
Comparing only “from_state” and “to_state” is prone to errors as imagine a case you clean the a room A LOT, and it’s only 39sqm - after a while the bin will be clogged but you will never get notified…

The problem is even bigger, as even if i’ll used a static number to compare with, once i clean the bin, that reference number need to be switched with the current number (the number that was present at the moment of cleaning the bin).

It might be solvable using input_number that keep incrementing every time i divide by 40

The total_cleaned_area refers to the area vacuumed by the robot in it’s entire lifespan, since you first set it up. For me it’s currently 6062m² (see pic).

Which means that if I start cleaning now, my trigger.from_state.attributes.total_cleaned_area will be equal to 6062. If I want notifications for every 50m² then as soon as the next cleaning completes and the trigger.to_state.attributes.total_cleaned_area surpasses 7000 the automation will trigger.

But yeah there are some flaws here which I guess is what you’re trying to point out:

  • It’s only when the cleaning completes that this happens so you could in theory have your robot go on for longer than you want it to. I guess you could change the trigger so it actually checks for every m² cleaned and then aborts the ongoing task to head to the bin instead (that’s not what i want myself though)
  • It’s not reset when it goes to the bin, so the accuracy of how much it has cleaned since it last visited the bin isn’t that great

So to summarize, my solution makes it so that if my apartment is 50m² and I want to be reminded circa every second cleaning of the whole apartment then this takes care of that if I set the number to 100m².

I don’t think it will work.
I totally understand what you’re saying.

I’ll try to simplify my explanation.
Your total_cleaned_area is updating every time you clean, right? as you said it’s the accumulation of all of your cleaned area.

So in your case, say you want to get notified every 40 sqm (Square meter), here’s the problem:

  • total_cleaned_area starts with 6062.
  • You run room cleanup which let’s say is only 30 sqm (not 40 sqm) - nothing triggers
  • Once the cleanup is done, the total_cleaned_area is no 6092 (6062 + 30)
  • You run another room cleanup which is 30 sqm (again, not 40) and the comparison of the new_state to the old_state would be not compared to the 6062 rather to the updated number (because it’s a new cleaning run) which is now 6092.
  • Once the cleanup is done, the total_cleaned_area would now be 6122 (6092 + 30) - which again doesn’t activate the automation and it’s now been 60 sqm worth of cleaning (30 sqm * 2 runs).

And you can basically repeat that process over and over again without the automation will ever triggers itself. your bin can be full and you’ll never be notified.

It’s only when you run full cleaning of your entire house, is when the automation will be triggered.

The flaw here is that the from_state.attributes.total_cleaned_area is keep getting updated

*If you don’t use zone cleanups like i do - you don’t have that problem.

I must say i love your passion on this topic and I love a good challenge to see if I’ve covered my bases :slight_smile:

I think the misunderstanding here is that I believe you think I’m comparing the difference between total_cleaned_area (from_state) and total_cleaned_area (to_state) but I’m not.

What I’m comparing is the number of 50m2 that can fit into total_cleaned_area (from_state) vs into total_cleaned_area (to_state). If the latter is bigger than the former it means the robot must have passed a multiple of 50m2, i.e. it’s gone from 6062 to 6101 (or from 6099 to 6101) but not when going from 6062 to 6099. Speaking in mathematical terms it’s all about the integer division.

So, to use your example and 40m2 as the “limit”, this is actually what happens:

  1. total_cleaned_area starts with 6062. 6062/40 = 151,55 or simply 151 with integer division. You could see that as the number of how many 40m2 runs have been made since first setup.
  2. I run room cleanup which is only 30m2.
  3. Once cleanup is done and the vacuum returns to charging, the to_state’s total_cleaned_area will be 6092 (6062+30) and the integer division will be 6092/40=152,3 → 152.
    • (trigger.to_state.attributes.total_cleaned_area / 40)|int = 152
    • (trigger.from_state.attributes.total_cleaned_area / 40)|int = 151
    • 152 > 151 → Automation is triggered
  4. I run another cleanup of 30m2, total_cleaned_area (from_state) is now 6092 (and that integer divided by 40 is 152)
  5. When cleanup completes, total_cleaned_area (to_state) is now 6122 which will trigger the automation because 153*40=6120 and 153>152 :slight_smile:
  6. If this last cleanup would have been only 20m2 then the total_area_cleaned would have ended up as 6112 and then no automation would have been triggered because 6112 divided by 40 equals the same as 6092/40 for integer division.

Basically what I’ve done is that whenever the vacuum surpasses 0, 40, 80 … 6040, 6080, 6120… m2 total area cleaned, the automation will trigger.

The feature here is that the from_state.attributes.total_cleaned_area is from the start of the cleanup run when the automation trigger is “when state goes to returning:slight_smile:

And this is how I’m using it:


Now it only says Finished cleaning, returning to base.. For every 50m2 cleaned it will also add “:warning: Check dustbin” to the message and for every 100m2 cleaned it says “:warning: Check dustbin and filter” instead :slight_smile:

All this because there’s no good notifications and sensors on Xiaomi robot vacuums :sweat_smile: But I do love my Robocop and Home Automation :smiley:

why not use the utility meter integration so you can count your totals on daily,. weekly or monthly basis…

utility_meter:
  energy:
    source: sensor.xxx
    cycle: monthly

I’ve got to admit, as a software eng. i’m shocked i’ve got so confused with this simple (yet sophisticated) way.
Thank you for the clarification.
I love this conversation!

Now there’s a new problem.
My automation actully does 2 things once it’s discover that the total_cleaned_area (from_state/30) < total_cleaned_area (to_state/30)

  1. Sends the roborock to the wait next to the trash bin
  2. Send notification to my phone after a minute (to make sure it arrived to the trash can already) letting me know to come and clean him.

The problem is that i have 2 other automations for scheduled cleanups.
every day at 23:00
and again at 10:00 on weekends (which also cleans more rooms).

I wonder what will happen if after one of the scheduled cleanups at 23:00 he finishes and then goes to stand next to the trash bin - but it’s late and we are asleep.
And by the time we wake up (if it’s after 10:00 for some reason and we didn’t manage to clean him and send him back to the dock) - the automation of 10:00 will start.

I wonder if it will start cleaning or skip that automation.

I’ll check

Covering distance cleaned, energy consumption or time that he was active is pretty much the same thing just different methods. but it will do the same trick.
The only preference for covering distance is that it’s more intuitive to us as humans… rather then energy consumption (unless you’re experienced enough).

But out of curiosity - i would you do that with the energy sensor?

For your information: after I updated to Home Assistant 2021.12.7 and removed my Xiaomi vacuum config from YAML in favor of UI my code above stopped working. This is because the total_cleaned_area is now an individual sensor instead of an attribute of the vacuum.

Solution:
Let the automation trigger on changes to sensor.robocop_total_clean_area instead. This works because this sensor is only updated once cleaning completes (instead of continuously). Then replace trigger.from_state.attributes.total_cleaned_area with int(trigger.from_state.state) and vice versa for the to state.

Or use inspiration from the following code snippet. Basically this will show different text in the notification:

  • For every new 40 m2 cleaned, it says “Empty dustbin”
  • For every new 80 m2 cleaned, it says “Empty dustbin and clean filter.”
  • And nothing if none of the above applies.

automations.yaml

- id: '123456789'
  alias: Send notification when vacuum returns to base with action to go to waste bin
  trigger:
    entity_id: sensor.robocop_total_clean_area
    platform: state
  action:
  - service: notify.mobile_app
    data_template:
      title: >
        {% set clean_area = states('sensor.robocop_last_clean_area') | round(0, 0) ~ ' ' ~ state_attr('sensor.robocop_last_clean_area', 'unit_of_measurement') %}
        {% set clean_duration = int(states('sensor.robocop_last_clean_duration')) // 60 ~ ' min' %}
        Robocop - Clean-up complete: {{ clean_area }}, {{ clean_duration }}
      message: >
        {% set apartment_size = 40 %}
        {% set clean_area_old = trigger.from_state.state | int %} 
        {% set clean_area_new = trigger.to_state.state | int %}
        {% if clean_area_new // (apartment_size*2) > clean_area_old // (apartment_size*2) -%}
          ⚠️ Empty dustbin and clean filter.
        {%- elif clean_area_new // apartment_size > clean_area_old // apartment_size -%}
          ⚠️ Empty dustbin.
        {%- endif %}
        Finished cleaning, returning to base.
      data:
        channel: Vacuum
        clickAction: "entityId:vacuum.robocop"
        notification_icon: "mdi:robot-vacuum"
        actions:
        - action: send_robocop_to_waste_bin
          title: Go to waste bin

This also uses // for integer division instead of simply / and | int (converting to int) as I did before. And with the help of some variables it becomes much easier to follow and understand :wink:

image

Thank you,
Yeah… mine stopped working as well.
I’m now playing around with it trying to see how to get it work with the same method as earlier.

My problem is that i want it to be sent for “cleaning” itself every absolute 40meters of cleaning and not relative 40meter of cleaning.

I see that the new sensor only tests relative cleaning time\area, correct? :\

The sensor.roborock_total_clean_area behaves the same as the previous total_cleaned_area attribute - they both return the absolute total and they both only updates once cleaning completes.

Do you want the robot to be “sent for cleaning” even when it’s busy vacuuming (basically stop what it’s doing)? Or only after vacuuming is complete?

My previous code used to sent the roborock (alias “alfred”) to wait for me to empty it every 60meters but only once it was back to the docking station and only at 8:00+ (so if it was cleaning at 23:00 for example and went back to the docking, and only at 8:00 it went to the trashcan - that way it won’t empty it’s battery while i’m asleep and also won’t interrupt us during the night when walking into the friedge or something like that).
*It also updated a input parameters that i can use to see when was the last time it was sent to be cleaned (in case i wanna know).

The current " `roborock_total_clean_area’" seem to only expose the last cleaned area and not the absolute value, see image attached.

Therefor my current code seem to send it to the trashcan after every time it cleans.
The problem is with this part of the code:
{{ (trigger.to_state.state|int / 60) > (trigger.from_state.state|int /60)}}

This is the entire code:

alias: Alfred Notifying When he's Full After 60sq
description: This sends Alfred to the trash can to wait to be cleaned.
trigger:
  - platform: state
    entity_id: sensor.roborock_vacuum_s5_last_clean_area
condition:
  - condition: template
    value_template: >-
      {{ (trigger.to_state.state|int / 60) > (trigger.from_state.state|int /
      60)}}
action:
  - wait_template: |-
      {% if states('vacuum.alfred') == "docked" %}
        True
      {% else %}
        False
      {% endif %}
    timeout: '3:00'
    continue_on_timeout: true
  - wait_template: >-
      {% if ((now().strftime('%H:%M')) > "08:40") and ((now().strftime('%H:%M'))
      < "20:00") %}

      true

      {% else %}

      false

      {%endif%}
    timeout: '13:00'
  - service: script.vacuum_maintenance_trash_can
  - delay:
      hours: 0
      minutes: 1
      seconds: 10
      milliseconds: 0
  - service: notify.mobile_app_michal_iphone_12
    data:
      message: >-
        Alfred is waiting for you next to the trash can, please empty the bin
        and send Alfred back to the dock.
      title: Please Clean Alfred
  - service: input_datetime.set_datetime
    target:
      entity_id: input_datetime.alfred_last_emptied
    data:
      date: '{{ now().strftime("%d/%m/%y") }}'
      time: '{{ now().strftime("%H:%M:%S") }}'
mode: single

Ah, looking at that screenshot you only seem to have the “last_ckeaned_area” sensor and not any “total_clean_area”. After the update I believe you have to enable a few sensors yourself.

Go to Configuration > Devices & services > Alfred Xiaomi Miio > click 16 entities

Here you should see a “total_clean_area” sensor. If it has a disabled icon next to it then click it see a toggle where you can enable it. Hope that helps!

I really like your automation by the way. Just a button in the notification as I have isn’t enough for me to clean it as often as I should :stuck_out_tongue:

First of, thank you!
So i’ve enabled those sensors and now my automation triggered by “sensor.roborock_vacuum_s5_total_clean_area” change.
I hope now it will work…

Regarding the automation, thank you!
It’s basically sends the roborock to the exact spot which is the most coinvent to be located for me to empty it.
It then sends a notification to my wife :sweat_smile: to clean it.

And it only does that in hours that we’re awake - so it won’t run out of battery or freak us out if he’ll be there during the night.
One of the best automations i’ve got.

1 Like