--- title: Arduino/Wemos Electronics Documentation for ESA/ESAC Space Summer School 2019 author: Fran Acien tags: ESA, Spacer Summer School 2019, ESP8266, WEMOS, Neopixel, Arduino --- # Introducción a WEMOS D1 (ESP8266) 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. ## Instalación de entorno de desarrollo ### Instalación Arduino IDE Para instalar Arduino IDE, dirigete la [página de Arduino](https://www.arduino.cc/en/Main/Software) y descarga la última versión compatible con tu equipo. Sigue los pasos de la instalción. ![](https://i.imgur.com/fxDgv1k.png) ### Instalación de los drivers de ESP8266 para Arduino IDE 1. Vete a **File->Preferences**, y en el campo `Additional Boards Manager URLs` añade lo siguiente: ``` https://arduino.esp8266.com/stable/package_esp8266com_index.json ``` ![](https://i.imgur.com/3Sixi09.png) 2. Vete a **Tools->Board->Board Manager**, y busca `ESP8266` e instala el siguiente paquete con el botón *install*: ![](https://i.imgur.com/lvW3nLj.png) ### Instalación de la librería NeoPixel 1. Vete a **Tools->Manage Libraries** y busca por la librería llamada `NeoPixel` e instala la última versión. ![](https://i.imgur.com/5GSH092.png) ### Instalación de la librearía DHT11/DHT22 Para poder usar el sensor de temperatura y humedad DHT11/DHT22 tendremos que descargarnos la librería. Esto se hace de la siguiente forma: 1. Vete a **Tools->Manage Libraries** y busca por la libreria `DHT Sensor`: ![](https://i.imgur.com/NdmWP46.png) 2. Vete a **Tools->Manage Libraries** y busca por la libreria `Adafruit Unified Sensor`: ![](https://i.imgur.com/nk6XEaN.png) ## Introducción al entorno de Arduino ### Estructura de un script de Arduino El programa más sencillo de Arduino, se encuentra en **File->Examples->01.Basics->Blink** y tiene el siguiente código. ```C= // 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. ### Ejecutar nuestro código en ESP8266 Para enviar nuestro código a nuestra placa ESP8266, tendremos que: 1. Configurar la placa en la cual enviaremos nuestro código: Nos vamos a **Tools->Board->LOLIN(WEMOS) D1 R2 & mini**. ![](https://i.imgur.com/yBGwFgO.png) 2. Seleccionamos el puerto: Nos vamos a **Tools->Port** y seleccionamos el puerto donde está conectada la placa. **Ojo, que el puerto suele cambiar cuando desconectamos la placa**. ![](https://i.imgur.com/m43uAJK.png) 3. Pulsar al botón de **Upload** ## Uso de Neopixel ### Conexiones de Neopixel a ESP8266 La conexión típica de Neopixel con el ESP8266 será: ![](https://i.imgur.com/XsqKMrN.jpg) ### Programación de Neopixel en ESP8266 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: ```C= // 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. ## Uso del sensor ultrasónico HC-SR04 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. ### Conexiones del HC-SR04 a ESP8266 Las conexeciones son las siguientes: ![](https://i.imgur.com/IPNNi0M.png) ### Programación del HC-SR04 en ESP8266 El código es el siguiente: ```C= // 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. ![](https://i.imgur.com/P39YDg2.jpg) ## Uso del sensor de Luminosidad con ESP8266 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). ### Conexiones del sensor de Luminosidad con ESP8266 ![](https://i.imgur.com/GXNnRjW.png) ### Programación del sensor de Luminosidad con ESP8266 Para recibir esta información, tendremos que leer el valor de la entrada analógica de la siguiente manera: ```C= 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. ## Implementación de los sensores 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. ## Implementación sensor de Humedad y temparatura DHT22 **Tenemos que instalar la librería** para utlizar este sensor **explicado más arriba**. ### Conexiones del sensor DHT22 a ESP8266 **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**. ![](https://i.imgur.com/CUgevJl.jpg) ### Uso de la librería de DHT22 ```C= #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); } ``` ## Implementación de un Servo Motor ### Conexiones de un ServoMotor a ESP8266 ![](https://i.imgur.com/whVnhj1.png) ### Código de un ServoMotor ```C= #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); } ``` ## Envio de telemetria por WiFi 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. ```C= #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: ![](https://i.imgur.com/of6TxXv.png) En este caso nos tendriamos que meter con nuestro telefono (conectados en el mismo Wifi), en la dirección 192.168.43.18: ![](https://i.imgur.com/g7hoBDu.jpg)