IoT? Niente di più semplice con ESP8266

Cosa è l' ESP8266?

Cosa è l' ESP8266?

L' ESP8266EX, comunemente chiamato ESP 8266, è un chip prodotto dalla Espressif ed è un SoC e racchiude al suo interno davvero tanto:

  • 17 GPIO - ogni piedino può configurato in diverse modalità (vedi pagina 9 del datasheet)
  • SDIO
  • SPI/HSPI
  • Interfaccia I2C
  • Interfaccia I2S
  • UART
  • PWM
  • IR Remote Control
  • Sniffer

Il chip ESP8266EX lo si può facilmente integrare nei nostri progetti perché è solitamente montato (con altri componenti di contorno) su dei moduli denominati ESP-01 - … - ESP-XX - … - ESP32.

Cosa è l' ESP-01?

Non starò a spigare minuziosamente tutte le funzionalità del chip e dei moduli in commercio, ma in questo articolo voglio proporre dei casi pratici focalizzandomi sull' ESP01 (datasheet) che è il modulo più piccolo ed economico tra tutti:

Esp01 Fronte/Retro

La piedinatura è la seguente:

Esp01 piedinatura

Dove:

  • TX e RX vanno collegati alla relativa scheda di controllo. Attenzione che anche se normalmente TX dell' ESP-01 va collegato a RX della scheda di controllo e RX dell'ESP-01 va collegato a TX della scheda di controllo, se utilizziamo un Arduino UNO TX va collegato a TX e RX a RX. Insomma dipende dalla cosa vogliamo collegarci!
  • CH_PD - Chip enable (se a livello logico alto) Normalmente connesso a VCC
  • GPIO 0,2 - Internal pull-up
  • VCC 3.3V
  • RST - Reset (attivo basso)

L'ESP-01 contiene un microcontrollore a  (MCU) a 32 bit (pagina 12 del datasheet) e 80MHz.

La prima cosa che è possibile notare è che la piedinatura non è compatibile con le schede di sviluppo. Esistono degli adattatori in commercio, ma io ho preferito costruirmene uno:

Adattatore esp01 per breadboard

Hello world!

Il classico e immancabile "Hello world" per l' ESP-01 è un led che lampeggia.

Il circuito è il seguente:

Breadboard con led

Breadboard con led e Esp-01

Il chip sulla parte bassa è un regolatore di tensione AMS 1117 ed ha lo scopo di abbassare la tensione di 5 V dalla linea di destra a 3.3 V sulla linea di sinistra.

Il codice è il seguente:

void setup() {
  pinMode(0,OUTPUT); //GPIO0 -> uscita
}

void loop() {
  digitalWrite(0,HIGH);
  delay(1000);
  digitalWrite(0,LOW);
  delay(1000);
}

Per l'upload del codice basta utilizzare l'adattatore seriale e scegliere "Generic ESP8266 Module":

Scelta scheda Generic Esp8266 Arduino IDE

Hello world ma WebServer

L'obbiettivo di questo esercizio è fare in modo che l'ESP01 immedesimi un WebServer. Avrà un suo IP al quale comparirà una pagina HTML con una casella di testo in cui si dovrà inserire un numero che identificherà il numero di lampeggii del led.

La buona notizia è che il circuito non cambia.

Il codice è il seguente:

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

ESP8266WebServer server(80);



void setup() {
  delay(1000);
  Serial.begin(115200);
  Serial.println();
  Serial.print("Configuring access point...");
  
  pinMode(0,OUTPUT); //GPIO0 -> uscita
  
  delay(2000);
  digitalWrite(0,HIGH);
  delay(2000);
  digitalWrite(0,LOW);
  
  WiFi.softAP("HelloWebServer", "00000000"); //Crea una nuova rete HelloWebServer con password
  IPAddress myIP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(myIP); //stampa l'ip del web server 192.168.4.1
  
  server.on("/", handleRoot);
  server.begin();

  Serial.println("HTTP server started"); 
}

void loop() {
  server.handleClient();
}

void handleRoot() {
  if (server.hasArg("paramNumero") ) { //se è stato inviato un valore
    handleSubmit();
  }
  else {
    server.send(200, "text/html", GetIndexHtml()); //invia la pagina iniziale
  }
}

void handleSubmit()
{
  server.send(200, "text/html", GetWorkingHtml());
  String numero= server.arg("paramNumero");
  int n=numero.toInt();
  for(int i=0; i<n; i++){
      digitalWrite(0,HIGH);
      delay(1000);
      digitalWrite(0,LOW);
      delay(1000);
  }
}

String GetIndexHtml(){

  String result = GetHtml(
     String("<FORM action=\"/\" method=\"post\">")+
    "<p>Immetti il numero di lampegii che il led dovrà fare:</p>" + 
    "Numero: <input type='text' name='paramNumero'><br>"+
    "<input type='submit' value='Submit'>"+
    "</form>");

  return result;
}

String GetWorkingHtml(){
  return GetHtml("<p>Working...</p>  <p><a href='/'>Go to home</a></p> ");
}

String GetOkHtml(){
  return GetHtml("<p>OK</p>");
}

String GetHtml(String content){
  String result = String( "<!DOCTYPE HTML>")+  
    "<html>"+
    "<head>"+
    "<meta name = \"viewport\" content = \"width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable=0\">"+
    "<title>ESP8266 - Hello WebServer</title>"+
    "<style>"+
    "\"body { background-color: #808080; font-family: Arial, Helvetica, Sans-Serif; Color: #000000; }\""+
    "</style>" +
    "</head>" +
    "<body>" +
    
    "<h1>ESP8266 - Hello WebServer</h1>" +

    content +
        
    "</body>" +
    "</html>";

  return result;
}

Leggere e scrivere nella EEPROM

Scrivere il nome della rete e la relativa password nel codice non è molto pratico.

Per ovviare a tale esigenza è possibile utilizzare la EEPROM interna al modulo e quindi salvare le informazioni che vogliamo. 

Di seguito due funzioni che consentono di leggere e scrivere nella EEPROM tre valori (in questo caso ho anche il parametro "hostName" che rappresenta l'hostname di alcuni servizi REST):

void loadCredentials() {
  EEPROM.begin(512);
  EEPROM.get(0, _ssid);
  EEPROM.get(0+sizeof(_ssid), _password);
  EEPROM.get(0+sizeof(_ssid)+sizeof(_password), _hostName);
  
  char ok[2+1];
  EEPROM.get(0+sizeof(_ssid)+sizeof(_password)+sizeof(_hostName), ok);
  EEPROM.end();
  if (String(ok) != String("OK")) {
    _ssid[0] = 0;
    _password[0] = 0;
    _hostName[0] = 0;
  }
  Serial.println("Recovered credentials:");
  Serial.println(_ssid);
  Serial.println(strlen(_password)>0?"********":"<no password>");
  Serial.println(_hostName);
}

/** Store WLAN credentials to EEPROM */
void saveCredentials() {
  EEPROM.begin(512);
  EEPROM.put(0, _ssid);
  EEPROM.put(0+sizeof(_ssid), _password);
  EEPROM.put(0+sizeof(_ssid)+sizeof(_password), _hostName );
  
  char ok[2+1] = "OK";
  EEPROM.put(0+sizeof(_ssid)+sizeof(_password)+sizeof(_hostName), ok);
  EEPROM.commit();
  EEPROM.end();

}