5.3 IoT WiFi Control Remoto IR: Archivo.ino

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 boton config_IR, una vez presionado espera hasta recibir una señal infraroja que se lee, y graba.
  • el Envío de la señal se realiza con la instrucción MQTT o  desde Home Assistant
  • Usa el LED_LeeIR  como indicador de estado de lectura o activación de 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
/* ESP8266 IRremoteESP8266: Receptor Infrarojo
 * edelros@espol.edu.ec
 * Debe usar un sensor detector/demodulador conectado al Receptor_Pin.
 *   Based on Mark Szabo's Version 0.2 June, 2017 and
 *   Ken Shirriff's IrsendDemo Version 0.1 July, 2009
 *   https://github.com/markszabo/IRremoteESP8266 
*  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 <PubSubClient.h>

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

#include <EEPROM.h>

#include <DHT.h>

// WIFI: conexión a Router
char* ssid = "giotirni20";
char* password = "Anera2020@";

// MQTT: Servidor
char* MQTT_IP = "192.168.10.50";
uint16_t MQTT_puerto = 1883;
char* MQTT_usuario = "usuarioprueba";
char* MQTT_contrasena = "usuarioclave";

// MQTT: Dispositivo Interruptor
char* MQTT_ID = "oficina_CtrlIR01";
char* MQTT_TOPIC = "oficina/CtrlIR01/estado";
char* MQTT_COMMAND = "oficina/CtrlIR01/cambia";

char* MQTT_TOPIC_T = "oficina/CtrlIR01/temperatura";
char* MQTT_TOPIC_H = "oficina/CtrlIR01/humedad";
char* MQTT_COMMAND_DHT = "oficina/CtrlIR01/actualiza";

char* MQTT_TOPIC_LeeIR = "oficina/CtrlIR01/leer";
char* MQTT_COMMAND_LeeIR = "oficina/CtrlIR01/grabar";

char MQTT_SensorEstado[10] = "OFF";
char MQTT_ActuadorEstado[10] = "OFF";
char MQTT_DHT_T[6] = "25"; // inicializa
char MQTT_DHT_H[6] = "50"; // inicializa
char MQTT_LeeIR[6] = "0"; // inicializa
volatile boolean mqtt_desconectado = true;

char* sensor_ON  = "ON";
char* sensor_OFF = "OFF";

// Actuador Control Remoto Emisor LED-IR en GPIO14
const uint8_t emisorIR_pin = 14;
uint32_t senal_ONOFF = 0xFF5AA5; // código de control
volatile boolean actuador_estado = false;
volatile boolean actuador_bandera = false;

// Sensor IR en GPIO05
const uint8_t receptorIR_pin = 5;
volatile boolean LeerIR_estado = false;
volatile boolean LeerIR_bandera = false;

// Boton de lectura y emitir IR
const uint8_t config_pin = 12;
const uint8_t emitir_pin = 0;

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

// Mensajes por Puerto Serial
volatile boolean serial_msg = true;

// Control de tiempo transcurrido entre lecturas temperatura
unsigned long ahora = millis();
const long intervalo = 5*60*1000;//minutos*60s*1000ms
unsigned long antes = ahora-intervalo-1; //leer al inicio

// Clientes WiFi y MQTT
WiFiClient wifiClient;
PubSubClient mqttclient(wifiClient);

// Receptor y Emisor Infrarojos
IRrecv irrecv(receptorIR_pin);
decode_results lecturaIR;
IRsend irsend(emisorIR_pin);

// Sensor de Temperatura&Humedad
#define DHTPIN 4
#define DHTTYPE   DHT11
DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(74880);//74880, 115200
  while (!Serial){delay(50);}
  
  // SENSOR IR // inicia receptor IR
  irrecv.enableIRIn(); 
  pinMode(LED_LeerIR, OUTPUT);
  Leer_Activaestado();
    
  // ACTUADOR IR // inicia emisor IR
  pinMode(emisorIR_pin, OUTPUT); 
  irsend.begin();

  // SENSOR Temperatura&Humedad
  dht.begin();
  
  // LED monitor, Enciende en LOW
  pinMode(LED_pin, OUTPUT);

  // Memoria lectura y escritura
  EEPROM.begin(64); //eeprom maximo 512 posiciones
  codigo_leermem();

  // Boton de lectura de código IR
  pinMode(config_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(config_pin),LeerActivado,CHANGE);

  // Boton de Emisor de código IR
  pinMode(emitir_pin, INPUT);
  attachInterrupt(digitalPinToInterrupt(emitir_pin),IR_Activado,CHANGE);
  
  // conexión WIFI y MQTT
  inicia_wifi();
  if (WiFi.status() == WL_CONNECTED){
    inicia_mqtt();
    }
  }

void loop() {
  // enviar señal IR
  if (actuador_bandera){
    irsend.sendNEC(senal_ONOFF ,32);
    // parpadeo
    digitalWrite(LED_LeerIR, LOW);
    delay(300);
    digitalWrite(LED_LeerIR, HIGH);
    delay(200);
    digitalWrite(LED_LeerIR, LOW);
    delay(300);
    digitalWrite(LED_LeerIR, HIGH);
    delay(200);
    // deja en estado anterior el LED Leer_IR
    Leer_Activaestado();
    publica_estado();
    actuador_bandera = false;
    
    if (serial_msg==true){
      Serial.print("\n Señal IR enviada: ");
      serialPrintUint64(senal_ONOFF, HEX);
      Serial.println("");
      }

    }
  yield(); // procesa wifi

  // Sensor IR, leer código
  if(LeerIR_bandera){
    if (irrecv.decode(&lecturaIR)) {
      // conversión a texto
      uint64_t numero = lecturaIR.value;
      unsigned long parte1 = (unsigned long)((numero & 0xFFFF0000) >> 16 );
      unsigned long parte2 = (unsigned long)((numero & 0x0000FFFF));
      String texto = String(parte1, HEX) + String(parte2, HEX);
      texto.toUpperCase();
      senal_ONOFF = lecturaIR.value;
      
      // Escribe a memoria EEPROM    
      // escribe a eeprom
      texto = texto+";"; //marca fin de texto
      int n = texto.length();
      int posicion = 0;
      int i = posicion;
      while(i<n){
        EEPROM.write(i,texto[i]);
        i=i+1;
        }
      EEPROM.commit();
      irrecv.resume();
       
      LeerIR_bandera = false;
      LeerIR_estado = false;

      publica_estado();
      Leer_Activaestado();
      
      if (serial_msg==true){
        Serial.print("\n lecturaIR:       ");
        // print() & println() no maneja enteros largos(uint64_t)
        serialPrintUint64(lecturaIR.value, HEX);
        Serial.println("");
        Serial.print(" grabado en memoria:   ");
        Serial.println(texto);
        }
    }
  }

  yield(); // procesa wifi
  
  // lectura Temperatura,Humedad
  unsigned long ahora = millis();
  unsigned long transcurre = ahora-antes;
  if (transcurre>=intervalo){
    antes = ahora;
    delay(50);
    // calibrar con una referencia más precisa
    // modo simple: resta factor de corrección=5
    float temperatura = dht.readTemperature();
    float humedad = dht.readHumidity();
    // convierte a texto mqtt; a 4 dígitos, 2 decimales
    dtostrf(temperatura, 4, 2, MQTT_DHT_T);  
    dtostrf(humedad, 4, 2, MQTT_DHT_H);
    publica_estado();
    
    if (serial_msg==true){
      Serial.print("\n tiempo: ");
      Serial.println(transcurre);
      Serial.print(" Temperatura,Humedad: ");
      Serial.print(MQTT_DHT_T);
      Serial.print(" , ");
      Serial.println(MQTT_DHT_H);
      Serial.println();
      }
    }
    
  yield(); // procesa wifi
  
  if (WiFi.status() != WL_CONNECTED){
    inicia_wifi();
    }else{
    if (mqttclient.connected()==false){
        mqtt_desconectado = true;
        inicia_mqtt(); // reintento
      }
    if (mqttclient.connected()==true){
      if (mqtt_desconectado==true){
        publica_estado();
        mqtt_desconectado=false;
        }
      mqttclient.loop();
      }
    }
  yield(); // procesa wifi
}

void codigo_leermem(){
  // lectura desde eeprom, codigo on/off
  int posicion = 0;
  int n = posicion+10;
  String codigotxt = "";
  char simbolo;
  int i = posicion;
  while(i<n){
    simbolo = char(EEPROM.read(i));
    if (simbolo!=';'){
      codigotxt = codigotxt+String(simbolo);
      }else{
        i=n; // terminar lectura antes
      }
    i=i+1;
    }
  // conversión de codigotxt a HEX
  char codigochar[64];
  codigotxt.toCharArray(codigochar, n);
  uint32_t codigoIRhex = strtoul(codigochar, 0, 16);
  // actualiza variable
  senal_ONOFF = codigoIRhex;
  if (serial_msg==true){
    Serial.print("texto leido:     ");
    Serial.println(codigotxt);
    Serial.print("codigo IR eprom: ");
    // print() & println() no maneja enteros largos(uint64_t)
    serialPrintUint64(senal_ONOFF, HEX);
    Serial.println("\n");
    }
  }

// ISR interrupción activada
ICACHE_RAM_ATTR void LeerActivado(){
  // evita repeticiones por rebotes del botonera
  if (LeerIR_bandera==false){
    LeerIR_bandera = true;
    LeerIR_estado = true;
    Leer_Activaestado();
    publica_estado();
    if (serial_msg){
      Serial.println(" Leer IR activado...");
      }
    }
  }
ICACHE_RAM_ATTR void IR_Activado(){
  // evita repeticionese por rebotes del botonera
  if (actuador_bandera ==false){
    actuador_bandera = true;
    if (actuador_estado == true) {
      actuador_estado = false;
      }else{
      actuador_estado = true;
      }
    publica_estado();
    if (serial_msg){
      Serial.println(" IR_envío activado...");
      }
    }
  }

// Actuador activar estado
void Leer_Activaestado(){
    if (LeerIR_estado){
      // ACTUADOR ACTIVA EN LOW
      // LED actuador ilumina en apagado
      digitalWrite(LED_LeerIR, LOW);
    }else{
      digitalWrite(LED_LeerIR, HIGH);
    }
  }

// Publicar el estado del dispositivo
void publica_estado() {
    if (actuador_estado){
      snprintf (MQTT_ActuadorEstado,10, sensor_ON);
    }else{
      snprintf (MQTT_ActuadorEstado,10, sensor_OFF);
    }
    if (LeerIR_estado){
      snprintf (MQTT_LeeIR,10, sensor_ON);
    }else{
      snprintf (MQTT_LeeIR,10, sensor_OFF);
    }
    if (mqttclient.connected()==true){
      mqttclient.publish(MQTT_TOPIC,MQTT_ActuadorEstado,true);
      mqttclient.publish(MQTT_TOPIC_LeeIR,MQTT_LeeIR,true);
      mqttclient.publish(MQTT_TOPIC_T,MQTT_DHT_T,true);
      mqttclient.publish(MQTT_TOPIC_H,MQTT_DHT_H,true);
    }else{
      mqtt_desconectado = true;
    }
}

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){
    //Fin de "..."
    Serial.println();
    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();
      }
    }
  }

void inicia_mqtt(){
  int intentos = 2;
  int cuenta = 0;
  
  if (serial_msg){
    Serial.print(" MQTT Conectando a ");
    Serial.println(MQTT_IP);
    }
  
  mqttclient.setServer(MQTT_IP, MQTT_puerto);
  mqttclient.connect(MQTT_ID, MQTT_usuario, MQTT_contrasena);
  mqttclient.setCallback(callback);
  
  while (!mqttclient.connected() && (cuenta<intentos)) {

    if (serial_msg){
      Serial.print(".");
    }
    
    cuenta = cuenta + 1;
    // Parpadeo de Monitor enciende en LOW
    digitalWrite(LED_pin, LOW);
    delay(200);
    digitalWrite(LED_pin, HIGH);
    delay(200);
    }
  publica_estado();
  mqttclient.subscribe(MQTT_COMMAND);
  mqttclient.subscribe(MQTT_COMMAND_LeeIR);
  mqttclient.subscribe(MQTT_COMMAND_DHT);
  
  if (serial_msg){
    //Fin de "..."
    Serial.println();
    Serial.print(" MQTT Conectado: ");
    Serial.println(mqttclient.connected());
    Serial.print(" MQTT Estado: ");
    Serial.println(mqttclient.state());
    }
  }

// llega mensaje MQTT
void callback(char* p_topic, byte* p_payload, unsigned int p_length) {
  // convierte a texto
  String payload;
  for (uint8_t i = 0; i < p_length; i++) {
    payload.concat((char)p_payload[i]);
    }
  // revisa mensaje por topico
  if (String(MQTT_COMMAND).equals(p_topic)) {
    if (payload.equals(String(sensor_ON))) {
      if (actuador_estado != true) {
        actuador_estado = true;
        }
      }
    if (payload.equals(String(sensor_OFF))) {
      if (actuador_estado != false) {
          actuador_estado = false;
        }
      }
    Leer_Activaestado();
    publica_estado();
    actuador_bandera = true;
    }

  if (String(MQTT_COMMAND_LeeIR).equals(p_topic)) {
    if (payload.equals(String(sensor_ON))) {
      if (LeerIR_estado != true) {
        LeerIR_estado = true;
        }
      }
    if (payload.equals(String(sensor_OFF))) {
      if (LeerIR_estado != false) {
          LeerIR_estado = false;
        }
      }
    LeerIR_bandera = true;
    Leer_Activaestado();
    publica_estado();
    }
  if (String(MQTT_COMMAND_DHT).equals(p_topic)) {
    antes = antes-(intervalo+2);
    }
  }