domingo, 28 de mayo de 2017

ESP8266 + servicio mqtt

Bueno, hoy les traigo una comunicación simple entre un ESP8266 y el celular (con la aplicación para android llamada MQTT Client, aunque cambiando un poco las cosas, se podría hacer entre dos ESP8266) y haciendo de intermediario un MQTT broker, más específicamente el broker que vamos a usar es el mosca. El broker se va a encargar de administrar la comunicación entre ambos dispositivos.

Primero que nada debemos descargar y ejecutar el mqtt broker:

Para esto vamos a abrir el git-bash (antes de continuar recomiendo leer los post del mqtt, el del esp8266 y el del node-red) y ejecutar el siguiente comando: "npm install mosca bunyan -g"



Luego de que se instale escribimos en la consola "mosca -v | bunyan" y eso va a iniciar el mqtt broker


Así nos debería quedar cuando lo ejecutamos por primera vez, esto sería el servidor por lo que hay que dejar abierta esta ventana (si la cerramos se detiene el servicio).

Ahora si bajamos la aplicación MQTT Client (presionando en el nombre los lleva a la página de descarga) (esta aplicación está para android, desconozco si se encuentra disponible para otros sistemas opera) y la abrimos nos vamos a encontrar con la siguiente pantalla


Si presionamos en donde aparece la llave (arriba a la derecha) podremos ingresar a las configuraciones para poner la ip local donde se aloja el servidor (al final del post dejo la forma de averiguarlo).


Yo puse la ip de mi pc (192.168.1.15) (esta ip varía dependiendo de como las administre el router, por lo que podría cambiar incluso si apagamos y prendemos el wifi o desconectamos el cable de ethernet o reiniciamos la pc o el router) y el puerto (1883) en el cual se encuentra nuestro mqtt broker (este puerto es por defecto), una vez finalizado esto ponemos "CONNECT" y en la consola nos va a aparecer lo siguiente:


Como aclaración, yo me conecté dos veces, por eso figura dos veces el texto "client connected".
Si ahora vamos a la aplicación a la parte donde dice "add topic" y agregamos uno debería quedarnos de la siguiente forma:


Como podemos ver, inmediatamente figura que nos subscribimos al tópico mensajes (el nombre es indistinto). Ahora vamos a mandar un mensaje al tópico mensajes presionando el ícono de subir (que se encuentra al lado del de configuración).


Y si lo enviamos deberíamos recibir el mensaje dado que estamos subscritos a ese tópico.

Bueno, esta fue la parte del celular, ahora si queremos mandar mensajes desde el esp8266, deberíamos meternos en arduino y hacer un programa que se comunique.

Primero vamos al gestor de librerías de arduino, y buscamos e instalamos la librería "PubSubClient", y cargamos el siguiente código:


#include <ESP8266WiFi.h>
#include <PubSubClient.h>

// Las siguientes tres constantes definen, ip del 
//mqtt broker, nombre de red wifi y su contraseña.

const char* mqtt_server = "192.168.1.15";
const char* ssid = "id_red_wifi";
const char* password = "contraseña_red_wifi";

// A continuación declaramos el nombre del cliente 
// que se va a conectar.
WiFiClient espClient;
PubSubClient client(espClient);

// En esta variable se almacena el mensaje recibido
// notar que tiene un máximo de 50 (en realidad son
// 49) caracteres.
char msg[50];

// Iniciamos la comunicación serie, la conexión por
// wifi y definimos en donde se aloja el servidor y
// en qué puerto, y la función donde administramos
// la llegada de mensajes.
void setup() {
  Serial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);
}

// En esta función se conecta con la red designada,
// mientras esté tratando de conectarse va a mandar
// un punto "." por el puerto serie y cuando lo 
// consiga nos avisará.
void setup_wifi() {

  delay(10);

  Serial.println();
  Serial.print("Conectando a: ");
  Serial.println(ssid);

  WiFi.begin(ssid, password);

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

  Serial.println("");
  Serial.println("WiFi conectado");
  Serial.println("Direccion IP: ");
  Serial.println(WiFi.localIP());
}

// En esta función se administra la llegada de 
// mensajes, nos avisa en qué tópico llegó y 
// cuál es el mensaje.
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Mensaje recibido [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();
}

// Esta función se encarga de conectar con el 
// mqtt broker, si lo consigue se subscribe a
// los tópicos que definamos (no es necesario
// subscribirnos en esta función, pero si lo
// recomiendo para organizar mejor el código.
// Prueba reconectarse cada cinco segundos si
// no lo consigue.
void reconectar() {

  while (!client.connected()) {
    Serial.print("Intentando conectar con el mqtt broker...");

    if (client.connect("ESP8266Client")) {
      Serial.println("conectado");
      client.subscribe("mensajes");
    } else {
      Serial.print("fallo, rc=");
      Serial.print(client.state());
      Serial.println(" prueba nuevamente en 5 segundos");

      delay(5000);
    }
  }
}

// En el loop principal no hacemos nada más 
// que verificar si perdimos la conexión con
// el servicio mqtt y verificamos que lleguen
// mensajes. El "client.loop();" se encarga 
// de revisar si llegaron mensajes, por lo 
// que habría que invocar esta función regu-
// larmente.
// Esta sección se podría mejorar si ponemos
// que revise si perdió la conexión con la
// red wifi.
void loop() {

  if (!client.connected()) {
    reconectar();
  }
  client.loop();
}


Este código sólo sirve para recibir mensajes en el tópico de "mensajes". Y como aclaración es un código editado mínimamente del ejemplo que nos da la librería PubSubClient (más específicamente
Ahora paso a explicar qué hace cada función.
Antes que nada se define la ip donde se aloja el mqtt broker, la id (o nombre) de la red wifi y su correspondiente contraseña (estas tres cosas, en este código, son constantes, pero se podría hacer algo más interesante para que sean variables)


Si queremos averiguar cuál es la ip que asignó el router a nuestra computadora simplemente abrimos la consola de comandos de windows y tecleamos "ipconfig" y debería aparecer algo similar a lo siguiente (dentro del recuadro rojo se encuentra la ip de la pc):


2 comentarios:

  1. si el mensaje se envio cuando el esp8266 estaba apagado, ya sea por apagon o perdio la coneccion wifi, como recuperar ese mesanje perdido al volver a iniciarse el esp8266?

    ResponderBorrar
    Respuestas
    1. Hola, la forma de hacer que el mensaje se pueda recuperar es activando la forma de retención del mensaje. La función publish tiene como parámetros el mensaje, el tópico y además puede tener una propiedad de retención del mensaje, por lo tanto cuando el servidor reciba el mensaje lo va a reenviar a cada dispositivo que se conecte, esta propiedad puede ser verdadera o falsa. Además dicha función puede tener como propiedad la longitud del mensaje.
      Acá te dejo la documentación de la librería:

      https://pubsubclient.knolleary.net/api.html#publish2

      es bastante útil para esos casos.

      Saludos!

      Borrar