TP-Link Tapo RV10/RV30

I’m very confused on how you got that. Can you please teach a noob like myself. Can you start/ stop it?

The 2025.2 beta is now available and ships with the initial support for these devices! :tada: Here’s a screenshot showing how the device page looks like on my RV20 Max Plus:

3 Likes

I was very excited to see that vacuums were being added to 2025.2, but after updating saw the update only supports the RV20 Max Plus and RV30 Max. Is there any plan to support the RV10?

Awesome to see this in 2025.2, so encouraging! Thankyou to everyone who has been working on it. I have an RV30C (Roger the Robovac) and looking forward to being able to tell him to start one of his saved routines via HA, maybe in a future update. Also happy to be part of testing if that would help. Thanks again

2 Likes

I also have a rv10. This doesn’t work (yet). Are you guys planning to get this implemented as well?

Thanks for the thanks, it has been a great team effort (as noted in the release notes Release 0.10.0 · python-kasa/python-kasa · GitHub) to get a new device family supported! Given there has been no (issue) reports so far, it’s either working or users are just shy on reporting :slight_smile:

The supported devices list is generated automatically based on information from users, so if you have a device that is working correctly but not listed, feel free to follow the instructions in Contributing — python-kasa documentation to contribute a test fixture file.

My original RV30 Max has experienced a side brush error which made the entire unit unusable within the first 2 months of ownership. I contacted support and started a RMA and now have the replacement.

I’m still facing Home Assistant hangs/restarts when I add the device to my integration. Within some hours the entire system hangs and HA goes offline. It behaves properly when I disable the device from the integration page. I’ve added a ticket : TP-Link RV30 Max vacuum causes HA to run out of memory and crash · Issue #139995 · home-assistant/core · GitHub
Has anyone else experienced this?

My RV30 Max Plus got the Matter update at some point in the last week or so. Exciting!

Good afternoon, I purchased a Tapo RV20 Max robot vacuum cleaner, and I’ve integrated it into HA without any problems using the TP-Link Smart Home integration. For your information, as an amateur HA user, it’s very useful.

1 Like

Hi,

Firstly … EXCELLENT WORK!!! integration was a breeze!

Quick question?..
Within the Tapo application under rooms tab, created a clean “Preset” called “Dining Kitchen” for the unit to only clean the fining kitchen area as I am planning to schedule cleans for specific rooms in the house on certain days?

Is it possible to send the command from the Home Assistant integration to start that preset?.

I tried the send_command option with the parameter “Dining Kicthen” but receive the error "HomeAssistantError: Validation error: Entity vacuum.rv20 does not support action “vacuum.send_command”?

is this option available? I may be using the wrong syntax.

Keep up the great work!!!

Hello, thank you for your work!
Do you know if there is beta version or plans for support for RV30 Max Plus ?

I just got the RV30 max and I just connected it via Matter no issues really basic stop dock hoover - no mapping as such but enough to automate

I found a workaround automation to control cleaning progress. My purpose is to know when a sepicific area is going to be cleaned in order to remove chairs etc. Tapo gives you the possibility to create shortcuts on iPhone and I used them to launch scheduled cleaning programs from Home Assistant. iOS will send a notification that a program is starting and if you click on the banner it will launch the tapo preset. if can be of help use it!

description: Crea dei reminder per ricordare l'avvio delle pulizie al primo piano
triggers:
  - at: "08:59:02"
    id: Camera
    alias: "Camera: Ma Ve Avvio ore 9,15"
    weekday:
      - tue
      - fri
    trigger: time
  - at: "10:31:07"
    id: Bagno
    alias: Bagno Me Avvio ore 10,15
    weekday:
      - wed
    trigger: time
  - at: "10:47:28"
    id: Tommaso
    alias: Tommaso Ma Ve Avvio ore 11,15
    weekday:
      - tue
      - fri
    trigger: time
  - at: "10:14:43"
    id: Giacinta
    alias: Giacinta Ogni due Sabati Avvio ore 10,30
    weekday:
      - sat
    trigger: time
  - at: "11:26:22"
    id: Tinello
    alias: Tinello ogni due Sabati Avvio ore 11,40
    weekday:
      - sat
    trigger: time
  - at: "10:07:29"
    id: Cantina
    alias: Cantina Ogni due Sabati Avvio ore 10,20
    weekday:
      - sat
    trigger: time
conditions:
  - condition: template
    value_template: |
      {% if trigger.id in ['Giacinta', 'Tinello'] %}
        {{ now().isocalendar().week % 2 == 0 }}
      {% elif trigger.id == 'Cantina' %}
        {{ now().isocalendar().week % 2 == 1 }}
      {% else %}
        true
      {% endif %}
actions:
  - variables:
      zona: "{{ schedule[trigger.id].zona }}"
      shortcut_asp: "{{ schedule[trigger.id].aspirazione }}"
      shortcut_lav: "{{ schedule[trigger.id].lavaggio }}"
  - alias: Annuncio avvio aspirazione
    data:
      target: "{{ notifiche_alexa }}"
      message: >
        <prosody rate="130%">"Tra 15 minuti inizia l'aspirazione in {{ zona }}.
        Preparare l'ambiente per evitare intoppi."</prosody>
      data:
        type: tts
    action: notify.alexa_media
  - delay:
      hours: 0
      minutes: 7
      seconds: 30
      milliseconds: 0
  - alias: Annuncio avvio aspirazione
    data:
      target: "{{ notifiche_alexa }}"
      message: >
        <prosody rate="130%">"Tra 7 minuti inizia l'aspirazione in {{ zona }}.
        Preparare l'ambiente per evitare intoppi e tenere il telefonino a
        portata di mano"</prosody>
      data:
        type: tts
    action: notify.alexa_media
  - delay:
      hours: 0
      minutes: 6
      seconds: 15
      milliseconds: 0
  - alias: Annuncio avvio aspirazione
    data:
      target: "{{ notifiche_alexa }}"
      message: >-
        <prosody rate="130%">"Tra poco inizia l'aspirazione in {{ zona }}.
        Pronti con il telefonino. Liberare l'ambiente."</prosody>
      data:
        type: tts
    action: notify.alexa_media
  - data:
      message: Avvio aspirazione in {{ zona }}
      data:
        shortcut:
          name: "{{ shortcut_asp }}"
    action: notify.mobile_app_iphone_di_xxxxxx
    enabled: true
    alias: Richiesta avvio aspirazione tramite notifica xxxxxx
  - data:
      message: Avvio aspirazione in {{ zona }}
      data:
        shortcut:
          name: "{{ shortcut_asp }}"
    action: notify.mobile_app_iphone_di_xxxxxx
    enabled: true
    alias: Richiesta avvio aspirazione tramite notifica xxxxxxxx
  - data:
      message: Avvio aspirazione in {{ zona }}
      data:
        shortcut:
          name: "{{ shortcut_asp }}"
    action: notify.mobile_app_xxxxxxx
    enabled: true
    alias: Richiesta avvio aspirazione tramite notifica xxxxxxxx
  - alias: Attesa conferma avvio aspirazione
    wait_for_trigger:
      - entity_id:
          - vacuum.robot_primo_piano
        to: cleaning
        trigger: state
    timeout: "00:03:00"
    continue_on_timeout: true
  - alias: Verifica avvio o timeout aspirazione
    choose:
      - conditions:
          - condition: state
            entity_id: vacuum.robot_primo_piano
            state: cleaning
        sequence:
          - alias: Aspirazione avviata correttamente
            action: notify.alexa_media
            data:
              target: "{{ notifiche_alexa }}"
              message: >
                <prosody rate="130%">Aspirazione avviata in {{ zona
                }}.</prosody>
              data:
                type: tts
    default:
      - alias: "Timeout: aspirazione annullata"
        action: notify.alexa_media
        data:
          target: "{{ notifiche_alexa }}"
          message: >
            <prosody rate="130%">Aspirazione in {{ zona }} non confermata entro
            3 minuti. Operazione annullata.</prosody>
          data:
            type: tts
      - alias: Crea notifica di timeout
        action: persistent_notification.create
        data:
          title: Automazione Pulizia - Timeout
          message: >-
            Aspirazione non confermata in {{ zona }} entro 3 minuti. Automazione
            annullata.
      - alias: Interrompi automazione
        stop: Aspirazione non confermata, automazione terminata.
  - wait_for_trigger:
      - entity_id:
          - sensor.robot_primo_piano_cleaning_progress
        to: "100"
        for:
          hours: 0
          minutes: 0
          seconds: 10
        trigger: state
  - alias: Annuncio aspirazione completata
    data:
      target: "{{ notifiche_alexa }}"
      message: >
        <prosody rate="130%">"Aspirazione completata in {{ zona }}. Inserire il
        panno e avviare il lavaggio."</prosody>
      data:
        type: tts
    action: notify.alexa_media
  - data:
      message: Avvio lavaggio in {{ zona }}
      data:
        shortcut:
          name: "{{ shortcut_lav }}"
    action: notify.mobile_app_iphone_di_xxxxxxxx
    enabled: true
    alias: Richiesta avvio lavaggio tramite notifica xxxxxx
  - data:
      message: Avvio lavaggio in {{ zona }}
      data:
        shortcut:
          name: "{{ shortcut_lav }}"
    action: notify.mobile_app_iphone_di_xxxxxx
    enabled: true
    alias: Richiesta avvio lavaggio tramite notifica xxxxxx
  - data:
      message: Avvio lavaggio in {{ zona }}
      data:
        shortcut:
          name: "{{ shortcut_lav }}"
    action: notify.mobile_app_xxxxxxx
    enabled: true
    alias: Richiesta avvio lavaggio tramite notifica xxxxxxx
  - alias: Attesa conferma avvio lavaggio
    wait_for_trigger:
      - entity_id:
          - vacuum.robot_primo_piano
        to: cleaning
        trigger: state
    timeout: "00:08:00"
    continue_on_timeout: true
  - alias: Verifica avvio o timeout lavaggio
    choose:
      - conditions:
          - condition: state
            entity_id: vacuum.robot_primo_piano
            state: cleaning
        sequence:
          - alias: Lavaggio avviata correttamente
            action: notify.alexa_media
            data:
              target: "{{ notifiche_alexa }}"
              message: |
                <prosody rate="130%">Lavaggio avviato in {{ zona }}.</prosody>
              data:
                type: tts
    default:
      - alias: "Timeout: lavaggio annullato"
        action: notify.alexa_media
        data:
          target: "{{ notifiche_alexa }}"
          message: >
            <prosody rate="130%">Lavaggio in {{ zona }} non confermato entro 8
            minuti. Operazione annullata.</prosody>
          data:
            type: tts
      - alias: Crea notifica di timeout
        action: persistent_notification.create
        data:
          title: Automazione Pulizia - Timeout
          message: >-
            Lavaggio non confermato in {{ zona }} entro 3 minuti. Automazione
            annullata.
      - alias: Interrompi automazione
        stop: Lavaggio non confermato, automazione terminata.
  - wait_for_trigger:
      - entity_id:
          - sensor.robot_primo_piano_cleaning_progress
        to: "100"
        for:
          hours: 0
          minutes: 0
          seconds: 10
        trigger: state
  - alias: Annuncio lavaggio completato
    data:
      target: "{{ notifiche_alexa }}"
      message: >
        <prosody rate="130%">"Pulizia completata in {{ zona }}. Verificare
        eventuale manutenzione."</prosody>
      data:
        type: tts
    action: notify.alexa_media
mode: single
variables:
  schedule:
    Camera:
      zona: Camera
      aspirazione: Inizio Camera aspirazione
      lavaggio: Inizio Camera lavaggio
    Bagno:
      zona: Bagno
      aspirazione: Inizio Bagno aspirazione
      lavaggio: Inizio Bagno lavaggio
    Sala TV:
      zona: Tommaso
      aspirazione: Inizio Tommaso aspirazione
      lavaggio: Inizio Tommaso lavaggio
    Salone:
      zona: Tinello
      aspirazione: Inizio Tinello aspirazione
      lavaggio: Inizio Tinello lavaggio
    Ingresso:
      zona: Giacinta
      aspirazione: Inizio Giacinta aspirazione
      lavaggio: Inizio Giacinta lavaggio
    Studio:
      zona: Cantina
      aspirazione: Inizio Cantina aspirazione
      lavaggio: Inizio Cantina lavaggio
  notifiche_alexa:
    - media_player.alexa_cucina
    - media_player.alexa_soggiorno
  notifiche_ios:
    - notify.mobile_app_iphone_di_xxxx
    - notify.mobile_app_iphone_di_xxxxxxxxxxxxxxxx
    - notify.mobile_app_xxxxxxxxxxxxxxxxxx

See my previous post. I also added a template sensor to let alexa say which are the next cleaning tasks. This is made for two units so you can scale it. Interesting part is that some areas are cleaned every other week and the senso handles it.

    - name: "Prossime Pulizie Robot"
      unique_id: aecbc378-d85f-4536-92be-2ad74a116cc2
      icon: mdi:robot-vacuum
      state: >-
        {% set today  = now().date() %}
        {% set base_w = today.isocalendar()[1] %}
        {% set now_ts = as_timestamp(now()) %}
        {% set pt     = namespace(dt=None, zona=None, dt_ts=None) %}
        {% set pp     = namespace(dt=None, zona=None, dt_ts=None) %}

        {% set piano_terra = [
          {'giorno': 0, 'ora': '09:15:00', 'stanza': 'Cucina',               'zona': 'Cucina',               'settimane': 1},
          {'giorno': 2, 'ora': '09:15:00', 'stanza': 'Cucina',               'zona': 'Cucina',               'settimane': 1},
          {'giorno': 4, 'ora': '09:15:00', 'stanza': 'Cucina',               'zona': 'Cucina',               'settimane': 1},
          {'giorno': 0, 'ora': '10:15:00', 'stanza': 'Bagno',            'zona': 'Bagno',            'settimane': 1},
          {'giorno': 2, 'ora': '10:15:00', 'stanza': 'Bagno',            'zona': 'Bagno',            'settimane': 1},
          {'giorno': 4, 'ora': '10:15:00', 'stanza': 'Bagno',            'zona': 'Bagno',            'settimane': 1},
          {'giorno': 0, 'ora': '11:15:00', 'stanza': 'Sala TV',              'zona': 'Sala TV',              'settimane': 1},
          {'giorno': 2, 'ora': '11:15:00', 'stanza': 'Sala TV',              'zona': 'Sala TV',              'settimane': 1},
          {'giorno': 4, 'ora': '11:15:00', 'stanza': 'Sala TV',              'zona': 'Sala TV',              'settimane': 1},
          {'giorno': 1, 'ora': '09:15:00', 'stanza': 'Tinello',               'zona': 'Tinello',               'settimane': 1},
          {'giorno': 3, 'ora': '09:15:00', 'stanza': 'Tinello',               'zona': 'Tinello',               'settimane': 1},
          {'giorno': 5, 'ora': '09:15:00', 'stanza': 'Tinello',               'zona': 'Tinello',               'settimane': 1},
          {'giorno': 5, 'ora': '10:30:00', 'stanza': 'Cantina',               'zona': Cantina',               'settimane': 2}
        ] %}

        {% set primo_piano = [
          {'giorno': 1, 'ora': '09:15:00', 'stanza': 'Camera Letto',         'zona': 'Camera Letto',         'settimane': 1},
          {'giorno': 4, 'ora': '09:15:00', 'stanza': 'Camera Letto',         'zona': 'Camera Letto',         'settimane': 1},
          {'giorno': 2, 'ora': '10:15:00', 'stanza': 'Corridoio', 'zona': 'Corridoio', 'settimane': 1},
          {'giorno': 1, 'ora': '11:15:00', 'stanza': 'Camera Tommaso',        'zona': 'Camera Tommaso',        'settimane': 1},
          {'giorno': 4, 'ora': '11:15:00', 'stanza': 'Camera Tommaso',        'zona': 'Camera Tommaso',        'settimane': 1},
          {'giorno': 5, 'ora': '10:30:00', 'stanza': 'Camera Giacinta',       'zona': 'Camera Giacinta',       'settimane': 2},
          {'giorno': 5, 'ora': '11:40:00', 'stanza': 'Zona Notte',           'zona': 'Zona Notte',           'settimane': 2},
          {'giorno': 5, 'ora': '10:20:00', 'stanza': 'Piano interrato',      'zona': 'Piano interrato',      'settimane': 2}
        ] %}

        {% for s in piano_terra %}
          {% set diff   = (s.giorno - today.weekday()) % 7 %}
          {% set target = today + timedelta(days=diff) %}
          {% set date_s = target.strftime('%Y-%m-%d') %}
          {% set dt     = as_datetime(date_s ~ 'T' ~ s.ora) %}
          {% set ts     = as_timestamp(dt) %}
          {% if (s.settimane == 1 or ((target.isocalendar()[1] - base_w) % s.settimane) == 0) and ts > now_ts %}
            {% if pt.dt_ts is none or ts < pt.dt_ts %}
              {% set pt.dt    = dt %}
              {% set pt.zona  = s.zona %}
              {% set pt.dt_ts = ts %}
            {% endif %}
          {% endif %}
        {% endfor %}

        {% for s in primo_piano %}
          {% set diff   = (s.giorno - today.weekday()) % 7 %}
          {% set target = today + timedelta(days=diff) %}
          {% set date_s = target.strftime('%Y-%m-%d') %}
          {% set dt     = as_datetime(date_s ~ 'T' ~ s.ora) %}
          {% set ts     = as_timestamp(dt) %}
          {% if (s.settimane == 1 or ((target.isocalendar()[1] - base_w) % s.settimane) == 0) and ts > now_ts %}
            {% if pp.dt_ts is none or ts < pp.dt_ts %}
              {% set pp.dt    = dt %}
              {% set pp.zona  = s.zona %}
              {% set pp.dt_ts = ts %}
            {% endif %}
          {% endif %}
        {% endfor %}

        {% macro day_name(obj) -%}
          {% if obj.dt.date() == today %}oggi
          {% elif obj.dt.date() == (today + timedelta(days=1)) %}domani
          {% else %}{{ obj.dt.strftime('%A') }}{% endif %}
        {%- endmacro %}
        

        {# 6) Output forzato #}
        {% if true %}
        La prossima pulizia di Robottino 1 sarà in {{ pt.zona }} {{ day_name(pt) }}
        alle {{ pt.dt.strftime('%H:%M') }}, mentre Robottino 2 pulirà {{ pp.zona }}
        {{ day_name(pp) }} alle {{ pp.dt.strftime('%H:%M') }}.
        {% endif %}  ```

For those who are looking for a quick solution for the RV30 Max Plus, you can do the following: (p.s. you’ll need IFTTT pro for this)

  1. In your Tapo app, create shortcuts of the different types of cleaning you’d like to do. For me, I made a shortcut that only cleans the kitchen.

  2. Sign up for an IFTTT account and create a new Applet that is triggered by a webhook.

  3. Let the Applet execute the Tapo shortcut

  4. Call the webhook from Home Assistant by adding this to your configuration.yaml

rest_command:
  clean_kitchen:
      url: "https://maker.ifttt.com/trigger/your/webhook/url"
  1. Call the rest_command via an action (e.g. rest_command.clean_kitchen)

Is this ideal? No… Is this secure? Also no… Am I proud of this? Hell no. Does this do the trick until Matter support has been properly introduced? Yep.

  1. If this was the only applet you wanted to run, would the free level of IFTTT work?
  2. In Nov 2025, is there a better way?
1 Like

This has become a not-so-good purchase nowadays…

1 Like

WHOA !! I have purchased a LOT of TP-Link, Kasa, & Tapo devices. Because they’ve been a good value, & have worked so well with Home Assistant.

I had just purchased an RV30, & was pleased with how well it worked with HA. Then it just stopped, & I hadn’t started troubleshooting yet. But if they’ve broken it, & callously dismiss the issue, that’ll be the last piece of their gear I buy.

The only saving grace might happen if they truly support Matter in a solid fashion.

2 Likes

I was checking here one last time before i was going to buy one. That was a seriously close call after months of research!