Protocollo MQTT ed errori comuni con dispositivi Tasmota
Il protocollo MQTT
Message Queue Telemetry Transport (MQTT) è un protocollo “leggero”, che si appoggia su TCP/IP ed è utilizzato per pubblicare / sottoscrivere messaggi tra dispositivi. “MQ Integrator SCADA Device Protocol” è un vecchio nome per quello che ora è noto come MQTT, questo la dice lunga sulle origine di questo protocollo legato al mondo dei controlli in ambito industriale (una delle prime applicazioni fu, negli anni 90, per collegare i sensori sugli oleodotti tramite link satellitari).
MQTT è progettato per essere aperto, semplice e facile da implementare, consentendo a migliaia di client leggeri di essere supportati da un singolo server chiamato broker. Queste caratteristiche lo rendono ideale per l’uso in ambienti con reti a bassa larghezza di banda ed elevata latenza, e client con limitate capacità sia di elaborazione che di memoria. MQTT anche in situazioni estremamente sfavorevoli riduce al minio i requisiti di larghezza di banda, mentre cerca di garantire l’affidabilità della consegna.
Modello Publish/Subscribe
Il protocollo MQTT deve la sua fortuna ad una serie di fattori:
- leggerezza: ha un’intestazione semplice per specificare il tipo di messaggio, un argomento basato su testo e quindi un payload che può essere binario. L’applicazione può utilizzare qualsiasi formato dati per il payload, come JSON, XML, binario crittografato o Base64, a condizione che i client di destinazione possano analizzare il payload.
- semplicità: esistono solo due tipi di entità, un broker di messaggi e i client. Il broker è un server che riceve tutti i messaggi dai client e quindi li indirizza ai client di destinazione. Un client è definito come tutto ciò che può interagire con il broker per inviare e ricevere messaggi,
- modello di comunicazione publish/subscribe , vediamo nel dettaglio come funziona:
- Il client si connette al broker. Può iscriversi a qualsiasi messaggio “topic” (argomento) nel broker. Questa connessione può essere una semplice connessione TCP / IP o una connessione TLS crittografata.
- Il client pubblica (publish) i messaggi sotto un topic inviando il messaggio stesso e il topic al broker.
- Il broker inoltra il messaggio a tutti i client che sono iscritti (subscribe) a tale topic.
Messaggi MQTT
Ogni messaggio MQTT è composto da un comando e da un payload, vediamo i principali comandi:
Messaggio CONNECT utilizzato da un client per stabilire una connessione con il broker
Parametri | Descrizione |
cleanSession |
Questo flag specifica se la connessione è persistente o meno. Una sessione persistente memorizza tutte le sottoscrizioni e i messaggi potenzialmente persi (a seconda della QoS) nel broker. |
username |
Le credenziali di autenticazione e autorizzazione del broker. |
password |
Le credenziali di autenticazione e autorizzazione del broker. |
lastWillTopic |
Quando la connessione viene interrotta in modo imprevisto, il broker pubblica automaticamente un messaggio di “ultima volontà” (lastWill) su un topic. |
lastWillQos |
QoS del messaggio “last will” |
lastWillMessage |
Il messaggio “last will” |
keepAlive |
Questo è l’intervallo di tempo senza comunicazione dopo il quale il client MQTT viene disconnesso per inattività. |
Messaggio SUBSCRIBE di sottoscrizione ad un argomento (topic).
Parametri | Descrizione |
qos |
Il flag qos (quality of service, o QoS) indica in che modo i messaggi in questo topic devono essere consegnati coerentemente ai client.
|
topic |
Un argomento a cui iscriversi. Un topic può avere più livelli separati dal carattere slash (“/”). Ad esempio, “dw/demo” e “db/bluemix/mqtt” sono argomenti validi |
Messaggio PUBLISH di pubblicazione di un topic
Parametri | Descrizione |
topicName |
L’argomento sotto il quale viene pubblicato il messaggio. . |
qos |
Qualità del livello di servizio del recapito dei messaggi. |
retainFlag |
Questo flag indica se il broker manterrà il messaggio come l’ultimo messaggio conosciuto per questo topic |
payload |
I dati effettivi nel messaggio. Può essere una stringa di testo o un blob binario di dati. |
Configurazioni MQTT per Tasmota
Dopo lo “spiegone” su MQTT, necessario per capire come funziona il protocollo, veniamo al problema di “ghost switching” (accensione non previste di luci/interruttori) per uno dei principali strumenti utilizzati per domotizzare le nostre case e cioè gli switch Sonoff con firmware Tasmota.
Sonoff
Vediamo i principali topic di Sonoff.
Messaggio | Scopo |
---|---|
cmnd |
Per attivare o disattivare il dispositivo elettronico (relay ad esempio) occorre inviare il payload corretto al topic cmnd |
stat |
Il Sonoff pubblica su questo topic eventuali modifiche nei dispositivi elettronici collegati al Sonoff, ad esempio se il relè passa da off a on, pubblicherà immediatamente “ON” sul suo topic stat. Questo topic viene utilizzato dal HA per conoscere lo stato corrente dei dispositivi tasmota. |
tele |
Segnala informazioni di telemetria non richieste come segnale Wifi, tensione di alimentazione, a intervalli periodici (di default ogni 5 minuti) |
Ognuno di questi topic specifici di Tasmota può essere inviato con il retainflag
che come detto nel capitolo precedente indica al broker di mantenere il messaggio come l’ultimo messaggio ricevuto, per fare questo il broker utilizza un “file di persistenza” dove mantiene tutti i messaggi con retainflag=true
per ogni topic MQTT.
Quando il nostro Sonoff Basic si riavvia, in successione si ricollega al server MQTT, si iscrive ai topic di pertinenza e riceve dal server MQTT l’ultimo messaggio conservato su ciascuno di questi topic, aggiornando il dispositivo su cosa è successo mentre era disconnesso.
Se per qualche motivo (scarsa connessione wifi o instabilità dell’alimentazione) il dispositivo Tasmota si riavvia, con il riavvio è eseguita la riscrittura dei topic MQTT. Se un messaggio retained
non è disponibile sul topic cmnd
, il sonoff utilizza un’opzione chiamata “powerOnState
“, che ha le seguenti opzioni:
- 0 / OFF = keep relay(s) OFF after power up
- 1 / ON = turn relay(s) ON after power up
- 2 / TOGGLE = toggle relay(s) from last saved state
- 3 = switch relay(s) to their last saved state (default)
- 4 = turn relay(s) ON and disable further relay control
- 5 = after a PulseTime period turn relay(s) ON (acts as inverted PulseTime mode)
questo stato è memorizzato in maniera persistente nella memoria non volatile del chip ESP8266 presente sul Sonoff
Da qui possono nascere i problemi di “ghost switching“: se hai configurato uno dei tuoi dispositivi Sonoff con Tasmota per pubblicare un messaggio con topic cmnd
e retainflag
, il dispositivo Tasmota riceverà un nuovo comando appena si connette al broker MQTT che può andare in conflitto con poweronstate
, vediamo come
- Si configura lo switch MQTT in HA con
retainflag on
senza attivare nella console Tasmota nessuna operazione di retain. - Se si accende la luce con HA, il topic
cmnd
con messaggio ON avrà unretainflag on
se successivamente spengo la luce utilizzando il pulsante a muro il messaggio OFF avrà un topiccmnd
conretainflag=off
, che non sovrascrive il precedente messaggio inviato da Home Assistant che haretainflag on
. - Se ad un certo punto il Sonoff effettua un reboot, la luce che avevo spento al punto 2) si accenderà perché in HA ho configurato il mio switch con il
retainflag on
(come scritto chiaramente sul github di Tasmota: “A message in your MQTT broker flagged as ‘retained’ will always override the PowerOnState“)
Le soluzioni possibili per evitare questo tipo di problematica sono due:
- Disabilitare il retain (
retainflag off)
in ogni singolo elemento dell’infrastruttura MQTT ed eliminare eventuali messaggi persistente dal broker (nella console di Tasmota usare i comandiswitchretain off
ebuttonretain off
) - Abilitare in ogni elemento dell’infrastruttura MQTT (Sonoff con Tasmota, HA, etc) il
retainflag
(nella console di Tasmota usare i comandiswitchretain on
ebuttonretain on
)
Personalmente preferisco la prima soluzione che si concretizza andando nella console di ogni dispositivo Tasmota ed inserire switchretain off
e buttonretain off
, verificare che PowerOnState
sia a 3, effettuare un’azione di pulizia dei topic persistenti su Home Assistant per esempio con il seguente codice YAML, in questo modo il Sonoff dopo il reboot ritornerà al suo stato precedente.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
########################################################## #### INPUT TEXT ########################################################## input_text: clear_mqtt_topic: name: MQTT Topic to Clear initial: '' ########################################################## #### AUTOMATION ########################################################## - alias: Clear MQTT Topic initial_state: true trigger: - platform: state entity_id: input_text.clear_mqtt_topic condition: - condition: template value_template: >- "{{ ('cmnd/' in states.input_text.clear_mqtt_topic.state) }}" action: - service: mqtt.publish data_template: topic: "{{ states.input_text.clear_mqtt_topic.state }}" retain: true - service: notify.telegram data_template: title: '*-- Attenzione --*' message: "Cancellato il topic: {{ states.input_text.clear_mqtt_topic.state }}" |
Nel paragrafo precedente abbiamo parlato di topic di tipo cmnd
per i quali la soluzione proposta è di non usare il retainflag on
, per quanto invece riguarda lo stato dei dispositivi (topic stat)
avere lo stato dei dispositivi con retainflag on
non ha il risvolto di avere comportamenti anomali, naturalmente occorre essere certi di impostare il flag solo per i topic giusti :-).
Tasmota Autodiscovery per HA
Nelle ultime versioni del firmware Tasmota è possibile utilizzare questa funzionalità in modo che Home Assistant rilevi immediatamaente i dispositivi Tasmota presenti. Al momento vengono rilevati i seguenti dispositivi collegati :
- Relay – visti in HA come
switch
- Light (LED dimmer) – visti in HA come
light
- Sensori collegati – visti in HA come
sensor
- Pulsanti collegati – visti in HA come
binary_sensor
- Interruttori collegati – visti in HA come
binary_sensor
Per fare vedere in Home Assistant un relay come una luce occorre:
- abilitare nella console Tasmota
SetOption30 1
- usare in Home Assistant il component
light.switch
(https://www.home-assistant.io/components/light.switch/)
Per abilitare l’auto discovery occorre inserire nella console Tasmota di ogni dispositivo il comando SetOption19 1
, il comando per disabilitare l’autodiscovery è invece SetOption19 0.
I più smalizziati utilizzatori di Home Asissatnt invece di andare manualmente su ogni dispositivo con Tasmota faranno un automazione che imposta l’auto-discovery per tutti, per rimuovere questa funzionalità basta fare un’altra automazione ma con paylod: "0"
.
1 2 3 4 5 6 7 8 9 10 |
## abilitazione MQTT discovery per tutti i dispositivi con Tasmota - alias: "Abilitazione MQTT discovery" trigger: platform: homeassistant event: start action: - service: mqtt.publish data: topic: "cmnd/sonoffs/SetOption19" payload: "1" |
#########
Con questo ultimo esempio si conclude l’articolo su MQTT e sulle problematiche derivanti dal suo utilizzo, per ogni domanda ci vediamo sul forum di HassioHelp!
Bibliografia
https://developer.ibm.com/articles/iot-mqtt-why-good-for-iot/
https://github.com/arendst/Sonoff-Tasmota/wiki/PowerOnState-Configuration
10 risposte
Questo è davvero un ottimo post sul retain flag di MQTT in ambito Tasmota per HOME ASSISTANT.
grazie!
Ciao innanzitutto Buon Natale, ho un piccolo problema, quando aggiorno una presa con tasmota, questa al momento del riavvio disattiva l’alimentazione per un secondo spegnendo il dispositivo collegato , come posso risolvere?
Se stai aggiornando il firmware tasmota via ota del dispositivo è normale che si riavvii interrompendo l’alimentazione. Dato che è un’operazione che non si fa molto spesso o eviti gli aggiornamenti o spegni manualmente il dispositivo collegato prima di aggiornalo.
Grazie mille!! hai risolto i miei problemi e mi hai migliorato il Natale! Buon Natale!!!!!!
Grazie 🙂
Ciao, come tutti ho il problema del retain. Ho un sonoff ch4 pro tasmotizzato che gestisce un impianto di irrigazione del giardino. Quando perde il wifi o si riavvia, si attiva una delle 4 zone. Ho dato i comandi da te indicati, ma non ho capito perché bisogna settare PowerOnState su 3 e non su 0 se non voglio avere il problema citato.
PowerOnstate 3 è il default cioè ripristina lo stato precedente, se vuoi puoi mettere anche 0 che manda sempre ad off
ciao, ottimo articolo, ma penmso che su una frase, manchi una parola fondamentale:
….”Personalmente preferisco la prima soluzione che si concretizza andando nella console di ogni dispositivo Tasmota ed inserire switchretain off e buttonretain off, verificare che PowerOnState sia a……”
Ovvero, il PoerOnState deve essere come ?
Grazie E.
c’è scritto : “verificare che PowerOnState sia a 3, “