Comment exécuter un serveur Web sur un Arduino

Dans ce tutoriel, je vais vous montrer comment démarrer un serveur Web sur un appareil Arduino avec WiFi, comme monArduino MKR WiFi 1010.

Nous nous connecterons à un réseau WiFi existant et nous pourrons interagir avec l'Arduino depuis notre navigateur viaHTTP.

Ceci est très intéressant pour une variété d'applications. De la simple vérification des données des capteurs à l'exécution d'actions basées surRequête HTTPexécuté.

Nous partirons de ce programme défini dans leConnectez-vous à un réseau WiFi en utilisant un ArduinoDidacticiel:

#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() {

}

Avant setup (), ajoutez cette ligne:

WiFiServer server(80);

pour initialiser unTCPserveur sur le port 80 et à la fin desetup()appeler

server.begin();

pour démarrer le serveur.

Maintenant, c'est un serveur TCP, pas un serveur HTTP. Mais comme HTTP (un protocole d'application TCP / IP) est construit sur TCP (la couche de transport), nous pouvons créer le serveur HTTP par nous-mêmes, assez facilement.

Nous devons d'abord écouter les connexions client. Nous le faisons enloop():

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

} }

La méthode available () deserverécoute les clients entrants.

À l'intérieur deif (client) {}vérifier, nous avons un client HTTP connecté. Ce que nous devons faire, c'est:

  • appelerclient.connected()pour vérifier si les données sont connectées et qu'il y a des données à lire
  • appelerclient.available()pour obtenir le nombre d'octets disponibles pour la lecture (cela garantit qu'il y a des données à lire)
  • appelerclient.read()pour lire un octet à partir des données entrantes (la requête HTTP envoyée par le client)
  • appelerclient.println()ouclient.print()pour envoyer des données au client, en créant une réponse HTTP appropriée
  • appelerclient.stop()pour mettre fin à la connexion

Nous commençons à imprimer sur l'interface série chaque caractère envoyé par le client, et à la fin nous fermons la connexion:

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

} }

Essayez de télécharger ce programme sur l'Arduino. Pointez votre navigateur vers l'adresse IP. Vous verrez quelque chose comme ceci imprimé sur l'interface série. Voici ce qui est envoyé par le navigateur:

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: