Sensori porte/finestre e ricevitore RF433 in Home Assistant con ESPHome
In questa guida cerco di spiegare passo-passo (diciamo per
principianti) come "costruire" un ricevitore RF433 usando un ESP32 per la parte HW e ESPHome per la parte SW, in modo da integrarlo in Home Assistant. Come sempre cercherò di scrivere un
articolo come piace a me: inserirò le informazioni necessarie senza dilungarmi
troppo, senza continue ripetizioni (in stile SEO) e andando al punto, ma
inserendo le informazioni che è necessario sapere (per capire cosa si sta
facendo).
Come prima cosa, naturalmente, dovete avere un’installazione
di Home Assistant funzionante e correttamente configurata.
È necessario anche avere un'istanza di ESPHome pronta e configurata sul nostro sistema (se non l'avete ancora fatto, eseguite questo passaggio prima di continuare).
Ovviamente dobbiamo avere a disposizione anche l'hardware necessario, cioè:
- Sensore porta/finestra 433mhz che trasmette con protocollo RC Switch
- ESP32
- Modulo ricevitore RF 433mhz Superheterodyne
- Cavetti per il collegamento (dupont o saldati, come volete)
1.
Configurazione tipo (HW/SW)
Nel mio caso mi trovo nella seguente situazione (cioè, se avete la mia stessa configurazione e seguite la guida, vi garantisco che funziona):
- SW:
- Home Assistant 2025.5.1
- ESPHome 2025.4.1
- HW:
- ESP32. Io ho utilizzato (per comodità) un ESP32-WROOM-32 NodeMCU come questo qui: https://www.amazon.it/QIQIAZI-ESP32-WROOM-32-Bluetooth-Microcontroller-compatibile/dp/B0DGG865GM/ref=sr_1_3_sspa
La comodità di avere i connettori già saldati è che è veloce per fare le prove mettendola su una breadboard o collegando direttamente con i cavetti dupont femmina-femmina - Ricevitore 433mhz Superetherodyne. Se usate quello che ho usato io non dovreste avere bisogno di modificare i parametri. Altrimenti dovete andare di tentativi finchè trovate quelli giusti. Io ho usato questo: https://www.aliexpress.com/item/1005006375506252.html
Ha il vantaggio che:
1) Funziona sia a 5v che a 3.3v
2) Ha l'antennza già saldata, quindi è già "pronto all'uso" - Cavetti Dupont femmina-femmina per collegare l'ESP32 al ricevitore RF433
- Sensori porta/finestra RF 433mhz compatibili con protocollo RC Switch (altrimenti dovete decodificarvi "a mano" il segnale). Quelli che ho usato io inviano un segnale per:
- Apertura
- Chiusura
- Tampering (tentativo di manomissione)
- Batteria scarica
Attenzione a non prendere un sensore che invia il segnale solo per l'apertura, altrimenti diventa abbastanza inutile.
Quelli che ho usato io sono uguali a questo: https://www.aliexpress.com/item/1005005880328949.html
2. Prerequisiti
3. Breve introduzione/spiegazione
Usare la frequenza dei 433Mhz porta diversi vantaggi (e anche svantaggi) rispetto ad altri tipi protocolli che usano invece la frequenza di 2.4Ghz (WiFi, Zigbee, Bluetooth).
Il primo vantaggio è la portata: essendo le onde molto più lunghe, la portata è decisamente maggiore, e meno attenuata dagli ostacoli.
Il secondo vantaggio è l'energia: serve molta meno energia per inviare un segnale su frequenza più bassa; quindi i sensori di questo tipo solitamente hanno batterie che durano anni.
Un ulteriore vantaggio è che non è necessario eseguire il pairing con un "master" per poter trasmettere. Il sensore trasmette sempre e chiunque (broadcast) è in ascolto può leggere il messaggio.
Il primo svantaggio è proprio l'ultimo vantaggio: il protocollo non è criptato quindi i messaggi viaggiano sempre in chiaro.
Il secondo grosso svantaggio è che il protocollo di comunicazione è molto semplice, per cui normalmente i sensori inviano un "codice" di pochi byte, non un messaggio strutturato.
Il terzo svantaggio è l'assenza di bidirezionalità: è rato trovare sensori a batteria che siano in grado di ricevere comandi, oltre che inviarli.
C'è un ulteriore svantaggio dato dal fatto che, se non c'è nessuno ad ascoltare un messaggio inviato da un sensore.... il messaggio è perso e non viene inviato nuovamente.
Per tutti questi motivi, normalmente tale frequenza è utilizzata da sensori porta/finestra o altri sensori semplici (gas, acqua, contatto, ecc.).
Nel mio caso specifico uso sensori porta/finestra RF433 perché, rispetto a Zigbee:
- Dovrei passare il tempo a cambiare le batterie dei sensori (soprattutto delle porte e delle finestre che vengono aperte più spesso)
- Dovrei essere sicuro di avere copertura Zigbee per tutta l'area
- A volte sensori di alcune marche si rifiutano di agganciarsi a router di altre marche e si collegano solo al coordinator; oppure si agganciano ad un noto e usano quello ad oltranza, anche se ce n'è uno "migliore" o se il "vecchio" è offline (per un sensore porta/finestra non è una cosa simpatica)
- Usare un sensore Zigbee, che però richiede un coordinator. Ho a disposizione 2 coordinator inutilizzati, ma entrambi USB. Quindi avrei dovuto "sacrificare" un Raspberry per metterci su Zigbee2Mqtt
- Usare la roba DIY che avevo in casa per fare un ricevitore RF433 (che nel punto dove lo devo piazzare devo anche mettere un lettore Rfid, quindi sfruttando lo stesso ESP32; ma questo sarà oggetto di un altro post)... Ma partendo da 0 sapevo già che sarebbe stato un po' un bagno di sangue riuscire ad avere qualcosa di funzionante (più che altro serve sempre moooolto tempo)
4. Preparazione ESP32
La prima cosa da fare è preparare l'ESP32 con ESPHome. La prima volta va collegato direttamente con il cavetto USB al PC, le volte successive si può aggiornare trami OTA (quindi basta che sia collegato in WiFi alla nostra rete).
Motivo per cui la prima volta è più comodo caricare un firmware minimale ESPHome, con i soli dati per il collegamento alla rete WiFi.
Apriamo quindi la pagina web di ESPHome. Se usate Home Assistant OS accedente tramite l'Add-on, se invece usate docker, collegatevi alla pagina web apposita.
Clicchiamo sul pulsante "+ NEW DEVICE"
Inseriamo un nome per il dispositivo, ad esempio "RF433_Receiver" (è il nome che vedremo in Home Assistant), e clicchiamo su "NEXT"
5. Collegamenti Hardware
Se avete preso lo stesso modulo che ho usato io, il collegamento è molto semplice. Usando 3 cavetti Dupont per VCC, GND e DATA possiamo facilmente collegarlo alla board ESP.
Io ho collegato all'ESP32 i cavetti in questo modo:
- Giallo --> GND
- Arancio --> 3V3
- Verde --> P27 (potete usare anche un altro PIN DIO, se volete)
Poi ho collegato (di conseguenza) i cavetti Dupont al modulo ricevente in questo modo:
- Giallo --> GND
- Arancio --> VCC
- Verde --> DATA (uno dei 2, sono uguali)
6. Capire il funzionamento (opzionale)
Questo passaggio è opzionale, serve solo per comprendere il perché e il come viene scritto il codice definitivo (e per poterlo modificare a seconda delle esigenze). Se non vi interessa, potete andare direttamente all'ultimo punto dove trovate il codice completo e finale.
Ora che abbiamo fatto i collegamenti Hardware, dobbiamo configurare il modulo ESP affinché legga e interpreti i dati provenienti da esso.
Andiamo quindi ad aggiungere il seguente codice in ESPHome, sostituendo "GPIO27" con il riferimento al PIN che avete utilizzato
# Example configuration entry
remote_receiver:
pin:
number: GPIO27
mode: INPUT
#inverted: True
dump: #all
#- abbwelcome #Decode and dump ABB-Welcome codes. Messages are sent via copper wires. See transmitter description for more details.
#- aeha #Decode and dump AEHA infrared codes.
#- byronsx #Decode and dump Byron SX doorbell RF codes.
#- canalsat #Decode and dump CanalSat infrared codes.
#- canalsatld #Decode and dump CanalSatLD infrared codes.
#- coolix #Decode and dump Coolix infrared codes.
#- dish #Decode and dump Dish infrared codes.
#- dooya #Decode and dump Dooya RF codes.
#- drayton #Decode and dump Drayton Digistat RF codes.
#- jvc #Decode and dump JVC infrared codes.
#- keeloq #Decode and dump KeeLoq RF codes.
#- haier #Decode and dump Haier infrared codes.
#- lg #Decode and dump LG infrared codes.
#- magiquest #Decode and dump MagiQuest wand infrared codes.
#- midea #Decode and dump Midea infrared codes.
#- nec #Decode and dump NEC infrared codes.
#- nexa #Decode and dump Nexa (RF) codes.
#- panasonic #Decode and dump Panasonic infrared codes.
#- pioneer #Decode and dump Pioneer infrared codes.
#- pronto #Print remote code in Pronto form. Useful for using arbitrary protocols.
#- raw #Print all remote codes in their raw form. Also useful for using arbitrary protocols.
#- rc5 #Decode and dump RC5 IR codes.
#- rc6 #Decode and dump RC6 IR codes.
- rc_switch #Decode and dump RCSwitch RF codes.
#- roomba #Decode and dump Roomba infrared codes.
#- samsung #Decode and dump Samsung infrared codes.
#- samsung36 #Decode and dump Samsung36 infrared codes.
#- sony #Decode and dump Sony infrared codes.
#- toshiba_ac #Decode and dump Toshiba AC infrared codes.
#- mirage #Decode and dump Mirage infrared codes.
#- toto
# Settings to optimize recognition of RF devices
tolerance: 50%
filter: 250us
idle: 3ms
Come potete notare tutti i protocolli sono commentati ad eccezione di "rc_switch" (il protocollo utilizzato dalla stragrande maggioranza di questi sensori). Gli altri protocolli utili potrebbero essere "pronto" e "raw", ma se attivate uno di questi 2 vedrete arrivare tantissimi dati per lo più inutili al nostro scopo.
Possono comunque venire utili nel caso stiate cercando di affinare i parametri di lettura/riconoscimento (per vedere se vi arrivano dati o meno).
I valori che vedete in "tolerance", "filter" e "idle" sono dati che ho trovato empiricamente: ho fatto svariati test affinando ognuno di essi finchè non ho trovato la combinazione ottimale.
Se usate li stesso modulo che ho usato io dovrebbero andare bene anche per voi.
Ripulito un po' dalla parte inutile, dovreste avere un codice del genere:
Ora salviamo cliccando su "SAVE" in alto a destra
E aggiorniamo il firmware sul modulo cliccando su "INSTALL"
Poi su "Wirelessly"
E attendiamo che finisca la compilazione e l'installazione
Non chiudiamo la finestra ma rimaniamo in attesa per veder i log del modulo. La finestra sarà simile a questa:
Ora allontaniamo il magnete dal sensore porta, in modo che si accenda il led (il sensore effettua una trasmissione)
A questo punto nel log di ESPHome dovrebbero comparire diverse righe simili a queste
Se così non fosse i casi sono 2:
- il sensore che avete non utilizza il protocollo RC Switch (difficile che sia questo il caso)
- i parametri di decodifica non sono ottimali per il vostro caso
7. Inviare i dati a Home Assistant (opzionale)
Come il precedente, anche questo punto serve solo a capire il perché del codice inserito. Se non vi interessa, saltate anche questo punto.
Per poter iniziare ad interpretare i dati che arrivano dal sensore in maniera un po' più efficiente, dobbiamo mandarli ad Home Assistant. Per fare questo io utilizzo 2 sistemi (concomitanti):
- Un sensore testuale che cambia valore ogni volta che riceve un nuovo messaggio RF433
- Un evento inviato ad Home Assistant (usando il bus eventi nativo di HA) ogni volta che viene ricevuto un messaggio RF433
on_rc_switch:
then:
- lambda: 'char str[100]; sprintf(str, "%X", x.code); id(rf433_last_code).publish_state(str);'
- homeassistant.event:
event: esphome.rf_code_received
data:
code: !lambda 'char str[100]; sprintf(str, "%X", x.code); std::string sCode = str; return sCode;'
text_sensor:
- platform: template
name: "RF433 Last code"
id: "rf433_last_code"
icon: "mdi:waveform"
filters:
- to_upper:
Il codice dovrebbe presentarsi in questo modo
Come si può vedere dal codice sopra, abbiamo creato un sensore di tipo testo ("text_sensor") direttamente in Home Assistant (trovate l'entità direttamente nella pagina del dispositivo) con nome "RF433 Last code".
Poi abbiamo configurato il ricevitore per cui, in caso di ricevimento di un messaggio "rc_switch":
- Aggiorna lo stato del sensore "RF433 Last code" scrivendo il codice ricevuto (in esadecimale)
- Invia un evento in Home Assistant con tipo "esphome.rf_code_received" e con un parametro chiamato "code" che contiene il codice ricevuto dal sensore (in esadecimale)
E aggiorniamo il firmware sul modulo cliccando su "INSTALL"
Poi su "Wirelessly"
E attendiamo che finisca la compilazione e l'installazione
7. Filtrare gli eventi identici ripetuti (opzionale)
Come i precedenti, anche questo punto serve solo a capire il perché del codice inserito. Se non vi interessa, saltate anche questo.
- l'oggetto "time"
- le variabili globali
globals:
- id: last_command_time
type: int
restore_value: no
initial_value: '0'
- id: last_command_code
type: std::string
restore_value: no
initial_value: '""'
time:
- platform: sntp
id: sntp_time
timezone: Europe/Rome
Abbiamo cioè dichiarato 2 variabili globali:
- "last_command_time" che useremo per salvarci il timestamp di ricezione dell'ultimo segnale ricevuto dal sensore
- "last_command_code" che useremo per salvare il codice dell'ultimo segnale ricevuto dal sensore
on_rc_switch:
then:
- if:
condition:
or:
- lambda: |-
char strHex[100];
sprintf(strHex, "%x", x.code);
std::string sCode = strHex;
std::string sPreviusCode = id(last_command_code);
int timenow = id(sntp_time).now().timestamp;
if (sCode != sPreviusCode || (timenow - id(last_command_time)) > 1)
{
id(last_command_code) = sCode;
id(last_command_time) = timenow;
return sCode.size() == 6;
}
id(last_command_time) = timenow;
return false;
then:
- lambda: 'char str[100]; sprintf(str, "%X", x.code); id(rf433_last_code).publish_state(str);'
- homeassistant.event:
event: esphome.rf_code_received
data:
code: !lambda 'char str[100]; sprintf(str, "%X", x.code); std::string sCode = str; return sCode;'
Il codice qui sopra aggiunge una condizione all'invio dell'evento a Home Assistant e all'aggiornamento del valore dell'entità "RF433 Last code". Per prima cosa "converte" il codice ricevuto ("x.code") da numerico a testuale, con 2 tipologie: esadecimale (di più facile e comoda interpretazione) e binario (utile per capire la lunghezza del dato ricevuto).
Successivamente controlla che sia verificata almeno una delle 2 condizioni:
- il codice ricevuto è diverso dall'ultimo codice ricevuto
- è passato più di 1 secondo dall'ultimo codice ricevuto
8. Il codice completo
Se avete seguito i passi opzionali, dovreste già aver scritto il codice completo, in caso contrario questo è quello che dovete aggiungere in ESPHome dopo "captive portal:"
# Example configuration entry
remote_receiver:
pin:
number: GPIO27
mode: INPUT
#inverted: True
dump: #all
#- raw #Print all remote codes in their raw form. Also useful for using arbitrary protocols.
- rc_switch #Decode and dump RCSwitch RF codes.
# Settings to optimize recognition of RF devices
tolerance: 50%
filter: 250us
idle: 3ms
on_rc_switch:
then:
- if:
condition:
or:
- lambda: |-
char strHex[100];
sprintf(strHex, "%x", x.code);
std::string sCode = strHex;
std::string sPreviusCode = id(last_command_code);
int timenow = id(sntp_time).now().timestamp;
if (sCode != sPreviusCode || (timenow - id(last_command_time)) > 1)
{
id(last_command_code) = sCode;
id(last_command_time) = timenow;
return sCode.size() == 6;
}
id(last_command_time) = timenow;
return false;
then:
- lambda: 'char str[100]; sprintf(str, "%X", x.code); id(rf433_last_code).publish_state(str);'
- homeassistant.event:
event: esphome.rf_code_received
data:
code: !lambda 'char str[100]; sprintf(str, "%X", x.code); std::string sCode = str; return sCode;'
text_sensor:
- platform: template
name: "RF433 Last code"
id: "rf433_last_code"
icon: "mdi:waveform"
filters:
- to_upper:
globals:
- id: last_command_time
type: int
restore_value: no
initial_value: '0'
- id: last_command_code
type: std::string
restore_value: no
initial_value: '""'
time:
- platform: sntp
id: sntp_time
timezone: Europe/Rome
Ho evidenziato in rosso le parti che dovreste/potreste personalizzare: il PIN (GPIO a cui avete collegato il PIN DATA del ricevitore 433Mhz) e la lunghezza del codice inviato dal sensore nel filtro (in questo caso sono 6 caratteri esadecimali).
A questo punto clicchiamo sul tasto "SAVE" in alto a destra
poi su "INSTALL"
quinsd scegliamo "Wirelessly"
e attendiamo che finisca la compilazione e il caricamento del firmware
9. I template sensor in Home Assistant
Ci siamo quasi, ora non rimane che andare a configurare in Home Assistant la nostra entità collegata al sensore RF433.
Aprite l'edito testuale che usate per modificare la configurazione di Home Assistant (io uso Code Server, ma voi potete usare il vostro preferito) e apriamo il file "configuration.yaml".
Se avete abilitato la cartella packages (altamente consigliato), è meglio se invece di aprire il file "configuration.yaml" create un nuovo file chiamandolo, ad esempio, "rf433.yaml", per tenere il codice più pulito possibile.
Ora incollate il codice che trovate qui sotto
template:
#-------- Porta garage --------
- trigger:
- trigger: event
event_type: esphome.rf_code_received
event_data:
code: "B99673" #Apertura
- trigger: event
event_type: esphome.rf_code_received
event_data:
code: "B99679" #Chiusura
#- trigger: event
# event_type: esphome.rf_code_received
# event_data:
# code: "B9967B" #Tampering
binary_sensor:
- name: "Porta garage"
unique_id: b325617e-c717-4225-a4ee-0a69f0eb6286
state: '{{ trigger.event.data.code == "B99673" }}'
icon: >-
{% if trigger.event.data.code == "B99673" %}
mdi:garage-open
{% else %}
mdi:garage
{% endif %}
device_class: door
#-------- Comandi Ricevuti --------
- trigger:
- trigger: event
event_type: esphome.rf_code_received
sensor:
- name: "Ultimo comando RF433 ESPHome"
unique_id: 189b2c03-8942-468a-98ff-506000b4e6a5
state: '{{ trigger.event.data.code }}'
icon: "mdi:waveform"
Commenti
Posta un commento