Programar fácil con Arduino

Programar fácil con Arduino, entiende cómo funciona el mundo.

  • Blog
  • ¿Quién soy?
  • Podcast
  • Curso Arduino [GRATIS]
  • Curso Domótica [GRATIS]
  • Acceder
Usted está aquí: Inicio / Blog / Ethernet Shield Arduino tutorial paso a paso parte 2

Ethernet Shield Arduino tutorial paso a paso parte 2

José Guerra Carmenate

Aquí puedes acceder a la primera parte de Ethernet Shield con Arduino.

En el artículo de hoy veras otra aplicación de la tarjeta de expansión ethernet para Arduino o también conocida como Ethernet Shield.

Recuerda que estas placas son un aditivo para nuestro microcontrolador. Tiene una similitud a las mejoras o complementos para una computadora de escritorio.

Precisamente este artículo trata sobre el control de varios LEDs mediante un servidor web basado en Arduino utilizando el Ethernet Shield.

Te aseguro que al terminar estas líneas, tendrás nociones sobre:

  • Protocolo HTTP.
  • Principales tipos de mensajes HTTP.
  • Interpretar peticiones HTTP.
  • Por último, veras cómo armar tu propio servidor web para control de LEDs.

Si quieres partir de la base con un ejemplo mas sencillo, te comento que tienes el artículo anterior donde puedes montar un servidor web en Arduino con Ethernet Shield.

Allí se muestra como implementar un monitor de temperatura y humedad. Utiliza el navegador del móvil o del ordenador y permite conocer parámetros útiles de forma simple y rápida. 

También se muestran las bases para el control del Ethernet Shield y el uso de la librería Ethernet que serán útiles a la hora de equipar servidores en Arduino. 

Si no tienes conocimientos sobre HTML puedes revisar el artículo de introducción a HTML5 donde se muestran los principios fundamentales de este lenguaje.

Bueno, sin más vacilación, se levanta el telón :)

ethernet shield v1 v2 Arduino uno mega conexion parte 2

Indice de contenidos

  • 1 ¿Qué es HTTP?
  • 2 Control de LEDs con servidor web en Arduino y Ethernet Shield
  • 3 Funcionamiento del servidor web con Arduino y Ethernet Shield
  • 4 Conclusión proyecto Ethernet Shield y Arduino

¿Qué es HTTP?

El Protocolo de transferencia de hipertexto (en inglés, Hypertext Transfer Protocol o HTTP) es el protocolo de comunicación que permite las transferencias de información en la World Wide Web.

Cuidado, no confundir HTTP y HTML.

HTML se trata del lenguaje con el que se define el contenido de las páginas web, mientras que HTTP es el que hace posible la comunicación entre navegadores y servidores.

En realidad, la mayoría de los servidores utilizan HTTPS, que es la versión segura de HTTP. La principal diferencia entre estos radica en que en HTTPS los datos se envían encriptados.

HTTP es un protocolo orientado a transacciones y sigue el esquema petición-respuesta entre un cliente y un servidor.

Por ejemplo:

Supón que necesitas información sobre Arduino UNO y decides revisar en internet. De seguro abres tu navegador, te diriges al buscador de Google, escribes algo como “programar Arduino UNO” y presionas la tecla ENTER.

programar Arduino UNO

En ese momento tu navegador realiza una petición enviando un mensaje al servidor de Google. Ese mensaje lleva las palabras claves que escribiste en el buscador.

El servidor, por su parte, toma el mensaje recibido y envía una respuesta con los datos solicitados. En este caso serían los resultados de la búsqueda realizada.

02 respuesta datos solicitados

Todo este proceso de comunicación se realiza utilizando el protocolo HTTP.

El navegador por su parte recibe el mensaje y te muestra la información solicitada de forma visual.

Mensajes HTTP

Como comente anteriormente, HTTP se basa en el envío de mensajes. Esos mensajes son en texto plano, eso significa que son fáciles de leer e interpretar. Un mensaje HTTP está compuesto por varias líneas, como si fuera un archivo de texto. 

Existen dos tipos de mensajes HTTP: 

  • Petición: mensajes enviados por los clientes al servidor.
  • Respuesta: mensajes enviados por el servidor a los clientes en respuesta a una petición.

En la siguiente imagen se muestra la estructura de ambos tipos de mensajes, donde cada fila representa una línea de texto plano.

03 peticion y respuesta http

Petición HTTP

En la primera línea de un mensaje de petición se encuentran los campos para:

  • Método de petición: es una palabra que identifica la acción requerida por el servidor.
  • Recurso: es el recurso del sitio web sobre el que se desea operar. Puede ser una página web, una imagen u otro archivo.
  • Versión HTTP: es la versión HTTP soportada por el cliente.

Existen una serie de métodos de petición que pueden utilizarse. Cada uno de ellos indica la acción a realizar sobre el recurso indicado. Los métodos más conocidos son GET y POST.

El método GET permite solicitar un recurso. Por ejemplo, cuando ingresas a una página web o intentas abrir una imagen de un sitio el navegador realiza peticiones GET.

El método POST permite enviar datos para que sean procesados por el servidor. Por ejemplo, cuando rellenas un formulario en un sitio web y presionas en el botón “enviar” el navegador realiza una petición POST para enviar tus datos.

Respuesta HTTP

En caso de ser un mensaje de respuesta la primera línea cuenta con:

  • Versión HTTP: versión HTTP soportada por el cliente.
  • Código de respuesta: un número que envía el servidor al cliente indicando el resultado de su petición.
  • Frase: una frase asociada al código de respuesta.

A partir de la segunda línea ambos tipos de mensajes tienen la misma estructura.

Cabeceras HTTP o head HTTP

En la segunda línea comienzan las cabeceras, una por cada línea. Cada una se compone por un nombre de cabecera seguido de dos puntos (:), un espacio en blanco y el valor. Una línea en blanco es utilizada para indicar el final de las cabeceras.

Las cabeceras más comunes son:

  • Host: indica el servidor al que va dirigida la petición.
  • User-Agent: describe al cliente que realiza la petición.
  • Content-Length: indica la longitud del cuerpo del mensaje.
  • Accept-Language: indica el idioma aceptado.
  • Content-Type: tipo de contenido presente en el cuerpo del mensaje

Por último está el cuerpo del mensaje. Este campo es opcional y típicamente contiene los datos que se intercambian entre el cliente y el servidor. Puede ser un archivo de texto, una página web, una imagen u otro tipo de recurso.

Ejemplo de comunicación HTTP

Para comprender como ocurre el intercambio de información entre cliente y servidor utilizando el protocolo HTTP veras algunos ejemplos. 

Primer ejemplo de petición HTTP

El cliente inicia la comunicación con una petición HTTP tipo GET.

1
2
3
4
5
6
7
GET /index.html HTTP/1.1
Host: www.algunsitioweb.com
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:81.0) Gecko/20100101 Firefox/81.0
Accept-Language: es-ES,es;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Connection: keep-alive
 

Simplemente observando el mensaje podemos obtener la siguiente información:

  • Se trata de una petición GET del recurso /index.html
  • Utiliza la versión 1.1 de HTTP.
  • La petición se realiza al servidor www.algunsitioweb.com
  • Se hace desde un ordenador con sistema operativo Ubuntu
  • Utiliza el navegador web Mozilla.

Todo esto nos indica que la petición fue realizada escribiendo “www.algunsitioweb.com/index.html” en la barra de direcciones del navegador.

Puedes obtener mucha más información analizando todas las cabeceras, aquí solo he destacado algunas. 

Primer ejemplo respuesta HTTP

Una posible respuesta del servidor a esa petición sería:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
HTTP/1.1 200 OK
Date: Fri, 6 Nov 2020 20:52:37 GMT
Content-Type: text/html
Content-Length: 95
Connection: close
 
<html>
<head>
<title>Título del sitio</title>
</head>
<body>
<h1>Página principal</h1>
</body>
</html>
 
  • El mensaje de respuesta utiliza la versión 1.1 de HTTP
  • Retorna el código 200 (este código indica que la operación se realizó satisfactoriamente).
  • Las cabeceras indican la fecha en el servidor (Date); que el cuerpo del mensaje contiene información HTML (Content-Type); y que la longitud del mismo es de 33 bytes (Content-Length).
  • Después de la línea en blanco (en el cuerpo del mensaje) se encuentra el recurso solicitado, es decir, el contenido de la página web.

Segundo ejemplo «petición HTTP tipo POST«

1
2
3
4
5
6
7
8
9
10
11
12
13
POST / HTTP/1.1
Host: 192.168.1.125
Connection: keep-alive
Content-Length: 7
Origin: http://192.168.1.125
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36
 
Referer: http://192.168.1.125/
Accept-Encoding: gzip, deflate
Accept-Language: es-US,es-419;q=0.9,es;q=0.8
 
MOTOR=0
  • Se trata de una petición tipo POST al recurso “/”
  • Utiliza la versión 1.1 del protocolo HTTP.
  • La petición va destinada al servidor 192.168.1.125 y contiene un mensaje de 7 bytes.
  • La petición fue realizada desde un ordenador con sistema operativo Ubuntu
  • Utiliza el navegador web Chrome.
  • El cuerpo del mensaje se encuentra después de la línea, en blanco (MOTOR=0). 

Es responsabilidad del servidor interpretar el mensaje enviado por el cliente, es decir, el servidor es quien decide la acción a realizar. Por ejemplo, en este caso podría ser un mensaje indicando apagar un motor de DC.

Segundo ejemplo respuesta HTTP

La respuesta del servidor dependerá de la interpretación realizada.  

1
2
3
4
5
6
7
8
9
10
11
12
13
14
HTTP/1.1 200 OK
Date: Fri, 31 Dec 2003 23:59:59 GMT
Content-Type: text/html
Content-Length: 97
 
<html>
<head>
<title>Operación realizada</title>
</head>
<body>
<h1>Motor detenido </h1>
</body>
</html>
 

En este caso la respuesta es similar al ejemplo anterior, solo que más simple.

Diferencias entre GET y POST

La principal diferencia entre las peticiones de tipo GET y POST es que cuando realizas una petición GET la información viaja en la URL. Es decir, que el recurso solicitado se especifica en la barra de direcciones.

Por otra parte, cuando se realizan peticiones POST la información viaja en el cuerpo del mensaje. En otras palabras, no se muestran los datos enviados en la barra de direcciones del navegador. Esta diferencia es la que implica el hecho de que GET se utilice para acceder a los recursos y POST para modificarlos.

Veamos ahora como utilizar lo aprendido en un ejemplo práctico.

Control de LEDs con servidor web en Arduino y Ethernet Shield

En este ejemplo veras cómo implementar un servidor web en Arduino que permita controlar un grupo de LEDs. 

Puedes reemplazar los LEDs con relés y controlar las luces del portal o el sistema de riego del jardín.

Para este proyecto necesitarás:

  • 1x Router  *
  • 1x Ordenador
  • 2x Cables de red (cables ethernet)
  • 1x Arduino Mega **
  • 1x Shield Ethernet
  • 5x Resistencias de 1 kΩ
  • 5x LEDs (no importan los colores)
  • 1x placa de prototipos
  • Cables para conexiones

* Puede ser cualquier router, aunque si es uno con Wifi integrada mucho mejor.

** Si no dispones de un Arduino MEGA puedes utilizar un Arduino UNO sin problemas

Circuito eléctrico con Arduino y Ethernet Shield

Lo primero que debes hacer es conectar el Ethernet shield y Arduino. Al tratarse de un módulo tipo shield esta tarea se simplifica enormemente, ya que solo es necesario hacer coincidir los pines del Arduino con los del módulo.

Te recuerdo que hay una primera parte sobre teoría y ejemplos básicos para el Ethernet shield con Arduino.

Después se conectan los LEDs y se utiliza en cada caso una resistencia de 1 kΩ para limitar la corriente.

En la siguiente imagen representa la conexión completa.

04 circuito Ethernet Shield

Como puedes ver, he utilizado los pines digitales 2, 3, 5, 6 y 7 para conectar los LEDs. Tú puedes utilizar otros si lo prefieres, pero ten presente que tanto el bus SPI como el pin 10 son utilizados en la comunicación con el Shield Ethernet.

En la figura siguiente se aprecia el montaje.

05 conexion Ethernet Shield

Utiliza tres LEDs azules y dos rojos.

Ethernet Shield y su Arquitectura de red

Para este proyecto tendrás que montar  una red similar a la que se muestra en la imagen.

06 topologia ethernet shield

Es decir, que tienes que conectar tanto el ordenador como el Arduino con el Shield Ethernet al router. En ambos casos debes utilizar cables de red ethernet.

16 cable ethernet 1

En la siguiente imagen puedes ver el montaje realizado. En este caso he empleado un router TP-Link, el mismo que utilizo para conectarme a internet.

07 conectar ethernet shield

Si tu router admite conexiones Wifi entonces también podrás acceder al servidor y controlar los LEDs desde tu móvil.

Programar el servidor web en Arduino con Ethernet Shield

Con todo el sistema montado. Ahora solo queda darle vida programando la placa Arduino y el modulo Ethernet Shield.

De modo general en el Arduino se implementa un servidor web que solo admite dos tipos de peticiones: GET y POST.

Ante una petición GET el servidor responderá con una página web donde se muestra el estado actual de los LEDS y un grupo de botones para modificar el estado de estos.

Si se presiona uno de los botones de la página el navegador enviará una petición POST al servidor para cambiar el estado del LED correspondiente.

A continuación, por simplicidad, se analiza el código en partes.

Librerías, constantes y variables globales

Se empieza como de costumbre, incluyendo las librerías necesarias. En este caso solo es necesaria la librería Ethernet para el control del módulo de red. 

1
2
// Programación del servidor web en Arduino con Ethernet Shield
#include <Ethernet.h>

Se declaran cinco constantes para definir los pines digitales a utilizar para controlar los LEDs. Una sexta constante indica la cantidad de LEDs que se utilizan.

1
2
3
4
5
6
7
// Constantes
#define LED1 2
#define LED2 3
#define LED3 5
#define LED4 6
#define LED5 7
#define NUM_OF_LEDS 5

Los pines digitales son almacenados en un arreglo para facilitar su manejo.

1
const int leds[] = { LED1, LED2, LED3, LED4, LED5 };

Se declaran las constantes ip y mac con las direcciones IP y MAC del Arduino, respectivamente.

Si no tienes claro qué dirección IP o MAC asignarle a tu Arduino puedes revisar el artículo anterior sobre Ethernet Shield donde se muestra ese proceso paso a paso.

1
2
3
const IPAddress ip(192,168,1,125); // dirección IP
 
const byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xA0, 0x88 };// dirección MAC

Se define un objeto EthernetServer para la implementación del servidor web. Se utiliza el puerto 80 porque este es el predefinido para HTTP.

1
EthernetServer webServer(80);

Función setup()

En la función setup() se inicializan todos los componentes necesarios. Se comienza configurando los pines de los LEDs como salida y en estado bajo (LOW).

1
2
3
4
5
6
7
void setup() {
 
  // Inicalizar LEDs
  for( int i = 0; i < NUM_OF_LEDS; i++ ){
    pinMode( leds[i], OUTPUT );
    digitalWrite(leds[i], LOW);
  }

Luego se inicializa el puerto serie y el Ethernet Shield.

1
2
3
4
5
  // Inicializar puerto Serial
  Serial.begin(9600);
 
  // Inicializar Ethernet Shield
  Ethernet.begin(mac, ip);

Por último, se comprueba el estado del Ethernet Shield. Si este no presenta ningún problema se inicializa el servidor.

1
2
3
4
5
6
7
8
9
10
11
  // Verificar Ethernet Shield
  if( Ethernet.hardwareStatus() == EthernetNoHardware ){
    Serial.println("No se ha detectado Ethernet shield");
    while(1); // no hacer nada
  }
  // Verificar cable Ethernet
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("El cable Ethernet no está conectado o está defectuoso");
  }
  webServer.begin();
}

Función loop()

En la función loop() simplemente se ejecuta la función checkForClients(). Es la encargada de atender las peticiones de los clientes.

1
2
3
void loop() {
  checkForClients();
}

Función checkForClients()

La función comienza declarando una variable tipo String donde se almacenará el mensaje enviado por el cliente. También se crea un objeto EthernetClient utilizando la instrucción webServer.available(). 

1
2
3
4
void checkForClients(){
 
  String sms_client;
  EthernetClient client = webServer.available();

Utilizando una instrucción if se comprueba la existencia de peticiones por parte de algún cliente. En caso de que se detecte alguna petición se indica mediante el monitor serie y se almacena el mensaje HTTP en la variable sms_client.

Para obtener el mensaje se van leyendo los caracteres enviados por el cliente hasta que se llegue a la línea en blanco que separa las cabeceras del cuerpo del mensaje. Para indicar que se ha encontrado el final de las cabeceras se asigna true a la variable ok.

Luego de haber leído los caracteres se verifica el valor de la variable ok. Si es false no se procesa la petición, ya que se considera un mensaje incompleto.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
  if( client ){
    Serial.print( "Nuevo cliente conectado con ip " );  
    Serial.println( client.remoteIP() );  
    Serial.println("----------------------------------------------");
 
    boolean currentLineIsBlank = true;
    boolean ok = false;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        sms_client += c;
        Serial.print(c);
        if (c == '\n' && currentLineIsBlank) { // fin de la solicitud
          ok = true;
          
          break;
        }
        
        if (c == '\n') {
          // comienza una nueva línea
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // se ha escrito un caracter en la nueva línea
          currentLineIsBlank = false;
        }
      }
    }
 
    if( !ok ) // mensaje HTTP inválido
      return;

Si el mensaje es válido se comprueba el tipo de petición. En este caso solo se procesan dos tipos: GET y POST.

Para identificar el tipo de petición se implementó la función checkRequest(). Esta retorna false cuando el mensaje corresponde a GET y true para POST.

Si la petición es de tipo GET se invoca a la función responseToClient(), la cual envía un mensaje de respuesta al cliente a partir del estado de los LEDs.

En caso de ser una petición POST se lee el cuerpo del mensaje y se almacena en la variable payload. Luego se ejecuta la función makePOST() que interpreta el mensaje y actúa en consecuencia. También se ejecuta responseToClient() para que los cambios ocurridos sean actualizados en el navegador.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    int tipo_sms = checkRequest( sms_client );
    
    if( tipo_sms == 0 ){  // es un GET
      responseToClient( client );
    }
    else if( tipo_sms == 1 ){  // es un POST
      
      String payload = "";
      
      // leer cuerpo del mensaje
      while( client.available() ){
        char c = client.read();
        payload += c;
      }
 
      Serial.print("payload: ");
      Serial.println(payload);
 
      makePOST(payload);
      
      responseToClient( client );
    }

Una vez se ha enviado la respuesta al cliente se realiza un pequeño retardo para que el navegador reciba los datos y por último se cierra la conexión con el cliente.

1
2
3
4
5
6
7
8
    // esperar un tiempo para que el navegador reciba la información que envio el Ethernet shield
    delay(1);
 
    client.stop(); // cerrar la conexión
    Serial.println("----------------------------------------------");
    Serial.println("client desconectado");  
  }
}

Función checkRequest()

La función checkRequest() recibe como parámetro un String con un mensaje HTTP y determina el método de petición. Para esto simplemente se comprueba si la palabra “GET” o “POST” se encuentra al principio del mensaje.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int checkRequest( String &sms_client ){
  // obtener la posición de GET
  int idx = sms_client.indexOf("GET");
 
  if( idx == 0 )
    return 0;
 
  idx = sms_client.indexOf("POST");
 
  if(idx == 0)
    return 1;
  
  return -1;
  
}

Función responseToClient()

Esta función que recibe como parámetro un objeto EthernetClient y él envía una página web en formato HTML utilizando el protocolo HTTP con el estado de los LEDs y botones que permitan controlarlos.

Comienza enviando la versión HTTP y el resultado de su solicitud.

1
2
void responseToClient( EthernetClient &client ){
  client.println("HTTP/1.1 200 OK");

Luego se envían las cabeceras indicando que es un mensaje HTML (Content-Type),  que la conexión se cerrará después de ese mensaje (Connection) y que el navegador se debe refrescar cada 5 segundos (Refresh). Se termina la sección de cabeceras con una línea en blanco, tal y como se vio anteriormente.

1
2
3
4
5
6
7
8
// Formato del cuerpo del mensaje en HTML
  client.println("Content-Type: text/html");
  // Cerrar conexión con el Ethernet shield al terminar la respuesta
  client.println("Connection: close");
  // El navegador refresca la página cada 5 segundos
  client.println("Refresh: 5");  
  // Línea en blanco
  client.println();

Por último, envía la página web en formato HTML. Esta cuenta con cinco botones que muestran el estado actual de cada LED. Además, haciendo clic sobre un botón se puede cambiar el estado del LED.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  // Enviar página web en HTML
  client.println( "<!DOCTYPE HTML>" );
  client.println( "<html>" );
 
  client.println( "<head>" );
  client.println( " <title>Control LED con Arduino</title>");
  client.println( "</head>" );
 
  client.println( "<body>" );
  client.println( " <h1>LEDs</h1>" );
  client.println( " <p> Click para encender o apagar los LEDs </p>" );
 
  for( int i = 0; i < NUM_OF_LEDS; i++ ){
    client.println( " <form method=\"POST\">" );
    client.print( " <label for=\"LED\">LED ");
    client.print(i+1);
    client.print(":</label>");
    client.print( "  <input type=\"submit\" name=\"LED");
    client.print(i+1);
    client.print( "\" ");
 
    if( digitalRead(leds[i]) == HIGH )
      client.print( "value=\"ON\">" );
    else
      client.print( "value=\"OFF\">" );  
    
    
    client.println( " </form>" );
    
  }
  
  client.println( "</body>" );
 
  client.println("</html>");
  
}

Más adelante se utiliza un navegador web para interactuar con la página y ver el código HTML generado.

Función makePOST()

La función makePOST() recibe el cuerpo de un mensaje de tipo POST y lo interpreta para identificar sobre qué LED tiene que actuar y qué operación realizar.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void makePOST(String &sms){
  int index = sms.indexOf("LED") + 1;
  int num_led;
  int state;
  
  while( !isdigit(sms[index]) ) index++;
 
  num_led = sms[index]-'0';
  
  // obtener estado
  if( sms.indexOf("ON") != -1 )
    state = HIGH;
  else
    state = LOW;  
 
  // modificar estado
  if( state == LOW )
    digitalWrite( leds[num_led-1], HIGH);
  else
    digitalWrite( leds[num_led-1], LOW);
}

Bueno, aquí tienes el código completo para que lo cargues a tu Arduino.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// Programación del servidor web en Arduino con Ethernet Shield
// Cabeceras
#include <Ethernet.h>
 
// Constantes
#define LED1 2
#define LED2 3
#define LED3 5
#define LED4 6
#define LED5 7
#define NUM_OF_LEDS 5
 
const int leds[] = { LED1, LED2, LED3, LED4, LED5 };
 
const IPAddress ip(192,168,1,125);
 
const byte mac[] = { 0x90, 0xA2, 0xDA, 0x0D, 0xA0, 0x88 };// dirección MAC.
 
EthernetServer webServer(80);
 
void setup() {
 
  // Inicalizar LEDs
  for( int i = 0; i < NUM_OF_LEDS; i++ ){
    pinMode( leds[i], OUTPUT );
    digitalWrite(leds[i], LOW);
  }
 
  // Inicializar puerto Serial
  Serial.begin(9600);
 
  // Inicializar Ethernet Shield
  Ethernet.begin(mac, ip);
 
  // Verificar Ethernet Shield
  if( Ethernet.hardwareStatus() == EthernetNoHardware ){
    Serial.println("No se ha detectado Ethernet shield");
    while(1); // no hacer nada
  }
 
  // Verificar cable Ethernet
  if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("El cable Ethernet no está conectado o está defectuoso");
  }
 
  webServer.begin();
  
}
 
void loop() {
  checkForClients();
}
 
 
 
void checkForClients(){
 
  String sms_client;
  EthernetClient client = webServer.available();
 
  if( client ){
    Serial.print( "Nuevo cliente conectado con ip " );  
    Serial.println( client.remoteIP() );  
    Serial.println("----------------------------------------------");
    
    boolean currentLineIsBlank = true;
    boolean ok = false;
    while (client.connected()) {
      if (client.available()) {
        char c = client.read();
        sms_client += c;
        Serial.print(c);
        if (c == '\n' && currentLineIsBlank) { // fin de la solicitud
          ok = true;
          
          break;
        }
        
        if (c == '\n') {
          // comienza una nueva línea
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // se ha escrito un caracter en la nueva línea
          currentLineIsBlank = false;
        }
      }
    }
 
    if( !ok ) // mensaje HTTP inválido
      return;
 
    int tipo_sms = checkRequest( sms_client );
    
    if( tipo_sms == 0 ){  // es un GET
      responseToClient( client );
    }
    else if( tipo_sms == 1 ){  // es un POST
      
      String payload = "";
      
      // leer cuerpo del mensaje
      while( client.available() ){
        char c = client.read();
        payload += c;
      }
 
      Serial.print("payload: ");
      Serial.println(payload);
 
      makePOST(payload);
      
      responseToClient( client );
    }
          
 
  
    // esperar un tiempo para que el navegador reciba la información que envio el Ethernet shield
    delay(1);
 
    client.stop(); // cerrar la conexión
    Serial.println("----------------------------------------------");
    Serial.println("client desconectado");  
  }
    
}
 
 
int checkRequest( String &sms_client ){
  // obtener la posición de GET
  int idx = sms_client.indexOf("GET");
 
  if( idx == 0 )
    return 0;
 
  idx = sms_client.indexOf("POST");
 
  if(idx == 0)
    return 1;
  
  return -1;
  
}
 
void makePOST(String &sms){
  int index = sms.indexOf("LED") + 1;
  int num_led;
  int state;
  
  while( !isdigit(sms[index]) ) index++;
 
  num_led = sms[index]-'0';
  
  if( sms.indexOf("ON") != -1 )
    state = HIGH;
  else
    state = LOW;
  
  // modificar estado
  if( state == LOW )
    digitalWrite( leds[num_led-1], HIGH);
  else
    digitalWrite( leds[num_led-1], LOW);
}
 
 
void responseToClient( EthernetClient &client ){
  // protocolo HTTP 1.1
  client.println("HTTP/1.1 200 OK");
  // Formato del cuerpo del mensaje en HTML
  client.println("Content-Type: text/html");
  // Cerrar conexión al terminar la respuesta
  client.println("Connection: close");
  // El navegador refresca la página cada 5 segundos
  client.println("Refresh: 5");  
  // Línea en blanco
  client.println();
 
  // Enviar página web en HTML
  client.println( "<!DOCTYPE HTML>" );
  client.println( "<html>" );
 
  client.println( "<head>" );
  client.println( " <title>Control LED con Arduino</title>");
  client.println( "</head>" );
 
  client.println( "<body>" );
  client.println( " <h1>LEDs</h1>" );
  client.println( " <p> Click para encender o apagar los LEDs </p>" );
 
  for( int i = 0; i < NUM_OF_LEDS; i++ ){
    client.println( " <form method=\"POST\">" );
    client.print( " <label for=\"LED\">LED ");
    client.print(i+1);
    client.print(":</label>");
    client.print( "  <input type=\"submit\" name=\"LED");
    client.print(i+1);
    client.print( "\" ");
 
    if( digitalRead(leds[i]) == HIGH )
      client.print( "value=\"ON\">" );
    else
      client.print( "value=\"OFF\">" );  
    
    
    client.println( " </form>" );
    
  }
  
  client.println( "</body>" );
 
  client.println("</html>");
  
}

Funcionamiento del servidor web con Arduino y Ethernet Shield

Si ya tienes tu placa Arduino programada, el Ethernet shield, y el resto de componentes conectados es hora de comprobar que el sistema funciona correctamente.

Lo primero es energizar todo el sistema. Asegúrate de encender el router y alimentar el Arduino correctamente.

Ahora abre un navegador web en tu ordenador. Da lo mismo el que sea, aunque te recomiendo utilizar Mozilla Firefox o Chrome.

08 navegador web Ethernet Shield

Una vez tengas el navegador abierto ve a la barra de direcciones y escribe la dirección IP que le asignaste al Arduino en el código. En mi caso sería 192.168.1.125.

09 direccion ip navegador web Ethernet Shield

Cuando la tecla ENTER sea presionada el navegador enviará una petición GET al servidor implementado en el Arduino. 

En la siguiente figura se puede observar la salida del monitor serie donde se muestra la petición enviada por el navegador.

10 salida monitor serie arduino Ethernet Shield

Para poder ver las peticiones enviadas al Arduino es necesario alimentarlo desde un puerto USB del ordenador y abrir el monitor serie.

Ten en cuenta que no es necesario alimentar el Arduino desde el ordenador para que el sistema funcione.

Al recibir la petición el Arduino evalúa el estado de los LEDs y envía una respuesta al navegador. En este último se debería cargar una página similar a la que se muestra en la siguiente figura.

11 pagina web Ethernet Shield

Como puedes ver, la página cuenta con 5 botones, uno para cada LED. El texto de cada botón indica el estado actual de los LEDs. Presionando el botón se cambia el estado del LED correspondiente.

En la siguiente imagen se muestra el resultado obtenido después de presionar los botones correspondientes a los LEDs 1 y 4.

12 prototipo Ethernet Shield

Si quieres ver el código fuente HTML de la página puedes hacer clic derecho y seleccionar la opción Ver código fuente de la página.

13 codigo fuente Ethernet Shield

Esto abre una nueva pestaña donde se muestra el código HTML. Este código es el generado por el Arduino utilizando la función responseToClient().

Si no tienes experiencia en HTML será difícil entender por completo el código de la página web, sin embargo, puede ser interesante saber que cuentas con esta herramienta.

14 codigo html Ethernet Shield

Como puedes ver cada botón pertenece a un formulario HTML (form), es por eso que al presionar uno de ellos el navegador envía una petición de tipo POST al Arduino. Por ejemplo, al presionar el botón correspondiente al LED 1 se envía la siguiente petición.

15 monitor arduino led Ethernet Shield

En el cuerpo de la petición se indica el estado actual del LED a modificar, es decir, que la instrucción LED1=OFF indica que el LED1 está actualmente apagado y debe encenderse. 

Conclusión proyecto Ethernet Shield y Arduino

En este artículo se comenta cómo funciona el protocolo HTTP.

Luego, cómo utilizar HTTP con una placa Arduino y Ethernet Shield para implementar un servidor web que permita encender y apagar otros dispositivos.

Recuerda que aunque en el ejemplo se emplean LEDs, pueden ser intercambiados por relés.

Sin duda, serán viejos ayudantes electrónicos con mucho más potencial. Si te embarcas en esa travesía te recomiendo el artículo sobre control de relés con Arduino.

Pero entonces, el servidor web con Arduino y Ethernet shield ¿No es suficiente?

Pues, ningún problema.

Combina la interacción de LEDs con un monitor de temperatura y humedad puesto en marcha en la primera parte de este artículo.

Por ultimo, espero que este pequeño prototipo te halla abierto el apetito Maker.

Ya sabes, cualquier duda o sugerencia será bien recibida en la caja de comentarios.

Gracias a Shutterstock por ceder los derechos de las imágenes.

Motor-DC

Motor DC con Arduino y driver L298N o L293D

Muchos de los proyectos que deseamos realizar con nuestro Arduino pueden incluir algún tipo de movimiento y, probablemente la primera idea que se nos … [+ info...]

Zigbee-y-Home-Assistant

Zigbee y Home Assistant

En este artículo vamos a hacer hincapié en la integración de Zigbee y Home Assistant. Se podría decir que este artículo es una segunda parte de otro … [+ info...]

Panel-de-energia-en-home-assistant-1

Panel de energía en Home Assistant

Hola a todos, bienvenidos al podcast La "Tecnología para Todos". En este capítulo nos encontramos con Germán y José Manuel en una charla sobre paneles … [+ info...]

Copyright © 2022 · Programar Fácil · Aviso legal

Utilizamos cookies propios y de terceros para mejorar nuestros servicios y experiencia de usuario. Si continua navegando, consideramos que acepta su uso.Aceptar Política de privacidad y cookies
Política de cookies

Privacy Overview

This website uses cookies to improve your experience while you navigate through the website. Out of these, the cookies that are categorized as necessary are stored on your browser as they are essential for the working of basic functionalities of the website. We also use third-party cookies that help us analyze and understand how you use this website. These cookies will be stored in your browser only with your consent. You also have the option to opt-out of these cookies. But opting out of some of these cookies may affect your browsing experience.
Necessary
Siempre activado
Necessary cookies are absolutely essential for the website to function properly. This category only includes cookies that ensures basic functionalities and security features of the website. These cookies do not store any personal information.
Non-necessary
Any cookies that may not be particularly necessary for the website to function and is used specifically to collect user personal data via analytics, ads, other embedded contents are termed as non-necessary cookies. It is mandatory to procure user consent prior to running these cookies on your website.
GUARDAR Y ACEPTAR