Il progetto che vi presento oggi, ESP32lights, è una centralina di controllo luci smart, basata sul chip esp32.
Tramite ESP32lights è possibile accendere/spegnere un carico (io lo utilizzo per le luci natalizie…)
[checklist]
- manualmente
- secondo una schedulazione oraria
- in base alla luminosità
[/checklist]
ESP32lights si collega alla rete wifi di casa, è gestito interamente via browser ed è ottimizzato per dispositivi mobile (interfaccia responsive basata su jQuery Mobile).
Componenti
Cuore della centralina ESP32lights è la scheda di sviluppo Lolin32 Lite di Wemos. Uno dei pin digitali della scheda è collegato ad un modulo relay, il quale controlla il carico. Due pin digitali, assegnati al primo controller i2c del chip esp32, sono invece connessi al sensore luminosità BH1750. L’alimentazione a tutti i dispositivi della centralina è infine fornita dal modulo HLK-PM01 di Hi-Link che converte i 220V AC della rete in 5V DC senza necessità di componenti esterni:
Tutti i componenti sono inseriti in un contenitore a tenuta stagna, in modo da poter collocare la centralina anche all’esterno:
Programmazione
Il programma in esecuzione sulla devboard esp32 è disponibile nel mio repository Github.
In uno dei successivi paragrafi vi illustrerò il suo funzionamento. Se volete semplicemente realizzare la vostra centralina, potete effettuare la programmazione del firmware come segue:
1) effettuare il clone del mio repository in una cartella locale del vostro PC (dovete avere installato l’ambiente di sviluppo esp-idf):
2) configurare i parametri della vostra rete wifi e del fuso orario tramite menuconfig:
3) compilare e programmare il firmware:
make flash
4) memorizzare nella flash la partizione SPIFFS (utilizzate la vostra porta COM e il path dove avete salvato il file img):
python $IDF_PATH/components/esptool_py/esptool/esptool.py --chip esp32 --port COM15 --baud 115200 write_flash --flash_size detect 0x180000 /home/esp32lights.img
Se tutto è stato eseguito correttamente, collegandosi in seriale (make monitor) alla scheda di sviluppo dovrebbe apparire il seguente output:
Utilizzo
ESP32light mette a disposizione una interfaccia HTTP attraverso la quale è possibile inserire la programmazione (oraria o basata su una soglia di intensità luminosa) o controllare manualmente l’accensione e lo spegnimento del carico collegato alla centralina.
E’ possibile visualizzare l’interfaccia collegandosi (da PC o smartphone) all’indirizzo http://<esp_ip> (l’indirizzo IP della scheda è visibile dall’output seriale come mostrato nel paragrafo precedente).
L’interfaccia è divisa in 3 tab, uno per ogni modalità di funzionamento:
La barra di stato visualizza la modalità di funzionamento attuale:
Nel breve video che segue, potete vedere l’utilizzo della centralina (sottotitoli in italiano disponibili):
Software
Il firmware di ESP32lights è stato realizzato sfruttando quando appreso nei miei precedenti tutorial. Se infatti seguite il mio blog, avrete sicuramente capito che prediligo il metodo divide et impera, ovvero suddividere un progetto complesso in task più semplici.
Tutti i parametri di configurazione di ESP32lights (modalità di funzionamento, programmazione oraria…) sono memorizzati nella partizione NVS come vi ho spiegato in questo tutorial; in questo modo è possibile conservarli anche in caso di riavvio del chip esp32:
nvs_handle my_handle; int working_mode; [...] esp_err_t err = nvs_flash_init(); err = nvs_open("storage", NVS_READWRITE, &my_handle); err = nvs_get_i32(my_handle, "mode", &working_mode); |
I diversi elementi della interfaccia web (pagine html, fogli di stile css…) sono memorizzati all’interno di una partizione SPIFFS. In un precedente tutorial vi ho mostrato come preparare l’immagine ed accedere al suo contenuto:
Anche il collegamento ad una rete wifi e l’utilizzo dei pin digitali del chip esp32 per il controllo del relay sono stati oggetto di tutorial dedicati.
La fase di setup iniziale si conclude con la configurazione del sensore di luminosità BH1750. Tale sensore offre una interfaccia i2c e può essere quindi collegato ad uno dei due controller i2c del chip come spiegato in questo tutorial. Nel mio programma ho utilizzato un driver preparato da pcbreflux.
Il programma principale è composto da tue task distinti:
xTaskCreate(&http_server, "http_server", 20000, NULL, 5, NULL); xTaskCreate(&monitoring_task, "monitoring_task", 2048, NULL, 5, NULL); |
Il primo pubblica l’interfaccia web, mentre il secondo si occupa di verificare – ogni secondo – se esistono le condizioni (orario o intensità luminosa) per accendere o spegnere il carico:
if(working_mode == MODE_LIGHT && lux_valid) { int actual_light_value = get_light_value(); if(actual_light_value < lux) { if(relay_status == false) { gpio_set_level(CONFIG_RELAY_PIN, 1); relay_status = true; } |
Ecco nel dettaglio come funziona il server http quando viene richiesta una risorsa statica, memorizzata nella partizione SPIFFS.
Per prima cosa al path della risorsa deve essere aggiunta la root della partizione SPIFFS (/spiffs):
sprintf(full_path, "/spiffs%s", resource); |
quindi il programma verifica se la risorsa esiste nella partizione:
if (stat(full_path, &st) == 0) { |
in caso affermativo, apre il file in lettura:
FILE* f = fopen(full_path, "r"); |
e ne invia il contenuto al client, leggendo blocchi di 500 bytes:
char buffer[500]; while(fgets(buffer, 500, f)) { netconn_write(conn, buffer, strlen(buffer), NETCONN_NOCOPY); } |
Vediamo infine il funzionamento dell’interfaccia web. Questa è composta da una pagina html (index.html) che utilizza jQuery per effettuare chiamate AJAX al server e aggiornare l’interfaccia responsive (basata su jQuery Mobile). Non è necessario inserire il nome della pagina nel browser perché il server http effettua una redirect automatica se viene richiesta la pagina di default:
if(strstr(request_line, "GET / ")) spiffs_serve("/index.html", conn); |
Gli endpoints pubblicati dal server e invocati dalla pagina con chiamate AJAX sono 3:
[checklist]
- setConfig, per inviare una nuova configurazione
- getConfig, per leggere la configurazione attuale
- getLight, per leggere il valore attuale di luminosità
[/checklist]
Al primo caricamento della pagina, questa chiama la getConfig per visualizzare la configurazione attuale; inoltre schedula ogni cinque secondi la chiamata a getLight per tenere aggiornato il valore visualizzato:
refreshConfig(); setInterval("refreshLightLevel()", 5000); |
Alla pressione del pulsante SET, viene invece invocata la setConfig per inviare al server la nuova configurazione:
Lo scambio di informazioni avviene utilizzando il formato JSON. Il framework esp-idf include la libreria cJSON che semplifica sia il parsing che la costruzione di un nuovo messaggio json:
cJSON *root = cJSON_Parse(body); cJSON *mode_item = cJSON_GetObjectItemCaseSensitive(root, "mode"); [...] cJSON *root = cJSON_CreateObject(); cJSON_AddNumberToObject(root, "lux", light_value); char *rendered = cJSON_Print(root); |
Making of
Ho iniziato la costruzione della centralina tagliando un pezzo di breadboard delle dimensioni del contenitore:
La breadboard è collegata al contenitore tramite due distanziali e due fori:
Ho praticato due fori in un lato del contenitore per ospitare l’interruttore principale e un led di stato:
Ho saldato i vari componenti sulla breadboard e realizzato – tramite filo – i vari collegamenti:
Per rendere più facile l’installazione, tutti i componenti esterni (led, modulo relay…) sono collegati tramite jumpers:
Primo test di funzionamento:
Ho fissato il sensore di luminosità al coperchio del contenitore, dopo aver praticato un foro per consentirgli di “vedere” la luce esterna:
Ho infine realizzato i collegamenti elettrici, installando un interruttore generale:
e collegando l’uscita del modulo relay ad cavo che termina con una presa universale:
Hello, I see that you use a lot that AC/DC convertor. Are you satisfied with it. I just started using one for an ESP8266 project and so far no smoke and everything seems to work fine. Did you have any issues with them?
Thank you.
Hi, so far the AC/DC modules I used in my projects worked great! No issues at all!
Thank you, I hope that mine will do just fine too. Great work.
hi, Luca, i am in China and we want develop a device using ESP32 as the WIFI module. we have a device needs to be controlled remotelly with mobile phone. do you know any company or ppl who is good at this ESP32 based development?
Thanks.
Hi Tom, try asking on esp32.com, it’s the “official” forum and there are freelancers who regularly write on it
thanks, i will go for it.
Economics of scale kicking in. A 1A USB charger is much cheaper than the Hi-Link module, and is about the same size.
The build quality is questionable and you have to pot them yourself then of course, but I have had good luck with them in similar applications.
If you really wanted to get cheap since your design can be entirely isolated: Switch your relay out for a logic level triac and you can then drive this directly from mains with just two capacitors, a switching diode, and a zener. This comes with the warning that one leg of the ESP32 will be at mains level then so no human contact allowed once in circuit, and triac failure will likely fry the ESP32.
Hi Daren, thanks for your suggestions! To be honest I had some Hi-Link modules laying around and I this was a good project to test them.
Hi Luca, great project, is there anywhere that describes how the data in the webapp is accessed by the esp32 ?
js and web development is not my strongpoint by any stretch
thanks ! keep up the good work
ah sorry, ignore my question i hadn’t got that far down the article 🙂
Your Hi-Link is dead!
Thanks Ted, now fixed
Ciao Luca, chiaro come sempre: avrei una domanda sul relay.. I 5 v per la bobina sono presi dalla esp32 board ma il pin per azionare il relay è a 3.3 v (uscita della scheda) : non hai paura che bruci la scheda (oppure hai tolto il jumper vcc che si trova sul relay e alimentazione e controllo sono su 2 linee separate?)
Per farla breve si può connettere in maniera così semplice un relay 5 v dc alla scheda esp32?
Grazie in anticipo della risposta
Mauro
Ciao Mauro! In effetti il relay è dichiarato a 5v (avevo solo quello) ma “scatta” anche se lo controlli a 3.3V… non c’è rischio di bruciare la scheda, al massimo se la tensione non è sufficiente il relay non si aziona.
Hi Luca,
Great project, it is almost exactly what I was looking for.
I had a timer for years that turns the lights on when it gets dark, and turns it off at given time so it won’t be on until the morning. Since I am not a programmer, I want to ask you if your program can be modified to do that. It would be of great help to me since the timer I used is EOL and there are no replacements for a usable price.
Thanks.
Hi Herman, you should be able to modify the program… to keep it simple you could use one of the time fields already present in the GUI to set the “off” time instead of designing a dedicated GUI (more complex)
Ciao Luca, grazie per la condivisione del progetto.
Ho un dubbio sui collegamenti elettrici.
l’uscita massa e +5 volt del convertitore su quali pin della scheda lolin32 li collego?
A me sembra che questa scheda si alimenti solo dalla presa usb.
Tu come li hai collegati?
Infine confermami per cortesia gli altri pin di collegamento che sono pin 0=comando relè, il 4=SCL il 16=SDA del sensore BH1750.
Grazie mille in anticipo.
Felice.
Ciao Felice, ho utilizzato il connettore batteria (vedi questa immagine). Il pin del relay lo configuri da menuconfig, mentre quelli del sensore sono i pin 18 e 19 (ma li puoi cambiare editando bh1750.c
Ciao Luca, ieri ho inserito una richiesta, vorrei solo sapere se è stata ricevuta, grazie.
Massimo
ciao massimo, no non ho ricevuto nulla… mi hai scritto tramite form?
Ciao Luca. Sei grande.Bravo. Un rumeno chi aprezza tuo lavoro.
grazie mille!
Ciao Luca,
grazie per le spiegazioni molto chiare!
Ho un problema con il file .img della partizione SPIFFS relativa ai files css e html.
Se utilizzo quello incluso nel progetto tutto funziona correttamente, mentre semplicemente rigenerando il file .img con i comandi da te indicati nel tutorial, ottengo un file binariamente differente rispetto all’originale con l’effetto di non riuscire ad avviare la pagina web dal browser
Hai qualche consiglio sulla origine delle differenze?
Grazie
Roberto
ciao Roberto, a partire da una certa versione in avanti, espressif ha “rotto” la compatibilità con l’utility mkspiffs… quale versione stai usando?
Ciao Luca,
ho scaricato e compilato la versione dal link
https://github.com/loboris/ESP32_spiffs_example
per generare il file di creazione dei file immagine .img
Per quanto riguarda i files da allegare al progetto ho lasciato quelli da te inclusi nel progetto (cartella firmware\components\spiffs\).
ciao Roberto, prova ad aggiornare anche la libreria spiffs che sta nella sottocartella components, probabilmente se usi la versione più recente di mkspiff devi usare anche la libreria relativa
Ciao Luca,
problema risolto.
L’origine del problema era il disallineamento tra i files spiffs_config.h: il primo necessario per generare il file mkspiffs.exe di creazione della immagine .img , il secondo quello per accedere tramite applicazione scaricata su esp32 ai files contenuti nell’immagine stessa.
Roberto
Ciao Roberto volevo chiederti un chiarimento: come capitato a te provando a creare una nuovo file .img non visualizzo i contenuti sul web browser.
Hai accennato a un problema di disallineamento dei file spiffs_config.h.
Puoi spiegarmi in dettaglio quale operazione hai effettuato ?
Ciao Nicola,
io avevo trovato una differente definizione dei parametri
SPIFFS_OBJ_META_LEN
SPIFFS_USE_MAGIC_LENGTH
SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
tra il progetto di Luca e quanto scaricato da internet, necessario per generare il file mkspiffs.exe.
Ti consiglio di mettere alcune std::cout nel main per stampare dette defines, ricompilare ed eseguire mkspiffs.exe: in questo modo potrai vedere con quali parametri sta creando l’immagine il software mkspiffs.exe e confrontarli con quelli del tuo progetto. io me ne sono accorto in questo modo.
Ciao Luca
Sto sviluppando un progetto simile al tuo che in pratica prevede che dei relè siano comandati da un’app e ho già sviluppato tutto. La mia domanda è la seguente: dato che usi in questo progetto un relè uguale al mio per comandare la 220. Dovrei pilotare un carico di circa 10A sulla 220AC, secondo te va bene o esplode? Ho anche preso, sempre made in cina, un relè più grosso, che indica 30A o 1/2 HP su 240VAC. In pratica dovrei comandare due motori elettrici, uno da 0,6HP e uno da 1 HP credo che neanche il relè più grosso vada bene o sbaglio?
Aspettavo anche una tua risposta sul progetto al link
http://www.lucadentella.it/2015/09/12/collegare-arduino-a-dispositivi-a-3-3v/