- #esp32
- #esphome
- #home-assistant
- #sntp
- #rtttl
- #oled
- #making
Costruire una sveglia con ESPHome quando il telefono sul comodino è il problema
Costruire una sveglia vera per togliere il telefono dal comodino. ESP32-C3, OLED, buzzer, Home Assistant.
-5 min read
Il problema
Uso il telefono come sveglia. Come tutti.
Il risultato è che il telefono finisce sul comodino, e prima di dormire scrollo per venti minuti cose che non mi servono. La mattina, prima ancora di alzarmi, controllo le notifiche. Lo so che è un problema, ma finché il telefono ha un motivo per stare lì — la sveglia — non c’è verso di spostarlo.
Serviva un oggetto fisico che facesse solo quello: suonare a un’ora precisa, con un pulsante per spegnerla.
Il contesto
Ho Home Assistant in casa. Ho un ESP32-C3 Mini nel cassetto. Ho un display OLED 128x64 e un buzzer piezo passivo avanzati da un altro progetto.
La soluzione ovvia sarebbe comprare una sveglia da 10 euro. Ma volevo una cosa che:
- si integrasse con Home Assistant per configurare le sveglie da telefono (non dal comodino)
- funzionasse anche se Home Assistant è spento
- avesse più allarmi con giorni della settimana
ESPHome era la scelta naturale: YAML, OTA, integrazione nativa con HA, niente codice Arduino da mantenere.
Il ragionamento
L’orologio deve essere autonomo
La prima tentazione è usare Home Assistant come sorgente dell’ora. ESPHome lo supporta nativamente con platform: homeassistant. Ma se HA si riavvia, o se il server è giù, la sveglia non sa più che ore sono.
Ho scelto SNTP (il protocollo standard per sincronizzare l’orologio via rete): l’ESP32 si sincronizza direttamente con i server NTP via WiFi. Serve solo la rete, non Home Assistant.
time:
- platform: sntp
id: sntp_time
timezone: "Europe/Rome"
servers:
- 0.pool.ntp.org
- 1.pool.ntp.org
- 2.pool.ntp.org
Quanti allarmi?
Volevo “N allarmi”, configurabili. Il problema è che ESPHome è statico: le entità si dichiarano in YAML a compile time. Non puoi creare switch e number a runtime.
Le opzioni realistiche erano:
- Un numero fisso di slot (es. 5), tutti dichiarati in YAML. Quelli non usati restano disabilitati.
- Allarmi gestiti da HA e inviati all’ESP via servizi o sensori. Più flessibile, ma dipende da HA — proprio quello che volevo evitare.
Ho scelto 5 slot fissi. Copre qualsiasi uso reale di una sveglia da comodino. È verboso nel YAML (ogni allarme ha ora, minuti, 7 toggle per i giorni, e un enable), ma è semplice da capire e funziona offline.
Ogni allarme: cosa serve
Per ogni slot:
- Ora e minuti — due
numberconrestore_value: true(sopravvivono al riavvio) - Enable/disable — un
switchconrestore_mode - Giorni della settimana — 7 switch (lun-dom), ciascuno con
restore_mode
Totale: 10 entità per allarme × 5 = 50, più il master switch e la durata suoneria. 52 entità in HA. Tante, ma ognuna ha un significato chiaro.
Il display
128×64 pixel monocromatici. Non c’è spazio per fronzoli.
Layout:
- Header (in alto a sinistra): Giorno della settimana corrente (LUN, MAR, ecc.)
- Icona (in alto a destra): Una piccola icona sveglia MDI (12×12px), visibile solo se c’è almeno una sveglia attiva nelle prossime 12 ore
- Centro: Orologio grande, 32px, formato
HH:MM, centrato nel display - Footer:
!! SVEGLIA N !!quando una sveglia sta suonando, altrimenti vuoto
Il limite di 12 ore per l’icona è una scelta di utilità: sul comodino ti interessa sapere se la sveglia suona stanotte o domattina, non se suona domani sera.
Il calcolo della prossima sveglia è fatto nel lambda del display: scorre i 5 slot, controlla giorno e ora, trova il delta minore entro 12 ore. Niente di elegante, ma non richiede componenti o entità aggiuntive.
Il buzzer
Piezo passivo su GPIO10, pilotato via il componente rtttl di ESPHome. RTTTL (Ring Tone Text Transfer Language) è un formato testuale per melodie — lo stesso usato dai Nokia negli anni ‘90. ESPHome lo supporta nativamente e gestisce il PWM in modo asincrono, senza bloccare il resto del firmware.
La suoneria è la ninna nanna di Brahms. Non un beep a 2200Hz: qualcosa di riconoscibile, che si sente senza essere aggressivo.
La suoneria si ferma in tre modi:
- Pulsante fisico sul comodino (GPIO4)
- Pulsante in Home Assistant (per test o emergenze)
- Timeout automatico — durata configurabile da 1 a 15 minuti, default 5
La soluzione
L’hardware:
| Componente | Modello |
|---|---|
| MCU | ESP32-C3 Mini |
| Display | SH1106 128x64 I2C |
| Buzzer | Piezo passivo |
| Pulsante | Normalmente aperto, pullup interno |
I pin:
| Funzione | GPIO |
|---|---|
| I2C SDA (display) | GPIO6 |
| I2C SCL (display) | GPIO7 |
| Buzzer PWM | GPIO10 |
| Pulsante stop | GPIO4 |
Il software è un singolo file YAML ESPHome (~750 righe). La logica degli allarmi gira in un interval da 1 secondo: costruisce un array di struct con i dati dei 5 allarmi, li scorre, e se ora e giorno corrispondono fa partire il suono. Un guard basato sul timestamp del minuto corrente impedisce di ritriggerare lo stesso allarme più volte: una volta scattato, quell’allarme viene ignorato finché non cambia il minuto.
Se il WiFi non è raggiungibile al boot, l’ESP32 attiva automaticamente un hotspot di emergenza che permette di raggiungere il captive portal di ESPHome per diagnostica o riconfigurazione.
Il codice sara disponibile nel repository sveglia-esphome su GitHub.
I limiti
- 52 entità in Home Assistant. Sono tante. L’interfaccia di default di HA le mostra tutte in lista, senza raggruppamento. Serve una card custom o un’automazione per renderle usabili. Questo è un problema di UX, non di funzionamento.
- Il YAML è lungo e ripetitivo. 5 allarmi × 10 entità ciascuno = molta copia-incolla. ESPHome supporta i package e le substitution, ma non i loop sulle entità. Si potrebbe usare un generatore esterno (Jinja2, script Python), ma aggiunge complessità alla build.
- Nessuna batteria di backup, nessun RTC hardware. L’ESP32 si alimenta via USB e usa il WiFi per sincronizzare l’ora. Se manca la corrente, al ritorno deve riconnettersi e sincronizzarsi prima di funzionare. È una scelta voluta: mantenere il progetto semplice, senza componenti aggiuntivi. Le implicazioni pratiche e le possibili evoluzioni (RTC esterno, batteria di backup) saranno oggetto di un post dedicato.
- Niente snooze. Per scelta. Nella v2 magari, ma per ora il pulsante fa solo stop.
- Il display non è retroilluminato in modo controllabile. L’OLED è sempre acceso. In una stanza buia potrebbe dare fastidio. Si potrebbe aggiungere un sensore di luminosità o un timer di spegnimento display, ma aggiunge hardware e complessità.
Conclusione
Un ESP32, un display, un buzzer e un pulsante. Configurazione da telefono via Home Assistant, funzionamento autonomo via NTP.
Non è la sveglia perfetta. Ma fa esattamente quello che serve: suona quando deve, si spegne quando la premi, e il telefono resta in un’altra stanza.
Il prossimo post sarà sull’integrazione con Home Assistant: come rendere usabili 52 entità senza impazzire.