Il robot di casa è un Dreame che aspira e lava, con la stazione base che lava il panno da sola. È collegato a Home Assistant con l'integrazione comunitaria dreame_vacuum e lo comando anche da WhatsApp: come funzionano avvisi e comandi «robot …» lo racconto in robot Dreame su WhatsApp. Il messaggio arriva al gateway, il gateway lo passa a un webhook di Home Assistant e lo script robot_comando capisce cosa voglio e risponde. Possono usarlo solo i mittenti autorizzati che hanno la categoria «robot», come spiego in ruoli Admin e Utente con categorie.

Un giorno scrivo «robot pulisci». Il robot parte, pulisce la stanza in cui si trova, al massimo un'altra, e rientra. La casa era tutta da fare.

🔎 L'indagine

Prima di toccare qualcosa sono andato a guardare cosa era successo davvero. Il recorder di Home Assistant tiene la storia di ogni entità, attributi compresi: ho letto quella del robot (stato e attributi started, paused, active_segments) e quella del sensore degli errori.

QuandoStato del robotCosa dicono gli attributi
MattinocleaningParte la pulizia programmata di tutta la casa
Poco dopoerrorErrore dell'acqua: serbatoio pulito vuoto
DopoerrorAltro errore dell'acqua: serbatoio sporco pieno
Fino al mio messaggiopausedstarted ancora vero: l'attività non è mai stata chiusa
«robot pulisci»cleaningRiprende la stessa attività e pulisce solo le stanze rimaste
Finereturning, poi dockedRientra alla base

Il pezzo che mancava era nel comando. Lo script chiamava vacuum.start, e ho aperto il codice dell'integrazione per vedere cosa fa: start() vuol dire «avvia o riprendi». Se c'è un'attività in pausa la riprende. Quindi il robot non stava sbagliando niente: finiva la pulizia del mattino dal punto in cui si era fermato.

⚠️ La causa, in una riga

vacuum.start non vuol dire sempre «pulizia nuova». Con un'attività avviata e in pausa, la riprende.

🛠️ La correzione

Adesso «robot pulisci» vuol dire sempre una pulizia nuova. Se trova un'attività aperta (avviata, in pausa, in errore o in rientro) prima la chiude, aspetta che il robot lo confermi, e solo dopo riparte: con vacuum.start per tutta la casa, oppure con dreame_vacuum.vacuum_clean_segment per le stanze nominate, come «robot pulisci cucina e bagno».

- variables:
    attivita_aperta: >-
      {{ state_attr('vacuum.robot', 'started') == true
         or states('vacuum.robot') in ['paused', 'error', 'returning'] }}
- if: "{{ attivita_aperta }}"
  then:
    - action: vacuum.stop
      target:
        entity_id: vacuum.robot
    - wait_template: "{{ state_attr('vacuum.robot', 'started') != true }}"
      timeout: "00:00:30"
      continue_on_timeout: true
    - delay: "00:00:03"
- if: "{{ stanze | count > 0 }}"
  then:
    - action: dreame_vacuum.vacuum_clean_segment
      target:
        entity_id: vacuum.robot
      data:
        segments: "{{ stanze | map(attribute='id') | list }}"
  else:
    - action: vacuum.start
      target:
        entity_id: vacuum.robot

Poi lo script aspetta, fino a 45 secondi, che lo stato diventi cleaning. Il robot spesso lava prima il panno nella base: anche quella fase per Home Assistant è cleaning, e per me conta come partito.

- wait_template: "{{ is_state('vacuum.robot', 'cleaning') }}"
  timeout: "00:00:45"
  continue_on_timeout: true
- variables:
    partito: "{{ wait.completed }}"
    errori:
      water_tank: "serbatoio dell'acqua pulita vuoto"
      dirty_water_tank: "serbatoio dell'acqua sporca pieno"
      battery_low: "batteria scarica"
    codice: "{{ states('sensor.robot_error') }}"
    errore: "{{ errori.get(codice, codice) }}"

La risposta su WhatsApp racconta l'esito vero, non quello sperato. Se il robot è partito, la risposta lo dice e avvisa che una pulizia interrotta è stata annullata. Se non è partito, mostra stato, batteria ed errore tradotto in italiano dalla piccola mappa qui sopra.

robot pulisci17:40
🧹 PULIZIA AVVIATA ━━━━━━━━━━━━━━ 🏠 Tutta la casa ♻️ Una pulizia interrotta è stata annullata Per continuare quella vecchia scrivi robot riprendi17:40

Esempio: pulizia nuova dopo una programmata rimasta in pausa

robot pulisci cucina08:15
⚠️ IL ROBOT NON È PARTITO ━━━━━━━━━━━━━━ 📍 Stato: error 🔋 Batteria: 64% 💧 Errore: serbatoio dell'acqua pulita vuoto08:16

Esempio: il robot non parte per un errore dell'acqua

«Robot riprendi» resta l'unico comando che riprende l'attività vecchia, con vacuum.start come prima. Così la scelta è mia, non del robot.

🧽 I nuovi comandi per la stazione base

Già che c'ero ho aggiunto i comandi che mi mancavano. Per lavare il panno scrivo «robot autopulizia», ma vanno bene anche «pulisci base» e «lava panno». Poi «robot asciuga» per l'asciugatura del panno e «robot svuota» per lo svuotamento automatico.

C'è un dettaglio importante. I pulsanti che l'integrazione crea per queste funzioni si comportano come interruttori: premerli durante un lavaggio lo ferma. Un secondo messaggio uguale, scritto per sicurezza, annullerebbe il primo. Per questo lo script preme il pulsante solo se il robot è in base e se l'attributo washing (o drying) non è già vero. Altrimenti risponde «già in corso» oppure «il robot non è nella base».

- if: "{{ state_attr('vacuum.robot', 'washing') == true }}"
  then:
    - action: script.whatsapp_rispondi
      data:
        chat: "{{ chat }}"
        testo: "🧽 Lavaggio del panno già in corso"
    - stop: Già in corso
- if: "{{ not is_state('vacuum.robot', 'docked') }}"
  then:
    - action: script.whatsapp_rispondi
      data:
        chat: "{{ chat }}"
        testo: "🏠 Il robot non è nella base"
    - stop: Non in base
- action: button.press
  target:
    entity_id: button.robot_self_clean

script.whatsapp_rispondi sta per lo script con cui rispondi già a una chat.

🔧 Manutenzione e reset dei consumabili

«Robot manutenzione» risponde con lo stato di ogni consumabile: spazzola principale, spazzola laterale, filtro, sensori, panno e detergente. Per ognuno legge dai sensori dell'integrazione la percentuale e le ore residue, e mette un semaforo: 🟢 sopra il 25%, 🟡 sotto il 25%, 🔴 sotto il 10%.

robot manutenzione19:05
🔧 MANUTENZIONE ROBOT ━━━━━━━━━━━━━━ 🟢 Spazzola principale: 72% · 216 h 🟡 Spazzola laterale: 18% · 27 h 🟢 Filtro: 55% · 82 h 🔴 Sensori: 6% · 2 h 🟢 Panno: 41% · 33 h 🟢 Detergente: 64% Dopo la sostituzione: robot reset spazzola laterale19:05

Esempio con valori inventati

«Robot reset» seguito dal nome della parte preme il pulsante di reset di quella parte, rilegge il sensore e mostra prima e dopo, per esempio «18% → 100%». Le parti stanno in una lista, ognuna con i suoi sinonimi, il sensore e il pulsante:

parti:
  - nome: Spazzola laterale
    parole: ['laterale']
    sensore: sensor.robot_side_brush_left
    reset: button.robot_reset_side_brush
  - nome: Filtro
    parole: ['filtro']
    sensore: sensor.robot_filter_left
    reset: button.robot_reset_filter
  - nome: Spazzola principale
    parole: ['spazzola', 'principale']
    sensore: sensor.robot_main_brush_left
    reset: button.robot_reset_main_brush

L'ordine conta: in «reset spazzola laterale» c'è anche la parola «spazzola», quindi «laterale» deve vincere. La spazzola principale si cerca per ultima. Se scrivo solo «robot reset», senza la parte, lo script chiede quale e mostra l'elenco.

📋 I comandi in una tabella

ComandoCosa faQuando funziona
robot pulisciPulizia nuova di tutta la casa; annulla un'attività interrottaSempre; dice se il robot è partito davvero
robot pulisci cucina e bagnoPulizia nuova delle sole stanze nominateCome sopra
robot riprendiContinua l'attività in pausaSolo se ce n'è una aperta
robot autopulizia (pulisci base, lava panno)Lavaggio del panno nella stazioneRobot in base e lavaggio non già in corso
robot asciugaAsciugatura del pannoRobot in base e asciugatura non già in corso
robot svuotaSvuotamento automaticoRobot in base
robot manutenzionePercentuale, ore residue e semaforo dei consumabiliSempre, non muove il robot
robot reset <parte>Azzera il contatore della parte e mostra prima → oraSempre; senza la parte chiede quale
robot reset spazzola laterale19:12
🔄 RESET FATTO ━━━━━━━━━━━━━━ 🧹 Spazzola laterale: 18% → 100%19:12
robot autopulizia19:20
🧽 AUTOPULIZIA ━━━━━━━━━━━━━━ Lavaggio del panno già in corso19:20

Esempio: un reset e un lavaggio chiesto due volte

🧪 Come l'ho provato

Il riconoscimento delle frasi l'ho provato senza toccare il robot. Dentro il container ho usato jinja2 puro, caricando le variabili dal file YAML dello script, e gli ho fatto leggere 17 frasi, da «pulisci» a «reset spazzola laterale», controllando che per ognuna scegliesse il comando e la parte giusti.

Dal vivo ho provato solo i comandi che non muovono il robot, cioè «robot manutenzione» e «robot reset» senza la parte. Il testo inviato l'ho letto nella traccia dello script. I comandi che lo muovono o cambiano qualcosa sul robot li provo io, di persona.

🪤 Intoppi e lezioni

💡 Quello che ho imparato

  • Avvia e riprendi sono spesso lo stesso servizio. Se voglio ripartire da zero, prima va annullata l'attività in corso. E prima di dare la colpa al robot conviene leggere il codice dell'integrazione e la storia degli attributi nel recorder.
  • I pulsanti che funzionano da interruttore vanno protetti. Un controllo dello stato prima di premerli evita che il secondo comando annulli il primo.
  • Le notifiche di avviso dell'integrazione non vanno chiuse da Home Assistant. Chiuderle cancella l'avviso anche sul robot, e si perde l'informazione proprio dove serve.
  • Se la programmata si ferma ogni mattina per l'acqua, il problema è di manutenzione. Non di automazione: l'avviso tradotto su WhatsApp lo fa notare subito, e il serbatoio va riempito o svuotato.