PROYECTO FINAL
INTEGRANTES :
William Cahuana Rosales
"LOLIN - ESP8266"
Pineado de NodeMCU
A continuación puedes ver el pineado de la NodeMCU original.
El nombre de los pines de NodeMCU tiene una nomenclatura diferente de la que utiliza el ESP8266. Por ejemplo los pines D0, D1, y D2 en la NodeMCU correponden con GPIO16, 5 y 4 en el ESP8266. El framework para Arduino permite utilizar ambas para referirse a los pines de entrada salida.
Estas dos sentencias son equivalentes.
Conectando el NodeMCU al PC
Las placas NodeMCU incorporan un conversor USB a serie. Solamente es necesario conectar el puerto USB de la placa a uno de los puertos de nuestro ordenador con un buen cable.
El sistema operativo normalmente detecta el hardware e instala los drivers automáticamente.
Si tienes un sistema operativo MAC, sigue estas instrucciones.
Hay diferentes fabricantes que hacen tarjetas de este tipo. Cada uno puede utilizar conversores diferentes. Los más utilizados son el CP1202 de Silabs, y CH340 del fabricante chino WCH. He leído que también hay placas que utilizan el conversor FT232RL de FTDI, pero no he llegado a ver ninguna.
Por mi experiencia, estos 3 chips funcionan bien con velocidades de hasta 921kbps sin problema. Éste es el máximo bitrate que soporta el IDE de Arduino. Te interesa utilizar esta velocidad para reducir el tiempo de carga del programa en la memoria flash del ESP8266, pero es necesario utilizar un buen cable USB.
Si ves que no funciona a esa velocidad, prueba a 115200 y haz diferentes pruebas hasta que encuentres el límite de tu sistema.
Para configurar el entorno de Arduino te recomiendo ver el video sobre cómo programar el ESP8266 con el IDE de Arduino.
Puede que al principio no sepas para qué sirven las opciones de configuración de la placa. Ésta es la configuración que yo utilizo y que funcionará con todas las NodeMCU. Si el IDE de Arduino no puede programar la placa prueba a bajar el campo “upload speed” a 115200 bps.
NodeMCU: Ejemplos para empezar
Ahora vamos a ponernos manos a la obra. Para empezar de la manera más sencilla vamos a aprender cómo utilizar el botón y el led que incluye la NodeMCU. El LED está conectado, internamente, al GPIO2 y el botón al GPIO0.
Lo primero que vamos a hacer es que parpadee el LED de NodeMCU. Copia y pega este código en el IDE de Arduino.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#define LED_BUILTIN 2
void setup() {
// El LED integrado está conectado al pin 2.
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
// Encender el LED (Está conectado con una resistencia pull-up,
// por eso se enciende si el pin está a nivel bajo)
digitalWrite(LED_BUILTIN, LOW);
delay(1000); // Esperar un segundo
// Apagar el LED
digitalWrite(LED_BUILTIN, HIGH);
delay(1000); // Esperar un segundo
}
|
En el siguiente código vamos a utilizar el botón FLASH de NodeMCU. Este botón nos permite poner en modo carga del firmware. Como ya te he comentado, esto lo hace automáticamente al igual que las placas de Arduino, en un modo normal no tenemos que pulsar nada para cargar nuestro código.
Sin embargo, podemos utilizarlo como un botón normal una vez que se ha cargado el código al NodeMCU pero siempre y cuando se haya iniciado la ejecución. Recuerda, el GPIO donde está conectado el botón FLASH de NodeMCU es el GPIO0.
Carga el siguiente código que lo que hace es encender el LED conectado el GPIO2 cuando se pulsa el botón.
¿A qué no te ha parecido complicado? ¿A que el código te suena? Como ya te he comentado, hay pocas diferencias entre programar un Arduino y un NodeMCU o cualquier otra placa basada en el ESP8266.
Acceder a una web desde NodeMCU
Cuando tenemos un módulo como el NodeMCU que puede conectarse a Internet mediante WiFi, lo primero que se nos puede ocurrir hacer con él es acceder a datos en la red. Esto podemos hacerlo, por ejemplo, accediendo a una API REST mediante protocolo HTTP.
Las librerías que incluye el framework de Arduino para el ESP8266 hacen que esto sea una tarea muy sencilla.
Conectar a la red WiFi
Lo primero de todo hay que conectar el módulo a la red WiFi. Para ello, dentro de la función
setup() configuramos el NodeMCU como cliente WiFi e iniciamos la conexión pasando el nombre de nuestra red y la contraseña.Conectar a la red WiFi
Lo primero de todo hay que conectar el módulo a la red WiFi. Para ello, dentro de la función
setup() configuramos el NodeMCU como cliente WiFi e iniciamos la conexión pasando el nombre de nuestra red y la contraseña.Conectar al servidor
Después, una vez que verificamos que la conexión se ha realizado correctamente se puede enviar la petición. En este ejemplo voy a obtener la información de las condiciones meteorológicas. Lo voy a hacer consultando a la API del servicio Weather Underground. No te preocupes si no entiendes todo el código. En una próxima entrada del blog hablaremos de esto con mayor detalle.
Ahora ya podemos esperar y leer la respuesta.
Si todo ha ido correctamente, esto es lo que vamos a ver en el monitor serie:
Programa completo
El código del sketch será éste. Para hacerlo funcionar necesitas rellenar los datos de tu red WiFi y de la clave del API de Weather Underground que puedes obtener registrándote en su web.
¿Y si tengo que conectarme usando HTTP seguro?
Cada vez más sitios web exigen que las conexiones utilicen el protocolo seguro HTTPS. ¿Qué puedo hacer si el API al que tengo que acceder me obliga a usar comunicación segura?
El ESP8266 no tiene hardware de seguridad para encriptar la comunicación por lo tanto, NodeMCU tampoco. Pero la librería WiFi incluye funciones de encriptación por software. Gracias a esto podremos acceder de una forma muy similar a sitios HTTPS.
Solamente hay que cambiar la declaración
WiFiClient client por WiFiClientSecure client. Adicionalmente para asegurarnos de que estamos conectándonos realmente al servidor que queremos se puede comprobar que el certificado es el correcto, comprobando que la huella corresponde con la esperada.
Pero esto tiene un inconveniente. La encriptación y gestión de los certificados mediante software consume alrededor de 20 kB. Esto representa prácticamente la mitad de la memoria disponible para nuestro programa.
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
|
// Esta es la librería para utilizar las funciones de red del ESP8266
#include <ESP8266WiFi.h>
const char* ssid = "SSID"; // Rellena con el nombre de tu red WiFi
const char* password = "Contraseña"; // Rellena con la contraseña de tu red WiFi
const char* host = "api.wunderground.com";
const char* apiKey = "tu clave API de wunderground.com"; // Puedes obtenerla en
// https://www.wunderground.com/weather/api/
// Huella digital del certificado del servidor https://www.wunderground.com
const char * fingerprint = "a9 1f b9 fe 35 b8 38 b9 54 67 e7 34 52 8a 24 d4 17 29 fa 32";
void setup() {
Serial.begin(115200);
delay(10);
// Conectamos a la red WiFi
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
/* Configuramos el ESP8266 como cliente WiFi. Si no lo hacemos
se configurará como cliente y punto de acceso al mismo tiempo */
WiFi.mode(WIFI_STA); // Modo cliente WiFi
WiFi.begin(ssid, password);
// Esperamos a que estemos conectados a la red WiFi
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP()); // Mostramos la IP
}
void loop() {
Serial.print("connecting to ");
Serial.println(host);
// Creamos el cliente
WiFiClientSecure client;
const int httpPort = 443; // Puerto HTTPS
if (!client.connect(host, httpPort)) {
// ¿hay algún error al conectar?
Serial.println("Ha fallado la conexión");
return;
}
// Verificamos que el certificado coincide con el esperado
if(client.verify(fingerprint,host)){
Serial.println("El certificado es correcto");
} else {
Serial.println("Error de certificado");
}
// Creamos la URL para la petición
String url = "/api/";
url += apiKey;
url += "/conditions/lang:SP/q/autoip.json";
Serial.print("URL de la petición: https://");
Serial.print(host);
Serial.print(":");
Serial.print(httpPort);
Serial.println(url);
// Enviamos la petición
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Superado el tiempo de espera !");
client.stop();
return;
}
}
// Consutar la memoria libre
// Utilizando HTTPS se necesitan unos 20 kB de memoria libres adicionales
Serial.printf("\nMemoria libre en el ESP8266: %d Bytes\n\n",ESP.getFreeHeap());
// Leemos la respuesta y la enviamos al monitor serie
while(client.available()){
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("Cerrando la conexión");
while(1){
delay(0); // Siempre que hay un bucle que pueda durar mucho tiempo
// hay que llamar a la función delay() para atender a los
// procesos de la conexión WiFi. Si no se hace el ESP8266
// generará un error y se reiniciará a los pocos segundos
}
}
|
Conclusiones cómo programar NodeMCU
El microcontrolador ESP8266 es un dispositivo muy versátil y relativamente potente. Tiene también algunas limitaciones. Pero su precio hace que siga siendo el microcontrolador elegido por muchos para desarrollar proyectos del IoT.
Con NodeMCU, programar el ESP8266 es mucho más sencillo que hacerlo con módulos como el ESP01.
La integración en el IDE de Arduino evita la necesidad de tener que montar un entorno de desarrollo para utilizar la SDK de Espressif.
Hemos visto cómo conectar NodeMCU a nuestro ordenador y cómo configurar el IDE de Arduino para programarlo. También nos hemos iniciado con programas básicos para el control de los puertos de entrada salida.
La comunicación WiFi es la gran capacidad de este pequeño chip. En los ejemplos os he enseñado lo necesario para comenzar a usarlo. Si no te ha quedado claro todo lo referente a este último punto no te preocupes, en las siguientes entradas te contaré lo pasos para controlar las diferentes capacidades del ESP8266.
CODIGO
#include <ESP8266WiFi.h> //const char* ssid = "OSCAR"; //const char* password = "944012531"; const char* ssid = "ENTEL HOGAR"; const char* password = "QT6B6MJ6AJB"; //------------------------------------------------------------------------------ #define TRIGGER 4 #define ECHO 5 //------------------------------------------------------------------------------ int ledPin = 16; // GPIO13 int analogIn = A0; // GPIO13 int ledState = LOW; //------------------------------------------------------------------------------ int altavozPin = 13; int numTones = 2; //número de tonos (se puede cambiar) int tonos[] = {494}; //array de los tonos (se puede cambiar) //------------------------------------------------------------------------------ WiFiServer server(80); void setup() { Serial.begin(115200); delay(10); // Variable inits ledState = LOW; //------------------------------------------------------------------------------ pinMode(TRIGGER, OUTPUT); // define el pin 6 como salida (triger) pinMode(ECHO, INPUT); // define el pin 7 como entrada (echo) pinMode(14,OUTPUT); pinMode(13,OUTPUT); //------------------------------------------------------------------------------ //Init LED output pinMode(ledPin, OUTPUT); digitalWrite(ledPin, ledState); // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFi connected"); // Start the server server.begin(); Serial.println("Server started"); // Print the IP address Serial.print("Use this URL to connect: "); Serial.print("http://"); Serial.print(WiFi.localIP()); Serial.println("/"); } void loop() { // Check if a client has connected WiFiClient client = server.available(); if (!client) { return; } // Wait until the client sends some data Serial.println("new client"); while(!client.available()){ delay(1); } // Read the first line of the request String request = client.readStringUntil('\r'); Serial.println(request); client.flush(); //---------------------------------------------------------------------------- long duration, distance; digitalWrite(TRIGGER, LOW); delayMicroseconds(2); digitalWrite(TRIGGER, HIGH); delayMicroseconds(10); digitalWrite(TRIGGER, LOW); duration = pulseIn(ECHO, HIGH); distance = (duration/2) / 29.1; //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- if (distance <= 10 || distance >= 0) { // si la distancia es mayor a 500cm o menor a 0cm digitalWrite(14, 0); // en bajo el pin 3 LED } if (distance >= 10 && distance <= 100) { //bucle for en el cual llevamos a cabo las acciones para distancia menor o igual a 10cm y mayor o igual 1cm for (int i = 0; i < numTones; i++) { digitalWrite(14, 1); //LED encendido tone(altavozPin, tonos[0]); //suena el altavoz delay(100); //espera 100 ms } noTone(altavozPin); } delay(400); // espera 400ms para que se logre ver la distancia en la consola //---------------------------------------------------------------------------- // Find which, if any, commmand was sent: // This is a little hacky, we should parse the query string // then check for the existance of named variables, but this is a bit quicker to program - alls we do // is check if the command string is found, and if it is, execute the command if (request.indexOf("cmd=TURN_ON_LED") != -1) { // if the command is turn on the led, turn it on ledState = HIGH; } else if (request.indexOf("cmd=TURN_OFF_LED") != -1) { // if the command is turn off the led, turn it off ledState = LOW; } // Update the LED based on ledState digitalWrite(ledPin, ledState); // Always update the photocell value anytime there's a request // NOTE: We have the cmd=RELOAD_PHOTOCELL command because we need a way // to update the photocell without changing the led state for the user int photocell_value = analogRead(analogIn); // Return the response client.println("HTTP/1.1 200 OK"); client.println("Content-Type: text/html"); client.println(""); // do not forget this one client.println("<!DOCTYPE HTML>"); client.println("<html>"); client.print("Led pin esta ahora: "); if(ledState == HIGH) { client.print("On"); } else { client.print("Off"); } client.println("<br><br>"); client.println("<a href=\"?cmd=TURN_ON_LED\"><button>Turn On </button></a>"); client.println("<a href=\"?cmd=TURN_OFF_LED\"><button>Turn Off </button></a>"); // client.println("<p>El valor de la fotocelula es:<b> "); // client.println(photocell_value); //----------------------------------------------------------------------------- client.println("<p>El valor de la distancia es:<b> "); client.println(distance); //----------------------------------------------------------------------------- client.println("</b></p>"); client.println("<a href=\"?cmd=RELOAD_PHOTOCELL\"><button>Check for new photocell value</button></a>"); client.println("</html>"); delay(1); Serial.println("Client disonnected"); Serial.println(""); }
VÍDEO EXPLICATIVO :








