1. Instrucciones en Arduino IDE
Como la versión del ESP8266-01 no dispone de muchos pines de trabajo, se define el uso de los pines como:
- Lectura del sensor interruptor en GPIO1, que también es TXD configurado (setup) como entrada (INPUT).
- Control actuador con relay en GPIO3, que también es RXD configurado en modo de salida (OUTPUT).
- Monitor de operación del dispositivo: LED actuador GPIO2
- Monitor de conexión a la red: LED conexión GPIO0
Por el uso en operación de los pines de comunicación Serial (GPIO1 y GPIO3) se descartan las lineas Serial.print().
Si la subida del archivo.ino al módulo ESP01 se realiza fuera de la placa PCB.
Si el diseño realizado permite conectar un módulo USB-TTL a la placa PCB. Revise la configuración de las botoneras Reset, PROG o DIP-switch para realizar la carga del archivo.ino.
2. Funciones repetitivas
La conexión a WIFI y comunicación por MQTT al ser repetitivas entre algoritmos se separan en funciones, simplificando la configuración inicial (setup) y el bloque principal (loop).
Al inicio se definen las librerías y los valores para la conexión WIFI y los datos para comunicarse con el servidor MQTT-Mosquitto implementado en el Raspberry. Revisar de ser necesario la sección "Broker".
2.1 función para actuador
Para procesar las instrucciones enviadas por el broker MQTT se dispne de la función callback().
Para el control del Relé se usa la función ACTUADORactivaestado().
2.2 Función para sensor
Para monitorear sensor se usa una interrupción para sensar cambios de estado. Por el control de rebotes, se considera los intervalos entre cambios implementado en la función SensorActivado(). De confirmarse el cambio se pasa a publicar el estado en el broker MQTT con SENSORpublicaestado()
/* ESP8266 Interruptor AC.
* edelros@espol.edu.ec
* Sensor-Actuador Binario,
* control de un Relay con Tomacorriente o foco.
* 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>
// WIFI: conexión a Router
char* ssid = "xxxx";
char* password = "xxxx";
// MQTT: Servidor
char* MQTT_IP = "192.168.xx.xx";
uint16_t MQTT_puerto = 1883;
char* MQTT_usuario = "usuarioprueba";
char* MQTT_contrasena = "usuarioclave";
// MQTT: Dispositivo Interruptor
char* MQTT_ID = "oficina_luz1";
char* MQTT_TOPIC = "oficina/luz1/estado";
char* MQTT_COMMAND = "oficina/luz1/cambia";
char MQTT_SensorEstado[10] = "OFF";
char MQTT_ActuadorEstado[10] = "OFF";
volatile boolean mqtt_desconectado = true;
char* sensor_ON = "ON";
char* sensor_OFF = "OFF";
// Actuador Tomacorriente-Luz
const uint8_t actuador_pin = 3;
volatile boolean actuador_estado = false;
// Sensor Interruptor
const uint8_t sensor_pin = 1;
volatile boolean sensor_estado = false;
volatile boolean sensor_bandera = true;
// LED monitor //interno: ESP01-pin=1, ESP07-pin=2
const uint8_t LED_pin=0;
const uint8_t LED_actuador = 2;
// Clientes WiFi y MQTT
WiFiClient wifiClient;
PubSubClient mqttclient(wifiClient);
void setup() {
// SENSOR Interruptor
pinMode(sensor_pin, INPUT);
attachInterrupt(digitalPinToInterrupt(sensor_pin),sensorActivado,CHANGE);
// ACTUADOR Tomacorriente
pinMode(actuador_pin, OUTPUT);
pinMode(LED_actuador, OUTPUT);
// LED monitor, Enciende en LOW
pinMode(LED_pin, OUTPUT);
// conexión WIFI y MQTT
inicia_wifi();
if (WiFi.status() == WL_CONNECTED){
inicia_mqtt();
}
}
void loop() {
// Revisa cambios en interruptor
if (sensor_bandera){
delay(10);
sensor_estado = digitalRead(sensor_pin);
if (sensor_estado==LOW){
actuador_estado = true;
}
if (sensor_estado ==HIGH){
actuador_estado = false;
}
ACTUADORactivaestado();
publica_estado();
sensor_bandera = false;
}
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
}
// ISR interrupción activada
ICACHE_RAM_ATTR void sensorActivado(){
sensor_bandera = true;
}
// Actuador activar estado
void ACTUADORactivaestado(){
if (actuador_estado){
// ACTUADOR ACTIVA EN LOW
// LED actuador ilumina en apagado
digitalWrite(actuador_pin, LOW);
digitalWrite(LED_actuador, HIGH);
}else{
digitalWrite(actuador_pin, HIGH);
digitalWrite(LED_actuador, LOW);
}
}
// 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 (mqttclient.connected()==true){
mqttclient.publish(MQTT_TOPIC,MQTT_ActuadorEstado,true);
}else{
mqtt_desconectado = true;
}
}
void inicia_wifi(){
int intentos = 10;
int cuenta = 0;
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while ((WiFi.status() != WL_CONNECTED) && (cuenta < intentos)){
cuenta = cuenta+1;
// Parpadeo de Monitor enciende en LOW
digitalWrite(LED_pin, LOW);
delay(300);
digitalWrite(LED_pin, HIGH);
delay(200);
}
}
void inicia_mqtt(){
int intentos = 2;
int cuenta = 0;
mqttclient.setServer(MQTT_IP, MQTT_puerto);
mqttclient.connect(MQTT_ID, MQTT_usuario, MQTT_contrasena);
mqttclient.setCallback(callback);
while (!mqttclient.connected() && (cuenta <intentos)) {
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);
}
// 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;
}
}
ACTUADORactivaestado();
publica_estado();
}
}