Bluetooth BLE: Notify

 

  • Modificaremos el programa Servidor BLE.
  • Estudiaremos el caso de servidor BLE con Notify.
  • Presentaremos un programa con Notificaciones automáticas.
  •  

    Material requerido.

     

     vista lateral del esp32 Un ESP32

     

    Refinando el programa servidor

     

    Hemos conseguido que nuestro servidor BLE vaya publicando cada dos segundos el texto que calculamos como una String más un numero aleatorio, lo que no está mal, pero para poderlo leer tendríamos que ir leyendo progresivamente el valor de la Característica. Puede valer, pero para los que vayan a por nota, podríamos mejorar un poco esto combinando nuestro servidor con el ejemplo BLE notify que viene con las librerías del ESP32

    La idea es que sea nuestro servidor quien haga un “push” ( Bombeo) del valor requerido hacia nuestro cliente en cuanto nos conectemos, con un intervalo de tiempo que por defecto es de 1 segundo (Aunque siempre podemos frenarlo).

    Es algo parecido a suscribirse a un servicio de mensajes, no hay que ir a buscarlos, te llega a casa directamente al buzón sin tu intervención manual. Es un sistema muy comodo de recibir mensajes de digamos sensores. Imaginate que tu sensor de ttemperatura lee el valor una vez cada hora (La temperatura no cambia demasiado rapido)

    Es algo parecido a suscribirse a un servicio de mensajes, no hay que ir a buscarlos, te llega a casa directamente al buzón sin tu intervención manual. Es un sistema muy cómodo de recibir mensajes de digamos sensores. Imagínate que tu sensor de temperatura lee el valor una vez cada hora, (La temperatura no cambia demasiado rápido) en lugar de iniciar una llamada cada cierto tiempo para ver si hay nuevas lecturas, podemos sentarnos tranquilamente y esperar a que el servidor nos envié el dato cuando tenga disponible la nueva lectura. No es necesario comprobar periódicamente si hay nuevos valores. Recuerda que el Bluetooth BLE esta diseñado para ahorrar energía al máximo

    Para esto, tendrmos que hacer algunas modificaciones en el servidor, pero quien dijo miedo. Vamos allá.

    Empezamos con los include:

    #include <BLEDevice.h>
    #include <BLEServer.h>
    #include <BLEUtils.h>
    #include <BLE2902.h>
    
    #include <stdio.h>
    char buffer[32];

    Ya conocemos casi todas esas líneas, con excepción del último include, hablaremos de el mas adelante. Vamos ahora a crear los punteros públicos, para el servidor BLE y la Característica:

    BLEServer* pServer = NULL;
    BLECharacteristic* pCharacteristic = NULL;
    
    bool deviceConnected = false;
    bool oldDeviceConnected = false;
    uint32_t value = 0;

    Hemos creado un par de variables bool para saber si tenemos a alguien conectado al servidor o no, y ahora vamos con los UUIDs como siempre:

    #define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
    #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

    Vamos ahora con una cosa ligeramente mas truculenta, que consiste en vincular una función callback al Servidor BLE, para saber cuando hay alguien conectado o no, para bombear los datos:

    Aqui va el programa completo: BLE_Server_notify

    class MyServerCallbacks: public BLEServerCallbacks 
      {   void onConnect(BLEServer* pServer) 
           {   deviceConnected = true;
           };
    
          void onDisconnect(BLEServer* pServer) 
           {   deviceConnected = false;     }
      };

    Lo único que hace este código es conectar una función que se ejecuta cuando alguien se conecta al servidor y simplemente pone la variable deviceConnected a True, y a Ffalse cuando se desconecta, de este modo sabemos cuándo tenemos alguien conectado. Podríamos usar esta misma función para registrar el UUID de quien se conecte.

    Nos toca ahora, crear el servidor y vincular nuestra función callback (Con la 3ª línea) y con la última creamos el servicio:

      BLEDevice::init("Prometec");           // Create the BLE Device
      pServer = BLEDevice::createServer();   // Create the BLE Server
      pServer->setCallbacks(new MyServerCallbacks());
      BLEService *pService = pServer->createService(SERVICE_UUID

    Para crear la Característica vamos a añadir un par de flags:

    pCharacteristic = pService->createCharacteristic(
                          CHARACTERISTIC_UUID,
                          BLECharacteristic::PROPERTY_READ   |
                          BLECharacteristic::PROPERTY_WRITE  |
                          BLECharacteristic::PROPERTY_NOTIFY
                        );

    En los últimos ejemplos solo usábamos las propiedades READ & WRITE ( Para poder leer y escribir), pero aquí hemos añadido otra: NOTIFY (Notificaciones ), para que nos permita hacer el “push” de valores hacia los clientes.

    La razón es, que Bluetooth BLE dispone de una propiedad que permite bombear datos a un cliente , (Siempre que éste,  esté  dispuesto a aceptarlos), con la propiedad Notify, que activa las notificaciones para esa característica. Para que esto sea posible el cliente tiene que tener expresamente activada la capacidad de recibir notificaciones, y para eso añadimos arriba el include BLE2902.h que es quien se va a encargar de este tema.

    Para eso necesitamos crear un Descriptor de la Característica BLE con una instancia del BLE2902:

    pCharacteristic->addDescriptor(new BLE2902());

    Toca ahora, arrancar el Servicio BLE y el advertising para que nos vean los clientes externos:

    pService->start();   // Start the service
    
    BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();   // Start advertising
    pAdvertising->addServiceUUID(SERVICE_UUID);
    pAdvertising->setScanResponse(false);
    pAdvertising->setMinPreferred(0x0);  // set value to 0x00 to not advertise this parameter
    BLEDevice::startAdvertising();
    Serial.println("Waiting a client connection to notify...");

    Vamos con el loopp()

    void loop()
    {  if (deviceConnected)
    {   int r = random(0,1000) * 6 ;
        sprintf(buffer, "Prometec: %d",r);
        Serial.println(buffer);
        pCharacteristic->setValue(buffer);
        pCharacteristic->notify();
        // bluetooth stack will go into congestion,if too manypackets are sent
       delay(3); 
    }

    Comprobamos el Status de la variable deviceConnected, para calcular nuestro el valor a publicar y lo mandamos a la consola serie para que se vea, y añadimos el notify a la Característica. Si por el contrario el cliente se desconecta, empezamos de nuevo el advertising buscando nuevos clientes (Como un buen tendero).

    if (!deviceConnected && oldDeviceConnected)
       {    delay(500);    // give the bluetooth stack the chance to get things ready
            pServer->startAdvertising();            // restart advertising
            Serial.println("start advertising");
            oldDeviceConnected = deviceConnected;
       }

    Y por último, una función que parece nos permite hacer cosas cuando un usuario se conecta

    if (deviceConnected && !oldDeviceConnected)
     {      // do stuff here on connecting
            oldDeviceConnected = deviceConnected;
     }

    Si ahora nos conectamos con el nrf Connect a nuestro flamante nuevo servidor veremos algo así:

    Conexion a servidor ble con notify

    Comprueba el UUID del servicio (Para que veas que no hacemos trampa) y pulsa en el servicio para que se despliegue, y veras esta pantalla:

    Captura con vista de las propiedades

    Verás que ahora ha aparecido un nuevo icono a la derecha de las flechitas (Recuadrado en rojo en la imagen), que es el interruptor que nos permite activar la aceptación de las notificaciones.

    ¡Accede al contenido!

    Si lo pulsas, verás como aparecerá debajo el mensaje que estamos notificando con la cadena de texto mas el numero aleatorio, y esta vez, al aceptar el “push” del servidor BLE, va cambiando de forma continua el solito, no necesitamos pedirlo, simplemente lo recibimos enviado graciosamente por el servidor.

    Aquí os dejo un mini video de mi Xiaomi mostrando el resultado:

     

     

    IMAGEN DE MARCA

    Indice ESP32/IOT

    Índice General

    Índice Coms 

    Deja una respuesta