Servidor web básico Arduino –

Este tutorial describe los pasos para crear su propio servidor web Arduino.

Configurar un servidor web en Arduino es un proceso sencillo que cubre el proceso de ponerlo en funcionamiento. También cubriré algunos conceptos básicos como el uso de Ajax para actualizar en lugar de actualizar la página una y otra vez.

Necesitará saber algo de HTML básico que es increíblemente fácil de comprender los conceptos de. Si nunca ha hecho HTML, le recomiendo que acceda a w3schools para obtener una introducción básica.

Este servidor no podrá hacer nada demasiado sofisticado, pero es increíblemente útil para cualquiera que quiera mostrar datos de dispositivos conectados a los pines o quiera interactuar con un circuito desde una página web. El servidor web Raspberry Pi más potente podría interesarle si esto realmente no cubre lo que está buscando.

Todos los ejemplos de código se pueden encontrar en mi Github y se pueden descargar fácilmente (también están comentados). Si nota algún error, asegúrese de hacérmelo saber en la sección de comentarios al final de esta página.

Equipo

El equipo que necesitará para este tutorial del servidor web Arduino se enumera a continuación.

Arduino Uno

Blindaje de Ethernet o similar

Cable ethernet

Tarjeta micro SD (opcional)

** La tarjeta SD deberá formatearse en FAT16 o FAT32.

Conceptos básicos del código

Si es nuevo en la codificación o está interesado en que se expliquen algunos de los conceptos básicos, siga leyendo; de lo contrario, puede omitir esta sección y pasar a la configuración del servidor web con o sin una sección de tarjeta SD.

Inicialización

Para comenzar, primero deberá inicializar el servidor web definiendo algunas variables y luego llamando a una función.

En primer lugar, debe definir una dirección mac, la siguiente debería funcionar bien en la mayoría de las redes domésticas. Si sabe exactamente lo que busca, no dude en cambiarlo.

byte mac[] = {   0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

En segundo lugar, deberá definir una dirección IP, esto se hace simplemente llamando al IPAddress class con su IP elegida. Asegúrese de actualizar esto a una dirección IP que no entre en conflicto con su red.

IPAddress ip(192, 168, 1, 177);

En tercer lugar, deberá configurar el número de puerto en el que desea que el servidor escuche. De forma predeterminada, HTTP simple se ejecuta en el puerto 80. Si cambia esto, deberá definir el puerto cuando acceda a la página web en su navegador. Por ejemplo, si su puerto era 14213, la dirección se verá así: 192.168.1.177:14213

EthernetServer server(80);

Por último, en la función de configuración, deberá inicializar el dispositivo Ethernet. Una vez que esto se inicializa, simplemente haga una llamada a server.begin(), una vez hecho esto, debería poder escuchar conexiones y responder con datos cuando sea apropiado.

Ethernet.begin(mac, ip);   server.begin();

Detectando una nueva conexión

En la función de bucle, debemos verificar si hay una nueva conexión cada vez que se realiza un bucle. Si se detecta una nueva conexión, ingresamos el código lógico de nuestra página web.

El siguiente código detectará cuando un nuevo cliente intenta conectarse al servidor.

EthernetClient client = server.available();   if (client) {     while (client.connected()) {         if (client.available()) {

Una vez que se determina que hay un cliente disponible, pasamos a generar HTML desde el servidor web Arduino.

Devolver el encabezado de respuesta HTML

Para que un navegador muestre la página web correctamente, primero debemos responder con un encabezado de respuesta HTML. No tiene por qué ser nada complicado, el siguiente ejemplo es más que suficiente para que todo funcione correctamente.

Si busca más información sobre los campos del encabezado, esta página wiki increíblemente útil explica todo bastante bien.

client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println("Connection: close"); client.println();

Salida de HTML

La salida de HTML se puede hacer simplemente llamando client.println() o client.print() con el texto / HTML pasado como parámetro. Esto es sencillo, pero como puede ver en los ejemplos más abajo en esta página, realmente aumenta el código.

A continuación se muestra un ejemplo básico de cómo generar algo de HTML.

 client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.print("<h1>Analogue Values</h1>");

La otra opción es tener los archivos HTML almacenados en una tarjeta SD a la que puede acceder y cargar. Luego puede realizar solicitudes AJAX para actualizar elementos en la página web para que muestren los datos correctos.

También puede hacer esto para que Arduino realice acciones como encender y apagar un LED.

Cerrando la conexión

Una vez que haya terminado de procesar la página web, debe demorarse un poco para asegurarse de que el cliente obtenga los datos. Después de un segundo más o menos, simplemente cierre la conexión con el cliente.

delay(1);     client.stop();

Servidor web Arduino sin tarjeta SD

Si no está utilizando la tarjeta SD, entonces es increíblemente sencillo poner en funcionamiento un servidor web.

Es importante tener en cuenta que si tiene una tarjeta SD insertada, pero no está en uso, puede causar problemas con la comunicación del boceto con el Arduino. Para evitar que esto suceda, agregue las siguientes dos líneas en la función de configuración.

pinMode(4, OUTPUT); digitalWrite(4, HIGH);

Una vez que se agregan, puede volver a agregar la tarjeta SD al dispositivo.

Para poner rápidamente en funcionamiento un servidor web Arduino, simplemente abra el boceto y copie y pegue el código a continuación. También se puede encontrar en mi página de Github junto con el código completo para todos los ejemplos en este tutorial.

#include <SPI.h> #include <Ethernet.h>  byte mac[] = {   0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; IPAddress ip(192, 168, 1, 177);  EthernetServer server(80);  void setup() {   Serial.begin(9600);   while (!Serial) {     ; // wait for serial port to connect. Needed for native USB port only   }    Ethernet.begin(mac, ip);   server.begin();   Serial.print("server is at ");   Serial.println(Ethernet.localIP()); }  void loop() {   // listen for incoming clients   EthernetClient client = server.available();   if (client) {     Serial.println("new client");     // an http request ends with a blank line     boolean currentLineIsBlank = true;     while (client.connected()) {       if (client.available()) {         char c = client.read();         Serial.write(c);         if (c == 'n' && currentLineIsBlank) {           client.println("HTTP/1.1 200 OK");           client.println("Content-Type: text/html");           client.println("Connection: close");           client.println("Refresh: 5");           client.println();           client.println("<!DOCTYPE HTML>");           client.println("<html>");           client.print("<h1>Analogue Values</h1>");           for (int analogChannel = 0; analogChannel < 6; analogChannel++) {             int sensorReading = analogRead(analogChannel);             client.print("analog input ");             client.print(analogChannel);             client.print(" is ");             client.print(sensorReading);             client.println("<br />");           }           client.println("</html>");           break;         }         if (c == 'n') {           currentLineIsBlank = true;         } else if (c != 'r') {           currentLineIsBlank = false;         }       }     }     delay(1);     // close the connection:     client.stop();     Serial.println("client disconnected");   } }

Una vez que haya cargado este código en Arduino, debería tener un servidor web muy básico en funcionamiento.

Se actualizará cada 5 segundos actualizando los valores de los pines analógicos de Arduino (estos serán solo valores aleatorios a menos que tenga un dispositivo o sensor real conectado a ellos).

También puede supervisar el monitor en serie para detectar cualquier línea de depuración que se encuentre a lo largo del código.

Servidor web Arduino con tarjeta SD

Si decide seguir la ruta de la tarjeta SD para el servidor web Arduino, entonces los archivos HTML deberán crearse en su computadora y luego copiarse en la tarjeta SD antes de insertarlos en el Arduino.

Una ventaja de cargar la página web desde la tarjeta SD es que podría tener páginas más complejas / pesadas sin necesidad de escribir cientos de líneas de escritura de cliente. También ayuda a prevenir situaciones de poca memoria que generalmente ocurren cuando termina teniendo demasiado código ejecutándose en el Arduino.

Inicializar la tarjeta SD

Antes de poder acceder a la tarjeta SD, deberá importar el paquete SD e inicializarlo en la función de configuración. La verificación en la función de configuración verá si puede acceder a la tarjeta, de lo contrario arrojará un error en el monitor de serie.

Serial.println("Checking SD card is accessible...");   if (!SD.begin(4)) {     Serial.println("ERROR - SD card initialization failed!");     return;    // init failed   }   Serial.println("SUCCESS - SD card initialized.");

Cargando el archivo

Cuando esté listo para cargar el archivo, simplemente use sd.open(filename) para abrir el archivo. Use una instrucción if para asegurarse de que el archivo exista y luego recorra el contenido del archivo hasta que llegue al final.

webPage = SD.open("index.htm"); // open web page file if (webPage) {     while (webPage.available()) {     client.write(webPage.read()); // send web page to client } webPage.close();

A continuación se muestra un ejemplo de la página web que se carga a través de la tarjeta SD con Ajax (que se explica a continuación) actualizando los elementos de la página.

Realización de acciones a través de la página web (AJAX)

Puede haber un momento en el que desee controlar un dispositivo o sensor a través de la página web. En esta sección, analizaré la realización de solicitudes y actualizaciones mediante AJAX. Esto significa que no verá que la página se cargue una y otra vez, pero se mantendrá actualizada cuando sea necesario.

AJAX o JavaScript asincrónico y XML es demasiado complicado para cubrirlo por completo en este tutorial, pero repasaré los conceptos básicos para usarlo en Arduino. Debería poder ajustar los ejemplos para que se adapten a sus necesidades sin demasiados problemas.

Ejemplo de AJAX

AJAX funciona enviando una solicitud al servidor, el servidor luego verificará si la cadena ajaxrefresh o ledstatus existe en el encabezado (para este ejemplo). Si lo hace, generará los datos relevantes y los devolverá.

Luego, JavaScript encuentra el elemento HTML relevante con la identificación correcta y luego reemplaza el innerHTML con la respuesta de la solicitud AJAX.

El siguiente ejemplo envía una solicitud al servidor web que se ejecuta en Arduino con la variable GET ajaxrefresh. Si el servidor devuelve datos, reemplazará el innerHTML del elemento que tiene el id analogue_data.

Este script se ejecuta cada 5 segundos, pero se puede ajustar para que se adapte mejor a sus necesidades.

<script>window.setInterval(function(){   nocache = "&nocache=" + Math.random() * 10;   var request = new XMLHttpRequest();   request.onreadystatechange = function() {     if (this.readyState == 4) {       if (this.status == 200) {         if (this.responseText != null) {           document.getElementById("analoge_data").innerHTML = this.responseText;         }       }     }   }   request.open("GET", "ajaxrefresh" + nocache, true);   request.send(null);   }, 5000); </script> 

Funciones de Arduino Ajax

Las dos funciones siguientes se llaman siempre que la solicitud AJAX relevante llega al servidor. Son muy simples, el primero lee los pines analógicos y devuelve los datos relevantes.

La segunda función encenderá o apagará el LED ROJO dependiendo de su estado actual. También devolverá el estado del LED para que AJAX pueda actualizar el valor en la página web.

void ajaxRequest(EthernetClient client) {   for (int analogChannel = 0; analogChannel < 6; analogChannel++) {     int sensorReading = analogRead(analogChannel);     client.print("analog input ");     client.print(analogChannel);     client.print(" is ");     client.print(sensorReading);     client.println("<br />");   } }  void ledChangeStatus(EthernetClient client) {   int state = digitalRead(RED);   Serial.println(state);   if (state == 1) {     digitalWrite(RED, LOW);     client.print("OFF");   }   else {     digitalWrite(RED, HIGH);     client.print("ON");   } } 

AJAX con HTML generado por Arduino

El siguiente ejemplo tiene todo el HTML y JavaScript completamente generado por Arduino. El JavaScript realiza solicitudes AJAX al servidor Arduino, que actualiza la página según los resultados que proporciona.

Un problema que noté al generar todo el código en Arduino es que comenzó a quedarse sin espacio y a dar advertencias de estabilidad. Esto podría ser un problema si desea toneladas de sensores y opciones en la página. Es posible que desee considerar almacenar el HTML en una tarjeta SD y tomarlo desde allí.

void loop() {   EthernetClient client = server.available();   if (client) {     Serial.println("new client");     boolean currentLineIsBlank = true;     while (client.connected()) {       if (client.available()) {         char c = client.read();         if( HTTP_req.length() < 120)             HTTP_req += c; // save the HTTP request 1 char at a time             Serial.write(c);             if (c == 'n' && currentLineIsBlank)            {              // send a standard http response header             client.println("HTTP/1.1 200 OK");             client.println("Content-Type: text/html");             client.println("Connection: close");             client.println();             Serial.println(HTTP_req);             if (HTTP_req.indexOf("ajaxrefresh") >= 0 ) {             // read switch state and analog input             ajaxRequest(client);             break;           }           else if (HTTP_req.indexOf("ledstatus") >= 0 ) {             // read switch state and analog input             ledChangeStatus(client);             break;           }           else {             client.println("<!DOCTYPE HTML>");             client.println("<html lang="en">");             client.println("<script>window.setInterval(function(){");             client.println("nocache = "&nocache=" + Math.random() * 10;");             client.println("var request = new XMLHttpRequest();");             client.println("request.onreadystatechange = function() {");             client.println("if (this.readyState == 4) {");             client.println("if (this.status == 200) {");             client.println("if (this.responseText != null) {");             client.println("document.getElementById("analoge_data").innerHTML = this.responseText;");             client.println("}}}}");             client.println("request.open("GET", "ajaxrefresh" + nocache, true);");             client.println("request.send(null);");             client.println("}, 5000);");             client.println("function changeLEDStatus() {");             client.println("nocache = "&nocache=" + Math.random() * 10;");             client.println("var request = new XMLHttpRequest();");             client.println("request.onreadystatechange = function() {");             client.println("if (this.readyState == 4) {");             client.println("if (this.status == 200) {");             client.println("if (this.responseText != null) {");             client.println("document.getElementById("led_status").innerHTML = this.responseText;");             client.println("}}}}");             client.println("request.open("GET", "?ledstatus=1" + nocache, true);");             client.println("request.send(null);");             client.println("}");             client.println("</script></head>");             // output the value of each analog input pin             client.print("<h1>Analogue Values</h1>");             client.println("<div id="analoge_data">Arduino analog input values loading.....</div>");             client.println("<h1>Arduino LED Status</h1>");             client.println("<div><span id="led_status">");             if(digitalRead(RED) == 1)              client.println("On");             else               client.println("Off");             client.println("</span> | <button onclick="changeLEDStatus()">Change Status</button> </div>");             client.println("</html>");             break;           }         }         if (c == 'n') {           // you're starting a new line           currentLineIsBlank = true;         } else if (c != 'r') {           // you've gotten a character on the current line           currentLineIsBlank = false;         }       }     }     delay(1);     client.stop();     HTTP_req = "";     Serial.println("client disconnected");   } }

AJAX con archivos HTML en la tarjeta SD

Como puede ver a continuación, el resultado es mucho más limpio simplemente almacenando el HTML dentro de un archivo en la tarjeta SD. Esto debería ayudar a mantener su secuencia de comandos para procesar principalmente código, especialmente si hace todo a través de AJAX y carga el HTML de la tarjeta SD.

Tenga en cuenta que esta es solo la parte del bucle del código si desea que la versión completa vaya a mi página de Github.

void loop() {   EthernetClient client = server.available();   if (client) {     Serial.println("new client");     boolean currentLineIsBlank = true;     while (client.connected()) {       if (client.available()) {         char c = client.read();         if ( HTTP_req.length() < 80)           HTTP_req += c;         if (c == 'n' && currentLineIsBlank) {           client.println("HTTP/1.1 200 OK");           client.println("Content-Type: text/html");           client.println("Connection: close");           client.println();           if (HTTP_req.indexOf("ajaxrefresh") >= 0 ) {             ajaxRequest(client);             break;           }           else if (HTTP_req.indexOf("ledstatus") >= 0 ) {             ledChangeStatus(client);             break;           }           else {             webPage = SD.open("index.htm");             if (webPage) {               while (webPage.available()) {                 client.write(webPage.read());               }               webPage.close();             }             break;           }           if (c == 'n') {             currentLineIsBlank = true;           } else if (c != 'r') {             currentLineIsBlank = false;           }         }       }     }     delay(1);     client.stop();     HTTP_req = "";     Serial.println("client disconnected");   } }

Solución de problemas

Al igual que con cualquier proyecto de Arduino, puede encontrar algunos problemas, los siguientes problemas son solo algunos con los que me encontré al preparar este tutorial.

  • No puedo acceder a mi página web: verifique dos veces la dirección IP y asegúrese de que no esté en conflicto con otro dispositivo en la red. Además, intente hacer ping a la dirección IP y ver si obtiene una respuesta.
  • Mi tarjeta SD dice que es inaccesible: mantenga presionado el botón de apagado y luego inserte la tarjeta SD, encontré que esto generalmente soluciona el problema.
  • CSS: puede incluir CSS en sus páginas web, puede hacerlo en línea o ubicado en el encabezado entre las etiquetas de estilo. Esto es algo sobre lo que quizás quieras leer más si no has hecho mucho CSS. No es realmente necesario a menos que desee que sus páginas se vean bien.

Implementaciones adicionales

Hay muchas más formas en las que puede utilizar un servidor web que aumentarían la funcionalidad de su circuito. Rápidamente enumeraré algunos proyectos en los que es posible que desee implementar una interfaz web.

  • Control de ventilador / temperatura: controle una sala de servidores, un invernadero o algo similar donde el calor y el flujo de aire son importantes. Puede agregar controles para encender y apagar calefactores y ventiladores.
  • Contador: use un sensor de movimiento para detectar movimiento y contar cada vez que se activa el sensor. Podría aplicar esta misma lógica con casi cualquier tipo de sensor.

Espero que este tutorial del servidor web Arduino le haya ayudado a poner en marcha un sitio web donde pueda ver e interactuar con los datos. Si tiene alguna recomendación, consejo o notó que algo anda mal, no dude en dejar un comentario en nuestro foro.