home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
73.8k stars 30.9k forks source link

ESPHome bluetooth proxy, "start_notify", "Characteristic ... does not have a characteristic client config descriptor". #97608

Closed GrumpyMeow closed 1 year ago

GrumpyMeow commented 1 year ago

The problem

I'm working on an Integration for my OcleanX bluetooth toothbrush. I'm using an nRF USB dongle, nRF Connect iOS app and the decompiled Oclean APK as sources of information. For the communication it's needed to write a command-code to 1 characteristic ("9d84b9a3-000c-49d8-9183-855b673fbb85") and then receive the notifications on another characteristic ("5f78df94-798c-46f5-990a-855b673fbb86"). When i call "start_notify" i get the error "Characteristic ... does not have a characteristic client config descriptor". The "nRF Connect iOS app" is able to enable notifications for that characteristic.

In code i see that the ability for notification is related to the "Client Characteristic Configuration". The specific characteristic is in "nRF Connect" displayed to have "Properties: Read and Notify".

afbeelding

What version of Home Assistant Core has the issue?

core-2023.9.0.dev0

What was the last working version of Home Assistant Core?

No response

What type of installation are you running?

Home Assistant Supervised

Integration causing the issue

bluetooth

Link to integration documentation on our website

No response

Diagnostics information

No response

Example YAML snippet

No response

Anything in the logs that might be useful for us?

No response

Additional information

No response

home-assistant[bot] commented 1 year ago

Hey there @ottowinter, @jesserockz, @bdraco, mind taking a look at this issue as it has been labeled with an integration (esphome) you are listed as a code owner for? Thanks!

Code owner commands Code owners of `esphome` can trigger bot actions by commenting: - `@home-assistant close` Closes the issue. - `@home-assistant rename Awesome new title` Renames the issue. - `@home-assistant reopen` Reopen the issue. - `@home-assistant unassign esphome` Removes the current integration label and assignees on the issue, add the integration domain after the command.

(message by CodeOwnersMention)


esphome documentation esphome source (message by IssueLinks)

bdraco commented 1 year ago

2902 is CCCD

You can see what esphome sees by enabling debug logging for aioesphomeapi

GrumpyMeow commented 1 year ago

This is what i see in the logs for my OcleanX toothbrush.

The advertisement:

Got message of type BluetoothLERawAdvertisementsResponse: advertisements {
  address: 123318265456547
  rssi: -100
  data: "\002\001\004\007\002\003\030\002\030\365\376\007\377\243\'hE(p"
}

This is the charactistic which i'm trying to subscribe to using notifications:

  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828934
    handle: 23
    properties: 18
  }

The gathering of GATT data:

Sending BluetoothGATTGetServicesRequest: address: 123318265456547

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 26388279070720
  uuid: 9223372588214596859
  handle: 1
  characteristics {
    uuid: 46179488370688
    uuid: 9223372588214596859
    handle: 3
    properties: 2
  }
  characteristics {
    uuid: 46183783337984
    uuid: 9223372588214596859
    handle: 5
    properties: 2
  }
  characteristics {
    uuid: 46196668239872
    uuid: 9223372588214596859
    handle: 7
    properties: 2
  }
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 26392574038016
  uuid: 9223372588214596859
  handle: 8
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 26396869005312
  uuid: 9223372588214596859
  handle: 9
  characteristics {
    uuid: 46205258174464
    uuid: 9223372588214596859
    handle: 11
    properties: 4
  }
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 26401163972608
  uuid: 9223372588214596859
  handle: 12
  characteristics {
    uuid: 46205258174464
    uuid: 9223372588214596859
    handle: 14
    properties: 10
  }
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 26452703580160
  uuid: 9223372588214596859
  handle: 15
  characteristics {
    uuid: 46286862553088
    uuid: 9223372588214596859
    handle: 17
    properties: 18
    descriptors {
      uuid: 45088566677504
      uuid: 9223372588214596859
      handle: 18
    }
  }
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 9260186607831892001
  uuid: 10504178811444448280
  handle: 19
  characteristics {
    uuid: 11350401070612105688
    uuid: 10485370985069394821
    handle: 21
    properties: 10
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828934
    handle: 23
    properties: 18
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828935
    handle: 25
    properties: 10
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828936
    handle: 27
    properties: 18
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828937
    handle: 29
    properties: 10
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828944
    handle: 31
    properties: 18
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027773265190828945
    handle: 33
    properties: 18
    descriptors {
      uuid: 45088566677504
      uuid: 9223372588214596859
      handle: 34
    }
  }
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 280328220446720
  uuid: 9223372588214596859
  handle: 35
  characteristics {
    uuid: 9260186607831892001
    uuid: 10504178811444448308
    handle: 37
    properties: 10
  }
  characteristics {
    uuid: 8233224365517523807
    uuid: 9801031481696486993
    handle: 39
    properties: 10
  }
  characteristics {
    uuid: 7805823532325225982
    uuid: 11538922165998145492
    handle: 41
    properties: 2
  }
  characteristics {
    uuid: 11350401070612105688
    uuid: 10485370985069402673
    handle: 43
    properties: 10
  }
  characteristics {
    uuid: 5005876230643666081
    uuid: 10454640138829667506
    handle: 45
    properties: 14
  }
  characteristics {
    uuid: 6879494259595822837
    uuid: 11027824461247569032
    handle: 47
    properties: 18
    descriptors {
      uuid: 45088566677504
      uuid: 9223372588214596859
      handle: 48
    }
  }
  characteristics {
    uuid: 7046027426701854565
    uuid: 10695587543891491626
    handle: 50
    properties: 2
  }
  characteristics {
    uuid: 7256680763920564251
    uuid: 11681682987140485434
    handle: 52
    properties: 2
  }
  characteristics {
    uuid: 4810934969251548572
    uuid: 9535404122416085819
    handle: 54
    properties: 2
  }
  characteristics {
    uuid: 13249061146326811579
    uuid: 11794862072900936252
    handle: 56
    properties: 2
  }
}

Got message of type BluetoothGATTGetServicesResponse: address: 123318265456547
services {
  uuid: 26431228743680
  uuid: 9223372588214596859
  handle: 57
  characteristics {
    uuid: 46355582029824
    uuid: 9223372588214596859
    handle: 59
    properties: 2
  }
  characteristics {
    uuid: 46334107193344
    uuid: 9223372588214596859
    handle: 61
    properties: 2
  }
  characteristics {
    uuid: 46338402160640
    uuid: 9223372588214596859
    handle: 63
    properties: 2
  }
  characteristics {
    uuid: 46346992095232
    uuid: 9223372588214596859
    handle: 65
    properties: 2
  }
  characteristics {
    uuid: 46342697127936
    uuid: 9223372588214596859
    handle: 67
    properties: 2
  }
  characteristics {
    uuid: 46351287062528
    uuid: 9223372588214596859
    handle: 69
    properties: 2
  }
}

Got message of type BluetoothGATTGetServicesDoneResponse: address: 123318265456547

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 3

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 3
data: "Oclean X"

Sending plaintext frame 000a4908a3cfa0ab84851c1005
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 5
data: "\000\000"

Sending plaintext frame 000a4908a3cfa0ab84851c1007
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 7
data: "\220\001X\002\000\000X\002"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 11

Sending plaintext frame 000a4908a3cfa0ab84851c100b

Got message of type BluetoothGATTErrorResponse: address: 123318265456547
handle: 11
error: 2

Sending plaintext frame 000a4908a3cfa0ab84851c100e

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 14
data: "\000"

Sending plaintext frame 000a4908a3cfa0ab84851c1011

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 17
data: "\000"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 21

Sending plaintext frame 000a4908a3cfa0ab84851c1015
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 21

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 23

Sending plaintext frame 000a4908a3cfa0ab84851c1017

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 23

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 25

Sending plaintext frame 000a4908a3cfa0ab84851c1019
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 25

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 27

Sending plaintext frame 000a4908a3cfa0ab84851c101b

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 27

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 29

Sending plaintext frame 000a4908a3cfa0ab84851c101d
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 29

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 31

Sending plaintext frame 000a4908a3cfa0ab84851c101f
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 31

Got message of type BluetoothLERawAdvertisementsResponse: advertisements {
  address: 123318265456547
  rssi: -65
  data: "\002\001\004\007\002\003\030\002\030\365\376\007\377\243\'hE(p"
}

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 33

Sending plaintext frame 000a4908a3cfa0ab84851c1021
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 33

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 37

Sending plaintext frame 000a4908a3cfa0ab84851c1025
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 37

Got message of type BluetoothLERawAdvertisementsResponse: advertisements {
  address: 220949223483176
  rssi: -73
  address_type: 1
  data: "\007\377L\000\022\002\000\003"
}

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 39

Sending plaintext frame 000a4908a3cfa0ab84851c1027
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 39

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 41

Sending plaintext frame 000a4908a3cfa0ab84851c1029
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 41

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 43

Sending plaintext frame 000a4908a3cfa0ab84851c102b

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 43

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 45

Sending plaintext frame 000a4908a3cfa0ab84851c102d
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 45

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 47

Sending plaintext frame 000a4908a3cfa0ab84851c102f
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 47
data: "\000"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 50

Sending plaintext frame 000a4908a3cfa0ab84851c1032

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 50
data: "\201\000"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 52

Sending plaintext frame 000a4908a3cfa0ab84851c1034
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 52
data: "\r"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 54

Sending plaintext frame 000a4908a3cfa0ab84851c1036
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 54
data: "\364\000"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 56

Sending plaintext frame 000a4908a3cfa0ab84851c1038
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 56
data: "\000\002"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 59

Sending plaintext frame 000a4908a3cfa0ab84851c103b

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 59
data: "Dialog Semiconductor"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 61

Sending plaintext frame 000a4908a3cfa0ab84851c103d
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 61
data: "OCLEANY3S"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 63

Sending plaintext frame 000a4908a3cfa0ab84851c103f

Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 63
data: "123456"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 65

Sending plaintext frame 000a4908a3cfa0ab84851c1041
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 65
data: "Rev.D"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 67

Sending plaintext frame 000a4908a3cfa0ab84851c1043
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 67
data: "1.0"

Sending BluetoothGATTReadRequest: address: 123318265456547
handle: 69

Sending plaintext frame 000a4908a3cfa0ab84851c1045
Got message of type BluetoothGATTReadResponse: address: 123318265456547
handle: 69
data: "1.0.0.18"

Sending BluetoothGATTNotifyRequest: address: 123318265456547
handle: 23
enable: true

Sending plaintext frame 000c4e08a3cfa0ab84851c10171801
Got message of type BluetoothGATTNotifyResponse: address: 123318265456547
handle: 23

Sending BluetoothDeviceRequest: address: 123318265456547
request_type: BLUETOOTH_DEVICE_REQUEST_TYPE_DISCONNECT

Sending plaintext frame 000a4408a3cfa0ab84851c1001
Got message of type BluetoothDeviceConnectionResponse: address: 123318265456547
error: 22

Got message of type BluetoothConnectionsFreeResponse: free: 3
limit: 3

Got message of type BluetoothLERawAdvertisementsResponse: advertisements {
  address: 123318265456547
  rssi: -78
  data: "\002\001\004\007\002\003\030\002\030\365\376\007\377\243\'hE(p"
}

Got message of type BluetoothLERawAdvertisementsResponse: advertisements {
  address: 123318265456547
  rssi: -72
  data: "\002\001\004\007\002\003\030\002\030\365\376\007\377\243\'hE(p"
}
bdraco commented 1 year ago

the uuids are 2 uint64s

You can unpack them with

def _join_split_uuid(value: list[int]) -> str:
    """Convert a high/low uuid into a single string."""
    return str(UUID(int=(value[0] << 64) | value[1]))

The CCCD should be 2902

If the ESPHome device can see the CCCD that its probably a bug in the stack

If the ESPHome device can't see the CCCD its probably a bug in the device itself

GrumpyMeow commented 1 year ago

Ok. I did some research.. In the screenshot of the nRF-app on my iphone, i see that the CCCD is there for the service which contains the characteristic i want to subscribe to. If i look at the output of the log, i see that the characteristic i'm interested in has a properties-value of 18. If i'm not mistaking this correctly corresponds to READ(2)+NOTIFY(16) => 18.

This is the CCCD and i see the 2902 UUID is there:

characteristics {
    uuid: 46286862553088
    uuid: 9223372588214596859
    handle: 17
    properties: 18
    descriptors {
      uuid: 45088566677504
      uuid: 9223372588214596859
      handle: 18
    }
  }
characteristics {
    uuid: 6879494259595822837 <= 5F78DF94-798C-4690
    uuid: 11027773265190828945 <= 990A-855B673FBB91
    handle: 33
    properties: 18
    descriptors {
      uuid: 45088566677504    <= 2902-0000-1000
      uuid: 9223372588214596859 <= 8000-00805F9B34FB
      handle: 34
    }
  }
...
characteristics {
    uuid: 6879494259595822837 <= 5F78DF94-798C-4690
    uuid: 11027824461247569032 <= 990A-B3EB6A065C88
    handle: 47
    properties: 18
    descriptors {
      uuid: 45088566677504   <= 2902-0000-1000
      uuid: 9223372588214596859  <= 8000-00805F9B34FB
      handle: 48
    }
  }

With my BLE sniffer i see that:

  1. "Sent Write Request" is done to the CCCD above (handle 18) with a value of "0x0100"
  2. "Sent Write Request" is done to the CCCD above (handle 34) with a value of "0x0100"
  3. Then also a "Sent Write Request" is done to the second CCCD handle 48 with value "0x0100".
  4. Then a command is written to handle 21
  5. A notification is then triggered on handle 23 with data

I think that the app just enables notifications on all CCCDs and the toothbrush triggers a notification on a handle without actually the CCCD. Something like that..

While googling i found this thread which seems to describe somewhat the same:https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/367

Here i looped through all characteristics and logged the handle, retrieved value and also logged the descriptors:

Polling OcleanX device: 70:28:45:68:27:A3
00001800-0000-1000-8000-00805f9b34fb 00002a00-0000-1000-8000-00805f9b34fb 3 bytearray(b'Oclean X')
00001800-0000-1000-8000-00805f9b34fb 00002a01-0000-1000-8000-00805f9b34fb 5 bytearray(b'\x00\x00')
00001800-0000-1000-8000-00805f9b34fb 00002a04-0000-1000-8000-00805f9b34fb 7 bytearray(b'\x90\x01X\x02\x00\x00X\x02')
00001802-0000-1000-8000-00805f9b34fb 00002a06-0000-1000-8000-00805f9b34fb 11 NA
00001803-0000-1000-8000-00805f9b34fb 00002a06-0000-1000-8000-00805f9b34fb 14 bytearray(b'\x00')
0000180f-0000-1000-8000-00805f9b34fb 00002a19-0000-1000-8000-00805f9b34fb 17 bytearray(b'\x17')
    Descriptor= 00002902-0000-1000-8000-00805f9b34fb (Handle: 18): Client Characteristic Configuration
8082caa8-41a6-4021-91c6-56f9b954cc18 9d84b9a3-000c-49d8-9183-855b673fbb85 21 bytearray(b'')
8082caa8-41a6-4021-91c6-56f9b954cc18 5f78df94-798c-46f5-990a-855b673fbb86 23 bytearray(b'')
8082caa8-41a6-4021-91c6-56f9b954cc18 5f78df94-798c-46f5-990a-855b673fbb87 25 bytearray(b'')
8082caa8-41a6-4021-91c6-56f9b954cc18 5f78df94-798c-46f5-990a-855b673fbb88 27 bytearray(b'')
8082caa8-41a6-4021-91c6-56f9b954cc18 5f78df94-798c-46f5-990a-855b673fbb89 29 bytearray(b'')
8082caa8-41a6-4021-91c6-56f9b954cc18 5f78df94-798c-46f5-990a-855b673fbb90 31 bytearray(b'')
8082caa8-41a6-4021-91c6-56f9b954cc18 5f78df94-798c-46f5-990a-855b673fbb91 33 bytearray(b'')
    Descriptor= 00002902-0000-1000-8000-00805f9b34fb (Handle: 34): Client Characteristic Configuration
0000fef5-0000-1000-8000-00805f9b34fb 8082caa8-41a6-4021-91c6-56f9b954cc34 37 bytearray(b'')
0000fef5-0000-1000-8000-00805f9b34fb 724249f0-5ec3-4b5f-8804-42345af08651 39 bytearray(b'')
0000fef5-0000-1000-8000-00805f9b34fb 6c53db25-47a1-45fe-a022-7c92fb334fd4 41 bytearray(b'')
0000fef5-0000-1000-8000-00805f9b34fb 9d84b9a3-000c-49d8-9183-855b673fda31 43 bytearray(b'')
0000fef5-0000-1000-8000-00805f9b34fb 457871e8-d516-4ca1-9116-57d0b17b9cb2 45 bytearray(b'')
0000fef5-0000-1000-8000-00805f9b34fb 5f78df94-798c-46f5-990a-b3eb6a065c88 47 bytearray(b'\x00')
    Descriptor= 00002902-0000-1000-8000-00805f9b34fb (Handle: 48): Client Characteristic Configuration
0000fef5-0000-1000-8000-00805f9b34fb 61c8849c-f639-4765-946e-5c3419bebb2a 50 bytearray(b'\x81\x00')
0000fef5-0000-1000-8000-00805f9b34fb 64b4e8b5-0de5-401b-a21d-acc8db3b913a 52 bytearray(b'\r')
0000fef5-0000-1000-8000-00805f9b34fb 42c3dfdd-77be-4d9c-8454-8f875267fb3b 54 bytearray(b'\xf4\x00')
0000fef5-0000-1000-8000-00805f9b34fb b7de1eea-823d-43bb-a3af-c4903dfce23c 56 bytearray(b'\x00\x02')
0000180a-0000-1000-8000-00805f9b34fb 00002a29-0000-1000-8000-00805f9b34fb 59 bytearray(b'Dialog Semiconductor')
0000180a-0000-1000-8000-00805f9b34fb 00002a24-0000-1000-8000-00805f9b34fb 61 bytearray(b'OCLEANY3S')
0000180a-0000-1000-8000-00805f9b34fb 00002a25-0000-1000-8000-00805f9b34fb 63 bytearray(b'123456')
0000180a-0000-1000-8000-00805f9b34fb 00002a27-0000-1000-8000-00805f9b34fb 65 bytearray(b'Rev.D')
0000180a-0000-1000-8000-00805f9b34fb 00002a26-0000-1000-8000-00805f9b34fb 67 bytearray(b'1.0')
0000180a-0000-1000-8000-00805f9b34fb 00002a28-0000-1000-8000-00805f9b34fb 69 bytearray(b'1.0.0.18')
issue-triage-workflows[bot] commented 1 year ago

There hasn't been any activity on this issue recently. Due to the high number of incoming GitHub notifications, we have to clean some of the old issues, as many of them have already been resolved with the latest updates. Please make sure to update to the latest Home Assistant version and check if that solves the issue. Let us know if that works for you by adding a comment 👍 This issue has now been marked as stale and will be closed if no further activity occurs. Thank you for your contributions.