Mostrando las entradas con la etiqueta servidor web. Mostrar todas las entradas
Mostrando las entradas con la etiqueta servidor web. Mostrar todas las entradas

domingo, 13 de enero de 2019

Leer y escribir en una memoria SD

Después de mucho tiempo voy a dedicarle un post a las memorias SD. Las memorias SD nos van a permitir escribir y leer datos de forma no volátil y que perduren a través del tiempo sin necesidad de utilizar la memoria EEPROM. Esto tiene muchas ventajas como la gran capacidad de almacenamiento, el reemplazo rápido de la memoria, el uso de un sistema de archivos nos permite exportar e importar datos con una computadora, etc.

Para esto vamos a utilizar una librería que viene incluida con el software de arduino y algún módulo que nos facilite el cableado entre el microcontrolador y la tarjeta de memoria, en mi caso voy a utilizar alguna de las pantallas que tengo que ya vienen con lectores de memorias SD, aunque no vamos a sacar imágenes de la memoria para mostrar en la pantalla, si vamos a cargar una página web y a almacenar datos en la tarjeta.

Primero vamos a ver el ejemplo del almacenamiento de datos, utilizando el siguiente código:

#include <SPI.h>
#include <SD.h>

const int selectorChip = 4;

void setup() {
  
  Serial.begin(9600);
  while(!Serial)
  {
    ;
  }

  Serial.println("inicializando tarjeta SD");

  //intentamos inicializar la memoria
  if(!SD.begin(selectorChip))
  {
    Serial.println("Fallo el inicio de la tarjeta.");
    //no hace nada más
    return;
  }
  Serial.println("Tarjeta iniciada.");
}

void loop()
{
  //genero los datos
  String datos = "milisegundos desde encendido: " + String(millis());
  //abro el archivo en modo escritura
  File archivo = SD.open("datos.txt", FILE_WRITE);
  //si se abrió correctamente guardo los datos.
  if(archivo)
  {
    archivo.println(datos);
    archivo.close();
  }
  else
  {
    Serial.println("error al intentar abrir el archivo datos.txt");
  }
}


Para el siguiente ejemplo vamos a utilizar un ESP8266 y el código ya utilizado en esta entrada


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

#include <SPI.h>
#include <SD.h>
File archivo;

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String HTMLpage = "";

void setup() {

  Serial.begin(115200);
  pinMode(2, OUTPUT);

  Serial.print("Inicializando tarjeta SD");

  if (!SD.begin(4)) {
    Serial.println("Fallo al incializar");
    return;
  }
  Serial.println("Tarjeta iniciada con exito");

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a");
  Serial.println(red);
  Serial.print("Dirección IP:");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", paginaWeb());
  });

  servidorweb.begin();
}

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

String paginaWeb()
{
  String pagina = "";
  archivo = SD.open("pagina.txt");
  if(archivo)
  {
    //leo el archivo mientras esté disponible
    while(archivo.available())
    {
      //leo cada byte del archivo mientras esté disponible
      pagina +=archivo.read();
    }

    //cierro el archivo
    archivo.close();
    return pagina;
  }
}


Si queremos cargar otras páginas lo único que tenemos que hacer es "llamar" distintos archivos y modificar la función para que recupere otras cosas.

Hay que aclarar que la librería "SD" para el ESP8266 no es la misma que usamos normalmente para los arduinos, por lo que hay que especificar la ruta de la librería de la siguiente forma:

#include "c:\SD.h"

También lo que se puede hacer es poner la librería en la misma carpeta que el programa y de ahí "llamarla" colocando:

#include "SD.h"

En lugar de:

#include <SD.h>

De esta forma lo que conseguimos es que el preprocesador busque dentro de la carpeta del programa en lugar de la carpeta en donde se guardan las librerías normalmente.

De todas formas al ser tantos archivos que comparten el mismo nombre lo mejor va a ser modificar lo lo que diga SD por SD-esp de los siguientes ítem:
  • La carpeta (SD) 
  • El archivo SD.h (SD/src/SD.h)
  • El archivo SD.cpp (SD/src/SD.cpp)
  • La línea 53 del archivo SD.cpp (SD/src/SD.cpp)
  • La línea 15 del archivo File.cpp (SD/src/File.cpp)
Entonces en lugar de utilizar "#include <SD.h>" usaremos "#include <SD-esp.h>" (hay que modificar eso del programa).

Otro punto que hay que aclarar es la extensión del archivo, dado que la librería trabaja (por lo que tengo entendido) con nombres de archivo del estilo 8.3, es decir que el nombre puede tener un máximo de 8 caracteres y la extensión de 3, es por eso que no podemos utilizar un archivo ".html", pero como al final de cuentas a página es sólo texto, podemos utilizar un archivo de texto normal.

domingo, 30 de diciembre de 2018

Servidor web con ESP8266

Hoy les traigo la continuación del servidor simple, la idea es poder interactuar con el micro a través de una interfaz web. En este ejemplo vamos a encender y apagar el led del ESP8266 de forma remota, también se pueden agregar hojas de estilo y me imagino que también se puede agregar código en javaScript (después de todo lo que hay que hacer es mandar texto al navegador para que lo interprete), el único cuidado que hay que tener es escribir el html, el css y lo que necesiten uno a continuación del otro.

Para recuperar variables de la página web hay que hacerlo de la siguiente forma:

  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", HTMLpage);
  });

con el ".arg()" recuperamos el valor de la variable que pongamos entre paréntesis, luego podremos trabajar en función de eso.

El código total quedaría de la siguente forma:


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

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String HTMLpage =

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)<br>"
      " con el micro ESP8266 para controlar<br>"
      " el led integrado en la placa."
    "</h3>"
    "<form action=\"/\" method=\"post\">"
      "<td><button name=\"estado\" type=\"submit\" class = \"button\" value=\"ON\">ON</button></td>"
      "<td><button name=\"estado\" type=\"submit\" class = \"button\" value=\"OFF\">OFF</button></td>"
    "</form>"
  "<html>";

void setup() {

  Serial.begin(115200);
  pinMode(2, OUTPUT);

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a");
  Serial.println(red);
  Serial.print("Dirección IP:");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    String estado = servidorweb.arg("estado");
    if(estado == "ON")
    {
      digitalWrite(2, LOW);
    }
    else if(estado == "OFF")
    {
      digitalWrite(2, HIGH);
    }
    servidorweb.send(200, "text/html", HTMLpage);
  });

  servidorweb.begin();
}

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

Recordemos que la página va a estar montada sobre la dirección ip 192.168.4.1, por lo que hay que ingresar ahí para ver la página. Si bien la página y el código son muy sencillos, como mencioné antes, se puede agregar javaScript y css para que la página sea más interesante, pero hay que tener en cuenta que si queremos agregar librerías o frameworks de JS la memoria del microcontrolador va a empezar a escasear. En teoría se podría agregar una memoria externa (ej. una microSD) para almacenar la página web con todas las librerías y demás. A continuación les dejo cómo luce la página que acabamos de hacer.


Básicamente cuando presionamos los botones se "manda" al argumento "estado" el valor "ON" u "OFF" el cuál el servidor va a procesar para prender o apagar el led. Como los estados del ESP8266 están negados el estado low va a encender el led y el high lo va a apagar.

domingo, 4 de noviembre de 2018

Servidor web simple con ESP8266

Hola nuevamente, en esta publicación voy a explicar cómo hacer un servidor web muy simple que sólo muestra texto estático (mejor dicho html), si bien esto es básico, creo que hay que empezar por algo.
Aclaro, no voy a explicar cómo hacer páginas web, sólo voy a explicar cómo montar una en el micro ESP8266, para aprender pueden ir aquí.

Las librerías que vamos a usar son la "ESP8266WebServer", viene con las dependencias del ESP8266 para arduino por lo que no hace falta instalarlo aparte, "DNSServer" que sirve para administrar las conexiones de los clientes y la "ESP8266WiFi" que se encarga de configurar el micro para que funcione correctamente.


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

ESP8266WebServer servidorweb(80);

const char* red = "red"/*ingrese aquí el nombre de id*/;
const char* contra = "contra"/*ingrese aquí la contraseña*/;
String pagina = 

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)"
      " con el micro ESP8266"
    "</h3>"
  "<html>";

void setup() {

  Serial.begin(115200);

  WiFi.begin(red, contra);

  while (WiFi.status() != WL_CONNECTED) 
  {
    delay(500);
    Serial.print(".");
  }
  
  Serial.println("");
  Serial.print("Conectado a: ");
  Serial.println(red);
  Serial.print("Direccion IP: ");
  Serial.println(WiFi.localIP());
  
  servidorweb.on("/", []()
  {
    servidorweb.send(200, "text/html", pagina);
  });

  servidorweb.begin();

}

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


Como podemos ver se debe declarar el objeto:

ESP8266WebServer servidorweb(80);

y es el que vamos a utilizar cuando hagamos referencia a la librería. Luego se define el nombre de la red a la que nos vamos a conectar, la contraseña y por último definimos lo que va a ser la página web en sí.
Como podemos observar la página está escrita de una forma poco convencional:

String pagina = 

  "<!DOCTYPEhtml>"
  "<html>"
    "<head>"
      "<title>"
        "Tutorial de servidor web"
      "</title>"
    "</head>"
    "<h3>"
      "Esto es un servidor web (de ejemplo)"
      " con el micro ESP8266"
    "</h3>"
  "<html>";

pero esto es equivalente a escribir todo en una sola línea (si bien acá aparece en 3, es por el formato de la página):


String pagina= "<!DOCTYPEhtml><html><head><title>Tutorial de 

servidor web</title></head><h3>Esto es un servidor web (de ejemplo)

con el micro ESP8266</h3><html>";

Cuál de las dos formas se use va a quedar a su gusto, para mi se ve más claro de la primera forma porque tiene una estructura tabulada y ordenada, lo que lo hace más fácil de visualizar.

Luego de definir la página web, vamos a dar inicio al programa, inicializando el puerto serie (cambiar la velocidad acá no infiere en nada) e inicializar la conexión a la red wifi predefinida, esperamos a que se conecte y damos notificación por el puerto serie de que se conectó a la red deseada y dejamos la dirección IP que el router le asignó. Todo esto básico y ya lo hicimos en otro post.

A continuación tenemos la siguiente porción de código (cuya sintaxis no es la normal):

  servidorweb.on("/", []()
  {
    servidorweb.send(200, "text/html", pagina);
  });

acá lo que estamos haciendo es indicarle al servidor cómo responder ante el "llamado" del cliente bajo la ruta "/", en este caso el servidor va a ejectuar la línea:

servidorweb.send(200, "text/html", pagina);

y lo que va a hacer es enviar como respuesta la página que tenemos almacenada en la variable "pagina" (vale aclarar que en lugar de poner "/" podríamos poner "/encender" y vamos a usar esa otra ruta, incluso podríamos declarar ambas, más adelante hablaremos de ello en más detalle). Una vez indicado cómo tiene que respoder podemos dar inicio al servidor web bajo el comando:

servidorweb.begin();

En el loop lo que tenemos que hacer es revisar constantemente si hay algún cliente esperando, y esto lo vamos a hacer con la siguiente línea:

servidorweb.handleClient();

Esta última línea debemos llamarla constantemente para que se manejen los clientes de forma regular.