ESPHome as Fitbit Exercise Equipment

Hi All,

I’d like to monitor my HR in realtime while exercising and output it to a display. My Fitbit Charge 6 is able to send my HR to a fitness device via bluetooth. Has anyone ever been able to configure ESPHome as a fitness device that Fitbit will connect to? I have a Polar chest strap HR monitor and it works with the configuration below, but the Fitbit requires a connection which I am having issues configuring.

I can see the advertisements with ESPHome but it will not connect to get the HR data. Fitbit will not acknowledge that ESPHome is trying to connect and start sending data. When testing I can connect to nrf Connect on my phone via bluetooth I can see the HR data being sent, so I know the service and characteristic UUIDs are correct.

esp32_ble:

esp32_ble_tracker:
  on_ble_advertise:
    - mac_address:
        - <redacted>
      then:
        - lambda: |-
            ESP_LOGD("ble_adv", "  name: %s", x.get_name().c_str());
            ESP_LOGD("ble_adv", "  Advertised service UUIDs:");
            for (auto uuid : x.get_service_uuids()) {
                ESP_LOGD("ble_adv", "    - %s", uuid.to_string().c_str());
            }
            ESP_LOGD("ble_adv", "  Advertised service data:");
            for (auto data : x.get_service_datas()) {
                ESP_LOGD("ble_adv", "    - %s: (length %i)", data.uuid.to_string().c_str(), data.data.size());
            }
ble_client:
  - mac_address: <redacted>
    id: charge6
    auto_connect: true
    on_connect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Connected to BLE Charge 6");
    on_disconnect:
      then:
        - lambda: |-
            ESP_LOGD("ble_client_lambda", "Disconnected from Charge 6");
  - mac_address: <redacted>
    id: polar

sensor:
  - platform: ble_client
    ble_client_id: charge6
    type: characteristic
    name: "Heartrate"
    service_uuid: '180D'
    characteristic_uuid: '2A37'
    notify: true
    # lambda: |-
    #   return *((float*)(&x[0]));
    lambda: |-
      uint16_t heart_rate_measurement = x[1];
      if (x[0] & 1) {
          heart_rate_measurement += (x[2] << 8);
      }
      return (float)heart_rate_measurement;
    icon: 'mdi:heart'
    unit_of_measurement: 'bpm'    
  - platform: ble_client
    ble_client_id: polar
    type: characteristic
    name: "Polar"
    service_uuid: '180d'
    characteristic_uuid: '2a37'
    notify: true
    accuracy_decimals: 0
    lambda: |-
      uint16_t heart_rate_measurement = x[1];
      if (x[0] & 1) {
          heart_rate_measurement += (x[2] << 8);
      }
      return (float)heart_rate_measurement;
    icon: 'mdi:heart'
    unit_of_measurement: 'bpm'

Logs of ESPHome on boot

[13:41:58][D][esp32_ble_client:110]: [0] [CB:B8:31:A4:E7:31] Found device
[13:41:58][D][esp32_ble_tracker:671]: Found device CB:B8:31:A4:E7:31 RSSI=-66
[13:41:58][D][esp32_ble_tracker:692]:   Address Type: RANDOM
[13:41:58][D][esp32_ble_tracker:694]:   Name: 'Charge 6'
[13:41:58][D][esp32_ble_tracker:697]:   TX Power: 2
[13:41:58][D][esp32_ble_tracker:219]: Pausing scan to make connection...
[13:41:58][D][esp32_ble_tracker:219]: Pausing scan to make connection...
[13:41:58][D][esp-idf:000][BTU_TASK]: E (20846) BT_BTM: BTM_BleScan scan not active


[13:41:58][I][esp32_ble_client:067]: [0] [CB:B8:31:A4:E7:31] 0x01 Attempting BLE connection
[13:42:11][D][esp32_ble_client:110]: [0] [CB:B8:31:A4:E7:31] ESP_GATTC_CONNECT_EVT
[13:42:11][D][esp32_ble_client:110]: [0] [CB:B8:31:A4:E7:31] ESP_GATTC_OPEN_EVT
[13:42:11][I][ble_sensor:031]: [Fitbit] Connected successfully!
[13:42:11][D][esp32_ble_tracker:270]: Starting scan...
[13:42:15][D][esp32_ble_client:306]: [0] [CB:B8:31:A4:E7:31] Event 46
[13:42:15][D][esp32_ble_client:110]: [0] [CB:B8:31:A4:E7:31] ESP_GATTC_SEARCH_CMPL_EVT
[13:42:15][I][esp32_ble_client:227]: [0] [CB:B8:31:A4:E7:31] Connected
[13:42:15][D][ble_client_lambda:050]: Connected to BLE Charge 6
[13:42:15][D][esp32_ble_client:188]: [0] [CB:B8:31:A4:E7:31] cfg_mtu status 0, mtu 247
[13:42:15][D][esp32_ble_client:110]: [0] [CB:B8:31:A4:E7:31] ESP_GATTC_REG_FOR_NOTIFY_EVT
[13:42:15][D][esp32_ble_client:296]: Wrote notify descriptor 1, properties=16
[13:42:15][D][ble_sensor:103]: Register for notify on 0x2A37 complete
[13:42:15][D][ble_client:058]: All clients established, services released
[13:42:15][D][esp32_ble_client:110]: [0] [CB:B8:31:A4:E7:31] ESP_GATTC_WRITE_DESCR_EVT

Logs when I try to send the HR from fitbit, but no connection is made or data is sent.

[13:38:57][D][ble_adv:035]:   name: Charge 6
[13:38:57][D][ble_adv:036]:   Advertised service UUIDs:
[13:38:57][D][ble_adv:038]:     - 0x180D

Any help or push in the right direction would be appreciated

Hi

I don’t think you’ll succeed easily as all these devices use proprietary protocol that are not public. You’ll have to reverse-engineer it which might be complicated. Something that can help is to look at source code of Gadgetbridge (open source app to use with fitness tracker, I use it since ages with Xiaomi band and it works great !).

Vincèn

Well the Bluetooth standards do include a lot of bodily functions.

Not sure what you are talking about ? Bluetooth is just a serial protocol through Radio ! You need the protocol to be able to decode datas sent through it !

And many of those protocols are standardized.

See https://www.bluetooth.com/wp-content/uploads/Files/Specification/HTML/Assigned_Numbers/out/en/Assigned_Numbers.pdf?v=1729762663146

Yeah but not for fitnes devices as far as I know and that’s the reason that some devices like Withings among others are not even supported by Gadgetbridge as their protocol is so complicated that it’s nearly impossible to reverse-engineer it :frowning:

Let’s see wat Fitbit has to say

Hit a dead end with this. Even contacted their support via chat and they don’t have anything in their DB they can offer.

My Polar chest strap seems to be superior in this regard.