Para la realización del taller utilizaremos la placa Wemos D1, basada en el microcontrolador ESP8266, las Luces NeoPixel, y diferentes sensores.
El microcontrolador Wemos D1 se trata de una placa con muchas prestaciones y con dimesiones muy reducinas, por eso es perfecta para hacer prototipos de Iot, wearables, etc. Es compatible con Arduino IDE, con lo que seremos capaces de programarla como si fuese un arduino. Además cuenta con WiFi.
Las luces NeoPixel, se tratan de un componente super sencillo de utilizar creado por la empresa Adafruit. Se tratan de unas luces RGB, con bastante luminosidad, capaces de juntarse en serie para formar tiras de leds. Su programación es bastante sencilla.
Para instalar Arduino IDE, dirigete la página de Arduino y descarga la última versión compatible con tu equipo. Sigue los pasos de la instalción.
Additional Boards Manager URLs
añade lo siguiente:https://arduino.esp8266.com/stable/package_esp8266com_index.json
ESP8266
e instala el siguiente paquete con el botón install:NeoPixel
e instala la última versión.Para poder usar el sensor de temperatura y humedad DHT11/DHT22 tendremos que descargarnos la librería. Esto se hace de la siguiente forma:
DHT Sensor
:Adafruit Unified Sensor
:El programa más sencillo de Arduino, se encuentra en File->Examples->01.Basics->Blink y tiene el siguiente código.
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Este programa se dedica a encender y apagar un led cada segundo. Cuenta con las 2 funciones más importantes de Arduino: void setup()
y void loop()
.
La función void setup()
es lo primero que se ejecuta al enceder la placa Arduino, y se ejecuta una única vez. Se utilizá en la mayoría de los casos para configurar la placa, configurar sensores, etc.
La funcion void loop()
se ejecuta inmediatamente después de void setup()
y se está ejecutando todo el rato en bucle. Es donde pondremos la lógica de nuestro programa Arduino.
En el programa Blink, en el void setup()
configura el pin del led instalado en nuestra placa como salida, y en el void loop()
lo enciende y lo apaga cada segundo.
Para enviar nuestro código a nuestra placa ESP8266, tendremos que:
La conexión típica de Neopixel con el ESP8266 será:
Para aprender cómo se usa este componente, nos será muy útil utilizar los ejemplos proprocionados por Adafruit. Estos, se encuentran en File->Examples->Adafruit Neopixel.
El ejemplo más básico es el simple
. Nos servirá para explicar cómo se utiliza Neopixel:
// Include Adafruit Neopixel Library
#include <Adafruit_NeoPixel.h>
// Which pin on the Arduino is connected to the NeoPixels?
#define PIN D8
// How many NeoPixels are attached to the Arduino?
#define NUMPIXELS 16 // Popular NeoPixel ring size
// When setting up the NeoPixel library, we tell it how many pixels,
// and which pin to use to send signals. Note that for older NeoPixel
// strips you might need to change the third parameter -- see the
// strandtest example for more information on possible values.
Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
#define DELAYVAL 500 // Time (in milliseconds) to pause between pixels
void setup() {
pixels.begin(); // INITIALIZE NeoPixel strip object (REQUIRED)
}
void loop() {
pixels.clear(); // Set all pixel colors to 'off'
// The first NeoPixel in a strand is #0, second is 1, all the way up
// to the count of pixels minus one.
for(int i=0; i<NUMPIXELS; i++) { // For each pixel...
// pixels.Color() takes RGB values, from 0,0,0 up to 255,255,255
// Here we're using a moderately bright green color:
pixels.setPixelColor(i, pixels.Color(0, 150, 0));
pixels.show(); // Send the updated pixel colors to the hardware.
delay(DELAYVAL); // Pause before next pass through loop
}
}
En el ejemplo, se encienden una a una las luces de color verde, y cuando están todas encendidas las apaga y vuelve a empezar.
Lo primero que hacemos es importar la librería, definir las conexiones y las variables. En el void setup()
inicializamos nuestra tira de leds.
En el void loop()
podemos ver la lógica del programa, y cómo se utiliza neopixel.
La función pixels.clear()
nos servirá para apagar los LEDs.
La función pixels.setPixelColor(i, pixels.Color(R, G, B))
la utilizaremos para enviar la información de cómo queremos iluminar nuestro LEDS. i
seleccionaremos el LED que queremos encender (ojo, que el primer led es el 0
). R, G, B
será el color que tomarán el rojo, verde y amarillo, en un rango de 0 a 255. Esto es que negro será (0,0,0)
, blanco será (255, 255, 255)
y rojo poco intenso (100, 0, 0)
.
Las luces no se ilumarán hasta que hagamos pixels.show()
. Con esta función haremos que las luces se iluminan con la información que anteriormente le hayamos enviado.
Se trata de un sensor muy fácil de programar con el que podremos determinar la proximidad de objetos. Se basa en emitir una señal y medir el tiempo que tarda en volver, para así determinar la distancia a la que se encuentra el objeto.
Las conexeciones son las siguientes:
El código es el siguiente:
// defines pins numbers
const int trigPin = D6;
const int echoPin = D7;
// defines variables
long duration;
int distance;
void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
}
void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance= duration*0.034/2;
// Prints the distance on the Serial Monitor
Serial.print("Distance: ")
Serial.println(distance);
}
En este ejemplo estamos haciendo uso del puerto serie. Esto es, que no estamos conectando con la placa, para que nos de en la pantalla del ordenador el valor de los sensores. Para abrir el puerto serie se hace en el void setup()
con Serial.begin(9600)
, y escribiremos en el con Serial.println()
. Para ver la información que nos envia, le daremos al botón Serial Monitor del IDE de Arduino.
Se trata de un foto resistencia de cambiar su valor de resistencia con la incidencia de la luz solar. Se trata de un sensor analógico, que tendrá un rango de 0 (totalmente oscuro) a 1023(mucha luz).
Para recibir esta información, tendremos que leer el valor de la entrada analógica de la siguiente manera:
void setup() {
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A0);
int bright = map(sensorValue, 200, 1023, 255, 1);
// print out the value you read:
Serial.println(sensorValue);
delay(1); // delay in between reads for stability
}
Inicialmente el rango de valores del sensor es de 0 a 1023. Por este motivo se ha añadido la utilización de la función map para que el rango sea de 0 a 255, para poder usar estos valores con las luces Neopixel.
Esta parte se deja al alumno. Se tratará de juntar las conexiones de los dos circuitos, y juntar los dos códigos.
Tenemos que instalar la librería para utlizar este sensor explicado más arriba.
MUY IMPORTANTE. La resistencia tiene un valor de 10 K Ohm. El cable rojo (VCC) está conectado a 3.3 V, el cable verde (de datos) está conectado al pin D8.
#include "DHT.h"
#define DHTPIN D8 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
// as the current DHT reading algorithm adjusts itself to work on faster procs.
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
Serial.println(F("DHTxx test!"));
dht.begin();
}
void loop() {
// Wait a few seconds between measurements.
delay(2000);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
// Read temperature as Celsius (the default)
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
Serial.println(F("Failed to read from DHT sensor!"));
return;
}
Serial.print(F("Humidity: "));
Serial.print(h);
Serial.print(F("% Temperature: "));
Serial.println(t);
}
#include <Servo.h>
Servo servo;
void setup() {
servo.attach(D0); //D4
servo.write(0);
delay(2000);
}
void loop() {
servo.write(90);
delay(1000);
servo.write(0);
delay(1000);
}
Ahora, vamos a suponer que queremos enviar el valor del sensor de temperatura por WiFi. Configuraremos nuestro ESP8266 para que se conecte a un Wifi, utilizaremos un wifi creado por nuestro móvil, y desde una página web ver los datos.
Esto se haría de la siguiente forma.
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include "DHT.h"
// Uncomment one of the lines below for whatever DHT sensor type you're using!
//#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
/*Put your SSID & Password*/
const char* ssid = "YourNetworkName"; // Enter SSID here
const char* password = "YourPassword"; //Enter Password here
ESP8266WebServer server(80);
// DHT Sensor
uint8_t DHTPin = D8;
// Initialize DHT sensor.
DHT dht(DHTPin, DHTTYPE);
float Temperature;
float Humidity;
void setup() {
Serial.begin(115200);
delay(100);
pinMode(DHTPin, INPUT);
dht.begin();
Serial.println("Connecting to ");
Serial.println(ssid);
//connect to your local wi-fi network
WiFi.begin(ssid, password);
//check wi-fi is connected to wi-fi network
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected..!");
Serial.print("Got IP: "); Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient();
}
void handle_OnConnect() {
Temperature = dht.readTemperature(); // Gets the values of the temperature
Humidity = dht.readHumidity(); // Gets the values of the humidity
server.send(200, "text/html", SendHTML(Temperature,Humidity));
}
void handle_NotFound(){
server.send(404, "text/plain", "Not found");
}
String SendHTML(float Temperaturestat,float Humiditystat){
String ptr = "<!DOCTYPE html> <html>\n";
ptr +="<meta charset=\"utf-8\">\n";
ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
//ptr +="<meta http-equiv=\"refresh\" content=\"2\">\n";
ptr +="<link href=\"https://fonts.googleapis.com/css?family=Open+Sans:300,400,600\" rel=\"stylesheet\">\n";
ptr +="<title>ESP8266 Weather Report</title>\n";
ptr +="<style>html { font-family: 'Open Sans', sans-serif; display: block; margin: 0px auto; text-align: center;color: #333333;}\n";
ptr +="body{margin-top: 50px;}\n";
ptr +="h1 {margin: 50px auto 30px;}\n";
ptr +=".side-by-side{display: inline-block;vertical-align: middle;position: relative;}\n";
ptr +=".humidity-icon{background-color: #3498db;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
ptr +=".humidity-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".humidity{font-weight: 300;font-size: 60px;color: #3498db;}\n";
ptr +=".distance-icon{background-color: #19b80b;width: 30px;height: 30px;border-radius: 50%;line-height: 36px;}\n";
ptr +=".distance-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".distance{font-weight: 300;font-size: 60px;color: #19b80b;}\n";
ptr +=".temperature-icon{background-color: #f39c12;width: 30px;height: 30px;border-radius: 50%;line-height: 40px;}\n";
ptr +=".temperature-text{font-weight: 600;padding-left: 15px;font-size: 19px;width: 160px;text-align: left;}\n";
ptr +=".temperature{font-weight: 300;font-size: 60px;color: #f39c12;}\n";
ptr +=".superscript{font-size: 17px;font-weight: 600;position: absolute;right: -20px;top: 15px;}\n";
ptr +=".data{padding: 10px;}\n";
ptr +="</style>\n";
ptr +="</head>\n";
ptr +="<body>\n";
ptr +="<div id=\"webpage\">\n";
ptr +="<h1>ESP8266 Weather Report</h1>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side temperature-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n";
ptr +="width=\"9.915px\" height=\"22px\" viewBox=\"0 0 9.915 22\" enable-background=\"new 0 0 9.915 22\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M3.498,0.53c0.377-0.331,0.877-0.501,1.374-0.527C5.697-0.04,6.522,0.421,6.924,1.142\n";
ptr +="c0.237,0.399,0.315,0.871,0.311,1.33C7.229,5.856,7.245,9.24,7.227,12.625c1.019,0.539,1.855,1.424,2.301,2.491\n";
ptr +="c0.491,1.163,0.518,2.514,0.062,3.693c-0.414,1.102-1.24,2.038-2.276,2.594c-1.056,0.583-2.331,0.743-3.501,0.463\n";
ptr +="c-1.417-0.323-2.659-1.314-3.3-2.617C0.014,18.26-0.115,17.104,0.1,16.022c0.296-1.443,1.274-2.717,2.58-3.394\n";
ptr +="c0.013-3.44,0-6.881,0.007-10.322C2.674,1.634,2.974,0.955,3.498,0.53z\"/>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side temperature-text\">Temperature</div>\n";
ptr +="<div class=\"side-by-side temperature\">";
ptr +=(int)Temperaturestat;
ptr +="<span class=\"superscript\">°C</span></div>\n";
ptr +="</div>\n";
ptr +="<div class=\"data\">\n";
ptr +="<div class=\"side-by-side humidity-icon\">\n";
ptr +="<svg version=\"1.1\" id=\"Layer_2\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\"\n\"; width=\"12px\" height=\"17.955px\" viewBox=\"0 0 13 17.955\" enable-background=\"new 0 0 13 17.955\" xml:space=\"preserve\">\n";
ptr +="<path fill=\"#FFFFFF\" d=\"M1.819,6.217C3.139,4.064,6.5,0,6.5,0s3.363,4.064,4.681,6.217c1.793,2.926,2.133,5.05,1.571,7.057\n";
ptr +="c-0.438,1.574-2.264,4.681-6.252,4.681c-3.988,0-5.813-3.107-6.252-4.681C-0.313,11.267,0.026,9.143,1.819,6.217\"></path>\n";
ptr +="</svg>\n";
ptr +="</div>\n";
ptr +="<div class=\"side-by-side humidity-text\">Humidity</div>\n";
ptr +="<div class=\"side-by-side humidity\">";
ptr +=(int)Humiditystat;
ptr +="<span class=\"superscript\">%</span></div>\n";
ptr +="</div>\n";\
ptr +="</div>\n";
ptr +="<script>\n";
ptr +="setInterval(loadDoc,200);\n";
ptr +="function loadDoc() {\n";
ptr +="var xhttp = new XMLHttpRequest();\n";
ptr +="xhttp.onreadystatechange = function() {\n";
ptr +="if (this.readyState == 4 && this.status == 200) {\n";
ptr +="document.getElementById(\"webpage\").innerHTML =this.responseText}\n";
ptr +="};\n";
ptr +="xhttp.open(\"GET\", \"/\", true);\n";
ptr +="xhttp.send();\n";
ptr +="}\n";
ptr +="</script>\n";
ptr +="</body>\n";
ptr +="</html>\n";
return ptr;
}
Para poder recibir la información, nos tendremos que ir al puerto Serie, y ver la dirección en la que nos tenemos que meter:
En este caso nos tendriamos que meter con nuestro telefono (conectados en el mismo Wifi), en la dirección 192.168.43.18: