Il numero WhatsApp di casa ormai fa parecchie cose. Risponde a stato con la salute del server, aggiunge voci alla lista della spesa anche da un vocale, manda la foto di una telecamera a richiesta. È tutto Home Assistant, collegato a WhatsApp tramite il gateway OpenWA.
Fino a ieri l'unico numero ammesso era il mio, scritto in un file di configurazione. Volevo poter aggiungere qualcuno di famiglia dalla dashboard, senza toccare file, e volevo che chi scrive per sbaglio a quel numero ricevesse almeno una risposta invece del silenzio.
Dove si fermavano i messaggi
La prima cosa che ho scoperto riguardava il gateway. Il webhook con cui OpenWA inoltra i messaggi a Home Assistant aveva un filtro sul mittente: passava solo il mio numero. Gli altri messaggi arrivavano al gateway e lì si fermavano, quindi Home Assistant non poteva rispondere a nessuno perché non sapeva nemmeno che qualcuno avesse scritto.
Ho tolto il filtro e spostato la decisione in Home Assistant. È più comodo, perché l'elenco diventa modificabile dalla dashboard, ma comporta una responsabilità: adesso ogni messaggio arriva fino all'automazione, quindi è l'automazione a dover essere prudente. I gruppi e gli aggiornamenti di stato di WhatsApp vengono ignorati subito.
Un dettaglio che ha semplificato tutto: con il motore Baileys il mittente arriva come numero di telefono e non come identificativo anonimo, quindi l'elenco può contenere semplicemente numeri.
L'elenco nella dashboard
Nella vista Setup ci sono cinque righe, nome e numero, fatte con normali campi di testo di Home Assistant. Le modifiche valgono subito, senza pulsanti da premere. Un sensore template raccoglie i numeri validi, cioè solo cifre e almeno otto:
numeri: >-
{%- set ns = namespace(l=[]) -%}
{%- for i in range(1, 6) -%}
{%- set n = states('input_text.wa_aut%d_numero' | format(i)) | regex_replace('[^0-9]', '') -%}
{%- if n | length >= 8 %}{% set ns.l = ns.l + [n] %}{% endif -%}
{%- endfor -%}
{{ ns.l }}
Al primo avvio il campo uno viene precompilato con il numero che era già autorizzato, così il passaggio non chiude fuori nessuno.
La risposta agli sconosciuti, senza farsi spammare
Chi non è in elenco riceve un messaggio breve: questo è il numero automatico di casa e risponde solo alle persone autorizzate. Qui serviva un freno, per due motivi. Uno sconosciuto che insiste non deve ricevere cento risposte, e ogni risposta conta nel limite giornaliero di messaggi, che serve agli avvisi veri.
Le regole sono due: al massimo una risposta ogni 24 ore per lo stesso mittente, e al massimo cinque risposte al giorno in tutto. In ogni caso Home Assistant mi manda una notifica con nome e numero, e la vista Setup mostra l'ultimo mittente non autorizzato: se è qualcuno che voglio aggiungere, copio il numero nell'elenco.
Il limite giornaliero, ora regolabile
Gli invii su WhatsApp hanno un tetto giornaliero, pensato per non far sembrare il numero di casa uno spammer agli occhi di WhatsApp. Era fisso a 30. Durante una giornata di prove l'ho esaurito, e da quel momento ogni risposta veniva bloccata in silenzio: io scrivevo stato e non arrivava niente.
Ora nella stessa vista c'è un interruttore per attivarlo o disattivarlo, un campo per il massimo, il contatore del giorno e un pulsante per azzerarlo. Lo script che invia legge da lì:
limite: >-
{{ (states('input_number.wa_limite_max') | int(30))
if not is_state('input_boolean.wa_limite_attivo', 'off') else 1000000 }}
Il bug: il proprietario non autorizzato
Alla prima prova, dal mio numero, ho scritto stato e mi è arrivato «numero riservato». Ero nell'elenco, ma Home Assistant non mi riconosceva.
La causa è un comportamento di Home Assistant che conviene conoscere. Nelle variabili di un'automazione il risultato di un template viene convertito nel tipo che sembra più adatto. Il numero del mittente, estratto come testo da 393…@c.us, diventava quindi un intero. L'elenco degli autorizzati invece contiene testi, e il confronto tra il numero 393… e il testo «393…» è sempre falso.
# prima: falso anche per chi è in elenco
numero in numeri_autorizzati
# dopo: confronto sempre tra testi
(numero | string) in (numeri_autorizzati | map('string') | list)
L'avevo già incontrato quella mattina, con i numeri dell'elenco delle telecamere, e l'avevo anche annotato. Mi è sfuggito lo stesso, perché nell'editor dei template il valore resta testo e tutto sembra funzionare. Da allora la verifica la faccio simulando il caso reale:
{% set numero = '393...' | int %}
vecchio confronto: False nuovo confronto: True numero estraneo: False
Un messaggio perso al riavvio
Durante le prove è successa anche un'altra cosa: un messaggio mandato pochi secondi dopo un riavvio di Home Assistant non ha avuto nessuna risposta. Il gateway l'aveva consegnato, ma in quel momento le automazioni non erano ancora caricate. Non è un errore della configurazione, è il prezzo di un riavvio: basta rimandare il messaggio.
In sintesi
- Un filtro nel gateway può fermare i messaggi prima che arrivino a Home Assistant: se la decisione deve essere modificabile dalla dashboard, va presa in Home Assistant.
- Rispondere agli sconosciuti va bene, ma con un freno per mittente e uno giornaliero.
- Un limite fisso prima o poi si esaurisce nel momento sbagliato: meglio regolabile, con un pulsante per azzerarlo.
- In Home Assistant un numero estratto da un testo può diventare un intero: nei confronti,
| stringsu entrambi i lati. - Un test che non riproduce il tipo reale del dato non prova niente.