Cómo ejecutar un servidor web en un Arduino

En este tutorial, le mostraré cómo iniciar un servidor web en un dispositivo Arduino con WiFi, como miArduino MKR WiFi 1010.

Nos conectaremos a una red WiFi existente y podremos interactuar con Arduino desde nuestro navegador a través deHTTP.

Esto es muy interesante para una variedad de aplicaciones. Desde la simple verificación de los datos de los sensores, hasta la realización de acciones basadas enSolicitud HTTPrealizado.

Partiremos de este programa definido en elConéctese a una red WiFi usando un Arduinotutorial:

#include <SPI.h>
#include <WiFiNINA.h>

void setup() {
  char ssid[] = SECRET_SSID;
  char pass[] = SECRET_PASS;

Serial.begin(9600); while (!Serial);

int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { Serial.print("Connecting to "); Serial.println(ssid); status = WiFi.begin(ssid, pass); delay(5000); }

Serial.print("IP address: "); Serial.println(WiFi.localIP()); }

void loop() {

}

Antes de setup (), agregue esta línea:

WiFiServer server(80);

para inicializar unTCPservidor en el puerto 80 y al final desetup()llamada

server.begin();

para iniciar el servidor.

Ahora bien, este es un servidor TCP, no un servidor HTTP. Pero dado que HTTP (un protocolo de aplicación TCP / IP) está construido sobre TCP (la capa de transporte), podemos construir el servidor HTTP por nuestra cuenta, con bastante facilidad.

Primero necesitamos escuchar las conexiones del cliente. Lo hacemos enloop():

void loop() {
  WiFiClient client = server.available();
  if (client) {

} }

El método available () deserverescucha a los clientes entrantes.

Dentro deif (client) {}comprobar, tenemos un cliente HTTP conectado. Lo que tenemos que hacer es:

  • llamadaclient.connected()para comprobar si los datos están conectados y hay datos para leer
  • llamadaclient.available()para obtener la cantidad de bytes disponibles para leer (esto asegura que haya datos para leer)
  • llamadaclient.read()para leer un byte de los datos entrantes (la solicitud HTTP enviada por el cliente)
  • llamadaclient.println()oclient.print()para enviar datos al cliente, creando una respuesta HTTP adecuada
  • llamadaclient.stop()para terminar la conexión

Empezamos a imprimir a la interfaz serial cada carácter enviado por el cliente, y al final cerramos la conexión:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
      }
    }
client.stop();

} }

Intente cargar este programa en Arduino. Apunte su navegador a la dirección IP. Verá algo como esto impreso en la interfaz serial. Esto es lo que envía el navegador:

GET / HTTP/1.1
Host: 192.168.1.40
Upgrade-Insecure-Requests: 1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15
Accept-Language: en-us
Accept-Encoding: gzip, deflate
Connection: keep-alive

Note the ending empty line. This is the end of the HTTP request.

We need to intercept this empty line.

Each line in the HTTP request is terminated by a CR carriage return character (\r), and a LF line feed character (\n).

So the end of the request can be determined by 2 sets of those sequences: \r\n\r\n.

This simple algorithm will work, we just memorize 2 characters prior to the current one, and we check if we identify the sequence \n\r\n (the last 3 characters in that sequence are enough to determine the last line):

void loop() {
  WiFiClient client = server.available();
  if (client) {
<span style="color:#66d9ef">char</span> prevprev;
<span style="color:#66d9ef">char</span> prev;

<span style="color:#66d9ef">while</span> (client.connected()) {
  <span style="color:#66d9ef">if</span> (client.available()) {
    <span style="color:#66d9ef">char</span> c <span style="color:#f92672">=</span> client.read();
    Serial.write(c);

    <span style="color:#66d9ef">if</span> (prevprev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> prev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\r'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      <span style="color:#75715e">//we can send the response!

}

    prevprev <span style="color:#f92672">=</span> prev;
    prev <span style="color:#f92672">=</span> c;
  }
}

client.stop();

} }

So now we can send the response inside the if, we can use client.println() for this, and we add a simple response like this:

HTTP/1.1 200 OK
Content-Type: text/html
Connection: close

<!DOCTYPE HTML> <html> test </html>

In this way:

client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close");
client.println();
client.println("<!DOCTYPE HTML>");
client.println("<html>");
client.println("test");
client.println("</html>");
break;

The break; statement ends the while (client.connected()) {} block.

Here is the full program:

#include <SPI.h>
#include <WiFiNINA.h>

WiFiServer server(80);

void setup() { char ssid[] = SECRET_SSID; char pass[] = SECRET_PASS;

Serial.begin(9600); while (!Serial);

int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { Serial.print("Connecting to "); Serial.println(ssid); status = WiFi.begin(ssid, pass); delay(5000); }

Serial.print("IP address: "); Serial.println(WiFi.localIP());

server.begin(); }

void loop() { WiFiClient client = server.available(); if (client) {

<span style="color:#66d9ef">char</span> prevprev;
<span style="color:#66d9ef">char</span> prev;
<span style="color:#66d9ef">while</span> (client.connected()) {
  <span style="color:#66d9ef">if</span> (client.available()) {
    <span style="color:#66d9ef">char</span> c <span style="color:#f92672">=</span> client.read();
    Serial.write(c);

    <span style="color:#66d9ef">if</span> (prevprev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> prev <span style="color:#f92672">==</span> <span style="color:#e6db74">'\r'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      client.println(<span style="color:#e6db74">"HTTP/1.1 200 OK"</span>);
      client.println(<span style="color:#e6db74">"Content-Type: text/html"</span>);
      client.println(<span style="color:#e6db74">"Connection: close"</span>);
      client.println();
      client.println(<span style="color:#e6db74">"&lt;!DOCTYPE HTML&gt;"</span>);
      client.println(<span style="color:#e6db74">"&lt;html&gt;"</span>);
      client.println(<span style="color:#e6db74">"test"</span>);
      client.println(<span style="color:#e6db74">"&lt;/html&gt;"</span>);
      <span style="color:#66d9ef">break</span>;
    }

    prevprev <span style="color:#f92672">=</span> prev;
    prev <span style="color:#f92672">=</span> c;
  }
}

client.stop();

} }

Try it, you should see test showing up in the browser:

The approach works until you need to figure out how what the client asked us.

In that case you want to read each line, so this alternative approach works better:

void loop() {
  WiFiClient client = server.available();
  if (client) {
    String line = "";
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        Serial.write(c);
    <span style="color:#66d9ef">if</span> (c <span style="color:#f92672">!=</span> <span style="color:#e6db74">'\n'</span> <span style="color:#f92672">&amp;&amp;</span> c <span style="color:#f92672">!=</span> <span style="color:#e6db74">'\r'</span>) {
      line <span style="color:#f92672">+=</span> c;
    }

    <span style="color:#66d9ef">if</span> (c <span style="color:#f92672">==</span> <span style="color:#e6db74">'\n'</span>) {
      <span style="color:#66d9ef">if</span> (line.length() <span style="color:#f92672">==</span> <span style="color:#ae81ff">0</span>) {
        client.println(<span style="color:#e6db74">"HTTP/1.1 200 OK"</span>);
        client.println(<span style="color:#e6db74">"Content-Type: text/html"</span>);
        client.println(<span style="color:#e6db74">"Connection: close"</span>);
        client.println();
        client.println(<span style="color:#e6db74">"&lt;!DOCTYPE HTML&gt;"</span>);
        client.println(<span style="color:#e6db74">"&lt;html&gt;"</span>);
        client.println(<span style="color:#e6db74">"test"</span>);
        client.println(<span style="color:#e6db74">"&lt;/html&gt;"</span>);
        <span style="color:#66d9ef">break</span>;
      } <span style="color:#66d9ef">else</span> {
        line <span style="color:#f92672">=</span> <span style="color:#e6db74">""</span>;
      }
    }
  }
}

client.stop();

} }

In the last else we can inspect the line because the line is terminated, and act accordingly to our needs.


More electronics tutorials: