Etiqueta: Bluetooth

  • Controlar un ESP32 (o esp8266) con Android utilizando AppInventor2

    Controlar un ESP32 (o esp8266) con Android utilizando AppInventor2

    App Inventor 2 es una plataforma en línea de código abierto que permite crear aplicaciones para dispositivos Android sin necesidad de conocimientos avanzados de programación. F

    App Inventor 2 fue desarrollado por Google y posteriormente transferido al MIT (Instituto Tecnológico de Massachusetts).

    Para este proyecto se creará una aplicación en App Inventor que se conecte a un slider a través de Bluetooth y lo controle desde un dispositivo programado con Arduino IDE

    Aplicación en App Inventor que se conecte a un slider a través de Bluetooth y se controle desde un dispositivo Arduino con un ESP32, puedes seguir estos pasos generales:

    Lado de la Aplicación en App Inventor:

    1. Crear la Interfaz Gráfica:

    2. Comienza un nuevo proyecto

    3. Componentes Bluetooth: Añadir el componente Bluetooth al diseño.

    4. Configurar Bluetooth:

    • Configurar el componente Bluetooth para buscar dispositivos y establecer la conexión.
    1. Programar la Interacción con el Slider:
      • Programar la lógica que enviará los datos del slider a través de Bluetooth al dispositivo Arduino cuando se modifique su valor.
    2. Manejar la Conexión y Desconexión:
      • Implementar lógica para gestionar la conexión y desconexión con el dispositivo Bluetooth.
    3. Diseñar la Interfaz de Usuario:
      • Diseñar la interfaz de usuario para mostrar el estado de la conexión y otra información relevante.

    En la pantalla de diseño, agrega un componente Slider desde la paleta de componentes.

    
    
    Manejo del Slider y envío de datos:
    
    En el bloque "BluetoothClient1.SendText", el valor del slider se convierte a una cadena (Text), ya que el módulo Bluetooth envía datos como texto.
    
    Asegúrate de configurar correctamente el BluetoothClient1.Address con la dirección Bluetooth de tu dispositivo.
    
    Conecta tu dispositivo Android a tu Arduino mediante Bluetooth.
    

    Lado del Dispositivo Arduino (ESP32):

    1. Preparar todo para poder configurar el ESP32 con Arduino IDE.
    2. Programar la Lógica del Arduino Controlar el Slider (recibir datos)
      • Escribe un programa para el ESP32 que escuche los datos enviados por la aplicación a través de Bluetooth.
      • Implementa la lógica que ajustará el valor del slider según los datos recibidos a través de Bluetooth.

    Controlar un slider en App Inventor 2 y enviar los datos al ESP32 a través de Bluetooth

    Asegurarse tener un módulo Bluetooth conectado al microcontrolador.

    // Importar la librería para el módulo Bluetooth
    #include <SoftwareSerial.h>
    
    SoftwareSerial BTSerial(10, 11); // RX, TX
    
    void setup() {
      Serial.begin(9600);
      BTSerial.begin(9600);
    }
    
    void loop() {
      if (BTSerial.available()) {
        int valor = BTSerial.parseInt();
        if (valor >= 0 && valor <= 255) {
          // Aquí puedes utilizar el valor recibido como desees
          analogWrite(9, valor); // Por ejemplo, controlar un LED con el valor del slider
        }
      }
    }
    

    Este código utiliza la librería SoftwareSerial para comunicarse con el módulo Bluetooth en los pines 10 y 11. Luego, lee el valor entero enviado desde la aplicación y lo utiliza para controlar un LED conectado al pin 9 (se puede ajustar esto según tu configuración).

  • Conectar dos placas ESP32 con Bluetooth

    Creado:: 22 de marzo de 2023

    Ultima actualización: 7/5/2025

    Primeros pasos con ESP32 Bluetooth Low Energy (BLE) en Arduino IDE – Bluetooth de Bajo Consumo de Energía

    El ESP32 cuenta con con Bluetooth Clásico y Bluetooth Low Energy (BLE)

    Esta publicación es una introducción a BLE con el ESP32.

    En esta sección: ¿Qué es BLE y para qué se puede usar?

    También algunos ejemplos con el ESP32 usando Arduino IDE.

    ¿Qué es Bluetooth de baja energía?


    Bluetooth Low Energy, BLE para abreviar, es una variante de ahorro de energía de Bluetooth. La aplicación principal de BLE es la transmisión a corta distancia de pequeñas cantidades de datos (bajo ancho de banda).

    A diferencia de Bluetooth Clásico, que siempre está activado, BLE permanece en modo de suspensión constantemente, excepto cuando se inicia una conexión.

    Comparado con Bluetooth clásico, Bluetooth Low Energy está diseñado para proporcionar un bajo consumo de energía, manteniendo un rango de alcance de comunicación similar.

    Esto hace que consuma muy poca energía. BLE consume aproximadamente 100 veces menos energía que Bluetooth (según el caso de uso).

    Además, BLE admite no solo la comunicación punto a punto, sino también el modo de transmisión y la red de malla.

    Servidor y cliente BLE

    Con Bluetooth Low Energy, hay dos tipos de dispositivos: el servidor y el cliente.

    El ESP32 puede actuar como cliente o como servidor. El servidor anuncia su existencia, por lo que otros dispositivos pueden encontrarlo y contiene datos que el cliente puede leer. El cliente escanea los dispositivos cercanos y, cuando encuentra el servidor que está buscando, establece una conexión y escucha los datos entrantes. Esto se llama comunicación punto a punto.

    Hay otros modos de comunicación posibles, como el modo de transmisión y la red de malla.

    GATT

    GATT significa Atributos Genéricos y define una estructura de datos jerárquica que está expuesta a los dispositivos BLE conectados. Esto significa que GATT define la forma en que dos dispositivos BLE envían y reciben mensajes estándar. Comprender esta jerarquía es importante porque facilitará la comprensión de cómo usar BLE con el ESP32.

    Perfil: colección estándar de servicios para un caso de uso específico;

    Servicio: recopilación de información relacionada, como lecturas de sensores, nivel de batería, frecuencia cardíaca, etc.;

    Característica: es donde se guardan los datos reales en la jerarquía (valor);

    Descriptor: metadatos sobre los datos;

    Propiedades: describe cómo se puede interactuar con el valor característico. Por ejemplo: leer, escribir, notificar, difundir, indicar, etc.

    En nuestro ejemplo, crearemos un servicio con dos características.

    Uno para la temperatura y otro para la humedad.

    Las lecturas reales de temperatura y humedad se guardan en el valor bajo sus características. Cada característica tiene la propiedad de notificación, de modo que notifique al cliente cada vez que cambien los valores.

    UUI

    Cada servicio, característica y descriptor tiene un UUID (Universally Unique Identifier). Un UUID es un número único de 128 bits (16 bytes).

    Por ejemplo:

    55072829-bc9e-4c53-938a-74a6d4c78776

    Hay UUID abreviados para todos los tipos, servicios y perfiles especificados en el SIG (Bluetooth Special Interest Group).

    Si su aplicación necesita su propio UUID, puede generarlo utilizando este sitio web generador de UUID.

    En resumen, el UUID se utiliza para identificar información de manera única. Por ejemplo, puede identificar un servicio particular proporcionado por un dispositivo Bluetooth.

    Conectando el ESP32

    Este ejemplo funcionaría para cualquier placa de desarrollo actual con ESP-32. En este caco se utilizaron las siguientes placas:

    Heltec ESP32 Lora V2, LolinD32, NodeMCU ESP32S

    Sketch para Servidor BLE

    #define LED_BUILTIN 2
    #include <BLEDevice.h>
    #include <BLEServer.h>
    #include <BLEUtils.h>
    #include <BLE2902.h>
    
    #define temperatureCelsius
    #define BLE_server "ESP32_Server"
    
    #define SERVICE_UUID "huecat23-6d3c-4a17-a71f-ece2e6075f9b"
    
    BLECharacteristic dhtTemperatureCelsiusCharacteristics("huecat23-c85e-4596-9bd9-015e2eaa4888", BLECharacteristic::PROPERTY_NOTIFY);
    BLEDescriptor dhtTemperatureCelsiusDescriptor(BLEUUID((uint16_t)0x2902));
    
    BLECharacteristic dhtHumidityCharacteristics("huecat23-4a2f-4cf3-96e6-38b79be71a61", BLECharacteristic::PROPERTY_NOTIFY);
    BLEDescriptor dhtHumidityDescriptor(BLEUUID((uint16_t)0x2903));
    
    
    bool device_connected = false;
    
    class MyServerCallbacks: public BLEServerCallbacks {
        void onConnect(BLEServer* pServer) {
          device_connected = true;
        };
    
        void onDisconnect(BLEServer* pServer) {
          device_connected = false;
        }
    };
    
    void setup() {
    
      Serial.begin(115200);
    
      BLEDevice::init(BLE_server);
      BLEServer *pServer = BLEDevice::createServer();
      pServer->setCallbacks(new MyServerCallbacks());
      BLEService *dhtService = pServer->createService(SERVICE_UUID);
    
    
      dhtService->addCharacteristic(&dhtTemperatureCelsiusCharacteristics);
      dhtTemperatureCelsiusDescriptor.setValue("DHT Temperature (Celsius)");
      dhtTemperatureCelsiusCharacteristics.addDescriptor(new BLE2902());
    
      dhtService->addCharacteristic(&dhtHumidityCharacteristics);
      dhtHumidityDescriptor.setValue("DHT humidity");
      dhtHumidityCharacteristics.addDescriptor(new BLE2902());
      dhtService->start();
      pServer->getAdvertising()->start();
      Serial.println("Esperando a Cliente Bluetooth");
    }
    void loop() {
    
    
      //Timer cada 5 segundos: envía la info por bluetooth
      static unsigned long enviaDato;
      if (millis() > enviaDato + 5000) {
        enviaDato = millis();
    
        ///////////////////////////////// 
          if (device_connected) {
    
        //Datos de prueba
        float temp = 25;
        float hum = 88;
        
        static char temperature_celsius[7];
        dtostrf(temp, 6, 2, temperature_celsius);
        dhtTemperatureCelsiusCharacteristics.setValue(temperature_celsius);
        dhtTemperatureCelsiusCharacteristics.notify();
        Serial.print("Temperatura: ");
        Serial.print(temp);
        Serial.print(" *C");
    
        static char humidity[7];
        dtostrf(hum, 6, 2, humidity);
        dhtHumidityCharacteristics.setValue(humidity);
        dhtHumidityCharacteristics.notify();
        Serial.print("  Humedad: ");
        Serial.print(hum);
        Serial.println(" %");
      }
    
    
    
        
      }
    
      
    
      //Parpadeo del LED
      static unsigned long parpadeo;
      if (millis() > parpadeo + 80) {
        digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
        parpadeo = millis();
      }
    
    }
    

    Sketch para el Cliente BLE

    #include "BLEDevice.h"
    #include "heltec.h"
    #include "Arduino.h"
    
    
    SSD1306Wire display(0x3c, SDA_OLED, SCL_OLED, RST_OLED); //128_64
    
    #define SCREEN_WIDTH 128
    #define SCREEN_HEIGHT 64
    
    #define temperatureCelsius
    #define BLE_server "ESP32_Server"
    
    
    // Generador de UUIDs:
    // https://www.uuidgenerator.net/
    
    //***********************************
    //BLE ID UNICO PARA SERVICIO
    static BLEUUID                dhtServiceUUID("huecat23-6d3c-4a17-a71f-ece2e6075f9b");
    //***********************************
    
    //BLE ID UNICO PARA CARACTERÍSTICA (TEMPERATURA)
    static BLEUUID temperatureCharacteristicUUID("huecat23-c85e-4596-9bd9-015e2eaa4888");
    
    //BLE ID UNICO PARA CARACTERÍSTICA (HUMEDAD)
    static BLEUUID    humidityCharacteristicUUID("huecat23-4a2f-4cf3-96e6-38b79be71a61");
    
    
    /*
    
      //***********************************
      //BLE ID UNICO PARA SERVICIO
      static BLEUUID dhtServiceUUID("d29181ad-6d3c-4a17-a71f-ece2e6075f9b");
      //***********************************
    
      //BLE ID UNICO PARA CARACTERÍSTICA (TEMPERATURA)
      static BLEUUID temperatureCharacteristicUUID("ea4963df-c85e-4596-9bd9-015e2eaa4888");
    
      //BLE ID UNICO PARA CARACTERÍSTICA (HUMEDAD)
      static BLEUUID humidityCharacteristicUUID("b61decbb-4a2f-4cf3-96e6-38b79be71a61");
    
    
    */
    static boolean bleConectado = false;
    static boolean connected = false;
    
    static BLEAddress *pServerAddress;
    static BLERemoteCharacteristic* temperatureCharacteristic;
    static BLERemoteCharacteristic* humidityCharacteristic;
    
    const uint8_t notificationOn[] = {0x1, 0x0};
    const uint8_t notificationOff[] = {0x0, 0x0};
    
    
    bool conectarAServidor(BLEAddress pAddress) {
      BLEClient* pClient = BLEDevice::createClient();
    
      pClient->connect(pAddress);
      Serial.println("Conectado al Servidor");
    
      BLERemoteService* pRemoteService = pClient->getService(dhtServiceUUID);
    
      if (pRemoteService == nullptr) {
        Serial.print("Failed to find our service UUID: ");
        Serial.println(dhtServiceUUID.toString().c_str());
        return (false);
      }
    
      temperatureCharacteristic = pRemoteService->getCharacteristic(temperatureCharacteristicUUID);
      humidityCharacteristic = pRemoteService->getCharacteristic(humidityCharacteristicUUID);
    
      if (temperatureCharacteristic == nullptr || humidityCharacteristic == nullptr) {
        Serial.print("Failed to find our characteristic UUID");
        return false;
      }
      Serial.println(" Characteristics Found!");
    
      temperatureCharacteristic->registerForNotify(temperatureNotifyCallback);
      humidityCharacteristic->registerForNotify(humidityNotifyCallback);
    }
    
    class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
        void onResult(BLEAdvertisedDevice advertisedDevice) {
          if (advertisedDevice.getName() == BLE_server) {
            advertisedDevice.getScan()->stop();
            pServerAddress = new BLEAddress(advertisedDevice.getAddress());
            bleConectado = true;
            Serial.println("Dispositivo encontrado. Conectando...");
          }
        }
    };
    
    static void temperatureNotifyCallback(BLERemoteCharacteristic*pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify)
    {
    
      String informarTemperatura = "";
      informarTemperatura = "Temperatura: ";
      informarTemperatura += (char*)pData;
      informarTemperatura += " *C";
    
      imprimirConAltura(informarTemperatura, 20); ////// IMPRIME OLED Y SERIAL //////
    
    }
    
    static void humidityNotifyCallback(BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
    
      String informarHumedad = "Humedad: ";
      informarHumedad += (char*)pData;
      informarHumedad += " %";
    
      //imprimirConAltura(informarHumedad, 28); ////// IMPRIME OLED Y SERIAL //////
    
      Serial.println(informarHumedad);
    }
    
    void setup()
    {
      Serial.begin(115200);
      Serial.println("\nESP-32--B-BLE-CLIENTE");
    
      ///////////////////////////////////////// PARA PANTALLA OLED
      initHeltecEsp32(); //Inicializaciones correspondientes a modelo Pantalla OLED elegido.
    
      imprimirConAltura("Comenzando conexión BLE ( Cliente)", 0); ////// IMPRIME OLED Y SERIAL //////
    
      BLEDevice::init("");
    
      BLEScan* pBLEScan = BLEDevice::getScan();
      pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
      pBLEScan->setActiveScan(true);
      pBLEScan->start(30);
    
    
    }
    void loop() {
    
      if (bleConectado == true) {
    
        if (conectarAServidor(*pServerAddress)) {
    
          String conectando = "Conectado servidor BLE.";
          imprimirConAltura(conectando, 8); ////// IMPRIME OLED Y SERIAL //////
    
          temperatureCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
          humidityCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)notificationOn, 2, true);
          connected = true;
        } else {
          String conectando_error = "Falló conexión Servidor BLE";
          imprimirConAltura(conectando_error, 8); ////// IMPRIME OLED Y SERIAL //////
        }
        bleConectado = false;
      }
      delay(1000);
    }
    
    
    
    //Basado en ejemplo Heltec OLED_rotate.ino
    void VextON(void)
    {
      pinMode(Vext, OUTPUT);
      digitalWrite(Vext, LOW);
    }
    
    void VextOFF(void) //Vext default OFF
    {
      pinMode(Vext, OUTPUT);
      digitalWrite(Vext, HIGH);
    }
    
    void initHeltecEsp32() {
    
      VextON();
      delay(100);
    
      display.init();
      display.clear();
      display.display();
    
      display.setContrast(1);
    
      display.setTextAlignment(TEXT_ALIGN_CENTER);
      display.clear();
      display.display();
      display.screenRotate(ANGLE_0_DEGREE);
      display.setFont(ArialMT_Plain_16);
      display.drawString(64, 32 - 16 / 2, "HUE CAT"); //ROTATE_0
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_90_DEGREE);
      display.setFont(ArialMT_Plain_10);
      display.drawString(32, 64 - 10 / 2, "HUE CAT"); //ROTATE_90
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_180_DEGREE);
      display.setFont(ArialMT_Plain_16);
      display.drawString(64, 32 - 16 / 2, "HUE CAT"); //ROTATE_180
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_270_DEGREE);
      display.setFont(ArialMT_Plain_10);
      display.drawString(32, 64 - 10 / 2, "HUE CAT"); //ROTATE_270
      display.display();
      delay(400);
    
      display.clear();
      display.display();
      display.screenRotate(ANGLE_0_DEGREE);
      display.setFont(ArialMT_Plain_16);
      display.drawString(64, 32 - 16 / 2, "HUE CAT"); //ROTATE_0
      display.display();
      delay(500);
    
      display.clear();
      display.display();
    
      display.setTextAlignment(TEXT_ALIGN_LEFT);
      display.setFont(ArialMT_Plain_10);
    
    }
    
    
    void imprimirConAltura(String stringToPrint, int alturaAImprimir) {
      //Imprime en monitor serie y display
      Serial.print("OLED->" + stringToPrint);
      display.drawString(0, alturaAImprimir, stringToPrint);
      display.display();
    }