domingo, 31 de enero de 2016

ESP8266 Interrupciones con Arduino IDE

El tema de las interrupciones en el módulo ESP8266 es un poco distinto al utilizado con el Arduino UNO

En este ejemplo vamos a utilizar un pulsador conectado entre GPIO12 y masa para que, cuando lo pulsemos, se produzca un interrupción y cambie el estado de un led.

El esquema completo es el siguiente:


Untitled Sketch_bb.png



En primer lugar, hay que definir el pin en el que se producirá la interrupción:

#define BUTTON 12 //pulsador en GPIO12 (D6)



En setup() debemos indicar que el pin definido anteriormente  va a realizar funciones de interrupción:

pinMode(BUTTON, INPUT_PULLUP);


El modo INPUT_PULLUP hace que se utilicen las resistencias pull-up internas del módulo conectadas a Vcc. De este modo, el pin se encuentra a nivel alto en condiciones normales y cuando pulsamos el nivel pasa a 0v.



Por último, hay que indicar la función que se ejecutará cuando se produzca la interrupción:

attachInterrupt(BUTTON,parpadeo,FALLING);


En este caso, la interrupción se produce durante el flanco de bajada de la señal. Existen otros modos:

  • LOW: cuando pasa a nivel bajo
  • CHANGE: cuando cambia de valor
  • RISING: en el flanco de subida


La función parpadeo lo que hace es alternar el valor de la variable estado y en loop() enciende o apaga el led dependiendo del estado de dicha variable.



El código completo es el siguiente:


#define BUTTON 12 //botón en GPIO12 (D6)
#define LED 16 // GPIO16 (D0)
volatile int estado = HIGH; //estado inicial
void setup() { pinMode(LED,OUTPUT); digitalWrite(LED,LOW);
delay(2000);
pinMode(BUTTON, INPUT_PULLUP); attachInterrupt(BUTTON,parpadeo,FALLING); }
}
void parpadeo() { estado = !estado; } void loop() {
digitalWrite(LED,estado);
Fuentes:

sábado, 30 de enero de 2016

ESP8266 WiFi con el IDE de Arduino

Una vez que hemos configurado nuestro IDE de arduino para trabajar con el módulo ESP8266, vamos a realizar diferentes ejemplos.

Conexión a una red Wifi

En primer lugar vamos a configurar el módulo como un cliente WiFi. Para ello, lo primero que tenemos que hacer es declarar la librería ESP8266WiFi:

#include <ESP8266WiFi.h>

A continuación definimos el SSID y el Password de nuestra red WiFi:

const char* ssid ="SSID";
const char* password = "PASSWORD";

Nota: sustituir SSID y PASSWORD por el ssid y el password de vuestra red wifi.

En Setup():

En primer lugar programamos nuestro puerto serie para analizar el estado de la conexión y recibir información del módulo:

Serial.begin(115200);

Nota: no olvidar configurar la consola serie a 115200 baudios.

Establecemos el módulo como cliente WiFi y nos desconectamos de cualquier red WiFi a la que estuviéramos conectado previamente:

WiFi.mode(WIFI_STA); //Establece el módulo como cliente wifi
WiFi.disconnect(); //Se desconecta de cualquier WiFi conectado
delay(100);

Para conectarnos a nuestra WiFi utilizamos WiFi.begin(ssid, password):

Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);

A continuación esperamos que se produzca la conexión con la red Wifi:

while (WiFi.status() != WL_CONNECTED) {   // wait for WiFi
delay(500);
    Serial.print(".");
}


WiFi.status() es una función que nos devuelve un entero y que nos muestra el estado de la conexión. Los valores que se pueden obtener son:

  • 0 : WL_IDLE_STATUS cuando el Wi-Fi está en proceso de cambiar de estado
  • 1 : WL_NO_SSID_AVAIL en caso de que el SSID configurado no pueda ser alcanzado
  • 3 : WL_CONNECTED después de establecer una conexión satisfactoriamente
  • 4 : WL_CONNECT_FAILED si la contraseña es incorrecta
  • 6 : WL_DISCONNECTED si el módulo no está configurado en el modo de estación
Una vez conectados, mostramos la dirección IP que el router nos ha asignado por DHCP:

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
delay(1000);

Una vez ejecutado el programa, la consola nos muestra el siguiente resultado:

Connecting to SSID
......
WiFi connected
IP address:
192.168.1.43

El código completo será el siguiente:
 
#include <ESP8266WiFi.h>
const char* ssid ="SSID";
const char* password = "PASSWORD";

void setup() {
 Serial.begin(115200);
 WiFi.mode(WIFI_STA); //Establece el módulo como cliente wifi
 WiFi.disconnect(); //Se desconecta de cualquier WiFi
 delay(100);
 Serial.println();
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {   // wait for WiFi
    delay(500);
    Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected");
 Serial.println("IP address: ");
 Serial.println(WiFi.localIP());
 delay(1000);
}

void loop() {
}

Búsqueda de redes WiFi

En el siguiente ejemplo vamos a realizar una búsqueda de las redes Wifi que nuestro módulo es capaz de detectar.

La primera parte del código es igual al ejemplo anterior (configuración del puerto serie, desconexión de cualquier red que estemos conectado).

Para obtener el número de redes wifi detectadas utilizamos la función WiFi.scanNetworks() que devuelve el número de redes encontradas:

Serial.println("Comienza la busqueda de redes WiFi");
int n = WiFi.scanNetworks();
Serial.println("Busqueda realizada");

Luego, podemos mostrar por el puerto serie el SSID y el nivel de señal de cada una de estas redes:

if (n == 0)
    Serial.print("Redes no encontradas");
else {
for (int i = 0; i < n; i++) {
     Serial.print(i+1);
     Serial.print(": ");
     Serial.print(WiFi.SSID(i)); //SSID de la red
     Serial.print(" (");
     Serial.print(WiFi.RSSI(i)); //Nivel de señal
     Serial.println(")");
     //Serial.println((WiFi.encryptionType(i) == ENC_TYPE_NONE)?" ":"*");
     delay(10);
    }
 }

El código completo es el siguiente:

#include <ESP8266WiFi.h>

void setup() {
 Serial.begin(115200);
 WiFi.mode(WIFI_STA); //Establece el módulo como cliente wifi
 WiFi.disconnect();
 delay(100);
 Serial.println("setup completado");
 Serial.println("Comienza la busqueda de redes WiFi");
 int n = WiFi.scanNetworks();
 Serial.println("Busqueda realizada");
 if (n == 0)
    Serial.print("Redes no encontradas");
 else {
    for (int i = 0; i < n; i++) {
     //Muestra los datos de las redes encontradas
     Serial.print(i+1);
     Serial.print(": ");
     Serial.print(WiFi.SSID(i));
     Serial.print(" (");
     Serial.print(WiFi.RSSI(i));
     Serial.println(")");
     delay(10);
    }
 }
}

void loop() {
}

Servidor WEB


Para este ejemplo conectamos un led con su resistencia al pin D1 de nuestro NodeMCU que corresponde al GPIO5 del ESP8266.


La idea es que, al realizar una petición http con cierto formato el led se encienda o se apague.
Gran parte del código es el mismo que en el primer ejemplo (conexión a una red Wifi). En este ejemplo, definiremos primeramente tanto el pin donde conectaremos el led así como el servidor web indicando el puerto por el que escuchará las peticiones:

const int led = 5; //GPIO5 - D1
WiFiServer server(80); //Crea una instancia de Servidor WEB y especifica el puerto que escucha

En setup() inicializamos el puerto serie y a continuación establecemos el estado del led:

pinMode(led,OUTPUT);
digitalWrite(led,LOW);

Después conectamos el módulo a nuestra red WiFi e inicializamos el servidor WEB indicando la dirección IP del módulo por el puerto serie:

server.begin();
Serial.print("Servidor WEB activo: ");
Serial.println(WiFi.localIP());

En loop(), lo primero que hacemos es comprobar si hay algún cliente web conectado a nuestro servidor:

WiFiClient client = server.available();
if (!client) {
return;
}

Una vez se haya conectado, esperamos a recibir datos:

Serial.println("cliente conectado");
while(!client.available()) {
    delay(1);
}

Almacena la petición en una variable tipo String y lo muestra por el puerto serie:

String req =client.readStringUntil('\r');
Serial.println(req);
client.flush();

Busca si se ha recibido los comandos de encendido (/on) o apagado (/off) y establece el valor de una variable según la petición recibida:

int val;
if (req.indexOf("/off") != -1)
    val = 0;
else if (req.indexOf("/on") != -1)
    val = 1;
else {
    Serial.print("Petición inválida");
    client.stop();
    return;
}

Por último, enciende/apaga el led y envía la respuesta al cliente web:

digitalWrite(led,val);
client.flush();
//prepara la respuesta a la petición
String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nLed ";
s += (val)?"encendido":"apagado";
s += "</html>\n";
//envía la respuesta
client.print(s);
delay(1);
Serial.println("cliente desconectado");

Si queremos encender el led tenemos que escribir la siguiente url en nuestro navegador web:
http://direccionIP/on

Para apagarlo:
http://direccionIP/off

El código completo es el siguiente:

#include <ESP8266WiFi.h>
const char* ssid ="WLAN_E17C";
const char* password = "ced0ccb58c84e525e35f";
const int led = 5; //GPIO5 - D1
WiFiServer server(80); //Crea una instancia de Servidor WEB y especifica el puerto que escucha
void setup() {
 //inicializa el puerto serie
 Serial.begin(115200);
 delay(10);
 //inicializa el led
 pinMode(led,OUTPUT);
 digitalWrite(led,LOW);
 //Inicializa el módulo wifi
 WiFi.mode(WIFI_STA); //Establece el módulo como cliente wifi
 WiFi.disconnect(); //Se desconecta de cualquier WiFi conectado previamente
 Serial.println();
 //conecta con la red wifi
 Serial.print("Connecting to ");
 Serial.println(ssid);
 WiFi.begin(ssid, password);
 while (WiFi.status() != WL_CONNECTED) {   // Espera por una conexión WiFi
    delay(500);
    Serial.print(".");
 }
 Serial.println("");
 Serial.println("WiFi connected");
 Serial.println("IP address: ");
 IPAddress sensor_ip = WiFi.localIP();
 digitalWrite(led,HIGH);
 //inicializa el servidor web
 server.begin();
 Serial.print("Servidor WEB activo: ");
 Serial.println(WiFi.localIP());
}
void loop() {
 //comprueba si un cliente está conectado
 WiFiClient client = server.available();
 if (!client) {
    return;
 }
 //espera hasta que el cliente envía algún dato
 Serial.println("cliente conectado");
 while(!client.available()) {
    delay(1);
 }
 //lee la primera línea de la petición
 String req =client.readStringUntil('\r');
 Serial.println(req);
 client.flush();
 //busca en las peticiones los comandos de encendido y apagado
 int val;
 if (req.indexOf("/off") != -1)
    val = 0;
 else if (req.indexOf("/on") != -1)
    val = 1;
 else {
    Serial.print("Petición inválida");
    client.stop();
    return;
 }
 digitalWrite(led,val);
 client.flush();
 //prepara la respuesta a la petición
 String s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>\r\nLed ";
 s += (val)?"encendido":"apagado";
 s += "</html>\n";
 //envía la respuesta
 client.print(s);
 delay(1);
 Serial.println("cliente desconectado");
}

Fuentes:

martes, 5 de enero de 2016

Soporte del IDE de Arduino

En este artículo voy a tratar de explicar cómo dar soporte para la programación de ESP8266 y NodeMcu con el IDE de Arduino.

Lo primero es instalar el IDE de arduino. Para ello te recomiendo los artículos:


Si tu S.O. es otro, busca por internet ya que hay un montón de tutoriales de cómo instalarlo

Una vez instalado, lo ejecutamos (en mi caso la versión 1.6.7):


Hacemos click en Archivo -> Preferencias:



y copiamos el siguiente enlace en “Gestor de URLs adicionales de Tarjetas”:
http://arduino.esp8266.com/stable/package_esp8266com_index.json

Hacemos click en OK y abrimos el menú de Herramientas -> Placa -> Gestor de Tarjetas:


Al final del todo nos aparece esp8266 by ESP8266 Community. Hacemos click sobre esta opción y click en Instalar:


Una vez instalado cerramos el Gestor de Tarjetas y en el menú de Herramientas -> Placas nos aparecerán los diferentes modelos de ESP8266 que soporta el IDE (en mi caso NoseMCU 1.0). Además, en Archivos -> Ejemplos aparecen ejemplos de utilización.

Hay que tener en cuenta que cuando programamos con el IDE de Arduino, los pines corresponden al módulo ESP8266, es decir, si seleccionamos el pin 2 en Arduino corresponderá con GPIO02, que en lua sería el pin 4. Para ver las equivalencias:
También hay que tener en cuenta que si queremos volver a programar en Lua después de haber cargado un programa con el IDE de Arduino, la única forma que he encontrado ha sido volver a reiniciar el módulo.
 

Fuentes:
Ejemplo:

lunes, 4 de enero de 2016

NodeMCU y App Inventor


En este artículo voy a tratar de controlar los puerto GPIO del ESP8266 a través de una aplicación desarrollada con App Inventor.



Nota: si quieres aprender más sobre APP Inventor puedes consultar mi blog AppInventor a muete.

El esquema es sencillo y básico ya que simplemente voy a encender y apagar un led conectado al pin 2 del ESP8266:


Untitled Sketch_bb.png

El código LUA completo es el siguiente:

wifi.setmode(wifi.STATION)

wifi.sta.config("SSID WiFi","password WiFi")
print(wifi.sta.getip()) -- Muestra la IP
tmr.delay(5000)
-- Inicializa el puerto al que está conectado el Led

gpio.mode(2, gpio.OUTPUT)

gpio.write(2, gpio.LOW);
-- Servicios WEB
srv=net.createServer(net.TCP)
srv:listen(80,function(conn)
    conn:on("receive", function(client,request)
       local _, _, method, path, vars = string.find(request, "([A-Z]+) (.+)?(.+) HTTP")
       if(method == nil)then
            _, _, method, path = string.find(request, "([A-Z]+) (.+) HTTP")
        end
        local _GET = {}
        if (vars ~= nil)then
            for k, v in string.gmatch(vars, "(%w+)=(%w+)&*") do
                _GET[k] = v
            end
        end
        if(_GET.pin == "ON")then
              gpio.write(2, gpio.HIGH)
        elseif(_GET.pin == "OFF")then
              gpio.write(2, gpio.LOW)
        end
        print(_GET.pin) -- Para DEBUG
        client:close()
        collectgarbage()
    end)
end)

El código del programa es una modificación del ejemplo webap_toggle_pin presente en los ejemplos de lua en GitHub

En este caso, no se trata de enviar ninguna página web a un cliente que se conecte. La parte principal del programa es “capturar” los valores de la variable pin que se reciben en las peticiones a través del formato de la url recibida.

Ahora vamos con la aplicación android realizada con App Inventor 2. En la siguiente imagen se muestra un pantallazo de la aplicación corriendo en un dispositivo.


Screenshot_2016-01-04-22-33-48.png


En cuanto al programa realizado en App Inventor 2, hay que introducir manualmente la dirección IP en TextBox1 asignado al módulo NodeMCU (se almacena en TinyDB1 con tag = espaddress) y luego enviar los comandos a dicha dirección para encender y apagar el Led (TextBox1 se muestra cuando se hace pulsa el botón SET).

Pantallazo01.png

La parte principal del programa es la siguiente:

Pantallazo02.png

En ella, se compone un mensaje formado por http://direcciónIP/?pin=ON para encender el Led y http://direcciónIP/?pin=OFF para apagar el Led.

Para pasar una variable a través de una url se utiliza el formato:
http://example.com/pagina2.html?variable=valor

Luego, el módulo ESP8266 se encarga de capturar el valor de dichas variables y actuar en consecuencia.

La petición recibida cuando se pulsa el botón ON en la aplicación:

GET /?pin=ON HTTP/1.1
Host: 192.168.1.43
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux; Android 5.0.2; XT1068 Build/LXB22.99-16.3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: es-ES,en-US;q=0.8
X-Requested-With: appinventor.ai_miguel_diazgomez.ESP8266_GPIO_Control

La petición recibida cuando se pulsa el botón OFF en la aplicación:

GET /?pin=OFF HTTP/1.1
Host: 192.168.1.43
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux; Android 5.0.2; XT1068 Build/LXB22.99-16.3; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/46.0.2490.76 Mobile Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: es-ES,en-US;q=0.8
X-Requested-With: appinventor.ai_miguel_diazgomez.ESP8266_GPIO_Control


Pueden descargar el programa en este enlace y las fuentes en este otro.

Fuentes:
https://www.youtube.com/watch?v=qWKcOnoyBzE