martes, 20 de junio de 2017

Tutorial #7 ESP8266 - Guardar Ssid y Password en la Eeprom

En este tutorial de IOT (internet de las cosas), vamos a ver un ejemplo de cómo guardar (y leer) el ssid y el password en forma no volátil desde la memoria eeprom interna del ESP8266. Para eso nos valemos de un pulsador que usamos para iniciar el micro en el modo SoftAP (acces point) donde montamos un webserver, permitiéndonos configurar todos los datos que necesitamos desde el navegador de un smartphone.


Código Fuente:

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

//-------------------VARIABLES GLOBALES--------------------------
int contconexion = 0;
unsigned long previousMillis = 0;

char ssid[50];      
char pass[50];

const char *ssidConf = "tutorial";
const char *passConf = "12345678";

String mensaje = "";

//-----------CODIGO HTML PAGINA DE CONFIGURACION---------------
String pagina = "<!DOCTYPE html>"
"<html>"
"<head>"
"<title>Tutorial Eeprom</title>"
"<meta charset='UTF-8'>"
"</head>"
"<body>"
"</form>"
"<form action='guardar_conf' method='get'>"
"SSID:<br><br>"
"<input class='input1' name='ssid' type='text'><br>"
"PASSWORD:<br><br>"
"<input class='input1' name='pass' type='password'><br><br>"
"<input class='boton' type='submit' value='GUARDAR'/><br><br>"
"</form>"
"<a href='escanear'><button class='boton'>ESCANEAR</button></a><br><br>";

String paginafin = "</body>"
"</html>";

//------------------------SETUP WIFI-----------------------------
void setup_wifi() {
// Conexión WIFI
  WiFi.mode(WIFI_STA); //para que no inicie el SoftAP en el modo normal
  WiFi.begin(ssid, pass);
  while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(250);
    Serial.print(".");
    digitalWrite(13, HIGH);
    delay(250);
    digitalWrite(13, LOW);
  }
  if (contconexion <50) {   
      Serial.println("");
      Serial.println("WiFi conectado");
      Serial.println(WiFi.localIP());
      digitalWrite(13, HIGH);  
  }
  else { 
      Serial.println("");
      Serial.println("Error de conexion");
      digitalWrite(13, LOW);
  }
}

//--------------------------------------------------------------
WiFiClient espClient;
ESP8266WebServer server(80);
//--------------------------------------------------------------

//-------------------PAGINA DE CONFIGURACION--------------------
void paginaconf() {
  server.send(200, "text/html", pagina + mensaje + paginafin); 
}

//--------------------MODO_CONFIGURACION------------------------
void modoconf() {
   
  delay(100);
  digitalWrite(13, HIGH);
  delay(100);
  digitalWrite(13, LOW);
  delay(100);
  digitalWrite(13, HIGH);
  delay(100);
  digitalWrite(13, LOW);

  WiFi.softAP(ssidConf, passConf);
  IPAddress myIP = WiFi.softAPIP(); 
  Serial.print("IP del acces point: ");
  Serial.println(myIP);
  Serial.println("WebServer iniciado...");

  server.on("/", paginaconf); //esta es la pagina de configuracion

  server.on("/guardar_conf", guardar_conf); //Graba en la eeprom la configuracion

  server.on("/escanear", escanear); //Escanean las redes wifi disponibles
  
  server.begin();

  while (true) {
      server.handleClient();
  }
}

//---------------------GUARDAR CONFIGURACION-------------------------
void guardar_conf() {
  
  Serial.println(server.arg("ssid"));//Recibimos los valores que envia por GET el formulario web
  grabar(0,server.arg("ssid"));
  Serial.println(server.arg("pass"));
  grabar(50,server.arg("pass"));

  mensaje = "Configuracion Guardada...";
  paginaconf();
}

//----------------Función para grabar en la EEPROM-------------------
void grabar(int addr, String a) {
  int tamano = a.length(); 
  char inchar[50]; 
  a.toCharArray(inchar, tamano+1);
  for (int i = 0; i < tamano; i++) {
    EEPROM.write(addr+i, inchar[i]);
  }
  for (int i = tamano; i < 50; i++) {
    EEPROM.write(addr+i, 255);
  }
  EEPROM.commit();
}

//-----------------Función para leer la EEPROM------------------------
String leer(int addr) {
   byte lectura;
   String strlectura;
   for (int i = addr; i < addr+50; i++) {
      lectura = EEPROM.read(i);
      if (lectura != 255) {
        strlectura += (char)lectura;
      }
   }
   return strlectura;
}

//---------------------------ESCANEAR----------------------------
void escanear() {  
  int n = WiFi.scanNetworks(); //devuelve el número de redes encontradas
  Serial.println("escaneo terminado");
  if (n == 0) { //si no encuentra ninguna red
    Serial.println("no se encontraron redes");
    mensaje = "no se encontraron redes";
  }  
  else
  {
    Serial.print(n);
    Serial.println(" redes encontradas");
    mensaje = "";
    for (int i = 0; i < n; ++i)
    {
      // agrega al STRING "mensaje" la información de las redes encontradas 
      mensaje = (mensaje) + "<p>" + String(i + 1) + ": " + WiFi.SSID(i) + " (" + WiFi.RSSI(i) + ") Ch: " + WiFi.channel(i) + " Enc: " + WiFi.encryptionType(i) + " </p>\r\n";
      //WiFi.encryptionType 5:WEP 2:WPA/PSK 4:WPA2/PSK 7:open network 8:WPA/WPA2/PSK
      delay(10);
    }
    Serial.println(mensaje);
    paginaconf();
  }
}

//------------------------SETUP-----------------------------
void setup() {

  pinMode(13, OUTPUT); // D7 
  
  // Inicia Serial
  Serial.begin(115200);
  Serial.println("");

  EEPROM.begin(512);

  pinMode(14, INPUT);  //D5
  if (digitalRead(14) == 0) {
    modoconf();
  }

  leer(0).toCharArray(ssid, 50);
  leer(50).toCharArray(pass, 50);

  setup_wifi();
}

//--------------------------LOOP--------------------------------
void loop() {

  unsigned long currentMillis = millis();

  if (currentMillis - previousMillis >= 5000) { //envia la temperatura cada 5 segundos
    previousMillis = currentMillis;
    Serial.println("Funcionado...");
  }
}

10 comentarios:

  1. Genial! esta muy bueno el tutorial.. Es muy util... Te quiero hacer una consulta... A esto le quiero agregar el codigo que uso normalmente para recibir comandos http pero no me permite

    WiFiClient client = server.available();
    if (!client) {
    return;
    }
    Serial.println("new client"); // Wait until the client sends some data
    while(!client.available()){
    delay(1);
    }
    String req = client.readStringUntil('\r'); // Read the first line of the request
    Serial.println(req);
    client.flush();

    if (req.indexOf("/D3/0") != -1) // Match the request
    val1 = 0;
    else if (req.indexOf("/D3/1") != -1)
    val1 = 1;

    ese es el codigo que quiero agregar en el loop... pero me sale el siguiente error...


    C:\Users\xxx\Documents\Arduino\Tecla___config_wifi\Tecla___config_wifi.ino: In function 'void loop()':

    Tecla___config_wifi:260: error: 'class ESP8266WebServer' has no member named 'available'

    WiFiClient client = server.available();

    ^
    exit status 1
    'class ESP8266WebServer' has no member named 'available'

    Podras darme una mano? Gracias

    ResponderEliminar
    Respuestas
    1. Tendría que ver todo el código para estar seguro: pero me parece que te falta declarar: ESP8266WebServer server(80);

      O eliminar la línea: WiFiClient espClient;

      Eliminar
    2. Lo que quiero hacer es agregar al codigo la posibilidad de prender y apagar un led una vez realizada la configuracion. Si llegas a tener idea de como hacerlo te agradeceria muchisimo

      Eliminar
    3. Lo agregas al final de la función: void guardar_conf()
      Te recomiendo el tutorial 8, usar SPIFFS es mejor que usar la EEPROM

      Eliminar
  2. Buenas tardes, super bueno el tutorial, una pregunta porque es mejor spiffs que la eeprom

    ResponderEliminar
  3. Para mi gusto es mejor SPIFFS, fijate que hice un tutorial al respecto. Saludos.

    ResponderEliminar
  4. Buenas tardes, si no se disponer de un interruptor... ¿seria posible disponer del web server que permite introducir el SSID y de loop normal?, seria algo asi como una alternativa puramente software...

    ResponderEliminar
    Respuestas
    1. Si, tenés que iniciar tanto en modo softAP como station es decir: WIFI_AP_STA. Pero no te lo recomiendo, para mi es mejor no usar el modo softAP al menos que se lo necesite, para que sea más estable y consuma menos energía.

      Eliminar
    2. Pero, se puede mantener el server iniciado mientra en el bucle loop normal, se ejecutan otra acciones? por mas que lo pienso no encuentro manera

      Eliminar
    3. Si se puede, eso correr en otro hilo.Tenés que poner dentro del loop:

      server.handleClient();

      Eliminar