InicioTarjetas de DesarrolloAlcoholímetro con mensajes de WhatsApp RP2040 y ESP32

Alcoholímetro con mensajes de WhatsApp RP2040 y ESP32

A continuación se muestra el alcoholímetro basado en el RP2040 de una publicación anterior, pero esta vez añadiendo comunicación UART entre el RP2040 con el ESP32 integrados en la tarjeta UNIT DUAL MCU, el cual se encargara de enviar notificaciones a WhatsApp mediante una API llamada CallMeBot.

Introducción

En este proyecto te mostraremos cómo añadir comunicación remota al alcoholímetro construido basado en el RP2040 de la UNIT DUAL MCU destacando la ventaja de tener dos microcontroladores en una misma plataforma de desarrollo, ya que puedes dedicar al RP2040 a tareas de procesamiento y lectura de datos, y por su parte al ESP32 a la comunicación remota con otros servicios como en WhatsApp

Materiales

Diagrama de conexiones

Para prototipar el sistema propuesto se usará el siguiente diagrama donde el sensor MQ-3 y la tira NeoPixel están alimentados a 3.3 V que provienen directamente de la tarjeta de desarrollo UNIT DUAL MCU. 

En el diagrama se propone el uso de una batería Li Po para añadir portabilidad al proyecto, la cual se conecta fácilmente con el conector JST integrado en la placa 😉

Para que los microcontroladores puedan comunicarse mediante el protocolo UART ambos DIP-Switches deben estar colocados hacia arriba para habilitar las líneas de TX y RX de ambos dispositivos.

Código 

⚠️ Antes de cargar cualquier código en la UNIT DUAL MCU debes elegir con el selector USB el microcontrolador que desees programar ⚠️

A la par, asegúrate de elegir tu placa y tu puerto COM en el Arduino IDE

En la nueva versión de la UNIT DUAL MCU ONE el cambio de microcontrolador mediante el selector USB mecánico ya no es necesario, ya que la PC se puede comunicar a la vez con ambos dispositivos. Puedes tener dos monitores seriales recibiendo datos al mismo tiempo, uno para la ESP32 y otro para el RP2040 😉

Código RP2040

A continuación se muestra el código para el RP2040 que tiene las tareas de leer el sensor MQ-3 y encender los leds de la tira NeoPixel tal y como se describió en la lección “Alcoholímetro usando el RP2040 de la UNIT DUAL MCU” con las únicas modificaciones para realizar la comunicación con el ESP32 mediante UART, específicamente hablando de la línea en el void Setup() de: 

Serial1.begin(9600);

que inicializa el UART del RP2040 a 9600 baudios que sera utilizado para comunicarse con la ESP32, mismo que no debe ser confundido con  Serial.begin(115200); el cual usamos para comunicar al RP2040 con la computadora

Por otra parte, en este código se envía mediante UART el siguiente mensaje al ESP32 en la linea 110:

Serial1.write(“PELIGRO”);

Y eso es todo en el código para el RP2040, que como ya te habrás dado cuenta solo se le han agregado un par de líneas y por lo demás es exactamente igual al programa visto en la entrada pasada en este BLOG 🙂

#include <NeoPixelBus.h> // Librería para controlar tiras de LED NeoPixel


const uint16_t PixelCount = 8; // Número de LEDs en la tira
const uint8_t PixelPin = 2;    // Pin GPIO donde está conectada la tira LED


#define sensor A2             // Pin analógico (GPIO28) conectado al sensor MQ-3
#define colorSaturation 128   // Saturación de color para los LEDs (0-255)
#define buzzer 3              // Pin digital conectado al buzzer
#define espera 45000          // Tiempo de espera en ms para activación del buzzer (30 segundos)


// Inicialización de la tira con el método y características del tipo de LED
NeoPixelBus<NeoGrbFeature, NeoWs2812xMethod> strip(PixelCount, PixelPin);


// Definición de colores RGB para los LEDs
RgbColor red(colorSaturation, 0, 0);
RgbColor green(0, colorSaturation, 0);
RgbColor blue(0, 0, colorSaturation);
RgbColor white(colorSaturation);
RgbColor black(0);


float V0 = 0.0; // Valor base (en aire limpio) del sensor
float medicion_maxima = 0.0, ultima_medicion = 0.0;
int counter = 0, op = 0;


void setup() {
  Serial1.begin(9600);        // Inicializa a 9600 baudios el UART que se comunica con el ESP32
  pinMode(sensor, INPUT);     // Definimos el pin del sensor como entrada
  Serial.begin(115200);       // Iniciamos la comunicación serial con la computadora
  pinMode(buzzer, OUTPUT);    // Configuramos el buzzer como salida


  strip.Begin();              // Inicializamos la tira LED
  strip.Show();               // Apagamos todos los LEDs al principio


  Serial.println("Calibrando sensor...");
  delay(15000);               // Esperamos 15 segundos para estabilizar el sensor
 
  V0 = analogRead(sensor)/310.0; // Leemos valor inicial del sensor (base de comparación)
  Serial.print("V0 = ");
  Serial.println(V0);


  // Indicamos fin de calibración con un bip corto
  digitalWrite(buzzer, HIGH);
  delay(200);
  digitalWrite(buzzer, LOW);
}




void loop() {
  float lectura = analogRead(sensor)/310.0; // Leemos valor actual del sensor


  // Si la lectura supera cierto umbral respecto al valor base, activamos detección
  if (lectura - V0 > 0.2) {
    op = 6;
    counter = 0;
  } else {
    op = 0;
  }


  // Si se detectó alcohol (op > 4), procesamos lectura y encendemos LEDs
  while (op > 4) {
    float medicion_instantanea = 0.0;
    float lectura = 0.0;


    // Promediamos 40 lecturas para mayor precisión
    for (int i = 0; i < 40; i++) {
      medicion_instantanea = analogRead(sensor)/310.0;
      lectura += medicion_instantanea;
      delay(1);
    }
    lectura /= 40.0;


    counter = millis(); // Contador del tiempo transcurrido


    float alcohol = lectura - V0;             // Diferencia respecto a la base
    float barraled = pow(alcohol * 10, 2);    // Cuantificamos intensidad para los LEDs


    Serial.println(barraled);                 // Mostramos en monitor serial
    delay(50);


    // 🟢 Alcohol bajo (1-15): encendemos LED en verde
    if (0.0 < barraled && barraled < 15) {
      int leds = barraled * 0.533333;
      strip.SetPixelColor(leds, green);
      delay(5);
      strip.Show();
    }


    // 🔵 Alcohol medio (15-30): encendemos LED en azul
    else if (15 <= barraled && barraled < 30) {
      int leds = (barraled * 0.533333) - 8;
      strip.SetPixelColor(leds, blue);
      delay(5);
      strip.Show();
    }


    // 🔴 Alcohol alto (30-45): encendemos LED en rojo y activamos alerta
    else if (30 <= barraled && barraled < 45) {
      int leds = (barraled * 0.533333) - 16;
      strip.SetPixelColor(leds, red);
      delay(5);
      strip.Show();


      ultima_medicion = alcohol * 10;
      if (medicion_maxima < ultima_medicion)
        medicion_maxima = ultima_medicion;


      // Si pasa el tiempo definido y la última medición es menor que la máxima anterior
      if (counter > espera && medicion_maxima > ultima_medicion) {


        Serial1.write("PELIGRO");
        Serial.println("Mensaje enviado a la ESP32 por UART");
        // Activamos el buzzer varias veces para alerta


        digitalWrite(buzzer, HIGH);
        delay(30);
        digitalWrite(buzzer, LOW);
        delay(30);
        digitalWrite(buzzer, HIGH);
        delay(30);
        digitalWrite(buzzer, LOW);
        delay(10000); // Espera antes de reiniciar sistema


        while (1); // Detenemos el sistema
        op = 0;
      }
    }
  }
}

Código ESP32

A continuación se muestra el código para que el ESP32 realice la notificación en WhatsApp mediante la API CallMeBot en cuanto reciba la cadena “Peligro” desde el RP2040 por medio del protocolo UART. Además, se muestra el procedimiento para enlazar tu cuenta de WhatsApp con la API.

En el programa se destacan el uso de las librerías WiFi.h y Callmebot_ESP32.h

para la conexión del ESP32 a la red WiFi y para el enlace del mismo con la API CallMeBot 

Como es usual para la conexión a la red WiFi, debes escribir el nombre y contraseña de la red a la que deseas conectar el ESP32 en las siguientes lineas:

const char* ssid = “Escribe el nombre de tu red WiFi”;

const char* password = “Escribe la contraseña de tu red”;

Por otra parte, escribe el número de teléfono al que vas a enlazar con la API para recibir mensajes de texto en WhatsApp y la API key que te devuelve CallMeBot cuando lo registras en tu teléfono dentro de las siguientes lineas

String phoneNumber = “Escribe tu número telefónico”;

String apiKey = “Escribe la API key que te dio CallMeBot en WhatsApp”;

Por último, para que el ESP32, a través de la API, envíe el mensaje de WhatsApp, se tiene que recibir la cadena de “PELIGRO” desde el RP2040 usando el protocolo UART, esto lo logramos con las siguientes líneas de código

 Revisa si se ha recibido algo en la UART

if(uartESP.available() > 0)

Lo que se haya recibido lo lee hasta el carácter de salto de línea y lo asigna a la variable tipo cadena llamada mensaje_desde_RP2040

String mensaje_desde_RP2040 = uartESP.readStringUntil(‘\n’);

Limpia el mensaje eliminando caracteres raros

mensaje_desde_RP2040.trim();

Se entra a la condicional si el mensaje recibido es la cadena “PELIGRO”

if(mensaje_desde_RP2040 == “PELIGRO”)

// Incluye las librerías necesarias para conectarse al WiFi y para enviar mensajes por WhatsApp usando CallmeBot
#include <WiFi.h>
#include <Callmebot_ESP32.h>


// Define las credenciales de la red WiFi
const char* ssid = "Escribe el nombre de tu red WiFi";
const char* password = "Escribe la contraseña de tu red";


// Número de teléfono al que se enviará el mensaje (formato internacional, este ejemplo usa +52 para México)
String phoneNumber = "Escribe tu número telefónico";


// Clave API obtenida desde Callmebot para enviar mensajes
String apiKey = "Escribe la API key que te dio CallMeBot en WhatsApp";


// Mensaje que se enviará en caso de detectar un nivel peligroso de alcohol
String messsage = "Nivel peligroso de alcohol detectado";


// Se crea un objeto para comunicarse por el puerto serial UART2 (usado para la comunicación con otro microcontrolador, como un RP2040)
HardwareSerial uartESP(2);


void setup() {
  // Inicia el puerto serial principal para depuración
  Serial.begin(115200);


  // Inicia la comunicación serial por UART2 (pin 16 como RX y 17 como TX a 9600 baudios)
  uartESP.begin(9600, SERIAL_8N1, 16, 17);


  // Conexión a la red WiFi
  WiFi.begin(ssid, password);
  Serial.println("Conectado");


  // Espera hasta que se establezca la conexión WiFi
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }


  // Muestra en el monitor serial que se conectó correctamente y cuál es la IP asignada
  Serial.println("");
  Serial.print("Conectado a la red con la IP: ");
  Serial.println(WiFi.localIP());


  // Aquí podría ir código adicional para enviar un mensaje inicial o notificación de inicio, si se desea
}


void loop() {
  // Verifica si hay datos disponibles en la comunicación serial con el RP2040
  if(uartESP.available() > 0){
    // Lee el mensaje enviado desde el RP2040 hasta encontrar un salto de línea
    String mensaje_desde_RP2040 = uartESP.readStringUntil('\n');
   
    // Elimina espacios o saltos de línea al inicio/final del mensaje
    mensaje_desde_RP2040.trim();


    // Si el mensaje recibido es "PELIGRO", se envía un mensaje de WhatsApp
    if(mensaje_desde_RP2040 == "PELIGRO"){
      Callmebot.whatsappMessage(phoneNumber, apiKey, messsage); // Envía el mensaje
      Serial.println(Callmebot.debug()); // Muestra el resultado o errores del intento de envío
    }
  }


  // Si no hay datos disponibles, no se hace nada
  else{}
}

Para que nuestro ESP32 envíe notificaciones por medio de mensajes de WhatsApp debemos realizar el enlace dentro del programa a través del número de teléfono que recibirá los mensajes  y la API key (clave de API) que obtendremos siguiendo los pasos aquí mostrados:

1. Agregue el número de teléfono +34 694 26 48 06 a sus contactos. (Nómbrelo como desee). 

2. Envíe el mensaje “I allow callmebot to send me messages” al nuevo contacto creado (usando WhatsApp, por supuesto). 

3. Espere hasta que reciba el mensaje “API Activated for your phone number. Your APIKEY is 123123” del bot. 

Nota: Si no recibe la clave API en 2 minutos, inténtelo de nuevo después de 24 horas. 

4. El mensaje de WhatsApp del bot contendrá la clave API necesaria para enviar mensajes usando la API. Puede enviar mensajes de texto usando la API después de recibir la confirmación.

Ejemplo:

Conclusión

En la presente entrada del blog se demuestra la capacidad de la UNIT DUAL MCU para realizar tareas cada vez más grandes y complejas, debido a que podemos dividir las funciones de una implementación completa para cada microcontrolador, aprovechando las ventajas que cada uno tiene. 

En este caso delegamos la comunicación remota al ESP32 y, la lectura del sensor y la lógica de control al RP2040 que para un alcoholímetro, esto se realiza cómodamente en dos programas, pero que muchas más aplicaciones se pueden escalar sin ningún problema.

Para más información, consulta el GitHub, la documentación oficial, el Pinout y la wiki del producto en el siguiente enlace 👍:

TUTORIALES RELACIONADOS