6. Actuador/Sensor -Emisor/Receptor Infrarojo ESP07

El objetivo es disponer de un dispositivo que permita controlar el encendido o apagado de un acondicionador de aire.

Las premisas para el desarrollo son:

  • independencia del equipo acondicionador de aire, no intervenga físicamente en los circuitos del equipo,
  • integre el reconocimiento del código de encendido/apagado desde el control remoto
  • Para acceso remoto, fuera del sitio, permita monitorear el estado del medio ambiente antes de encender/apagar.
  • Se conecte al broker mediante MQTT
  • Incorpore la configuración de red mediante SmartConfig.
  • Las consideraciones de los dispositivos anteriores, open software/hardware, etc.

Se desarrolla a partir de los ejemplos:

ESP07 IR detector/demodulador

ESP07 IR Emisor

4. Sensor Temperatura/Humedad ESP-01

Referencias 

El pin del emisor infrarojo se lo toma de la hoja de datos para el ESP8266 donde se indica usar el pin 5 para emisor y el 14 para receptor. Sección 4.4.Interfaces, página 12.

https://www.mikrocontroller.net/attachment/338570/Ai-thinker_ESP-07_WIFI_Module-EN.pdf

Observaciones

Por la variedad de receptores infrarojos, se recomienda verificar la configuración de pines antes de conectar.

El encendido del LED infrarojo se realiza por medio de un transistor para manejar más corriente que la salida del ESP8266

Por la necesidad de usar más entradas/salidas de control se usó el ESP07


Esquema propuesto

Se integran el diseño presentado en los ejemplos de Receptor, Emisor infrarojo y sensor de temperatura/humedad, lo que lo convierte en un ejercicio sumativo de experiencias previas.

Protoboard

Como referencia a las conexiones en también se adjunta la conexión usando un protoboard.

Instrucciones

Las instrucciones enfocadas en cada sensor o actividad se resumen en funciones, tratando de mantener la simplicidad del lazo principal.

Las instrucciones incorporan las siguientes características:

  • El control se realiza mediante las instrucciones MQTT
  • Usa el LED del ESP8266 como indicador de estado del acondicionador de aire o equipo activado por control remoto
  • Se emite la señal de control mediante la variable senal_ONOFF
  • Se controla el estado de lectura del sensor/decodificador infrarojo mediante MQTT, y la respuesta se emite a la conexión serial.
  • La temperatura y humedad se actualizan con el parametro «intervalo» cuyo primer número es minutos
/* Control Remoto con sensor de temperatura/Humedad
 *  version 1.0
Para usar, se debe actualizar las secciones de:
 - WIFI datos para conexión a Router
 - MQTT: Servidor MQTT 
 - MQTT: identificador de dispositivo y topics
Se está usando ESP8266-07, pero para programar,
usar Placa:ESP8285
*/
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <dht.h>

#include <IRremoteESP8266.h>
#include <IRsend.h>
#include <IRrecv.h>

#ifndef UNIT_TEST
#include <Arduino.h>
#endif
#include <IRutils.h>
// The following are only needed for extended decoding of A/C Messages
#include <ir_Coolix.h>
#include <ir_Daikin.h>
#include <ir_Fujitsu.h>
#include <ir_Gree.h>
#include <ir_Haier.h>
#include <ir_Hitachi.h>
#include <ir_Kelvinator.h>
#include <ir_Midea.h>
#include <ir_Mitsubishi.h>
#include <ir_MitsubishiHeavy.h>
#include <ir_Panasonic.h>
#include <ir_Samsung.h>
#include <ir_Tcl.h>
#include <ir_Teco.h>
#include <ir_Toshiba.h>
#include <ir_Vestel.h>
#include <ir_Whirlpool.h>

// WIFI datos para conexión a Router
const PROGMEM char* ssid = "xxxx";
const PROGMEM char* password = "xxxx";

// MQTT: Servidor MQTT 
const PROGMEM char* MQTT_SERVER_IP = "xx.xx.xx.xx";
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
const PROGMEM char* MQTT_USER = "username";
const PROGMEM char* MQTT_PASSWORD = "password";

// MQTT: identificador de dispositivo y topics
const PROGMEM char* MQTT_CLIENT_ID = "Control Remoto 01";
const PROGMEM char* MQTT_SENSOR_TOPIC_T = "oficina/CR01/Temperatura";
const PROGMEM char* MQTT_SENSOR_TOPIC_H = "oficina/CR01/Humedad";

// MQTT: Control remoto enciende
const PROGMEM char* MQTT_SENSOR_TOPIC_10 = "oficina/CR01/enciende/status";
const PROGMEM char* MQTT_SENSOR_STATE_TOPIC_10 = "oficina/CR01/enciende/switch";
const PROGMEM char* MQTT_SENSOR_COMMAND_TOPIC_10 = "oficina/CR01/enciende/set";


// MQTT: lectura sensor IR
const PROGMEM char* MQTT_SENSOR_TOPIC_IR = "oficina/CR01/lectura/status";
const PROGMEM char* MQTT_SENSOR_STATE_TOPIC_IR = "oficina/CR01/lectura/switch";
const PROGMEM char* MQTT_SENSOR_COMMAND_TOPIC_IR = "oficina/CR01/lectura/set";
const PROGMEM char* MQTT_SENSOR_AVAILABILITY_TOPIC_IR = "oficina/CR01/lectura/available";


char MQTT_SENSOR_STATE_T[10] = "0"; // inicializa
char MQTT_SENSOR_STATE_H[10] = "0"; // inicializa
char MQTT_SENSOR_STATE[10] = "OFF"; // inicializa LED interno
char MQTT_SENSOR_STATE_IR[10] = "OFF"; // inicializa lectura IR

const PROGMEM char* SENSOR_ON  = "ON";
const PROGMEM char* SENSOR_OFF = "OFF";

volatile boolean SENSOR_estado = false;
volatile boolean SENSOR_IR = false;

// LED monitor interno
//ESP01-pin=1, ESP07-pin=2
const PROGMEM uint8_t LED_pin = 2; 

// Sensor de Temperatura&Humedad
dht DHT;
#define DHT11_PIN 13

// Control de tiempos
unsigned long antes = 0; 
unsigned long ahora = millis();
const long intervalo = 5*60*1000;//minutos*60s*1000ms

// Control Remoto Emisor LED
const PROGMEM uint8_t IR_LED = 5;
uint32_t senal_ONOFF = 0xFF5AA5; // código de control

IRsend irsend(IR_LED);  // configura emisor

// Control Remoto Receptor -------
const uint16_t kRecvPin = 4;
const uint32_t kBaudRate = 115200;
const uint16_t kCaptureBufferSize = 1024;
#if DECODE_AC
// Some A/C units have gaps in their protocols of ~40ms. e.g. Kelvinator
// A value this large may swallow repeats of some protocols
const uint8_t kTimeout = 50;
#else   // DECODE_AC
// Suits most messages, while not swallowing many repeats.
const uint8_t kTimeout = 15;
#endif  // DECODE_AC
const uint16_t kMinUnknownSize = 12; //12
IRrecv irrecv(kRecvPin, kCaptureBufferSize, kTimeout, true);
decode_results results;  // Somewhere to store the results

WiFiClient wifiClient;
PubSubClient client(wifiClient);

void setup() {
    // Conexion serial
    Serial.begin(115200);//74880);
    Serial.setTimeout(2000);
    // espera inicializar serial
    while(!Serial) { }

    // SENSOR Temperatura&Humedad
    pinMode(DHT11_PIN, INPUT);

    // Control Remoto Emisor LED
    irsend.begin();

    // LED monitor
    pinMode(LED_pin, OUTPUT);

    // Inicia redes
    if(WiFi.status() != WL_CONNECTED){
        inicia_wifi();
        }
    if (!client.connected()){
        inicia_mqtt();
        }

    // Inicia Receptor IR
    #if DECODE_HASH
    // Ignore messages with less than minimum on or off pulses.
    irrecv.setUnknownThreshold(kMinUnknownSize);
    #endif                  // DECODE_HASH
    irrecv.enableIRIn();  
}

void loop() {
    unsigned long ahora = millis();
    
    if(WiFi.status() != WL_CONNECTED){
        inicia_wifi();
        }
    if (!client.connected()){
        inicia_mqtt();
        }
    delay(10);   
    client.loop();

    if (((ahora - antes)> intervalo)) {
        antes = ahora;
    
        // lectura de sensores
        SensorTempHum();
        Serial.print("ESTADO DISPOSITIVO: \nLED ");
        Serial.print(SENSOR_estado);
        Serial.print(" , IR ");
        Serial.println(SENSOR_IR);
    }
    
    if (SENSOR_IR == true){
        sensarcodigos();
    }
    delay(10);
}

// establece estado LED monitor en ESP8266
void CR01activaestado(){
        irsend.sendNEC(senal_ONOFF,32);
}

// llega mensaje MQTT
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
    // convierte a cadena
    String payload;
    for (uint8_t i = 0; i < p_length; i++) {
        payload.concat((char)p_payload[i]);
        }
    Serial.print(" Llegó un mensaje: ");
    Serial.println(p_topic);
    Serial.println(payload);
    // analiza mensaje por topico
    if (String(MQTT_SENSOR_COMMAND_TOPIC_10).equals(p_topic)) {
        if (payload.equals(String(SENSOR_ON))) {
            if (SENSOR_estado != true) {
                SENSOR_estado = true;
                LEDactivaestado();
                CR01activaestado();
                SENSORpublicaestado();
                }
        } else if (payload.equals(String(SENSOR_OFF))) {
            if (SENSOR_estado != false) {
                SENSOR_estado = false;
                LEDactivaestado();
                CR01activaestado();
                SENSORpublicaestado();
                }
        }
     }
     if (String(MQTT_SENSOR_COMMAND_TOPIC_IR).equals(p_topic)) {
        Serial.print("+++ cambio de estado detectado para IR: ");
            if (payload.equals(String(SENSOR_ON))) {
                Serial.println("Lectura ON");
                if (SENSOR_IR != true) {
                SENSOR_IR = true;
                SENSOR_IRpublicaestado();
                }
            } else if (payload.equals(String(SENSOR_OFF))) {
                Serial.println("Lectura OFF");
                if (SENSOR_IR != false) {
                SENSOR_IR = false;
                SENSOR_IRpublicaestado();
                }
            }
     }
}

// establece estado LED monitor en ESP8266
void LEDactivaestado(){
    if (SENSOR_estado){
        digitalWrite(LED_pin, LOW);
    }else{
        digitalWrite(LED_pin, HIGH);
    }
}

void SensorTempHum(){
    int chk = DHT.read11(DHT11_PIN);
    float temperatura = DHT.temperature;
    float humedad = DHT.humidity;
    Serial.println("Temperatura,Humedad: ");
    Serial.print(temperatura);
    Serial.print(",");
    Serial.println(humedad);
    client.publish(MQTT_SENSOR_TOPIC_T, 
                    String(temperatura).c_str(), 
                    true);
    client.publish(MQTT_SENSOR_TOPIC_H, 
                    String(humedad).c_str(), 
                    true);
    delay(1000);
}

void inicia_wifi() {
    // conexion WiFi
    Serial.print("\n Conectando a ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    int cuenta = 0;
    while (WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        cuenta = cuenta+1;
        if (cuenta>=40){
            Serial.println();
            cuenta = 0;}
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(250);
        digitalWrite(LED_pin, HIGH);
        delay(250);
        }
    Serial.print("\n WiFi conectado \n Dirección IP: ");
    Serial.println(WiFi.localIP());
    delay(10);
}

void inicia_mqtt(){
    client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
    client.setCallback(callback);
    while (!client.connected()) {
        Serial.println("\n Conectando a MQTT ");
        if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
            Serial.println(" MQTT conectado");  
        } else {
            Serial.print("Falló, estado: ");
            Serial.print(client.state()); 
            Serial.print(" , reintento en 5 segundos");
            // LED interno enciende en LOW 
            for (int i=0;i&lt;=5;i=i+1){
                digitalWrite(LED_pin, LOW);
                delay(600);
                digitalWrite(LED_pin, HIGH);
                delay(400);
            }
        }
    }
    client.publish(MQTT_SENSOR_TOPIC_10, MQTT_SENSOR_STATE_TOPIC_10);
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC_10);

    client.publish(MQTT_SENSOR_TOPIC_IR, MQTT_SENSOR_STATE_TOPIC_IR);
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC_IR);
}

// Publicar el estado del dispositivo
void SENSORpublicaestado() {
    if (SENSOR_estado) {
        client.publish(MQTT_SENSOR_TOPIC_10, SENSOR_ON, true);
    }else{
        client.publish(MQTT_SENSOR_TOPIC_10, SENSOR_OFF, true);
    }
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC_10);
}
// Publicar el estado del dispositivo IR
void SENSOR_IRpublicaestado() {
    if (SENSOR_IR) {
        client.publish(MQTT_SENSOR_TOPIC_IR, SENSOR_ON, true);
    }else{
        client.publish(MQTT_SENSOR_TOPIC_IR, SENSOR_OFF, true);
    }
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC_IR);
}

// Sensor IR para recibir códigos
void sensarcodigos(){
  // Check if the IR code has been received.
  if (irrecv.decode(&results)) {
    // Display a crude timestamp.
    uint32_t now = millis();
    Serial.printf("Timestamp : %06u.%03u\n", now / 1000, now % 1000);
    if (results.overflow)
      Serial.printf(
          "WARNING: IR code is too big for buffer (>= %d). "
          "This result shouldn't be trusted until this is resolved. "
          "Edit & increase kCaptureBufferSize.\n",
          kCaptureBufferSize);
    // Display the basic output of what we found.
    Serial.print(resultToHumanReadableBasic(&results));
    dumpACInfo(&results);  // Display any extra A/C info if we have it.
    yield();  // Feed the WDT as the text output can take a while to print.

    // Display the library version the message was captured with.
    Serial.print("Library   : v");
    Serial.println(_IRREMOTEESP8266_VERSION_);
    Serial.println();

    // Output RAW timing info of the result.
    Serial.println(resultToTimingInfo(&results));
    yield();  // Feed the WDT (again)

    // Output the results as source code
    Serial.println(resultToSourceCode(&results));
    Serial.println("");  // Blank line between entries
    yield();             // Feed the WDT (again)
  }
}

// Display the human readable state of an A/C message if we can.
void dumpACInfo(decode_results *results) {
  String description = "";
  #if DECODE_DAIKIN
  if (results->decode_type == DAIKIN) {
    IRDaikinESP ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_DAIKIN
  #if DECODE_DAIKIN2
  if (results->decode_type == DAIKIN2) {
    IRDaikin2 ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_DAIKIN2
  #if DECODE_DAIKIN216
  if (results->decode_type == DAIKIN216) {
    IRDaikin216 ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_DAIKIN216
  #if DECODE_FUJITSU_AC
  if (results->decode_type == FUJITSU_AC) {
    IRFujitsuAC ac(0);
    ac.setRaw(results->state, results-&gt>bits / 8);
    description = ac.toString();
  }
  #endif  // DECODE_FUJITSU_AC
  #if DECODE_KELVINATOR
  if (results->decode_type == KELVINATOR) {
    IRKelvinatorAC ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_KELVINATOR
  #if DECODE_MITSUBISHI_AC
  if (results->decode_type == MITSUBISHI_AC) {
    IRMitsubishiAC ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_MITSUBISHI_AC
  #if DECODE_MITSUBISHIHEAVY
  if (results->decode_type == MITSUBISHI_HEAVY_88) {
    IRMitsubishiHeavy88Ac ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  if (results->decode_type == MITSUBISHI_HEAVY_152) {
    IRMitsubishiHeavy152Ac ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_MITSUBISHIHEAVY
  #if DECODE_TOSHIBA_AC
  if (results->decode_type == TOSHIBA_AC) {
    IRToshibaAC ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_TOSHIBA_AC
  #if DECODE_GREE
  if (results->decode_type == GREE) {
    IRGreeAC ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_GREE
  #if DECODE_MIDEA
  if (results->decode_type == MIDEA) {
    IRMideaAC ac(0);
    ac.setRaw(results->value);  // Midea uses value instead of state.
    description = ac.toString();
  }
  #endif  // DECODE_MIDEA
  #if DECODE_HAIER_AC
  if (results->decode_type == HAIER_AC) {
    IRHaierAC ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_HAIER_AC
  #if DECODE_HAIER_AC_YRW02
  if (results->decode_type == HAIER_AC_YRW02) {
    IRHaierACYRW02 ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_HAIER_AC_YRW02
  #if DECODE_SAMSUNG_AC
  if (results->decode_type == SAMSUNG_AC) {
    IRSamsungAc ac(0);
    ac.setRaw(results->state, results->bits / 8);
    description = ac.toString();
  }
  #endif  // DECODE_SAMSUNG_AC
  #if DECODE_COOLIX
  if (results->decode_type == COOLIX) {
    IRCoolixAC ac(0);
    ac.setRaw(results->value);  // Coolix uses value instead of state.
    description = ac.toString();
  }
  #endif  // DECODE_COOLIX
  #if DECODE_PANASONIC_AC
  if (results->decode_type == PANASONIC_AC &&
      results->bits > kPanasonicAcShortBits) {
    IRPanasonicAc ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_PANASONIC_AC
  #if DECODE_HITACHI_AC
  if (results->decode_type == HITACHI_AC) {
    IRHitachiAc ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_HITACHI_AC
  #if DECODE_WHIRLPOOL_AC
  if (results->decode_type == WHIRLPOOL_AC) {
    IRWhirlpoolAc ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_WHIRLPOOL_AC
  #if DECODE_VESTEL_AC
  if (results->decode_type == VESTEL_AC) {
    IRVestelAc ac(0);
    ac.setRaw(results->value);  // Like Coolix, use value instead of state.
    description = ac.toString();
  }
  #endif  // DECODE_VESTEL_AC
  #if DECODE_TECO
  if (results->decode_type == TECO) {
    IRTecoAc ac(0);
    ac.setRaw(results->value);  // Like Coolix, use value instead of state.
    description = ac.toString();
  }
  #endif  // DECODE_TECO
  #if DECODE_TCL112AC
  if (results->decode_type == TCL112AC) {
    IRTcl112Ac ac(0);
    ac.setRaw(results->state);
    description = ac.toString();
  }
  #endif  // DECODE_TCL112AC
  // If we got a human-readable description of the message, display it.
  if (description != "") Serial.println("Mesg Desc.: " + description);
}

La configuración en el broker para activar la señal LED y Receptor infrarojo se establece como un switch. Revisar la sección correspondiente en el broker.

Se realizaron pruebas con un acondicionador de aire marca genérica (ECOX), también con un TV Sony; ambas para encendido y apagado.

La siguiente actividad será aumentar la cantidad de botones/actividades que se puedan manejar.

 

5. Sensor de Batería/Temp-Hum ESP-07

Se implementa un dispositivo alimentado por baterías a partir del sensor de Temperatura/Humedad con el sensor DHT11.

El dispositivo es de tipo inalámbrico, WIFI, usa protocolo MQTT para comunicación con el broker y es implementado con ESP8266 versión ESP-07. El ESP-07 tiene una entrada de tipo analógica en el rango [0,1] de 10 bits, 1024 muestras [0,1023].

Premisas para el desarrollo del prototipo, versión 1:

  • Supone que ya se ha implementado un Broker MQTT
  • Dispone de Arduino IDE para cargar las instrucciones en el ESP9266-07 (Revisar)
  • Dispone de una base para el desarrollo de dispositivos, verificando funcionamiento de WIFI y MQTT, en formato DIY (Do It Yourself)
  • Identifica otros elementos de desarrollo e inconvenientes para la implementación.
  • Usa diseños abiertos tipo: Open hardware y Open software
  • Usa componentes disponibles en el mercado local
  • Considera alternativas para los componentes que solo se puedan conseguir por internet
  • Conecta dispositivos por medios inalámbricos.

Para activar el Sensor en la plataforma con Raspberry, consulte la sección de Broker, donde se detallan las instrucciones.

Observaciones

Las baterías usadas son de tipo Ni-MH,  por disponibilidad y capacidad de recarga.

Se descartó el uso de bancos de baterias para celulares a pesar de tener disponibilidad, para realizar mediciones de consumo y considerar realizar el experimento con baterias no recargables AA

  • La temperatura puede ser medida a intervalos largos, por ejemplo 1 hora.
  • Entre intervalos de lecturas se pone en modo sleep el sensor, para ahorrar energía.
  • Se prueban los modos de ahorro de energía para el ESP-07 en modo Deep-Sleep.  Se analiza luego el uso de otros modos para otro tipo de sensores.

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


Esquema Propuesto

Para sensar el estado de la batería se usa el convertidor analógico-digital ADC marcado como pin A0.

El pin analógico tiene rango de operación entre 0 y 1 Voltio, por lo que se usa un divisor de voltaje de la batería. El divisor consume constantemente energía de la batería, motivo por el que se añade un interruptor para cerrar su operación.

El interruptor se puede implementar de varias formas, sin embargo, por disponibilidad local de componentes se usó un transistor PNP, que se activa con la señal enviada en GPIO5 usando un optoacoplador. El optoacoplador también fue usado en el actuador binario, tratando de reutilizar técnicas anteriores.

Por generalidad con los dispositivos previos, se mantiene en el esquema el módulo de alimentación AC. Observe que no se encuentran conectados al diagrama principal.


Protoboard

Se usó un ESP-07 adaptado a una placa con pines que permita su inserción. La adaptación con pines funciona, sin embargo, para implementación es preferible soldar directamente el módulo a la placa definitiva.

Al soldar el módulo a la placa definitiva se limita la posibilidad de actualización de instrucciones, lo que genera la necesidad de disponer de control sobre GPIO0 y los TX-RX. Se añadieron los conectores presentados en el esquemático como sección de Modo programación.


Circuito impreso – PCB

En el modelo presentado, la placa principal es la del sensor. Por generalidad se mantiene en placa separada la fuente AC, y el programa también muestra la relación con el porta-batería.


Instrucciones Arduino

Se reutilizan las funciones de conexión a WIFI y al servidor MQTT.

Las instrucciones se desarrollan en la parte de configuración Setup() en lugar del lazo, Loop(), debido a que se utiliza el modo de ahorro de energía (deep-sleep).

Se han separado el sensor de batería y el sensor de temperatura y humedad en dos funciones.

En el circuito se implementaron las partes de comunicación serial para monitorear el estado del circuito y reprogramación una vez que se encuentra en la placa.

/* Sensor de Temperatura y Humedad DHT11
Sensor de Estado de Batería
Funcionamiento con Batería
Para usar, se debe actualizar las secciones de:
 - WIFI datos para conexión a Router
 - MQTT: Servidor MQTT 
 - MQTT: identificador de dispositivo y topics
Se está usando ESP8266-07, pero para programar,
usar Placa:ESP8285
*/
#include <ESP8266WiFi.h>
#include <<PubSubClient.h>
#include <dht.h>

// WIFI datos para conexión a Router
const PROGMEM char* ssid = "iotirni19";
const PROGMEM char* password = "anera2018";

// MQTT: Servidor MQTT 
const PROGMEM char* MQTT_SERVER_IP = "192.168.10.100";
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
const PROGMEM char* MQTT_USER = "username";
const PROGMEM char* MQTT_PASSWORD = "password";

// MQTT: identificador de dispositivo y topics
const PROGMEM char* MQTT_CLIENT_ID = "Temp_humedad01";
const PROGMEM char* MQTT_SENSOR_TOPIC_T = "oficina/DHT_Temperatura";
const PROGMEM char* MQTT_SENSOR_TOPIC_H = "oficina/DHT_Humedad";
const PROGMEM char* MQTT_SENSOR_TOPIC_B = "oficina/DHT_Bateria";
const PROGMEM char* MQTT_SENSOR_TOPIC_BS = "oficina/DHT_BatSistema";
char MQTT_SENSOR_STATE_T[10] = "0"; // inicializa
char MQTT_SENSOR_STATE_H[10] = "0"; // inicializa
char MQTT_SENSOR_STATE_B[10] = "0"; // inicializa
char MQTT_SENSOR_STATE_BS[10] = "0"; // inicializa

// LED monitor interno
//ESP01-pin=1, ESP07-pin=2
const PROGMEM uint8_t LED_pin = 2; 

// Sensor de Temperatura&Humedad
dht DHT;
#define DHT11_PIN 12

// Bateria
#define bat_estado A0
const PROGMEM uint8_t bat_activa = 4;

// tiempo de dormir
int durmiendo = 5; //segundos

WiFiClient wifiClient;
PubSubClient client(wifiClient);

void setup() {
    // Conexion serial
    Serial.begin(9600);//74880);
    Serial.setTimeout(2000);

    // SENSOR Temperatura&Humedad
    //pinMode(DHT11_PIN, INPUT);

    // SENSOR Bateria
    pinMode(bat_activa, OUTPUT);
    digitalWrite(bat_activa, LOW);

    // LED monitor
    pinMode(LED_pin, OUTPUT);
    // LEDactivaestado();

    // Inicia redes
    if(WiFi.status() != WL_CONNECTED){
        inicia_wifi();
        }
    if (!client.connected()){
        inicia_mqtt();
        }
    client.loop();
    
    // espera inicializar serial
    while(!Serial) { }
    // actividad al despertar
    Serial.println();
    Serial.println("despertando");
    
    // lectura de sensores
    SensorTempHum();
    SensorBateria();

    // a dormir
    Serial.println("A dormir por " + String(durmiendo) + " segundos");
    ESP.deepSleep(durmiendo*1e6); //en microsegundos
}

void loop() {
    // modo sleep usa función setup
}

void SensorTempHum(){
    int chk = DHT.read11(DHT11_PIN);
    float temperatura = DHT.temperature;
    float humedad = DHT.humidity;
    Serial.println("Temperatura,Humedad: ");
    Serial.print(temperatura);
    Serial.print(",");
    Serial.println(humedad);
    client.publish(MQTT_SENSOR_TOPIC_T, 
                    String(temperatura).c_str(), 
                    true);
    client.publish(MQTT_SENSOR_TOPIC_H, 
                    String(humedad).c_str(), 
                    true);
    delay(1000);
}
void SensorBateria(){

    // Activar, Leer, Desactivar, publicar
    digitalWrite(bat_activa, HIGH);
    
    float bateria = analogRead(A0)*(57/10)/1024;
    int bat_sistema = ESP.getVcc()*100/65535;
    //delay(5000); // observar cambio
    digitalWrite(bat_activa, LOW);
    
    Serial.println("Bateria (V), sistema (%):");
    Serial.print(bateria);
    Serial.print(",");
    Serial.println(bat_sistema);
    
    client.publish(MQTT_SENSOR_TOPIC_B,
                    String(bateria).c_str(),
                    true);
    client.publish(MQTT_SENSOR_TOPIC_BS,
                    String(bat_sistema).c_str(),
                    true);
    delay(10);
}

void inicia_wifi() {
    // conexion WiFi
    Serial.print("\n Conectando a ");
    Serial.println(ssid);
    WiFi.begin(ssid, password);
    int cuenta = 0;
    while (WiFi.status() != WL_CONNECTED){
        Serial.print(".");
        cuenta = cuenta+1;
        if (cuenta>=40){
            Serial.println();
            cuenta = 0;}
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(250);
        digitalWrite(LED_pin, HIGH);
        delay(250);
        }
    Serial.print("\n WiFi conectado \n Dirección IP: ");
    Serial.println(WiFi.localIP());
    delay(10);
}

void inicia_mqtt(){
    client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
    //client.setCallback(callback);
    while (!client.connected()) {
        //Serial.println("\n Conectando a MQTT ");
        if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
            Serial.println(" MQTT conectado");  
        } else {
            Serial.print("Falló, estado: ");
            Serial.print(client.state()); 
            Serial.print(" , reintento en 5 segundos");
            // LED interno enciende en LOW
            for (int i=0;i<=5;i=i+1){
                digitalWrite(LED_pin, LOW);
                delay(600);
                digitalWrite(LED_pin, HIGH);
                delay(400);
            }
        }
    }
}

Implementación con una caja eléctrica Dexon

Lecturas registradas con baterías, con periodos de lectura cada 5 segundos, se lograron obtener hasta 4600 muestras antes de que se presentara el apagado del dispositivo.

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.

4. Sensor Temperatura-Humedad ESP-01

Dispositivo de Temperatura-Humedad usando el sensor DHT11.

El dispositivo es de tipo inalámbrico, WIFI, usa protocolo MQTT para comunicación con el broker y es implementado con ESP8266 versión ESP-01

Premisas para el desarrollo del prototipo, versión 1:

  • Supone que ya se ha implementado un Broker MQTT
  • Dispone de Arduino IDE para cargar las instrucciones en el ESP9266-01
  • Dispone de una base para el desarrollo de dispositivos, verificando funcionamiento de WIFI y MQTT, en formato DIY (Do It Yourself)
  • Identifica otros elementos de desarrollo e inconvenientes para la implementación.
  • Usa diseños abiertos tipo: Open hardware y Open software
  • Usa componentes disponibles en el mercado local
  • Considera alternativas para los componentes que solo se puedan conseguir por internet
  • Conecta dispositivos por medios inalámbricos.

Para activar el Sensor Binario en la plataforma con Raspberry, consulte la sección de Broker, donde se detallan las instrucciones.

Observaciones

El sensor de temperatura se usará para realizar pruebas de trabajo con baterías considerando:

  • La temperatura puede ser medida a intervalos largos, por ejemplo 1 hora.
  • Entre intervalos de lecturas se pone en modo sleep el sensor, para ahorrar energía.
  • Se prueban los modos de ahorro de energía para el ESP8266:
    Modem-Sleep, Light-Sleep y Deep-Sleep

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


Esquema Propuesto


Protoboard


Circuito impreso – PCB

Una imagen de la versión ensamblada en placa perforada:

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

2. Actuador Binario: Tomacorriente ESP-01

El dispositivo se enfoca en controlar un tomacorriente AC usando un relé, es presentado como base para el desarrollo de otros circuitos.

Premisas para el desarrollo del prototipo, versión 1:

  • Supone que ya se ha implementado un Broker MQTT
  • Dispone de Arduino IDE para cargar las instrucciones en el ESP9266-01
  • Dispone de una base para el desarrollo de dispositivos, verificando funcionamiento de WIFI y MQTT, en formato DIY (Do It Yourself)
  • Identifica otros elementos de desarrollo e inconvenientes para la implementación.
  • Usa diseños abiertos tipo: Open hardware y Open software
  • Usa componentes disponibles en el mercado local.
  • Considera alternativas para los componentes que solo se puedan conseguir por internet
  • Conecta dispositivos por medios inalámbricos.

Para activar el Sensor Binario en la plataforma con Raspberry, consulte la sección de Broker, donde se detallan las instrucciones.


Esquema de conexión:

Actuador Binario para controlar un elemento eléctrico AC de baja potencia como elemento complementario a un interruptor de control.

Por ejemplo, una luz iluminación y un interruptor de pared.

El actuador binario responde al interruptor de forma tradicional, sin embargo, al usar el Broker cambiará al estado deseado. El estado del interruptor físico puede volver a usarse para obtener el resultado deseado.

El límite de capacidad del dispositivo está dado por el Relé usado en el circuito.

Para activar el Sensor Binario en la plataforma con Rasberry, consulte la sección de Broker, donde se detallan las instrucciones.


Esquema Propuesto

La alimentación de energía se realiza con 110V AC. La reducción al voltaje de operación del ESP8266-01 se realiza en dos pasos: 5VDC y luego 3.3V DC, considerando la disponibilidad de:

  • Relé con voltaje de operación de 5V DC
  • Regulador de voltaje de 110V a 5 V DC

Protoboard

Para probar el circuito se puede armar en un protoboard.
Considere que solo por Esquema se incluye la parte de conexión AC, que se debe realizar separada y tomando las precauciones de aislamiento que correspondan.

Instrucciones Arduino

En este caso, como la versión del ESP8266-01 no dispone de muchos pines de trabajo, se usa como:

  • monitor de operación del dispositivo al LED interno (pin1 y TX)

Por el uso en operación de los pines de comunicación Serial (pines 1 y 3) se descartan las lineas Serial.print() convirtiéndolas en comentarios //.

A diferencia del modelo usado con el sensor binario, se requiere un pin adicional para la señal del actuador para controlar el Relé. Se seleccionó el PiN 2/GPIO_2 pues la configuración usada no presenta inconvenientes al momento del inicio del dispositivo en el modo requerido de trabajo: GPIO_0 y GPIO_2 en ALTO.

/*
 TOMACORRIENTE  | AC outlet
 Basic ESP8266 MQTT example with the ESP8266 board/library.
 Actuador Binario, para control de estado de una Luz.
 Para usar, se debe actualizar las secciones de:
 - WIFI datos para conexión a Router
 - MQTT: Servidor MQTT 
 - MQTT: identificador de dispositivo y topics
 Al usar ESP8266-01 se toman los pines TX para LED y GPI02 actuador
 por lo que se no se usa Serial.print(), con mesajes usado para depuración.
*/

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

// WIFI datos para conexión a Router
const PROGMEM char* ssid = "---";
const PROGMEM char* password = "---";

// MQTT: Servidor MQTT 
const PROGMEM char* MQTT_SERVER_IP = "192.168.xx.xxx";
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
const PROGMEM char* MQTT_USER = "username";
const PROGMEM char* MQTT_PASSWORD = "password";

// MQTT: identificador de dispositivo y topics
const PROGMEM char* MQTT_CLIENT_ID = "luz1";
const PROGMEM char* MQTT_SENSOR_TOPIC = "oficina/luz1/contact";
const PROGMEM char* MQTT_SENSOR_COMMAND_TOPIC = "oficina/luz1/switch";
const PROGMEM char* SENSOR_ON  = "ON";
const PROGMEM char* SENSOR_OFF = "OFF";
char MQTT_SENSOR_STATE[10] = "OFF"; // inicializa

// Actuador Switch Luz
const PROGMEM uint8_t ACTUADOR_pin = 2;

// LED monitor interno
const PROGMEM uint8_t LED_pin = 1; //ESP01-pin=1

// Control de tiempos
unsigned long antes = 0; 
const long intervalo = 300;

WiFiClient wifiClient;
PubSubClient client(wifiClient);

void setup() {
    // Conexion serial
    // Serial.begin(115200);

    // SENSOR Binario
    pinMode(SENSOR_pin, INPUT);
    attachInterrupt(digitalPinToInterrupt(SENSOR_pin),SensorActivado,CHANGE);
    
    // ACTUADOR Binario
    pinMode(ACTUADOR_pin, OUTPUT);
    digitalWrite(ACTUADOR_pin, HIGH);
    ACTUADORactivaestado();
    
    // LED monitor
    pinMode(LED_pin, OUTPUT);
    LEDactivaestado();
    
    // conexión WIFI y MQTT
    inicia_wifi();
    inicia_mqtt();
}

void loop() {
    if(WiFi.status() != WL_CONNECTED){
        inicia_wifi();
        }
    if (!client.connected()){
        inicia_mqtt();
        }
    client.loop();
    if (SENSOR_bandera){
        SENSOR_estado = digitalRead(SENSOR_pin);
        
        // Serial.println("Actualiza LED");
        LEDactivaestado();
        ACTUADORactivaestado();
        
        // actualiza estado del Sensor en MQTT
        if (SENSOR_estado){
            snprintf (MQTT_SENSOR_STATE,10, SENSOR_ON);
        }else{
            snprintf (MQTT_SENSOR_STATE,10, SENSOR_OFF);
        }
        // Serial.print("Sensor, estado: ");
        // Serial.println(MQTT_SENSOR_STATE);
        
        client.publish(MQTT_SENSOR_TOPIC,MQTT_SENSOR_STATE);
        client.subscribe(MQTT_SENSOR_COMMAND_TOPIC);

        SENSOR_bandera=false;
    }
    delay(10);
}

void inicia_wifi() {
    // conexion WiFi
    //Serial.print("\n Conectando a ");
    //Serial.println(ssid);
    WiFi.begin(ssid, password);
    int cuenta = 0;
    while (WiFi.status() != WL_CONNECTED){
        //Serial.print(".");
        cuenta = cuenta+1;
        if (cuenta>=40){
            //Serial.println();
            cuenta = 0;}
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(250);
        digitalWrite(LED_pin, HIGH);
        delay(250);
        }
    //Serial.print("\n WiFi conectado \n Dirección IP: ");
    //Serial.println(WiFi.localIP());
    delay(10);
}

void inicia_mqtt(){
    client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
    client.setCallback(callback);
    while (!client.connected()) {
        //Serial.println("\n Conectando a MQTT ");
        if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
            //Serial.println(" MQTT conectado");  
        } else {
            //Serial.print("Falló, estado: ");
            //Serial.print(client.state()); 
            //Serial.print(" , reintento en 5 segundos");
            // LED interno enciende en LOW
            for (int i=0;i<=5;i=i+1){
                digitalWrite(LED_pin, LOW);
                delay(600);
                digitalWrite(LED_pin, HIGH);
                delay(400);
            }
        }
    }
    client.publish(MQTT_SENSOR_TOPIC, MQTT_SENSOR_STATE);
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC);
}

// llega mensaje MQTT
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
    // convierte a cadena
    String payload;
    for (uint8_t i = 0; i < p_length; i++) {
        payload.concat((char)p_payload[i]);
        }
    // analiza mensaje por topico
    if (String(MQTT_SENSOR_COMMAND_TOPIC).equals(p_topic)) {
        if (payload.equals(String(SENSOR_ON))) {
            if (SENSOR_estado != true) {
                SENSOR_estado = true;
                LEDactivaestado();
                ACTUADORactivaestado();
                SENSORpublicaestado();
                }
        } else if (payload.equals(String(SENSOR_OFF))) {
            if (SENSOR_estado != false) {
                SENSOR_estado = false;
                LEDactivaestado();
                ACTUADORactivaestado();
                SENSORpublicaestado();
                }
        }
    }
}

// Publicar el estado del dispositivo
void SENSORpublicaestado() {
    if (SENSOR_estado) {
        client.publish(MQTT_SENSOR_TOPIC, SENSOR_ON, true);
    }else{
        client.publish(MQTT_SENSOR_TOPIC, SENSOR_OFF, true);
    }
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC);
    
}

// establece estado LED monitor en ESP8266
void LEDactivaestado(){
    if (SENSOR_estado){
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
    }else{
        digitalWrite(LED_pin, HIGH);
    }
}

3. Actuador/Sensor Binario ESP-01

Actuador Binario para controlar un elemento eléctrico AC de baja potencia como elemento complementario a un interruptor de control.

Por ejemplo, una luz iluminación y un interruptor de pared.

El actuador binario responde al interruptor de forma tradicional, sin embargo, al usar el Broker cambiará al estado deseado. El estado del interruptor físico puede volver a usarse para obtener el resultado deseado.

El límite de capacidad del dispositivo está dado por el Relé usado en el circuito.

Premisas para el desarrollo del prototipo, versión 1:

  • Supone que ya se ha implementado un Broker MQTT
  • Dispone de Arduino IDE para cargar las instrucciones en el ESP9266-01
  • Dispone de una base para el desarrollo de dispositivos, verificando funcionamiento de WIFI y MQTT, en formato DIY (Do It Yourself)
  • Identifica otros elementos de desarrollo e inconvenientes para la implementación.
  • Usa diseños abiertos tipo: Open hardware y Open software
  • Usa componentes disponibles en el mercado local.
  • Considera alternativas para los componentes que solo se puedan conseguir por internet
  • Conecta dispositivos por medios inalámbricos.

Para activar el Sensor Binario en la plataforma con Rasberry, consulte la sección de Broker, donde se detallan las instrucciones.


Esquema Propuesto

La alimentación de energía se realiza con 110V AC. La reducción al voltaje de operación del ESP8266-01 se realiza en dos pasos: 5VDC y luego 3.3V DC, considerando la disponibilidad de:

  • Relé con voltaje de operación de 5V DC
  • Regulador de voltaje de 110V a 5 V DC

Se podría simplificar el uso del reductor de voltaje de 5V a 3.3V en caso de disponer en el mercado local de un Relé de 3.3v y de disponer del componente HLK-PM03, que realiza la reducción completa hasta 3.3V.

Como el diseño está realizado en modo DiY (Do it Yourself) para armar, se usaron únicamente los componentes disponibles.

Para la operación del Relé se usó un optoacoplador que permite acoplar la salida digital del ESP8266 con la corriente demandada por la operación del Relé de aproximadamente 10mA.

El optoacoplador opera un transistor que controla la corriente que activa el Relé. La configuración permite acoplar otros Relés con otros voltajes de operación usados para aplicaciones de mayor carga, incluso con fuentes de alimentación se mayor voltaje y separadas del circuito.

Alternativas a componentes

Se comprobó el funcionamiento sustituyendo el regulador de 110VAC a 5V por un cargador USB a 5V de los usado para teléfonos celulares.
Considere que se midieron voltajes aproximados a 5V DC

No fue posible durante la semana de desarrollo obtener localmente un HLK-PM-01 y un regulador DC de 5V a 3.3 V. De se optó por usar diodos para disminuir el voltaje hasta lo requerido.

Otras opciones para 5V a 3.3V:

  • usar diodos Zener de 3.3V
  • conexión de diodos en modo de paso para caídas de 0.7V por cada diodo.

Protoboard

Para probar el circuito se puede armar en un protoboard.
Considere que solo por Esquema se incluye la parte de conexión AC, que se debe realizar separada y tomando las precauciones de aislamiento que correspondan.


Circuito impreso – PCB

Se adjunta la imagen de la placa del circuito impreso realizada con Fritzing en vista superior.

Para el archivo de producción de placa, escribir al email de contacto al final de la página.

Alternativas durante el proceso de desarrollo

Durante el desarrollo del prototipo se usó placas perforadas de circuito impreso de 5×9 cm.

Luego de algunas pruebas, se dispondrá del diseño mejorado y se actualizará la versión 1 del circuito impreso.


Instrucciones Arduino

En éste caso, como la versión del ESP8266-01 no dispone de muchos pines de trabajo, se usa como:

  • monitor de operación del dispositivo al LED interno (pin1 y TX)
  • sensor el pin 3 que también puede ser configurado como RX

Por el uso en operación de los pines de comunicación Serial (pines 1 y 3) se descartan las líneas Serial.print() convirtiéndolas en comentarios //.

A diferencia del modelo usado con el sensor binario, se requiere un pin adicional para la señal del actuador para controlar el Relé. Se seleccionó el PiN 2/GPIO_2 pues la configuración usada no presenta inconvenientes al momento del inicio del dispositivo en el modo requerido de trabajo: GPIO_0 y GPIO_2 en ALTO.

La carga del archivo.ino se la realiza fuera del circuito. Una vez cargado el script se inserta el ESP8266 en la placa.

Las instrucciones para iniciar WIFI y MQTT se realizaron de forma separada en funciones  como base para otros dispositivos.

Para procesar las instrucciones enviadas por el Broker en MQTT se amplía la función callback.

Para el control del Relé se usa la función ACTUADORactivaestado() que realiza acciones semejantes a la de activar el monitor LED, y permite en futuro mantener separadas las acciones sobre el ACTUADOR o Relé.

/*
 TOMACORRIENTE E INTERRUPTOR | AC outlet and wall switch
 Basic ESP8266 MQTT example with the ESP8266 board/library.
 Actuador/Sensor Binario, para control de estado de una Luz.
 Para usar, se debe actualizar las secciones de:
 - WIFI datos para conexión a Router
 - MQTT: Servidor MQTT 
 - MQTT: identificador de dispositivo y topics
 Al usar ESP8266-01 se toman los pines TX para LED y RX para el sensor, GPI02 actuador
 por lo que se no se usa Serial.print(), con mesajes usado para depuración.
*/

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

// WIFI datos para conexión a Router
const PROGMEM char* ssid = "----";
const PROGMEM char* password = "----";

// MQTT: Servidor MQTT 
const PROGMEM char* MQTT_SERVER_IP = "192.168.x.x";
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
const PROGMEM char* MQTT_USER = "username";
const PROGMEM char* MQTT_PASSWORD = "password";

// MQTT: identificador de dispositivo y topics
const PROGMEM char* MQTT_CLIENT_ID = "luz1";
const PROGMEM char* MQTT_SENSOR_TOPIC = "oficina/luz1/contact";
const PROGMEM char* MQTT_SENSOR_COMMAND_TOPIC = "oficina/luz1/switch";
const PROGMEM char* SENSOR_ON  = "ON";
const PROGMEM char* SENSOR_OFF = "OFF";
char MQTT_SENSOR_STATE[10] = "OFF"; // inicializa

// Sensor Switch Luz
const PROGMEM uint8_t SENSOR_pin = 3;
volatile boolean SENSOR_estado = false;
volatile boolean SENSOR_bandera = false;

// Actuador Switch Luz
const PROGMEM uint8_t ACTUADOR_pin = 2;

// LED monitor interno
const PROGMEM uint8_t LED_pin = 1; //ESP01-pin=1

// Control de tiempos
unsigned long antes = 0; 
const long intervalo = 300;

WiFiClient wifiClient;
PubSubClient client(wifiClient);

void setup() {
    // Conexion serial
    // Serial.begin(115200);

    // SENSOR Binario
    pinMode(SENSOR_pin, INPUT);
    attachInterrupt(digitalPinToInterrupt(SENSOR_pin),SensorActivado,CHANGE);
    
    // ACTUADOR Binario
    pinMode(ACTUADOR_pin, OUTPUT);
    digitalWrite(ACTUADOR_pin, HIGH);
    ACTUADORactivaestado();
    
    // LED monitor
    pinMode(LED_pin, OUTPUT);
    LEDactivaestado();
    
    // conexión WIFI y MQTT
    inicia_wifi();
    inicia_mqtt();
}

void loop() {
    if(WiFi.status() != WL_CONNECTED){
        inicia_wifi();
        }
    if (!client.connected()){
        inicia_mqtt();
        }
    client.loop();
    if (SENSOR_bandera){
        SENSOR_estado = digitalRead(SENSOR_pin);
        
        // Serial.println("Actualiza LED");
        LEDactivaestado();
        ACTUADORactivaestado();
        
        // actualiza estado del Sensor en MQTT
        if (SENSOR_estado){
            snprintf (MQTT_SENSOR_STATE,10, SENSOR_ON);
        }else{
            snprintf (MQTT_SENSOR_STATE,10, SENSOR_OFF);
        }
        // Serial.print("Sensor, estado: ");
        // Serial.println(MQTT_SENSOR_STATE);
        
        client.publish(MQTT_SENSOR_TOPIC,MQTT_SENSOR_STATE);
        client.subscribe(MQTT_SENSOR_COMMAND_TOPIC);

        SENSOR_bandera=false;
    }
    delay(10);
}

void inicia_wifi() {
    // conexion WiFi
    //Serial.print("\n Conectando a ");
    //Serial.println(ssid);
    WiFi.begin(ssid, password);
    int cuenta = 0;
    while (WiFi.status() != WL_CONNECTED){
        //Serial.print(".");
        cuenta = cuenta+1;
        if (cuenta>=40){
            //Serial.println();
            cuenta = 0;}
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(250);
        digitalWrite(LED_pin, HIGH);
        delay(250);
        }
    //Serial.print("\n WiFi conectado \n Dirección IP: ");
    //Serial.println(WiFi.localIP());
    delay(10);
}

void inicia_mqtt(){
    client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
    client.setCallback(callback);
    while (!client.connected()) {
        //Serial.println("\n Conectando a MQTT ");
        if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
            //Serial.println(" MQTT conectado");  
        } else {
            //Serial.print("Falló, estado: ");
            //Serial.print(client.state()); 
            //Serial.print(" , reintento en 5 segundos");
            // LED interno enciende en LOW
            for (int i=0;i<=5;i=i+1){
                digitalWrite(LED_pin, LOW);
                delay(600);
                digitalWrite(LED_pin, HIGH);
                delay(400);
            }
        }
    }
    client.publish(MQTT_SENSOR_TOPIC, MQTT_SENSOR_STATE);
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC);
}

// llega mensaje MQTT
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
    // convierte a cadena
    String payload;
    for (uint8_t i = 0; i ≪ p_length; i++) {
        payload.concat((char)p_payload[i]);
        }
    // analiza mensaje por topico
    if (String(MQTT_SENSOR_COMMAND_TOPIC).equals(p_topic)) {
        if (payload.equals(String(SENSOR_ON))) {
            if (SENSOR_estado != true) {
                SENSOR_estado = true;
                LEDactivaestado();
                ACTUADORactivaestado();
                SENSORpublicaestado();
                }
        } else if (payload.equals(String(SENSOR_OFF))) {
            if (SENSOR_estado != false) {
                SENSOR_estado = false;
                LEDactivaestado();
                ACTUADORactivaestado();
                SENSORpublicaestado();
                }
        }
    }
}

// Publicar el estado del dispositivo
void SENSORpublicaestado() {
    if (SENSOR_estado) {
        client.publish(MQTT_SENSOR_TOPIC, SENSOR_ON, true);
    }else{
        client.publish(MQTT_SENSOR_TOPIC, SENSOR_OFF, true);
    }
    client.subscribe(MQTT_SENSOR_COMMAND_TOPIC);
    
}

// establece estado LED monitor en ESP8266
void LEDactivaestado(){
    if (SENSOR_estado){
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
    }else{
        digitalWrite(LED_pin, HIGH);
    }
}
// establece estado LED monitor en ESP8266
void ACTUADORactivaestado(){
    if (SENSOR_estado){
        // ACTURADOR ACTIVA EN LOW
        digitalWrite(ACTUADOR_pin, LOW);
    }else{
        digitalWrite(ACTUADOR_pin, HIGH);
    }
}

// ISR interrupción activada
void SensorActivado(){
    // Serial.println("ISR activada");
    unsigned long ahora = millis();
    if((ahora - antes)> intervalo) {
        antes = ahora;
        SENSOR_bandera = true;
    }
}

Temas para desarrollo posterior

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

Analizar consumos de corriente para uso con baterías.

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


implementación versión 1

Usando placas perforadas para el prototipo, se controla un tomacorriente que tiene conectada una lámpara de escritorio. El interruptor opera normalmente, en conjunto con el dispositivo.

Todas las partes se integraron en una caja eléctrica sin inconvenientes de espacio.

De implementar la placa del circuito PCB, el espacio usado es menor.

Se usó un circuito de cargador de celular, por disponibilidad inmediata en lugar del HLK-PM-01.

1. Sensor Binario Puerta-Ventana ESP-01

Sensor binario para registrar el estado abierto o cerrado de una puerta o ventana.

El dispositivo es de tipo inalámbrico, WIFI, usa protocolo MQTT para comunicación con el broker y es implementado con ESP8266 versión ESP-01

Premisas para el desarrollo del prototipo, versión 1:

  • Supone que ya se ha implementado un Broker MQTT
  • Dispone de Arduino IDE para cargar las instrucciones en el ESP9266-01
  • Dispone de una base para el desarrollo de dispositivos, verificando funcionamiento de WIFI y MQTT, en formato DIY (Do It Yourself)
  • Identifica otros elementos de desarrollo e inconvenientes para la implementación.
  • Usa  diseños abiertos tipo: Open Hardware y Open Software
  • Usa componentes disponibles en el mercado local.
  • Considera alternativas para los componentes que solo se puedan conseguir por internet
  • Conecta dispositivos por medios inalámbricos.

Para activar el Sensor Binario en la plataforma con Raspberry, consulte la sección de Broker, donde se detallan las instrucciones.


Esquema Propuesto

La alimentación de energía se realiza con 110V AC. Se requiere usar un regulador de voltaje para llegar hasta a 3.3V DC que es el voltaje de operación del ESP8266-01.

Por disponibilidad de componentes, la implementación se realiza dos pasos:

  •  Reducción de 110V AC a 5V DC
  •  Reducción de 5V DC a 3.3V DC

Los pasos se pueden simplificar si se dispone del componente HLK-PM03, que realiza la reducción completa hasta 3.3V.

Alternativas a componentes

Se comprobó el funcionamiento sustituyendo el regulador de 110VAC a 5V por un cargador USB a 5V de los usado para teléfonos celulares.
Considere que se midieron voltajes aproximados a 5V DC

No fué posible durante la semana de desarrollo obtener localmente un HLK-PM-01 y un regulador DC de 5V  a 3.3 V. De se optó por usar diodos para disminuir el voltaje hasta lo requerido.

Otra opciónes para 5V a 3.3V:

  • usar diodos Zener de 3.3V
  • conección de diodos en modo de paso para caidas de 0.7V por cada diodo.

Protoboard

Para probar el circuito se puede armar en un protoboard.
Considere que solo por Esquema se incluye la parte de conexión AC, que se debe realizar separada y tomando las precauciones de aislamiento que correspondan.


Circuito impreso – PCB

Se adjunta la imagen de la placa del circuito impreso realizada con Fritzing en vista superior.

Para el archivo de producción de placa, escribir al email de contacto al final de la página.

Alternativas durante el proceso de desarrrollo

Durante el desarrollo del prototipo se usó una placas perforadas de circuito impreso de 4×6 cm.

Luego de algunas pruebas, se dispondrá del diseño mejorado y se actualizará la versión 1 del circuito impreso.


Instrucciones Arduino

En éste caso, como la versión del ESP8266-01 no dispone de muchos pines de trabajo, se usa como:

  • monitor de operación del dispositivo al LED interno, pin1 (TX)
  • sensor el pin 3 que también puede ser configurado como RX

Por el uso en operación de los pines de comunicación Serial (pines 1 y 3) se descartan las lineas Serial.print() convirtiendolas en comentarios //.

La carga del archivo.ino se la realiza fuera del circuito. Una vez cargado el script se inserta el ESP8266 en la placa.

Las instrucciones para iniciar WIFI y MQTT se realizaron de forma separada en funciones como base para otros dispositivos.

/*
 Basic ESP8266 MQTT example with the ESP8266 board/library.
 Sensor Binario, para control de estado de puerta/ventana.
 Para usar, se debe actualizar las secciones de:
 - WIFI datos para conexión a Router
 - MQTT: Servidor MQTT 
 - MQTT: identificador de dispositivo y topics
 Al usar ESP8266-01 se toman los pines TX para LED y RX para el sensor,
 por lo que se no se usa Serial.print(), con mesajes usador para depuración.
*/

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

// WIFI datos para conexión a Router
const PROGMEM char* ssid = "xxxx";
const PROGMEM char* password = "xx";

// MQTT: Servidor MQTT 
const PROGMEM char* MQTT_SERVER_IP = "192.168.xx.xxx";
const PROGMEM uint16_t MQTT_SERVER_PORT = 1883;
const PROGMEM char* MQTT_USER = "username"; // sustituir
const PROGMEM char* MQTT_PASSWORD = "password";

// MQTT: identificador de dispositivo y topics
const PROGMEM char* MQTT_CLIENT_ID = "Sensor Puerta 1";
const PROGMEM char* MQTT_SENSOR_TOPIC = "oficina/puerta1/contact";
const PROGMEM char* SENSOR_ON  = "ON";
const PROGMEM char* SENSOR_OFF = "OFF";
char MQTT_SENSOR_STATE[10] = "OFF"; // inicializa

// Sensor puerta
const PROGMEM uint8_t SENSOR_pin = 3;
volatile boolean SENSOR_estado = false;
volatile boolean SENSOR_bandera = false;

// LED monitor interno
const PROGMEM uint8_t LED_pin = 1;

// Control de tiempos
unsigned long antes = 0; 
const long intervalo = 300;

WiFiClient wifiClient;
PubSubClient client(wifiClient);

void setup() {
    // Conexion serial
    // Serial.begin(115200);
       
    // SENSOR Binario
    pinMode(SENSOR_pin, INPUT);
    attachInterrupt(digitalPinToInterrupt(SENSOR_pin),SensorActivado,CHANGE);
    
    // LED monitor
    pinMode(LED_pin, OUTPUT);
    LEDactivaestado();

    // conexión WIFI y MQTT
    inicia_wifi();
    inicia_mqtt();
}

void loop() {
    if(WiFi.status() != WL_CONNECTED){
        inicia_wifi();
        }
    if (!client.connected()){
        inicia_mqtt();
        }
    client.loop();
    if (SENSOR_bandera){
        SENSOR_estado = digitalRead(SENSOR_pin);
        
        // Serial.println("Actualiza LED");
        LEDactivaestado();
        
        // actualiza estado del Sensor en MQTT
        if (SENSOR_estado){
            snprintf (MQTT_SENSOR_STATE,10, SENSOR_ON);
        }else{
            snprintf (MQTT_SENSOR_STATE,10, SENSOR_OFF);
        }
        // Serial.print("Sensor, estado: ");
        // Serial.println(MQTT_SENSOR_STATE);
        
        client.publish(MQTT_SENSOR_TOPIC,MQTT_SENSOR_STATE);
        //client.subscribe(MQTT_SENSOR_TOPIC);

        SENSOR_bandera=false;
    }
    delay(10);
}

void inicia_wifi() {
    // conexion WiFi
    // Serial.print("\n Conectando a ");
    // Serial.println(ssid);
    WiFi.begin(ssid, password);
    int cuenta = 0;
    while (WiFi.status() != WL_CONNECTED){
        // Serial.print(".");
        cuenta = cuenta+1;
        if (cuenta>=40){
            // Serial.println();
            cuenta = 0;}
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
        delay(250);
        digitalWrite(LED_pin, HIGH);
        delay(250);
        }
    // Serial.print("\n WiFi conectado \n Dirección IP: ");
    // Serial.println(WiFi.localIP());
    delay(10);
}

void inicia_mqtt(){
    client.setServer(MQTT_SERVER_IP, MQTT_SERVER_PORT);
    client.setCallback(callback);
    while (!client.connected()) {
        // Serial.println("\n Conectando a MQTT ");
        if (client.connect(MQTT_CLIENT_ID, MQTT_USER, MQTT_PASSWORD)) {
            // Serial.println(" MQTT conectado");  
        } else {
            // Serial.print("Falló, estado: ");
            // Serial.print(client.state()); 
            // Serial.print(" , reintento en 5 segundos");
            // LED interno enciende en LOW
            for (int i=0;i<=5;i=i+1){
                digitalWrite(LED_pin, LOW);
                delay(600);
                digitalWrite(LED_pin, HIGH);
                delay(400);
            }
        }
    }
    client.publish(MQTT_SENSOR_TOPIC, MQTT_SENSOR_STATE);
    // client.subscribe(MQTT_SENSOR_TOPIC);
}

void callback(char* topic, byte* payload, unsigned int length) {
    // Serial.print("\n MQTT Mensaje :");
    // Serial.print(topic);
    // Serial.print(" , ");
    for (int i = 0; i < length; i++) {
        // Serial.print((char)payload[i]);
    }
    // Serial.println();
    // client.subscribe(MQTT_SENSOR_TOPIC);
}

// establece estado LED monitor en ESP8266
void LEDactivaestado(){
    if (SENSOR_estado){
        // LED interno enciende en LOW
        digitalWrite(LED_pin, LOW);
    }else{
        digitalWrite(LED_pin, HIGH);
    }
}

// ISR interrupción activada
void SensorActivado(){
    // Serial.println("ISR activada");
    unsigned long ahora = millis();
    if((ahora - antes)> intervalo) {
        antes = ahora;
        SENSOR_bandera = true;
    }
}

Temas para desarrollo posterior

  • Otros dispositivos, actuadores
    Ampliar la forma de carga de scripts en el tablero, de forma alámbrica o inalámbrica.
  • Analizar consumos de corriente para uso con baterías.
  • Revisar el uso de los canales WIFI para evitar desconexiones por saturación de canal.

implementación versión 1

Instalado en una caja eléctrica en una puerta.