8. Sensor/Emisor Infrarojo ESP-07

1. Incorporar el dispositivo en Home Assistant

Actualizar el archivo de configuration.yaml

el archivo se encuentra en: /homeassistant/.homeassistant/configuration.yaml

Se modifica el archivo de configuración, añadiendo los datos del sensor en el servidor MQTT y se actualiza  la página de gestión luego de reiniciar el programa. (configuration, restart)

switch:
  - platform: mqtt
    name: 'CR01 enciende'
    command_topic: 'oficina/CR01/enciende/set'
    optimistic: false

  - platform: mqtt
    name: 'CR01 lectura'
    command_topic: 'oficina/CR01/lectura/set'
    optimistic: false

además de lo necesario para incorporar la parte del sensor de temperatura y humedad.

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.

 

ESP07 IR Emisor

El circuito permite la emisión de una señal infraroja semejante a un control remoto usando el módulo ESP07-ESP8266. El código infrarojo emitido corresponde al obtenido en el ejemplo del receptor infrarojo.

Com emisor se usa un LED IR, complementado con un transistor para aumentar la cantidad de corriente. El el puerto GPIO05 no es suficiente para obtener distancias de transmisión de la señal muy lejanas.

El esquemático muestra lo sencillo de la conexión del emisor infrarojo:

Protoboard

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

Instrucciones

Se usan las librerias Arduino IRremoteESP8266 como base para un dispositivo de control remoto con Home Assistant.

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

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

#define LED_pin 2 // ESP8266 LED interno
#define IR_LED 5  // ESP8266 GPIO pin para emisor
IRsend irsend(IR_LED);  // configura emisor
uint32_t Avanti_ONOFF = 0xFF5AA5; // código de control

void setup() {
    Serial.begin(115200);
    pinMode(LED_pin, OUTPUT);
    
    irsend.begin();
}

void loop() {
    Serial.println("Enciende/Apaga control remoto Avanti");
    // Parpadeo LED interno
    digitalWrite(LED_pin, LOW);
    delay(1000); // Esperar un segundo
    digitalWrite(LED_pin, HIGH);
    delay(1000); // Esperar un segundo
  
    irsend.sendNEC(Avanti_ONOFF,32);
    delay(4000);// tiempo antes de apagar dispositivo
}

Las pruebas de funcionamiento se realizan de dos formas:

1. Usando una cámara digital del móvil celular, para verificar que el LED IR parpadea, se puede ver en la pantalla que el LED enciente.

2. apuntando el led al dispositivo que activa el control remoto y usado en el ejemplo del receptor.

El siguiente paso es integrar el receptor y el emisor para el control mediante el servidor MQTT-Mosquitto.

ESP07 IR detector/demodulador

El ejemplo realiza la detección de señal de un control remoto infrarojo con el módulo ESP07-ESP8266 y muestra el resultado Hexadecimal en el Monitor Serial. Cada tecla del control remoto genera un código único que es detectado con el sensor.

Para el ejemplo se usa un TSOP382.., TSOP384, o alguna versión que incluya el circuito de demodulación. La versión del sensor infrarojo con detección y demodulación simplifica el circuito a un pin digital configurado como entrada en el módulo a usar, además de Vcc y Gnd.

El esquemático muestra lo sencillo de la conexión del sensor infrarojo para su lectura.

Protoboard

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

Lectura de datos

Para un control remoto dado, por ejemplo el básico para arduino, se obtienen los diferentes códigos en Hexadecimal de las teclas presionadas usando el monitor serial.

FF5AA5
FF5AA5

Si usa un ESP07 en versión 8285, puede ser necesario configurar los baudios a 74880 baudios, si los símbolos que llegan no son legibles.

Instrucciones

Se usan las librerias Arduino IRremoteESP8266 como base para un dispositivo de control remoto con Home Assistant.

/* IRremoteESP8266: Demo Receptor Infrarojo
 * Debe usar un sensor detector/demodulador conectado al Receptor_Pin.
 *  Changed the baud rate to 74880. para ESP8285
 *  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
 */

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

// Sensor Detector/demodulador IR conectado a GPIO04
const uint16_t Receptor_Pin = 4;
IRrecv irrecv(Receptor_Pin);
decode_results lectura;

void setup() {
    Serial.begin(115200);//74880, 115200
    while (!Serial){ delay(50);}
    
    // Inicia receptor
    irrecv.enableIRIn();
    
    Serial.println("\n Demo Receptor de IR en espera de mensaje.");
}

void loop() {
    if (irrecv.decode(&lectura)) {
        // print() & println() can't handle printing long longs. (uint64_t)
        serialPrintUint64(lectura.value, HEX);
        Serial.println("");
        // Prepara próximo valor
        irrecv.resume();
    }
    delay(100);
}

Con los cógidos obtenidos, el siguiente paso consiste en generar los códigos usando un LED IR para activar el dispositivo o equipo que se controlaba con el control remoto. Observe y seleccione un código del ejercicio realizado con el control remoto que haya seleccionado, el dato sirve para el próximo ejemplo como IR_Emisor.

Referencia:
https://learn.sparkfun.com/tutorials/ir-communication/all#hardware-hookup
https://github.com/markszabo/IRremoteESP8266


Decodificando

Una versión para obtener más detalles de los códigos la presenta en el ejemplo version 2 de Mark Sabo en:

https://github.com/markszabo/IRremoteESP8266/blob/master/examples/IRrecvDumpV2/IRrecvDumpV2.ino

Solo se requiere hacer el ajuste en el pin de sensor al GIPO05, con lo que se obtiene para el ejemplo anterior:

Timestamp : 000446.026
Encoding  : NEC
Code      : FF5AA5 (32 bits)
Library   : v2.6.0

Raw Timing[71]:
   +  9024, -  4556,    +   548, -   594,    +   546, -   568,    +   544, -   594, 
   +   548, -   592,    +   548, -   568,    +   546, -   594,    +   548, -   592, 
   +   548, -   566,    +   546, -  1738,    +   548, -  1710,    +   550, -  1710, 
   +   544, -  1740,    +   548, -  1712,    +   546, -  1712,    +   546, -  1740, 
   +   546, -  1712,    +   548, -   592,    +   548, -  1710,    +   548, -   592, 
   +   548, -  1710,    +   548, -  1712,    +   546, -   594,    +   548, -  1712, 
   +   544, -   596,    +   548, -  1712,    +   546, -   596,    +   548, -  1710, 
   +   546, -   594,    +   548, -   594,    +   548, -  1712,    +   548, -   592, 
   +   548, -  1710,    +   548, - 40334,    +  9024, -  2294,    +   550

uint16_t rawData[71] = {9024, 4556,  548, 594,  546, 568,  544, 594,  548, 592,  548, 568,  546, 594,  548, 592,  548, 566,  546, 1738,  548, 1710,  550, 1710,  544, 1740,  548, 1712,  546, 1712,  546, 1740,  546, 1712,  548, 592,  548, 1710,  548, 592,  548, 1710,  548, 1712,  546, 594,  548, 1712,  544, 596,  548, 1712,  546, 596,  548, 1710,  546, 594,  548, 594,  548, 1712,  548, 592,  548, 1710,  548, 40334,  9024, 2294,  550};  // NEC FF5AA5
uint32_t address = 0x0;
uint32_t command = 0x5A;
uint64_t data = 0xFF5AA5;

La información de Code, «32 bits» Es necesaria si requiere reproducir la instrucción on irsend.sendNEC(codigo,32).

En el caso de usar otro control remoto se debe disponer del número de bits.

ESP32-Serial Bluetooth

Se puede realizar una comunicación Serial por medio de Bluetooth con la libreria básica de ESP32 para arduino.

En un ejercicio básico par controlar los estados de un LED es enviar un mensaje de ‘1’  para encender el Led incorporado del módulo y un mensaje  de ‘0’ para apagar el Led.

Por un lado se usa un módulo ESP32, y por el otro un móvil/tablet con una aplicación básica de terminal serial, para tener resultados semejantes al mostrado.

Las instrucciones usadas son:

// Controlador Binario LED
// ESP32-Serial Bluetooth

#include <BluetoothSerial.h>

BluetoothSerial ESP_BT;

int mensaje;

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

void setup() {
  Serial.begin(115200);
  ESP_BT.begin("ESP32_LED");
  Serial.println("Listo dispositivo Bluetooth");
  pinMode (LED_pin, OUTPUT);
}

void loop() {
  
  if (ESP_BT.available()){
    // mensaje recibido
    mensaje = ESP_BT.read(); 
    Serial.print("Recibido:"); 
    Serial.println(mensaje);

    if (mensaje == 49){
        digitalWrite(LED_pin, HIGH);
        ESP_BT.println("LED Encendido");
        }
        
    if (mensaje == 48){
        digitalWrite(LED_pin, LOW);
        ESP_BT.println("LED Apagado");
        }
  }
  delay(20);
}

Referencia:

https://github.com/espressif/arduino-esp32/tree/master/libraries/BluetoothSerial

https://create.arduino.cc/projecthub/mayooghgirish/arduino-bluetooth-basic-tutorial-d8b737

ESP32 SmartConfig-App

Para la configuración inicial de los dispositivos requiere una aplicación en un dispositivo tablet o móvil para configurar la conexión a la red WiFi con los datos de SSID y Password.

El concepto presentado por espressif con documentación actualizada al 2018.06.08 se encuentra en:

https://www.espressif.com/en/products/software/esp-touch/overview

https://www.espressif.com/sites/default/files/faq/screen_shot_2016-04-27_at_1.30.27_pm_0.png
Figura: Espressif https://www.espressif.com/sites/default/files/faq/screen_shot_2016-04-27_at_1.30.27_pm_0.png

La implementación de la aplicación que se usó para probar el ejercicio se encuentra en Google Play. Revisar el desarro de la aplicación realizará como otro tema.

https://play.google.com/store/apps/details?id=com.cmmakerclub.iot.esptouch

El procedimiento de conexión tiene dos partes:

  1. Modo configuración de WiFi, usando la aplición SmartConfig
  2. Modo normal de conexión WiFi, con los datos WiFi ya configurados

Para seleccionar los modos se usa una botonera «Configuración»  en un pin digital disponible con funcion y circuito semejante a RESET, en el ejemplo se usa GPIO14.

Modo configuración de WiFi

Para iniciar el modo configuración de la red se deben usar las botoneras «Configuración» y «RESET» con la secuencia:

1. pulsar Botonena GPIO14 y mantener pulsada
2. Luego pulsar y soltar reset
3. Mantener pulsado GPIO14 por 5 segundos después y soltar
4. Usar el móvil/tableta con la aplicación SmartConfig para configurar
5. Escribir SSID y password en móvil/tablet y «confirmar»
6. Esperar confirmación y estará conectado.

Modo normal de conexión WiFi

Es el modo predeterminado de operación, no requiere presionar el botón de «Configuración». Arranca con los valores almacenados de SSID y PASSWORD.

Monitor Serial

Los resultados del proceso de configuración y conexión a WiFi se muestran a continuación. Para fines de muestra, se ha demorado la activación con el móvil/tablet, note que la conexión a WiFI se realiza casi inmediatamente (tres puntos …)

....ets Jun  8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
ets Jun  8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10088
load:0x40080400,len:6380
entry 0x400806a4
configurando WiFi
Esperando conexión SmartConfig móvil/tablet
........................................
 Esperando conexión SmartConfig móvil/tablet
...............
 Finalizado SmartConfig.

 Conectando a WiFi
...
 WiFi conectado , Dirección IP: iotirni19 , 192.168.10.102
conectado a:
iotirni19 , 192.168.10.102 , -56
conectado a:
iotirni19 , 192.168.10.102 , -53
conectado a:
iotirni19 , 192.168.10.102 , -54
conectado a:
iotirni19 , 192.168.10.102 , -55
conectado a:
iotirni19 , 192.168.10.102 , -55
conectado a:
iotirni19 , 192.168.10.102 , -55

Instrucciones Arduino

Las instrucciones se han dividido por bloques: configura_wifi() y conecta_wifi(). En ambas funciones se presentan mensajes y parpadeos de led.

Configura_wifi() espera a que se obtenga un valor afirmativo para WiFi.smartConfigDone() y finalizar.

Conecta_wifi() es muy semejante a la función inicia_wifi() usada en los primeros ejemplos que usaba variables para SSID y Password()

/* ESP32 Smart Config de Espressif
modificado a partir de:
https://www.espressif.com/en/products/software/esp-touch/overview
Usa el GPIO14 en estado LOW para entrar en modo configuración.
Usar BOTONERA "CONFIGURACION" en pin14, con pullup (HIGH)
Para configurar:
1. pulsar Botonena GPIO14 y mantener pulsada
2. Luego pulsar y soltar reset
3. Mantener pulsado GPIO14 por 5 segundos después y soltar
4. Usar el móvil/tableta con la aplicación SmartConfig para configurar
5. Escribir SSID y password en móvil/tablet y "confirmar"
6. Esperar confirmación y estará conectado.
*/
#include <WiFi.h>

// PIN configuración
const PROGMEM uint8_t CONFIG_pin = 14; 

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

void setup() {
    Serial.begin(115200);

    // PIN configuración
    pinMode(CONFIG_pin, INPUT);
    
    // LED monitor
    pinMode(LED_pin, OUTPUT);
    
    // Revisa si entra a modo configuración
    if (digitalRead(CONFIG_pin)==LOW){
        Serial.println("configurando WiFi");
        // configura con SmartConfig
        configura_wifi();
    }
    // Modo conexión a Router
    conecta_wifi();

}
void loop() {
    // Ejemplo de tarea a realizar.
    Serial.println("conectado a:");
    Serial.print(WiFi.SSID());
    Serial.print(" , ");
    Serial.print(WiFi.localIP());
    Serial.print(" , ");
    Serial.println(WiFi.RSSI());
    // LED interno enciende en LOW
    digitalWrite(LED_pin, HIGH);
    delay(100);
    digitalWrite(LED_pin, LOW);
    delay(100);
    digitalWrite(LED_pin, HIGH);
    delay(100);
    digitalWrite(LED_pin, LOW);
    delay(250);
    // termina ejemplo
    delay(1000);
}

void configura_wifi(){
    // inicia en modo estación
    WiFi.mode(WIFI_AP_STA);
    WiFi.beginSmartConfig();
    int cuenta = 0;
    // Espera por un paquete Smartconfig del móvil/tablet
    Serial.println("Esperando conexión SmartConfig móvil/tablet");
    while (!WiFi.smartConfigDone()) {
        delay(500);
        Serial.print(".");
        cuenta = cuenta+1;
        if (cuenta>=40){
            Serial.println("\n Esperando conexión SmartConfig móvil/tablet");
            cuenta = 0;}
        // LED interno enciende en LOW
        digitalWrite(LED_pin, HIGH);
        delay(50);
        digitalWrite(LED_pin, LOW);
        delay(50);
        }
    Serial.println("\n Finalizado SmartConfig.");
    }

void conecta_wifi() {
    // conexion WiFi
    Serial.println("\n Conectando a WiFi");
    
    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 , Dirección IP: ");
    Serial.print(WiFi.SSID());
    Serial.print(" , ");
    Serial.println(WiFi.localIP());
    delay(10);
}

Por desarrollar:
Personalizar la aplicación del móvil/tableta a partir del código básico de espressif.

Referencias:
https://www.espressif.com/en/products/software/esp-touch/overview

https://www.espressif.com/sites/default/files/documentation/esp-touch_user_guide_en.pdf

ESP32 BuscarRedes

Búsqueda de redes cercanas y sus respectivas potencias, la red marcada con rojo es el ESP32  revisado desde una laptop.

Busca redes WiFi cercanas
Busqueda completada 
29 redes encontradas
1: ESP_0A797B (-46) 
2: GUAIFAI (-62)*
3: Red Oculta
...

Instrucciones

Usando la libreria WiFi.h

/* Redes disponibles
 *  Realiza una búsqueda de redes Wifi cercanas
 */
#include <WiFi.h>

void setup()
{
    Serial.begin(115200);

    // Si estaba conectada como estación, se desconecta.
    WiFi.mode(WIFI_STA);
    WiFi.disconnect();
    delay(100);

    Serial.println("Configuración completada.");
}

void loop()
{
    Serial.println("Busca redes WiFi cercanas");

    //determina el número de redes cercanas
    int n = WiFi.scanNetworks();
    Serial.println("Busqueda completada ");
    
    if (n == 0) {
        Serial.println("NO se encontraron redes.");
    } else {
        Serial.print(n);
        Serial.println(" redes encontradas");
        for (int i = 0; i < n; ++i) {
            // Muestra el SSID y RSSI de cada red encontrada
            Serial.print(i + 1);
            Serial.print(": ");
            Serial.print(WiFi.SSID(i));
            Serial.print(" (");
            Serial.print(WiFi.RSSI(i));
            Serial.print(")");
            Serial.println((WiFi.encryptionType(i) == WIFI_AUTH_OPEN)?" ":"*");
            delay(10);
        }
    }
    Serial.println("");

    // Espera antes de la próxima búsqueda...
    delay(5000);
}

Referencia: https://github.com/espressif/arduino-esp32/blob/master/libraries/WiFi/examples/WiFiScan/WiFiScan.ino

ESP32 SoftAP

Para crear un Access Point se usa de la libreria la intrucción WIFI.softAP()

Como base se tiene el ejercicio de una página web para encender o apagar el LED incorporado.

En ésta ocasión no es necesario conectarse a un router, el AP aparece en la lista de dispositivos circundantes. Se selecciona y se ingresa con el nombre de red y la contraseña.

/* ESP32 Soft AP con web server para encender LED_Pin
forma básica con la función inicia_wifi
Referencia: https://www.arduino.cc/en/Tutorial/WiFiWebServer  
*/
#include <WiFi.h>

const char* ssid     = "iotirni19_AP";
const char* password = "anera2018";

// puerto de servidor web 80
const PROGMEM uint8_t puertoweb = 80;
WiFiServer server(puertoweb);

// LED monitor interno
//ESP01-pin=1, ESP07-pin=2; ESP32-pin=5
const PROGMEM uint8_t LED_pin = 5; 
int LED_estado = 0;

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

    // LED monitor
    pinMode(LED_pin, OUTPUT);
    delay(10);

    // Convertir en AP
    WiFi.softAP(ssid, password);
    //inicia_wifi(); // no se conecta a un router
    server.begin();
}

void loop(){
    WiFiClient client = server.available();
    if (client){
        String linea = "";
        Serial.println();
        Serial.println("Nuevo cliente.");
        while (client.connected()) {
            if (client.available()) {
                char c = client.read();
                Serial.write(c);
                if (c == '\n') {
                    // Si recibe fin de linea y la linea es vacia,
                    // la peticion http finalizó, se responde:
                    if (linea.length() == 0) {
                        // HTTP headers inician con ésta secuencia:
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-type:text/html");
                        client.println();
                        // contenido despues de headers
                        client.print("LED estado: ");
                        client.print(String(LED_estado)+"
");
                        client.print("Click <a href=\"/H\">ENCIENDE LED</a><br>");
                        client.print("Click <a href=\"/L\">   APAGA LED</a><br>");
                        // finaliza contenido:
                        client.println();
                        // sale del lazo:
                        break;
                    } else {
                        linea = "";
                    }
                } else if (c != '\r') {
                    linea = linea + c;
                }
            // Revisa click del cliente "GET /H" or "GET /L":
            if (linea.endsWith("GET /H")) {
                digitalWrite(LED_pin, HIGH);
                LED_estado = 1;
            }
            if (linea.endsWith("GET /L")) {
                digitalWrite(LED_pin, LOW);
                LED_estado = 0;
            }
        }
    }
    delay(1); // espera que browser procese
    client.stop(); // cierra conexión:
    Serial.println("Cliente desconectado.");
    }
}

ESP32 WebServer Blink

Enciender y Apagar elLED incorporado (Pin 5) en el módulo ESP32 desde una página web.

https://learn.sparkfun.com/tutorials/esp32-thing-hookup-guide

El módulo se configura como un Web Server para responder a las petición desde un browser. La dirección mostrada en la figura es un ejemplo.

La librería  básica usada es WiFi.h con los valores de SSID y Password para acceder a la red existente, valores que se deben actualizar de acuerdo a la configuración de su red. El router asigna una dirección IP de forma automática, y su valor se muestra en el monitor serial, dirección usada en un brower para observar el resultado.

Monitor Serial

ets Jun 8 2016 00:22:57

rst:0x10 (RTCWDT_RTC_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1100
load:0x40078000,len:10088
load:0x40080400,len:6380
entry 0x400806a4

Conectando a RedWifi
..
WiFi conectado 
Dirección IP: 192.168.10.104

Para simplificar las instrucciones, la sección de conexión a la red WiFi se realiza en la función inicia_wifi().

Instrucciones:

Para iniciar el modo servidor web se requiere WifiServer server(puertoweb), el puerto web es el 80.

En el programa se revisa el estado del cliente (client): conectado, disponible, leyendo cada caracter enviado por el browser e interpretando las instrucciones por cada fin de línea (‘\n’).

Si la línea recibida finaliza con «GET /H» o «GET /L» se realiza el cambio de estado del LED.

Al final se cierra la conexión, y se continua monitoreando el estado del cliente.

/* ESP32 web server para encender LED_Pin
forma básica con la función inicia_wifi
Referencia: https://www.arduino.cc/en/Tutorial/WiFiWebServer  
*/
#include <WiFi.h>

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

// puerto de servidor web 80
const PROGMEM uint8_t puertoweb = 80;
WiFiServer server(puertoweb);


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

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

    // LED monitor
    pinMode(LED_pin, OUTPUT);
    delay(10);

    inicia_wifi();
    server.begin();
}

void loop(){
    WiFiClient client = server.available();
    if (client){
        String linea = "";
        Serial.println();
        Serial.println("Nuevo cliente.");
        while (client.connected()) {
            if (client.available()) {
                char c = client.read();
                Serial.write(c);
                if (c == '\n') {
                    // Si recibe fin de linea y la linea es vacia,
                    // la peticion http finalizó, se responde:
                    if (linea.length() == 0) {
                        // HTTP headers inician con ésta secuencia:
                        client.println("HTTP/1.1 200 OK");
                        client.println("Content-type:text/html");
                        client.println();
                        // contenido despues de headers
                        client.print("Click <a href="\"/H\"">ENCIENDE LED</a>
");
                        client.print("Click <a href="\"/L\"">   APAGA LED</a>
");
                        // finaliza contenido:
                        client.println();
                        // sale del lazo:
                        break;
                    } else {
                        linea = "";
                    }
                } else if (c != '\r') {
                    linea = linea + c;
                }
            // Revisa click del cliente "GET /H" or "GET /L":
            if (linea.endsWith("GET /H")) {
                digitalWrite(LED_pin, HIGH);
            }
            if (linea.endsWith("GET /L")) {
                digitalWrite(LED_pin, LOW);
            }
        }
    }
    delay(1); // espera que browser procese
    client.stop(); // cierra conexión:
    Serial.println("Cliente desconectado.");
    }
}

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);
}

Puntos por desarrollar

  • Añadir en la pagina el estado del LED. Sugerencia: aumentar una variable de estado para el led y usarla en la página html.
  • Conectar a un servidor MQTT e iniciar el estado del LED con el correspondiente en el Estado MQTT.

Referencia: https://www.arduino.cc/en/Tutorial/WiFiWebServer