Autor: Edison Del Rosario

  • 4.1 IoT WiFi Sensor Temperatura-Humedad ESP-07

    Presentación

    El dispositivo de Temperatura-Humedad es la introducción al manejo de estados de sensores con valores numéricos diferentes a los estados binarios de encendido y apagado.

    El dispositivo incorpora el sensor DHT11 que entrega valores de temperatura y humedad en un mismo pin. Por lo que inicialmente el módulo ESP8266 versión ESP-01 es suficiente para cumplir con el objetivo.

    Sin embargo, si posteriormente se incorpora necesidad de usar dispositivos alimentados con baterías.

    Para la operación a baterías es necesario considerar:

    • Intervalos de lectura ajustables, por ejemplo 15 minutos o 1 hora
    • Operación en modo de ahorro de energía o "sleep" disponible en los módulos
    • Varios modos de ahorro de energía para el ESP8266: Modem-Sleep, Light-Sleep y Deep-Sleep

    La operación del ESP8266 en modo de ahorro de energía requiere el uso de un pin para reiniciar luego de finalizado el periodo "sleep" no disponible en la versión ESP-01. En consecuencia el dispositivo se desarrolla usando el módulo ESP07 que tienes más pines de conexión.

    Adicionalmente se requiere un pin para lectura analógica y el módulo ESP-07 dispone de un pin analógico con lecturas de valores de voltaje en rango [0,1] VDC  de 10 bits, 1024 muestras [0,1023].

    Referenciahttps://www.espressif.com/sites/default/files/9b-esp8266-low_power_solutions_en_0.pdf


    Implementación versión 1

    La versión 1 del prototipo mostrada en la imagen se ha realizado en una placa perforada, alimentada por 5VDC, que se incoporan en una caja electrica.

    Luego se monta sobre una caja eléctrica tipo Dexon para uso regular.

    Premisas para desarrrollo en la versión 1

    • Diseño de dispositivos con conexión inalámbrica WIFI
    • Conoce los datos para conexión a la red a WIFI y broker MQTT
    • Dispone de acceso a un broker MQTT local
    • Dispone de Arduino IDE para cargar las instrucciones en el ESP8266
    • Emplea diseños abiertos tipo: Open Hardware y Open Software
    • Dispone de los componentes en el mercado local
    • Considera componentes alternos a los no disponibles en el mercado local
    • Identifica las etapas de desarrollo e inconvenientes en la implementación.

    Resultados de implementación a baterías

    Con el prototipo operando a baterias se registraron la lecturas de temperatua y humedad cada 5 segundos, obteniendo hasta 4600 muestras consecutivas antes del apagado del dispositivo.

    Temas para desarrollo posterior

    • Como siguiente actividad, se analizará ampliar el tiempo "sleep" con intervalos de lecturas mayores, revisar las fases de ejecución del código y reducción de tareas para optimización de uso de energía.
    • Otros dispositivos tipo actuadores combinado con sensores
  • ESP8266 versión ESP07

    La versión del módulo ESP-07 ofrece más puntos de conexión que la versión ESP-01. http://wiki.ai-thinker.com/_media/esp8266/docs/aithinker_esp_07_datasheet_en.pdfPara la implementación básica ser recomienda usar la versión con antena incorporada y una placa para adaptar el módulo.

    La placa permite conectarlo a un protoboard, pues la separación entre conectores del módulo es pequeña (2 mm).

    Una de las ventajas del ESP-01 es convertidor Analógico-Digital (pin ADC), que tiene un rango de trabajo entre 0 y 1 voltio con pasos valorados entre 0-1023 (10 bits).

    El pin ADC permite por ejemplo obtener lecturas de estado de voltaje de las baterias, obtenido con un divisor de voltaje  para asegurar que el voltaje máximo no supere 1V .

    IDE Arduino

    Para incorporar la tarjeta al programa IDE Arduino se se realizan los mismos que para la versión ESP-01, seleccionando la placa ESP8285.

    Referencia: http://wiki.ai-thinker.com/_media/esp8266/docs/aithinker_esp_07_datasheet_en.pdf

     

  • 2.1 IoT WiFi Actuador Binario - Tomacorriente

    Presentación

    El dispositivo inalámbrico se usa para controlar el estado encendido o apagado (actuador) de un aparato eléctrico AC (lámpara) de baja potencia.

    El dispositivo se implementa usando un relé, como base para el desarrollo de otros circuitos.

    El relé seleccionado paa prototipos es el básico usado con arduinos, se alimenta de 5VDC y permite controlar cargas de 120VAC semejante al mostrado en la figura.

    El control del relé se realiza por medio de una instrucción MQTT de publicación.

    implementación versión 1

    La versión 1 ha instalado en una caja sobrepuesta plástica. Para pruebas, se ha conectado una lámpara al tomacorriente. Por ejemplo las lámparas de Jardín, Patio, balcón, etc.

    Es dispositivo es la introducción para desarrollar actuadores, se utiliza tomacorriente único considerando las limitaciones de los pines en el módulo ESP-01.

    De utilizar dos tomacorrientes independientes enla caja, será necesario disponer de dos pines de Control.

    Se propone usar GPIO3 o RXD debido a la estabilidad del pin durante el arranque del módulo ESP01.

    También se intentó probó configurar con GPIO0 y GPIO2 dado que su estado predeterminado se puede reconfigurar por software una vez iniciado el módulo en modo de operación. Sin embargo, al inciar el módulo al conectar energía, éstos pines tienen cambios de estado que causan "rebotes" inesperados en el relé, por lo que se desiste de usar éstos pines por posibles daños a los aparatos o cosas conectadas al tomacorriente.

  • 3.4 IoT WiFi Interruptor-Tomacorriente: MQTT-HA

    Esta es la última sección a realizar, pues se supone que tiene listo el dispositivo, construido y operativas las partes: Dispositivo y Broker.

    El objetivo es incorporar dispositivo Interruptor-Tomacorriente en el broker MQTT y observar los resultados.

    Se plantea observar los estados del dispositivo en dos formas:

    • Desde un navegador en la página local de Home-Assistant
    • Desde una consola conectando al servidor MQTT

    1. Incorporar el dispositivo en Home Assistant

    Se requiere modificar el archivo configuration.yaml en el raspberry.

    Se puede realizar en forma local desde el raspberry que tiene monitor, teclado y mouse conectado, y editar el archivo que se encuentra en el directorio:

     /home/homeassistant/.homeassistant/configuration.yaml

    La otra forma es conectarse via remota por medio de una sesión ssh. Requiere dirección, usuario y password. Los detalles se dan en la sección Raspberry.

    En el archivo se añade los datos del dispositivo interruptor-tomacorriente, que en el caso actual para pruebas se identifica como una luminaria (light).

    El sensor trabaja con MQTT, se le asigna un nombre más sencillo de reconocer como «oficina luz 1» y se complementa con la instrucción de identificación en el formato: lugar/cosa/acción.

    light:
      - platform: mqtt
        name: 'oficina_luz1'
        state_topic: 'oficina/luz1/estado'
        command_topic: 'oficina/luz1/cambia'
        optimistic: false
    

    Se añade la la instrucción de control para el dispositivo (command_topic) también con el formato indicado, "oficina/luz1/cambia".

    Interruptor Tomacorriente 01_Off

    otra forma de presentación en Home-Assistant. editando las tarjetas por dispositivo (Cards):

    Interruptor Tomacorriente 03_Off

    Interruptor Tomacorriente 04_On

     

    1.2  Monitoreo desde MQTT

    Para monitorear señal desde consola Raspberry usando MQTT, usar la instrucción:

    mosquitto_sub -h 192.168.10.100 -t oficina/luz1/estado
    

    En el caso de control del actuador, se utiliza una intruccion semejante para publicar:

    mosquitto_pub -h 192.168.10.100 -t oficina/luz1/cambia -m on

    Dispositivo como interruptor

    Se aplica el mismo concepto del dispositivo para el caso de un interruptor, no necesariamente de luz. Para el caso de interruptor, hay que observar la capacidad máxima de manejo de corriente del Relay usado, para evitar sobrecargas.

    Como ejemplo, se presenta el formato para interruptor en Home-Assistant, lo que requiere también realizar un cambio en el archivo.ino en la sección MQTT. Sin embargo no afecta al resto de las instrucciones.

    switch:
      - platform: mqtt
        name: 'oficina_Interruptor1'
        state_topic: 'oficina/switch1/estado'
        command_topic: 'oficina/switch1/cambia'
        optimistic: false
    

    Interruptor Tomacorriente 02_Off
    Entre algunas de las cosas que se pueden realiza con un dispositivo tipo binario.

  • 3.1 IoT WiFi Sensor-Actuador: Interruptor-Tomacorriente

    Presentación

    El dispositivo inalámbrico se usa para controlar el estado encendido o apagado (actuador) de un aparato eléctrico AC (lámpara) de baja potencia.

    El control se lo puede realizar físicamente al pulsar un interruptor tradicional (sensor) o por medio de una instrucción MQTT.

    El sensor de interruptor y el actuador de control AC trabajan en conjunto desde el mismo dispositivo. Éste dispositivo es la integración de los dos dispositivos anteriores: Sensor Puerta-Ventana y Actuador tomacorriente, ambos de estado binario (ON/OFF).

    implementación versión 1

    La versión 1 mostrada en la imagen se ha instalado en una caja sobrepuesta plástica. Para pruebas, se ha conectado una lámpara al tomacorriente.

    El control se realiza tanto por el interruptor como por la página en la computadora, ambos marcados en rojo en la imagen.

    La carga máxima AC de control depende del Relé  seleccionado.

    Se ha usado una placa perforada para ensamblar el prototipo, sin embargo al final del tema en Placas PCB se presenta el diseño de la placa de circuito.

    Premisas para desarrrollo en la versión 1

    • Diseño de dispositivos con conexión inalámbrica WIFI
    • Conoce los datos para conexión a la red a WIFI y broker MQTT
    • Dispone de acceso a un broker MQTT local
    • Dispone de Arduino IDE para cargar las instrucciones en el ESP8266
    • Emplea diseños abiertos tipo: Open Hardware y Open Software
    • Dispone de los componentes en el mercado local
    • Considera componentes alternos a los no disponibles en el mercado local
    • Identifica las etapas de desarrollo e inconvenientes en la implementación

    Temas para desarrollo posterior

    Incorporar Sensor para medir consumo de energía.

    Sensores Analógicos
    Ampliar la forma de carga de scripts en el tablero, de forma alámbrica o inalámbrica.

    Revisar el uso de los canales WIFI para evitar desconexiones por saturación de canal.

  • 4.2 IoT Base de datos. Home-Assistant

    Los datos registrados en Home-Assistant se pueden obtener de la base home-assistant_v2.db.

    Los datos se pueden leer mediante SQLite3 y exportarse para ser tratados con alguna herramienta informática para estadística.

    Referencia: Visualize your IoT data. https://www.home-assistant.io/blog/2016/07/19/visualizing-your-iot-data/

     

  • 4.1 IoT Broker - Gestión con Home Assistant

    En el esquema abierto, los mensajes de estado/acción con MQTT se administran (pub/sub) bastante bien con Mosquitto.

    Cada mensaje genera un dato de estado, que con el transcurrir el tiempo podría ser revisado mediante las estadísticas de uso o pretender realizar acciones sobre los artefatos ante una secuencia de estados predeterminados, realizar una presentación en una página web. Estos nuevos requerimientos  implican una mayor integración en software.

    Entre las versiones de software abierto para la gestión de los mensajes de estado/acción se encuentra Home Assistant, que junto a Mosquitto presentan una solución bastante aceptable de operar y personalizar.

    Home-Assistant se suscribe a MQTT- Mosquitto y realiza la gestión de datos, para por ejemplo presentarla en una página web. La presentación puede ser como texto o de forma gráfica.

    El acceso web se basa en la dirección IP del broker en el puerto 8123, también es valida el nombre de la maquina en la red (ej: miComputadorIoT:8123),

    El proceso de instalación y configuración de Home-Assistant se detalla en la sección de Broker/Gestión, donde se detalla la conexión a MQTT de forma abierta, con validación de usuario y password, finalmente con SSL/TLS.

    Esta sección se centra en la conexión de un dispositivo y la configuración de los parámetros del mensaje MQTT. Se supondrá que tiene ya configurado el servicio en algún "servidor/broker" con Raspberry Pi o en PC.

    La configuración básica de un dispositivo se realiza en el archivo configuration.yaml que se puede editar desde una consola ssh con la instrucción:

    sudo nano /home/homeassistant/.homeassistant/configuration.yaml
    

    donde se añaden los parámetros de cada dispositivo, sus propiedades, formas de presentación, etc.

    Por ejemplo, para observar el estado o valor del mensaje MQTT del tema "oficina/mensaje" es necesaria una suscripción al mosquitto. Se asume que ya se han realizado las pruebas de conectividad, por lo que para añadir el dispositivo y sus propiedades al archivo se añade:

    binary_sensor:
      - platform: mqtt
        name: 'Sensor01'
        state_topic: "oficina/mensaje"
    

    Reinicie Home Assistant en el menú de Configuración/Controles del Servidor. Recuerde siempre validar el cambio de configuración antes de reiniciar Home-Assistant. En la pagina de resumen de Home Assistant se obtendrá el estado del dispositivo.

     

  • 3.4 MQTT TLS - Archivo.ino para mensajes de estado LED

    Para añadir un nivel adicional de seguridad a los mensajes MQTT en la red, se incorpora SSL/TLS para un dispositivo ESP8266.

    Para simplificar el ejemplo, la explicación supone que tiene operando el dispositico con

    Mensajes con ESP8266-Parpadeo LED

    y se ha habilitado un broker SSL/TLS con certificado "local" siguiendo el ejemplo de

    MQTT – Mosquitto TLS

    Librerías Arduino

    Para manejar TLS en la conexión, se usa la libreria siguiente:

    #include <WiFiClientSecure.h>
    

    Servidor MQTT puerto

    El primer valor a actualizar para mensajes TLS es el puerto, revise este valor antes de continuar.

    // MQTT: Servidor
    char* MQTT_IP = "192.168.10.40";
    uint16_t MQTT_puerto = 8883;
    

    Certificados TLS

    Los certificados a usar corresponden al certificado de la autoridad y del servidor mqtt.

    Para el certificado de la autoridad mqtt-ca.crt se usa el contenido del archivo abierto como texto.

    El certificado del servidor mqtt-srv se usa en formato reducido de fingerprint, obtenido con la instruccion descrita anteriormente en la sección mosquitto TLS.

    // Certificados TLS: Certificate Authority
    const char caCert[] PROGMEM = R"EOF(-----BEGIN CERTIFICATE-----
    MIIDRzCCAi+gAwIBAgIUMtlZSXzSZfHpBI0vrnxdLrQuNgwwDQYJKoZIhvcNAQEL
    BQAwMzELMAkGA1UEBhMCRUMxDDAKBgNVBAcMA0d5ZTEWMBQGA1UEAwwNMTkyLjE2
    .... // ....
    OpA6IPNIHmDSSPxgejZq4booviVKro2/M++iOUuGj1jkjR6XSQ6x1JgK0DVyiBtD
    4od+M4mYk7gz/CHgl1JEsTVPyUZK4OO/oxC7
    -----END CERTIFICATE-----
    )EOF";
    
    // MQTT: cert SHA1 fingerprint
    const uint8_t mqttCertFingerprint[] = {0x19,0x50,0x25,0x2C,0xD8,0x6A,0x54,0xE6,0xBC,0x8B,0xA4,0x5F,0x76,0x3F,0xD0,0x7D,0xE0,0x5F,0x7C,0x6C};
    

    Conexiones WiFi Seguras

    Para usar los componentes de WifiClient y PubsubClient se requiere añadir los detallas de los certificados, por lo que se sustituyen las línea como se muestra:

    // Clientes WiFi y MQTT
    //WiFiClient wificlient;
    // PubSubClient mqttclient(wificlient);
    
    // X.509 parsed CA Cert 
    X509List caCertX509(caCert);
    // Secure client connection class
    WiFiClientSecure wificlient;
    // MQTT: Client connection
    PubSubClient mqttclient(wificlient);
    

    MQTT - Inicio

    En la sección de inicio de MQTT se añaden las partes para que tome en cuenta los certificados al momento de realizar la conexión por Wifi

      // Configura cliente TLS
      // añade CA cert en los sitios de confianza
      wificlient.setTrustAnchors(&caCertX509);
      // Habilita self-signed cert
      wificlient.allowSelfSignedCerts(); 
      // añade fingerprint para validar conexión
      wificlient.setFingerprint(mqttCertFingerprint); 
    

    El resto de las intrucciones se mantienen iguales al proceso anterior.


    Ejemplo: Parpadea LED

    /* ESP8266 Sensor Parpadea. edelros@espol.edu.ec
     *  con SSL/TLS, Para usar, actualice las secciones de:
     *  - WIFI:Router, MQTT:Servidor, MQTT:Dispositivo
     *  ESP-01 al usar GPIO1 y GPIO3,(Tx,Rx), NO USE Serial.print()
    */
    #include <ESP8266WiFi.h>
    #include <WiFiClientSecure.h>
    #include <PubSubClient.h>
    
    // WIFI: conexión a Router
    char* ssid = "miRouter";
    char* password = "miRouterclave";
    
    // MQTT: Servidor
    char* MQTT_IP = "192.168.10.40";
    uint16_t MQTT_puerto = 8883;
    char* MQTT_usuario = "usuarioprueba";
    char* MQTT_contrasena = "usuarioclave";
    
    // MQTT: Dispositivo
    char* MQTT_ID = "sensor01";
    char* MQTT_TOPIC = "oficina/mensaje";
    char MQTT_SensorEstado[10] = "OFF";
    
    // Certificados TLS: Certificate Authority
    const char caCert[] PROGMEM = R"EOF(-----BEGIN CERTIFICATE-----
    MIIDRzCCAi+gAwIBAgIUMtlZSXzSZfHpBI0vrnxdLrQuNgwwDQYJKoZIhvcNAQEL
    .......// ........
    OpA6IPNIHmDSSPxgejZq4booviVKro2/M++iOUuGj1jkjR6XSQ6x1JgK0DVyiBtD
    4od+M4mYk7gz/CHgl1JEsTVPyUZK4OO/oxC7
    -----END CERTIFICATE-----
    )EOF";
    
    // MQTT: cert SHA1 fingerprint
    const uint8_t mqttCertFingerprint[] = {0x19,0x50,0x25,0x2C,0xD8,0x6A,0x54,0xE6,0xBC,0x8B,0xA4,0x5F,0x76,0x3F,0xD0,0x7D,0xE0,0x5F,0x7C,0x6C};
    
    // Sensor 
    const uint8_t sensor_pin = 1;
    volatile boolean sensor_estado  = false;
    
    // LED monitor interno: ESP01-pin=1, ESP07-pin=2
    const uint8_t LED_pin = 2;
    
    // Mensajes por Puerto Serial
    volatile boolean serial_msg = true;
    
    // Clientes WiFi y MQTT
    //WiFiClient wificlient;
    // PubSubClient mqttclient(wificlient);
    
    // X.509 parsed CA Cert 
    X509List caCertX509(caCert);
    // Secure client connection class
    WiFiClientSecure wificlient;
    // MQTT: Client connection
    PubSubClient mqttclient(wificlient);
    
    void setup() {
    
      if (serial_msg){
        Serial.begin(74880);//74880, 115200
        while (!Serial){delay(50);}
        Serial.println("inicia setup");
      }
      
      // LED monitor, Enciende en LOW
      pinMode(LED_pin, OUTPUT);
    
      // conexión WIFI y MQTT
      inicia_wifi();
      if (WiFi.status() == WL_CONNECTED){
        inicia_mqtt();
      }
    }
    
    void loop() {
      
      // Parpadea estado de sensor
      if (sensor_estado==true){
        sensor_estado = false;
      }else{
        sensor_estado = true;
      }
      
      // LED Monitor Parpadea, enciende en LOW
      if (sensor_estado ==true) {
        digitalWrite(LED_pin, LOW);
        delay(1000); // un segundo
      }
      if (sensor_estado ==false) {
        digitalWrite(LED_pin, HIGH);
        delay(1000);
      }
    
      if (WiFi.status()==WL_CONNECTED) {
        publica_estado();
      }
      
      //Revisa estado de Wifi o reintenta conexión  
      if (WiFi.status() != WL_CONNECTED){
        inicia_wifi();
      }else{
        if (mqttclient.connected()==false){
            inicia_mqtt(); // reintento
        }
        if (mqttclient.connected()==true){
          mqttclient.loop();
        }
      }
      yield(); // procesa wifi
    } 
    

    sección de inicio MQTT completa:

    void inicia_mqtt() {
      int intentos = 5;
      int cuenta = 0;
    
      // Configura cliente TLS
      // añade CA cert en los sitios de confianza
      wificlient.setTrustAnchors(&caCertX509);
      // Habilita self-signed cert
      wificlient.allowSelfSignedCerts(); 
      // añade fingerprint para validar conexión
      wificlient.setFingerprint(mqttCertFingerprint); 
    
      mqttclient.setServer(MQTT_IP, MQTT_puerto);
      mqttclient.connect(MQTT_ID, MQTT_usuario, MQTT_contrasena);
      //mqttclient.setCallback(callback);
    
      if (serial_msg){
        Serial.print(" MQTT Conectando a ");
        Serial.println(MQTT_IP);
      }
      
      while (!mqttclient.connected()&&(cuenta<=intentos)){
        cuenta = cuenta + 1;
        
        // LED Monitor parpadeo MQTT, enciende LOW
        digitalWrite(LED_pin, LOW);
        delay(600);
        digitalWrite(LED_pin, HIGH);
        delay(400);
        
        if (serial_msg){
          Serial.print(".");
        }
      }
      
      // Si conectado, inicializa estado
      if (mqttclient.connected()){
          publica_estado();
      }
      
      if (serial_msg){
        //Fin de "...."
        Serial.println();
        Serial.print("; MQTT Conectado: ";);
        Serial.println(mqttclient.connected());
        Serial.print("; MQTT Estado: ";);
        Serial.println(mqttclient.state());
      }
    }
    

    sección de publicación MQTT es igual que en el ejercicio que le precede

    // Publicar el estados del dispositivo
    void publica_estado() {
      
      // formato para envio (Texto)
      if (sensor_estado == true ){
        snprintf(MQTT_SensorEstado,10, "ON");
      }else{
        snprintf(MQTT_SensorEstado,10, "OFF");
      }
    
      // publicar estados
      if (mqttclient.connected()==true) {
        mqttclient.publish(MQTT_TOPIC,MQTT_SensorEstado,true);
      }
    
      if (serial_msg){
        if (mqttclient.connected()==true) {
          Serial.println(MQTT_SensorEstado);
        }
        if (mqttclient.connected()==false) {
          Serial.println("MQTT desconectado");
        }
      }
    }
    

    sección de inicio de Wifi es igual que en el ejercicio que le precede.

    void inicia_wifi(){
      int intentos = 10;
      int cuenta = 0;
    
      if (serial_msg){
        Serial.print(" WIFI Conectando a ");
        Serial.println(ssid);
        }
      
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      
      while ((WiFi.status() != WL_CONNECTED) && (cuenta < intentos)){
        if (serial_msg){
          Serial.print(".");
          }
        cuenta = cuenta+1;
        // Parpadeo de Monitor enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(300);
        digitalWrite(LED_pin, HIGH);
        delay(200);
        }
      
      if (serial_msg){
        Serial.println();  //Fin de "..."
        if (WiFi.status() == WL_CONNECTED){
          Serial.print(" Estado: ");
          Serial.println(WiFi.status());
          Serial.print(" MAC: ");
          Serial.println(WiFi.macAddress());
          Serial.print(" IP: ");
          Serial.println(WiFi.localIP());
          Serial.print(" RSSI: ");
          Serial.println(WiFi.RSSI());
          Serial.println();
          }
        if (WiFi.status() != WL_CONNECTED){
          WiFi.printDiag(Serial);
          Serial.println();
          }
        }
      }
    

    Referencia: https://blog.thewalr.us/2019/03/27/using-esp8266-as-an-iot-endpoint-with-encrypted-mqtt-transport/

  • 3.3 MQTT - Archivo.ino - Mensajes de estado LED

    Referencia: Librería mqtt https://pubsubclient.knolleary.net/api

    Para esta sección se supone que ha establecido la conexión a la red WiFi y dispone de un un servidor/broker MQTT de pruebas,  semejante a lo realizado en las secciones anteriores.


    1. Bloque de inicio

    Para MQTT se incluye la libreria PubSubClient.h para la activación de un cliente sobre WiFi. como se indica en las intrucciones siguientes:

    #include <PubSubClient.h >
    
    // Clientes WiFi y MQTT
    WiFiClient wificlient;
    PubSubClient mqttclient(wificlient);
    

    2. Configuración de inicio setup()

    Para el bloque de configuración setup() se verifica el estado de la conexión WiFi antes del intento de conexión al broker MQTT-Mosquitto.

      // conexión WIFI y MQTT
      inicia_wifi();
      if (WiFi.status() == WL_CONNECTED){
        inicia_mqtt();
      }
    

    El proceso inicia_mqtt() se establecen los párámetros de servidor, identificación de usario, conexión y la primera actualización de estado con pub/sub que corresponda.

    3. Procedimientos MQTT

    Se usa el procedimiento de inicio de conexión y de publicación de estados con sensores. En el caso de actuador se añade el proceso de recepción de mensajes en el dispositivo (callback)

    3.1 Procedimiento inicia_mqtt()

    Con los parámetros del broker y dispositivo se establece la conexión con el servidor (setServer(), connect()).

    Se tiene un periodo de espera mientras se parpadea el led y se presenta un punto en el puerto serial. En caso de que se verifica conexión se publica el estado inicial del sensor antes de volver al bucle de operación.

    void inicia_mqtt() {
      int espera = 5;
      int cuenta = 0;
      
      mqttclient.setServer(MQTT_IP, MQTT_puerto);
      mqttclient.connect(MQTT_ID, MQTT_usuario,
                          MQTT_contrasena);
      //mqttclient.setCallback(callback);
    
      if (serial_msg){
        Serial.print(" MQTT Conectando a ");
        Serial.println(MQTT_IP);
      }
      
      while (!mqttclient.connected()&&(cuenta<=espera)){
        cuenta = cuenta + 1;
        
        // LED Monitor parpadeo MQTT, enciende LOW
        digitalWrite(LED_pin, LOW);
        delay(600);
        digitalWrite(LED_pin, HIGH);
        delay(400);
        
        if (serial_msg){
          Serial.print(".");
        }
      }
      
      // Si conectado, inicializa estado
      if (mqttclient.connected()){
          publica_mqtt();
      }
      
      if (serial_msg){
        //Fin de "...."
        Serial.println();
        Serial.print(" MQTT Conectado: ");
        Serial.println(mqttclient.connected());
        Serial.print(" MQTT Estado: ");
        Serial.println(mqttclient.state());
      }
    }
    

    Se añaden algunos mensajes de estado hacia el computador como parte del proceso de depuración en la etapa de desarrollo y programación.

    El resultado de esta subrutina en la pantalla "monitor_serie" es;

    inicia setup
     WIFI Conectando a miRouter
    .......
     Estado: 3
     MAC: 2C:3A:E8:0A:98:66
     IP: 192.168.10.11
     RSSI: -56
    
     MQTT Conectando a 192.168.10.50
    OFF
    
     MQTT Conectado: 1
     MQTT Estado: 0
    ON
    OFF
    ON
    OFF
    ON
    OFF
    
    ....
    
    OFF
    ON
    MQTT desconectado
     MQTT Conectando a 192.168.10.50
    .....
    

    Como una prueba de funcionamiento, al final se muestra el resultado al desconectar el cable del servidor MQTT.

    Estos parámetros se deben actualizar para cada dispositivo específico a desarrolar.

    Los valores para mqttclient.state() que se pueden obtener son:

    -4 : MQTT_CONNECTION_TIMEOUT - the server didn't respond within the keepalive time
    -3 : MQTT_CONNECTION_LOST - the network connection was broken
    -2 : MQTT_CONNECT_FAILED - the network connection failed
    -1 : MQTT_DISCONNECTED - the client is disconnected cleanly
     0 : MQTT_CONNECTED - the client is connected
     1 : MQTT_CONNECT_BAD_PROTOCOL - the server doesn't support the requested version of MQTT
     2 : MQTT_CONNECT_BAD_CLIENT_ID - the server rejected the client identifier
     3 : MQTT_CONNECT_UNAVAILABLE - the server was unable to accept the connection
     4 : MQTT_CONNECT_BAD_CREDENTIALS - the username/password were rejected
     5 : MQTT_CONNECT_UNAUTHORIZED - the client was not authorized to connect
    

    Referencia: https://pubsubclient.knolleary.net/api

    3.2 Procedimiento publica_mqtt()

    La publicación de estados se realiza como una subrutina, en el ejemplo es solo encendido y apagado de un LED

    // Publicar el estados del dispositivo
    void publica_mqtt() {
      
      // formato para envio (Texto)
      if (sensor_estado == true ){
        snprintf(MQTT_SensorEstado,10, "ON");
      }else{
        snprintf(MQTT_SensorEstado,10, "OFF");
      }
    
      // publicar estados
      if (mqttclient.connected()==true) {
        mqttclient.publish(MQTT_TOPIC,
                           MQTT_SensorEstado,
                           true);
      }
    
      if (serial_msg){
        if (mqttclient.connected()==true) {
          Serial.println(MQTT_SensorEstado);
        }
        if (mqttclient.connected()==false) {
          Serial.println("MQTT desconectado");
        }
      }
    }
    

    4. Instrucciones Arduino

    Las instrucciones usadas para que el estado del parpadeo de un LED se transmita al broker MQTT se incluyen en para la parte principal en la pestaña principal.

    /* ESP8266/ESP32 Sensor LED Parpadea. 
     * edelros@espol.edu.ec
     * Actualice: WIFI:Router, MQTT:Servidor, MQTT:Dispositivo
     * ESP-01, NO USE Serial.print()
    */
    // detectar placa al compilar
    # ifdef defined(ESP8266)
      #include <ESP8266WiFi.h>
    # elif defined(ESP32)
      #include <WiFi.h>
    # endif
    #include <PubSubClient.h>
    // Clientes WiFi y MQTT
    WiFiClient wificlient;
    PubSubClient mqttclient(wificlient);
    
    // WIFI: conexión a Router
    char* ssid = "miRouter";
    char* password = "miRouterClave";
    
    // MQTT: Servidor
    char* MQTT_IP = "192.168.10.50";
    uint16_t MQTT_puerto = 1883;
    char* MQTT_usuario = "usuarioprueba";
    char* MQTT_contrasena = "usuarioclave";
    
    // MQTT: Dispositivo
    char* MQTT_ID = "Dispositivo";
    char* MQTT_TOPIC = "oficina/mensaje";
    char MQTT_SensorEstado[10] = "OFF";
    boolean mqtt_desconectado = true;
    
    // Sensor 
    const uint8_t sensor_pin = 1;
    volatile boolean sensor_estado  = false;
    
    // LED monitor interno: ESP01-pin=1, ESP07-pin=2
    const uint8_t LED_pin = 2;
    
    // Mensajes por Puerto Serial
    volatile boolean serial_msg = true;
    
    void setup() {
    
      if (serial_msg){
        Serial.begin(115200);//74880, 115200
        while (!Serial){delay(50);}
        Serial.println("inicia setup");
      }
      
      // LED monitor, Enciende en LOW
      pinMode(LED_pin, OUTPUT);
    
      // conexión WIFI y MQTT
      inicia_wifi();
      if (WiFi.status() == WL_CONNECTED){
        inicia_mqtt();
      }
    }
    
    void loop() {
      // Parpadea estado de sensor
      if (sensor_estado==true){
        sensor_estado = false;
      }else{
        sensor_estado = true;
      }
      
      // LED Monitor Parpadea, enciende en LOW
      if (sensor_estado ==true) {
        digitalWrite(LED_pin, LOW);
        delay(1000); // un segundo
      }
      
      #ifdef defined(ESP8266)
        yield(); // procesa wifi
      #endif
      
      if (sensor_estado ==false) {
        digitalWrite(LED_pin, HIGH);
        delay(1000);
      }
    
      if (mqttclient.connected()==true){
        publica_mqtt();
      }
      
      //Revisa estado de Wifi o reintenta conexión  
      if (WiFi.status() != WL_CONNECTED){
        inicia_wifi();
      }else{
        if (mqttclient.connected()==false){
            inicia_mqtt(); // reintento
        }
        if (mqttclient.connected()==true){
          mqttclient.loop();
        }
      }
      #ifdef defined(ESP8266)
          yield(); // procesa wifi
      #endif
    } 
    

    Si no se ha implementado el broker MQTT solo obtendrá mensajes de "MQTT desconectado".

    Al final, recuerde añadir los otros procedimientos inicia_wifi(), inicia_mqtt(), publica_mqtt().

    void inicia_wifi(){
      int espera = 10; // >=10 para conectar
      int cuenta = 0;
    
      // mensajes por serial activado
      if (serial_msg){
        Serial.print(" WIFI Conectando a ");
        Serial.println(ssid);
        }
      
      WiFi.mode(WIFI_STA);
      WiFi.begin(ssid, password);
      
      while ((WiFi.status()!=WL_CONNECTED)&&(cuenta<espera)){
        cuenta = cuenta+1;
        
        // Parpadeo de Monitor enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(300);
        digitalWrite(LED_pin, HIGH);
        delay(200);
        
        if (serial_msg){
          Serial.print(".");
          }
        }
    
      //activado mensajes por serial
      if (serial_msg){
        Serial.println();  //Fin de "..."
        if (WiFi.status() == WL_CONNECTED){
          Serial.print(" Estado: ");
          Serial.println(WiFi.status());
          Serial.print(" MAC: ");
          Serial.println(WiFi.macAddress());
          Serial.print(" IP: ");
          Serial.println(WiFi.localIP());
          Serial.print(" RSSI: ");
          Serial.println(WiFi.RSSI());
          Serial.print(" Canal: ");
          Serial.println(WiFi.channel());
          Serial.println();
          }
        if (WiFi.status() != WL_CONNECTED){
          WiFi.printDiag(Serial);
          Serial.println();
          }
        }
      }
    
  • 3.2 MQTT - Broker de pruebas con usuario y contraseña

    Para probar el funcionamiento de un dispositivo con mensajes MQTT se requiere disponer de un broker MQTT.

    mosquitto Logo 01

    El ejercicio de Parpadeo LED, con validación de usuario y contraseña, presenta la recepción de los mensajes MQTT  de la siguiente forma:

    pi@raspberry:~ $ mosquitto_sub -d -t "oficina/mensaje" -u "usuarioprueba" -P "usuarioclave"
    oficina/mensaje ON
    oficina/mensaje OFF
    oficina/mensaje ON
    oficina/mensaje OFF
    oficina/mensaje ON
    oficina/mensaje OFF
    oficina/mensaje ON
    oficina/mensaje OFF
    oficina/mensaje ON
    

    Se propone disponer de uno usando Mosquitto instalado en un Raspberry Pi para todo lo que se presenta en el Blog.

    Sin embargo, si se está iniciando y no se dispone de todo o el acceso a un laboratorio, también es posible tener uno instalado en una pc.

    Mosquitto es open source y se puede descargar para instalarlo en varias plataformas.

    La descripción en detalle para Raspberry Pi se encuentra en la sección:

    Broker/Gestión / MQTT – Mosquitto instalar

    1. Instalación en Windows

    Descargue el instalador para Windows en el enlace siguiente

    https://mosquitto.org/download/

    1.1 Iniciar del servicio MQTT- Mosquitto

    Para que el servicio MQTT-Mosquitto esté activo se utiliza la apliación "Servicios" de "Windows.

    busque la apliación con el botón de búsqueda de windows:

    Mqtt Windows 04

    Con la apliación de servicios, localice el servicio "Mosquitto-Broker". Para establecer el estado puede usar las propiedades, con "click derecho" del mouse.

    Mqtt Windows 05

    Establezca el inicio en modo "manual", solo si va a utilizar el programa como pruebas, sino en "automático" para que siempre esté activo. Luego proceda con el botón de "iniciar"

    Mqtt Windows 06

    1.2 Verificar el servicio "Mosquitto-Broker"

    Las instrucciones anteriores habilitan y permiten observar que el servicio "Mosquitto-Broker" se encuentra "En ejecución".

    Mqtt Windows 07

    También se puede comprobar el funcionamiento usando una ventana "Símbolo de sistema" y la instrucción:

    netstat -an

    Observando que el puerto 1883 se encuentra en modo "LISTENING", esperando que lleguen los mensajes al broker.

    Mqtt Windows 08

    1.3 Pruebas de operación

    Para probar la mensajería, se requieren dos ventanas de "símbolo de sistema". La primera para "escuchar" los mensajes (sub) y la segunda para "enviar" los mensajes (pub).

    Mqtt Windows 09

    En una ventana de comando, se suscribirse a un tópico ejemplo, para recibir los mensajes:

    mosquitto_sub -v -t "oficina/mensaje"

    en otra ventana publicar un nuevo estado en el tópico:

    mosquitto_pub -t "oficina/mensaje" -m "mensaje mqtt"

    Si el resultado es semejante al mostrado en la imagen del ejemplo, MQTT se encuentra funcionando correctamente y listo para enviar y recibir mensajes desde un dispositivo.

    1.4 archivo de configuración en Windows

    La configuración de MQTT se realiza en el archivo mosquitto.conf que se encuentra en c:\program files\mosquitto\

    Mqtt Windows 10

    Recuerde que al cambiar la configuración debe reiniciar el servicio para que se apliquen los cambios.

    Puede proceder con otras acciones dadas en la sección "Broker/Gestión"/MQTT-Mosquito, semejante lo mostrado en el siguiente enlace:

    MQTT – Mosquitto usuario y contraseña

    Referencia: https://www.mundotelematico.com/instalacion-de-mosquitto-mqtt-broker-en-windows/