in Arduino Spiegato Facile

ESP8266 & Arduino-core — Gestire la connessione WiFi salvandola in EEPROM

Mi capita tantissime volte di partire con entusiasmo per un progetto basato su ESP, e trovarmi a dovere sbattere la testa con quel codice boilerplate necessario a mettere in piedi la connessione WiFi, che poi va sistematicamente modificato e ri-flashato se si vuole usare l’ESP sotto un’altra rete. Abbiamo visto diversi esempi di questo tipo di codice su antima, quando abbiamo parlato di raccolta dati in tandem con flask, di acquisizione di dati dal sensore di temperatura ed umidità.

In questo articolo vi propongo un approccio diverso a questo problema, con una libreria che ho reso disponibile sul github di antima.it, tramite cui è possibile impostare la connessione una volta sola da browser web, salvando i dati in EEPROM, se il micro in questione ne montasse una, o comunque su una memoria non volatile.

Vi cercherò di presentare il tutto a metà tra un’introduzione all’uso e un tutorial su gestione EEPROM e creazione di Web Server su ESP.

Link repo github: Antima.it@github – EspWifiManager

EspWifiManager.h – Introduzione

I problemi che vogliamo risolvere sono due:

  • non dovere utilizzare il codice sorgente per il setup della connessione di rete;
  • mantenere i dati relativi alla connessione al riavvio dell’ESP.

Ho deciso di approcciarli in maniera separata e poi connettere il tutto insieme tramite un’unica interfaccia che incapsuli i due comportamenti, esponendo delle funzionalità astratte che tolgano il peso allo sviluppatore di pensare a setup vari.

Le API della libreria sono minimali e di una semplicità disarmante, un esempio di applicazione potrebbe essere la seguente:

#include <EspWifiManager.h>

void setup() {
    // setup
}

void loop() {
    WiFiManager.loop();
    if(WiFiManager.isConnected()) {
        // logica applicativa
    }
}

Come si può vedere dall’estratto, una volta inclusa la libreria, per metterla in funzione basterà chiamare il metodo loop all’interno del loop dello sketch Arduino. Per intercettare l’evento connessione attiva, possiamo usare il metodo isConnected, che ritorna true quando l’ESP è connesso alla rete.

L’oggetto WiFiManager viene automaticamente esportato dalla libreria e può essere usato come singleton per chiamare i metodi sopracitati senza dovere inizializzare altro.

All’avvio dello sketch, vengono caricati i dati della connessione dalla EEPROM, dopodiché ad ogni giro della funzione loop la libreria controllerà che la connessione sia in piedi. Nel caso in cui non sia così, proverà a connettersi e, dopo 5 tentativi falliti l’ESP passerà in Access Point mode.

In questa modalità è possibile connettersi all’ESP tramite un dispositivo con WiFi, connettendosi alla rete ESPWiFi-xxx che apparirà come connessione WiFi disponibile. Una volta connessi, andando all’indirizzo http://192.168.4.1, sarà possibile inserire le proprie credenziali di connessione.

La libreria dipende dala bellissima repo ESP Async WebServer: istruzioni dettagliate sull’istallazione del tutto sono presenti nella pagina github linkata ad inizio articolo.

Salvare i dati in EEPROM

L’ESP che uso io è un ESP8266-01, che non ha una vera EEPROM, ma la emula all’interno della sua memoria Flash. Dal punto di vista funzionale cambia poco, in quanto il risultato di potere salvare i dati in un supporto non volatile rimane.

 Per parlare con la EEPROM, ho usato la libreria EEPROM.h, creando un wrapper che gestisca le operazioni astraendo da alcuni particolari e specializzando le interfacce per potere direttamente ragionare in termini di dati di connessione.

Ho creato una struct come tipo per contenere le credenziali con le lunghezze standard, usandola poi come tipo base di ritorno e di ingresso in scrittura/lettura per i metodi wrapper:

struct ConnectionInfo {
    char ssid[SSID_LENGTH];
    char key[KEY_LENGTH];
};

void writeConnectionInfo(ConnectionInfo*);
ConnectionInfo readConnectionInfo();

Queste operazioni sono interne alla libreria, e non entro nei dettagli del cosa fanno dietro le quinte, ma trovo interessante parlare dell’approccio a wrapper in quanto rende possibile rendere estendibili applicazioni di questo tipo.

Ipotizziamo che in un futuro volessi supportare una libreria diversa di accesso alla EEPROM o un’architettura ESP diversa che richiede diversi meccanismi di salvataggio. Con dei wrapper che astraggono le operazioni di basso livello, non dovrò cambiare le mie API quando avrò bisogno di implementare queste funzionalità.

Access Point Mode e Async Web Server

La funzione di loop che controlla che la connessione di rete sia attiva è corta e di semplice analisi:

if(!apMode) {
    bool wifiConn = WiFi.isConnected();
    if (!wifiConn) {
        bool okWifi = connectToWifi();
        if (!okWifi) {
            activateAPMode();
        }
    }
}

Se la connessione non va, passiamo all’AP mode, in cui l’ESP è raggiungibile come router WiFi. Attivare l’AP mode su ESP è molto semplice, bastano davvero due righe:

WiFi.mode(WIFI_AP);
WiFi.softAP(randSSID);

randSSID è una stringa con il nome con cui la connessione dell’ESP verrà visualizzata da un dispositivo WiFi che ci si vuole connettere. In AP mode, l’ESP rende possibile l’utilizzo dell’indirizzo 192.168.4.1 per far sì che applicazioni custom dell’utente siano raggiungibili a chi si connette al dispositivo. 

Per fare sì che l’utente possa inserire le sue credenziali, ho creato una piccolissima app front-end in HTML e Javascript, con due endpoint HTTP realizzati tramite Async Web Server.

Questa libreria permette di creare semplici web server totalmente async, con una sintassi intuitiva e diretta. Il mio server HTTP è composto da soli due endpoint, uno che ha lo scopo di caricare l’interfaccia utente, un altro che valida le informazioni inserite dall’utente, le salva in EEPROM e resetta l’ESP.

void createAPServer(AsyncWebServer &server)
{
    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
        request->send_P(200, "text/html", login_html);
    });

    server.on("/connect", HTTP_POST, [](AsyncWebServerRequest *request) {
        if (!validPostConnect(request))
        {
            request->send(422, "text/plain", "wrong syntax");
            return;
        }
        request->send(200, "text/plain", "ok");
        delay(1000);

        ConnectionInfo info;

        String ssid = request->getParam("ssid", true)->value();
        String key = request->getParam("key", true)->value();

        strncpy(info.ssid, ssid.c_str(), SSID_LENGTH);
        strncpy(info.key, key.c_str(), KEY_LENGTH);

        DEBUG_MSG("%s %s", info.ssid, info.key);

        EeManager.writeConnectionInfo(&info);
        ESP.reset();
    });
}

L’endpoint “/”, che fa riferimento all’interfaccia utente, carica la schermata di inserimento delle credenziali. Questa è contenuta in una variabile caricata in memoria Flash tramite la keyword PROGMEM, ed appare in questo modo:

Conclusioni

Spero che questa libreria possa tornarvi utile per rimuovere lo scoglio del setup WiFi e lasciare spazio alle idee applicative che sono la parte più divertente dell’approccio con i dispositivi ESP. Vi invito a scaricare e provare la libreria, e vi anticipo che sarà uno degli ingredienti che andrò ad usare nei prossimi articoli della serie di Telegram.

Per questo articolo è tutto, per eventuali approfondimenti o richieste di chiarimenti vi invito come al solito a commentare nella sezione qui sotto!

Scrivi un commento

Commento