Servidor Bluetooth BLE

 

  • Entraremos en el detalle del programa Servidor BLE
  • Modificaremos el servidor para publicar un numero aleatorio
  • Presentaremos un programa general como plantilla para que montes tu propio servidor BLE en tus proyectos.
  •  

    Material requerido.

     

     vista lateral del esp32 Un ESP32

    Bluetooth BLE

     

    En la última sesión hablamos de los conceptos precisos para comprender el Bluetooth BLE de baja energía y de cómo el modelo conceptual había cambiado con respecto al más limitado (Y sencillo) Bluetooth Classic.

    Cargamos el programa Servidor de ejemplo que nos suministran las librerías del ESP32 BLE, y vimos cómo, con la ayuda de una app para nuestro móvil, podíamos comprobar que publicaba correctamente nuestros datos, los pocos que habíamos manipulado, pero sin entrar en el detalle de funcionamiento del programa servidor.

    Tan imperdonable omisión no podía quedar impune, y por ello en esta nueva sesión vamos a entrar en el detalle de las líneas que conforman el programa Servidor BLE ESP32, para que podáis modificarlo en vuestros proyectos personales en caso de que sea necesario. Así que, sin más dilación, vamos al lío

     

    Servidor BLE

     

    Si recordáis la sesión anterior, habíamos comentado que teníamos que dar una serie de pasos para definir un servidor BLE:

     

  • Crear el Servidor BLE.
  • Crear un Servicio BLE.
  • Crear una Característica en el Servicio BLE.
  • Crear un descriptor BLE en la Característica.
  • Arrancar el Servidor.  
  •  

    Vamos como siempre a empezar por los include necesarios para mover todo, gracias a los que nos ahorramos todos los sucios detalles de bajar al barro.

    #include <BLEDevice.h>
    #include <BLEUtils.h>
    #include <BLEServer.h>

    Las dos primeras includes son precisos cuando vayas a usar BLE con tu ESP32 y el tercero (al igual que con la WIFI), se requiere para montar un servidor BLE. Para arrancar un servidor BLE necesitamos levantar al menos un Servicio y una Característica, cada uno con su propio UUID.

  • Si estás solo en tu casa haciendo pruebas de programación BLE, es seguro usar el UUID que viene en el programa de ejemplo, pero si por ejemplo estas en un aula con varios alumnos, no conviene que copies el del programa estándar, porque sino todos los servidores tendrán el mismo UUID y la cosa acabará mal.
  •  

    Lo siguiente es definir los UUIDs del Servicio y características por lo que conviene usar el generador aleatorio de claves que vimos en la última sesión  Le he pedido que me genere dos claves UUID (Con el generador versión 4) y me ha salido esto:

    40bc3f4d-8b63-4edc-a799-f3fd6a1e4417
    cf98f21a-2e5b-4341-83ee-e22b6bef0e52

    Así que las siguientes líneas van a ser:

    #define SERVICE_UUID        "40bc3f4d-8b63-4edc-a799-f3fd6a1e4417"
    #define CHARACTERISTIC_UUID "cf98f21a-2e5b-4341-83ee-e22b6bef0e52"

    Donde asignamos estos IDs a nuestros valores y así evitamos tener todos el mismo ID una y otra vez. Vamos con las características básicas del servidor BLE:

    BLEDevice::init("Prometec");
    BLEServer  *pServer = BLEDevice::createServer();
    BLEService *pService = pServer->createService(SERVICE_UUID);
    BLECharacteristic *pCharacteristic = pService->createCharacteristic
             (   CHARACTERISTIC_UUID,
                 BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_WRITE
             );

    He identificado en la primera línea, que publique el servicio con el nombre “Prometec”, pero Aquí puedes poner lo que se te ocurra. La segunda línea crea una instancia de un servidor BLE, y la tercera crea un servicio con el UUID que definimos arriba, y en la 4ª línea, creamos un servicio asociado al servicio pService que acabamos de definir.

    Asociamos a este pService, una característica (Con el segundo UUID que hemos creado) y dos propiedades ( READ + WRITE) para que podamos modificar los valores. Lo siguiente es dar valor a esas características y arrancar el servicio en el servidor BLE:

    pCharacteristic->setValue("Pues, aqui. Probando el BLE, oyes");
    pService->start();

    Ahora toca arrancar el advertising (Algo así como encender el cartel de abierto al público) y asignar el servicio al cartel de neon para que se vea

    BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
    pAdvertising->addServiceUUID(SERVICE_UUID);

    El resto es gimnasia:

    pAdvertising->setScanResponse(true);
    pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
    pAdvertising->setMinPreferred(0x12);
    BLEDevice::startAdvertising();
    Serial.println("Characteristic defined! Now you can read it in your phone!");

    La primera inicia la búsqueda de respuestas a nuestro anuncio (Clientes interesados)  y como podéis ver los iPhone siempre dando la nota con sus manías. La línea de start es la que físicamente inicia el advertising.

    Si ahora usas el nRF Connect veras que las servicios y características usan los UUIDs que les hemos proporcionado:

    Presentacion de los UUID BLE

     

    Mejorando un poco el programa

     

    Como la explicación del programa servidor ha quedado un poco corta (Y me pagan por páginas) podemos hacer alguna modificación que nos resulte mínimamente útil, porque en el ejemplo de arriba, no hemos puesto nada en el loop, sino que todo va en el setup. Cuando queramos publicar un valor de un sensor, por ejemplo, asignándole a las propiedades del servidor, nos vamos a encontrar con que los punteros al servidor servidor BLE no son de acceso público en nuestro programa.

  • Los punteros del servidor BLE , están definidos dentro del setup y solo se puede acceder a el y a sus características desde el propio setup()
  • Si queréis una explicación sobre el ámbito de uso de las variables en C++ os recomiendo esta sesion anterior:  «Ambito de las variables en C++»……[/fancy-ul] [/three-fourth]
  •  

    Por eso, y porque el tema de los punteros suelen ser el coco de los estudiantes de C++, vamos a hacer una pequeña modificación, que publique un número aleatorio en las características de nuestro servidor BLE, remedando la idea de un valor que cambia, como la lectura de un sensor, pongamos por caso.

    Para ello hay que reescribir este programa de forma que nos permita acceder al servidor desde cualquier punto y de ese modo conseguir que todo esto nos sirva como plantilla para cualquier proyecto bluetooth BLE que podáis necesitar en un momento dado. Vamos con los include:

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

    Lo de arriba es repetir los include del ejemplo anterior, pero he añadido el stdio.h, porque vamos a publicar un texto más un valor en valor de las características y para eso necesito la función sprinf() y un buffer de caracteres donde escribir el texto.

    #define SERVICE_UUID        "40bc3f4d-8b63-4edc-a799-f3fd6a1e4417"
    #define CHARACTERISTIC_UUID "cf98f21a-2e5b-4341-83ee-e22b6bef0e52”
    BLEServer *pServer ; BLEService *pService; BLECharacteristic *pCharacteristic ;

    Definimos los mismos UUIDs de antes y después, vamos a declarar el servicio y la característica de nuestro servidor BLE como punteros globales (Lo sé, es una chapuza, pero sencilla) para que podamos acceder a ellos desde nuestras funciones fuera del setup, que se reduce un poco y pasa a ser así:

    void setup() 
    { Serial.begin(115200);
      Serial.println("Starting BLE work!");
     
      BLEDevice::init("Prometec");
      pServer = BLEDevice::createServer();
      pService = pServer->createService(SERVICE_UUID);
      pCharacteristic = pService->createCharacteristic(
                        CHARACTERISTIC_UUID,
                        BLECharacteristic::PROPERTY_READ |
                        BLECharacteristic::PROPERTY_WRITE
                );
      pService->start(); 
      BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
      pAdvertising->addServiceUUID(SERVICE_UUID);
      pAdvertising->setScanResponse(true);
      pAdvertising->setMinPreferred(0x06);  // functions that help with iPhone connections issue
      pAdvertising->setMinPreferred(0x12);
      
      BLEDevice::startAdvertising();
      Serial.println("Characteristic defined! Now you can read it in your phone!");
    }

    El cambio solo ha sido que como hemos declarado arriba pServer, pService  y pCharacteristic  (Sin asignarlas) ahora podemos usarlas en cualquier sitio del programa y las asignamos dentro del setup().

    El loop va a ser bastante sencillo:

    void loop()
       { int r = random(0,1000) * 6 ;
         sprintf(buffer, "Prometec: %d",r);
         Serial.println(buffer);
    
          pCharacteristic->setValue(buffer);
          delay(2000);
       }

    Calculamos los valores con la cadena “Prometec: ” más un número aleatorio entre 0 y 6.000, (Que calculamos cada dos segundos) y s elo asignamos a la pCharacteristic del servidor y para eso necesitaba el sprintf().  Como veras, puedes usar este método como de uso general, para llenar los valores que publica el servidor BLE tanto para Textos como para números, en el caso de lecturas de sensores y similares.

    Aquí va el programa completo:  BLE_server_2

    Servidor BLE

     

     

    IMAGEN DE MARCA

    Indice ESP32/IOT

    Índice General

    Índice Coms 

    Deja una respuesta