BLE heart rate monitor custom sensor

Hi,
I was wondering if anyone knew how to transfer this code:

https://github.com/Merdeka/ESP32/blob/ad641bf9455a9b4bf964ee082cfb6f7a0fd240c1/ESP32_OLED_HRM/ESP32_OLED_HRM.ino

into a ESPHome custom sensor. I Don’t need the MQTT or OLED display part, just the BLE heart rate as a sensor. I’ve had a go myself but without any luck. Is it actually possible with the connection classes outside of the ‘void setup’ and ‘void loop’. I’ve only just started with ESPHome and I’m not very good with advanced coding (well advanced to me anyway).

Thanks for any help in advance.

1 Like

ok. so i stripped out the mqtt and display code i didn’t need. I realise there’s no actual output yet. At the moment i’m just wanting to show some stuff up in the logs when the ble connects but i don’t get any ‘custom’ log outputs.

#include "esphome.h"
#include "BLEDevice.h"
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

static  BLEUUID serviceUUID(BLEUUID((uint16_t)0x180D));
static  BLEUUID    charUUID(BLEUUID((uint16_t)0x2A37));

static BLEAddress *pServerAddress;
static boolean doConnect = false;
static boolean connected = false;
static boolean notification = false;
static BLERemoteCharacteristic* pRemoteCharacteristic;

typedef struct {
  char ID[20];
  uint16_t HRM;
}HRM;
HRM hrm;

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    ESP_LOGD("custom","BLE Advertised Device found: ");
    if (advertisedDevice.haveServiceUUID() && advertisedDevice.getServiceUUID().equals(serviceUUID)) {
      ESP_LOGD("custom","Found our device!  address: "); 
      advertisedDevice.getScan()->stop();
      pServerAddress = new BLEAddress(advertisedDevice.getAddress());
      doConnect = true;
    }
  }
};

class MyCustomSensor : public Component, public Sensor {
 public:
 
   static void notifyCallback( BLERemoteCharacteristic* pBLERemoteCharacteristic, uint8_t* pData, size_t length, bool isNotify) {
    if (bitRead(pData[0], 0) == 1) {
    ESP_LOGD("custom","16bit HeartRate Detected");
    } else {
    ESP_LOGD("custom","8bit HeartRate Detected");
    }
    if (length == 2) {
    hrm.HRM = pData[1];
    ESP_LOGD("custom","Heart Rate: %d", hrm.HRM);
  }
  }
 
  bool connectToServer(BLEAddress pAddress) {
    ESP_LOGD("custom","Forming a connection to ");
    ESP_LOGD("custom",pAddress.toString().c_str());

    BLEClient*  pClient  = BLEDevice::createClient();
    ESP_LOGD("custom"," - Created client");
    
    // Connect to the HRM BLE Server.
    pClient->connect(pAddress);
    ESP_LOGD("custom"," - Connected to server");

    // Obtain a reference to the service we are after in the remote BLE server.
    BLERemoteService* pRemoteService = pClient->getService(serviceUUID);
    if (pRemoteService == nullptr) {
      ESP_LOGD("custom","Failed to find our service UUID: ");
      ESP_LOGD("custom",serviceUUID.toString().c_str());
      return false;
    }
    ESP_LOGD("custom"," - Found our service");

    // Obtain a reference to the characteristic in the service of the remote BLE server.
    pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
    if (pRemoteCharacteristic == nullptr) {
      ESP_LOGD("custom","Failed to find our characteristic UUID: ");
      ESP_LOGD("custom",charUUID.toString().c_str());
      return false;
    }
    ESP_LOGD("custom"," - Found our characteristic");

    // Register for Notify
    pRemoteCharacteristic->registerForNotify(notifyCallback);
}
  
  void setup() override {
  
  // Start BLE
  BLEDevice::init("");

  // Retrieve a Scanner and set the callback we want to use to be informed when we
  // have detected a new device.  Specify that we want active scanning and start the
  // scan to run for 30 seconds.
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);
  pBLEScan->start(30);
  }
 
  void loop() override {
  
  // If the flag "doConnect" is true then we have scanned for and found the desired
  // BLE Server with which we wish to connect.  Now we connect to it.  Once we are 
  // connected we set the connected flag to be true.
  if (doConnect == true) {
    if (connectToServer(*pServerAddress)) {
      ESP_LOGD("custom","We are now connected to the BLE HRM");
      connected = true;
    } else {
      ESP_LOGD("custom","We have failed to connect to the HRM; there is nothin more we will do.");
    }
    doConnect = false;
  }

  // Turn notification on
  if (connected) {
    if (notification == false) {
      ESP_LOGD("custom","Turning Notifocation On");
      const uint8_t onPacket[] = {0x1, 0x0};
      pRemoteCharacteristic->getDescriptor(BLEUUID((uint16_t)0x2902))->writeValue((uint8_t*)onPacket, 2, true);
      notification = true;
    }
    
  }
  }//end of loop overide
};//end of class

The code will compile with these warnings:

In file included from src/main.cpp:15:0:
src/my_custom_sensor.h: In member function ‘bool MyCustomSensor::connectToServer(BLEAddress)’:
src/my_custom_sensor.h:80:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^

Appreciate if anyone could give me some pointers to what i’m done wrong.

Any progress on this issue?
I’m trying to create a heart rate sensor for Amazfit but the solution from here doesn’t work: Connecting to Bluetooth Low Energy devices in ESPHome | Koen Vervloesem - Technology Writer
Maybe this low-level programing is a chance…