-
• #2
Wow, that's a strange one - and you're sure you were calling
startNotifications
on the right characteristic? Could you post up your code?CCCD Handle not found
normally gets called when it *can't*find ahandle_cccd
property so I'm surprised one was actually set... -
• #3
There was no
handle_cccd
property before, so I tried to set it manually viacharacteristic.hande_cccd = 0x1
.const BoseAR = { SERVICE_UUID: "0000fdd2-0000-1000-8000-00805f9b34fb", CHARACTERISTIC_UUIDs: { GESTURE_INFORMATION: "a0384f52-f95a-4bcd-b898-7b9ceec92dad", GESTURE_CONFIGURATION: "21e550af-f780-477b-9334-1f983296f1d7", GESTURE_DATA: "9014dd4e-79ba-4802-a275-894d3b85ac74", SENSOR_INFOMRATION: "855cb3e7-98ff-42a6-80fc-40b32a2221c1", SENSOR_CONFIGURATION: "5af38af6-000e-404b-9b46-07f77580890b", SENSOR_DATA: "56a72ab8-4988-4cc8-a752-fbd1d54a953d", }, GESTURE_IDs: { 129 : 'double tap', 130 : 'head nod', 131 : 'head shake', 192 : 'unknown gesture 192', 193 : 'unknown gesture 193', 194 : 'unknown gesture 194', }, getGestureNameByGestureId: function (GESTURE_ID) { return this.GESTURE_IDs[GESTURE_ID]; }, getGestureIdByGestureName: function(GESTURE_NAME) { return Object.keys(this.GESTURE_IDs).find(GESTURE_ID => { return this.GESTURE_IDs[GESTURE_ID] == GESTURE_NAME; }); }, _ableGesture : function(gestureName, enabled) { const _gestureId = this.getGestureIdByGestureName(gestureName); if(this.isConnected()) { return this.characteristics.GESTURE_CONFIGURATION.readValue().then(dataView => { for(let offset = 0; offset < dataView.byteLength; offset+=2) { const gestureId = dataView.getUint8(offset); if(gestureId == _gestureId) { dataView.setUint8(offset+1, enabled); } } return this.characteristics.GESTURE_CONFIGURATION.writeValue(dataView.buffer); }); } }, enableGesture : function(gestureName) { return this._ableGesture(gestureName, true); }, disableGesture : function(gestureName) { return this._ableGesture(gestureName, false); }, SENSOR_NAMEs: [ 'accelerometer', 'gyroscope', 'rotation', 'game rotation' ], SENSOR_SAMPLE_PERIODs: [ 320, 160, 80, 40, 20 ], ACCURACY_NAMEs: [ 'unreliable', 'low', 'medium', 'high' ], connect: function() { return NRF.requestDevice({ filters: [{services: [this.SERVICE_UUID]}], }).then(device => { this.device = device; return device.gatt.connect(); }).then(server => { this.server = server; return server.startBonding(); }).then(() => { return this.server.getPrimaryService(this.SERVICE_UUID); }).then(service => { this.service = service; this.characteristics = {}; return Object.keys(this.CHARACTERISTIC_UUIDs).reduce((promise, CHARACTERISTIC_NAME) => { const CHARACTERISTIC_UUID = this.CHARACTERISTIC_UUIDs[CHARACTERISTIC_NAME]; return promise.then(() => { return this.service.getCharacteristic(CHARACTERISTIC_UUID).then(characteristic => { console.log(CHARACTERISTIC_NAME); this.characteristics[CHARACTERISTIC_NAME] = characteristic; switch(CHARACTERISTIC_NAME) { case 'GESTURE_INFORMATION': break; case 'GESTURE_CONFIGURATION': break; case 'GESTURE_DATA': break; case 'SENSOR_INFOMRATION': break; case 'SENSOR_CONFIGURATION': break; case 'SENSOR_DATA': break; default: break; } if(characteristic.properties.notify) { //characteristic.handle_cccd = 0x1; characteristic.on('characteristicvaluechanged', event => { console.log(event); }); return characteristic.startNotifications(); } }); }); }, Promise.resolve([])); }).then(() => { console.log("FINISHED"); }); }, isConnected : function() { return this.device && this.device.gatt && this.device.gatt.connected; }, disconnect : function() { if(this.isConnected()) { this.device.gatt.disconnect(); } }, }; BoseAR.connect();
-
• #4
Ahh - thanks for posting up the code. That looks pretty good.
I guess my thought is maybe the CCCD isn't at handle
1
? Usually the CCCD is next to the characteristic that it is for. Perhaps you could try setting it with something like the nRF Connect app, and then look at the log? -
• #5
It turns out the CCCD value for all the Notify characteristics are 0, which triggers the
"CCCD Handle Not Found"
error. I'm not sure if that's an invalid CCCD or it is but it triggers the error because0
is considered a false value. -
• #6
Wow, thanks for tracking that down! I bet 0 is valid. I'll try and get a fix into Espruino for that today - I'll post up when done
-
• #7
Hmm... from the Nordic SDK:
/**@brief Invalid Attribute Handle. */ [#define](https://forum.espruino.com/search/?q=%23define) BLE_GATT_HANDLE_INVALID 0x0000 /**@brief First Attribute Handle. */ [#define](https://forum.espruino.com/search/?q=%23define) BLE_GATT_HANDLE_START 0x0001 /**@brief Last Attribute Handle. */ [#define](https://forum.espruino.com/search/?q=%23define) BLE_GATT_HANDLE_END 0xFFFF
So it looks a lot like the Bose device is actually using an out of spec handle. It does seem amazingly unlikely that anything would have a 0xFFFF handle, but then if we used that as an invalid handle we'd end up potentially breaking something that was ok.
What I've done for now is to modify the code so that if you manually set
handle_cccd=0
as you were doing,startNotifications
should then work.So if you try a 'cutting edge' build now and you can get it working, let me know and i'll figure out another way of handling the CCCD discovery that will deal with a CCCD handle of 0.
-
• #8
I flashed the latest build and now I don't get errors when I set
characteristic.handle_cccd = 0;
, but I still don't get any notifications.And thank you so much for taking the time to help out so far
-
• #9
Thanks for letting me know - I'd be pretty sure it is setting the CCCD characteristic now, so I wonder whether there's something else that's not quite normal in the Bose bluetooth setup
-
• #10
The weirdest thing happened - when I enabled the sensors from my desktop browser (which triggers the device to stream sensor/gesture data), the CCCD's changed to
0x0100
(some are still0
, but the ones I need to be notified of changed to0x0100
).I'm still not getting notifications, but I'll keep playing with it.
-
• #11
Are there any tools besides the nRF Connect app I can use to debug this further?
Also is there anyone I can pay to figure this out?
-
• #12
All I could really suggest is https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Sniffer-for-Bluetooth-LE for sniffing the actual bluetooth traffic.
However if bonding is required then it likely wouldn't be much use as the connection would be encrypted.
Just a thought but is is possible that the device is expecting a number to be entered during the bonding process, and so the bonding actually fails? What does
server.getSecurityStatus
say after bonding completes? http://www.espruino.com/Reference#l_BluetoothRemoteGATTServer_getSecurityStatusAlso is there anyone I can pay to figure this out?
You could post on http://forum.espruino.com/microcosms/1202/ and see if anyone replies?
I can do consultancy work as well if needed?
-
• #13
Hi,
I have the same error as the topic starter, not sure if my problem is related, I'm rather new to Espruino/BLE so it may be a "user error".
Here's my code, and the output it produces. It seems to run OK until the point when Notifications are enabled:
var d; var out=""; function getData(){ print("Getting data now"); g.drawString("Getting data now",0,60); NRF.connect("A4:C1:38:4E:75:A0 public").then(function(device) { print("Device connected:",device.device.id); out=device.device.id; g.drawString(out,0,80); d=device; return d.getPrimaryService("EBE0CCB0-7A0A-4B0C-8A1A-6FF2997DA3A6"); }).then(function(s) { out=s.uuid; g.drawString(out,0,105); if(s) { print("Service:",s.uuid); } else { print("S-error"); } return s.getCharacteristic("EBE0CCC1-7A0A-4B0C-8A1A-6FF2997DA3A6"); }).then(function(c) { print("Characteristic:",c.uuid); print("C:",c); out=c.uuid; g.drawString(out,0,130); c.on('characteristicvaluechanged', function(event) { buf =E.toString(event.target.value.buffer); g.drawString(buf,0,155); print(buf); print(event.target.value.buffer); // For 26.0 degrees and 54% is like : new Uint8Array([47, 10, 54, 98, 10]).buffer b=event.target.value.buffer; temp=b[1]*256+b[0]; hum=b[2]; print("temp:",temp, " Hum:",hum); }); // c.on return c.startNotifications(); }).then(function() { console.log("Done!"); }); } // end getData function setWatch(function(){ print("Bangle setwatch on TOP button activated"); g.clear(); g.setFont("Vector",15); getData(); },BTN ,{ repeat:true,debounce:25 } ); /* WEBIDE OUTPUT _ | __|___ ___ ___ _ _|_|___ ___ | __|_ -| . | _| | | | | . | |____|___| _|_| |___|_|_|_|___| |_| espruino.com 2v06 (c) 2019 G.Williams > Bangle setwatch on TOP button activated Getting data now Device connected: A4:C1:38:4E:75:A0 public Service: ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6 Characteristic: ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6 C: BluetoothRemoteGATTCharacteristic: { "uuid": "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6", "handle_value": 54, "handle_decl": 53, "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": true, "indicate": false, "authenticatedSignedWrites": false } } Uncaught Error: Unhandled promise rejection: CCCD Handle not found > */
The NrfConnect output for the Notification is below.
I know the handle for the notification is 0x0038. When I connect to the device using RPI-gatttool using this handle it starts Notifications immediately.:
pi@raspberrypi3:~/Mydata/python/Xiaomi $ gatttool -b a4:c1:38:4e:75:a0 --char-write-req --handle='0x0038' --value="0100" --listen Characteristic value was written successfully Notification handle = 0x0036 value: c5 09 3a 4e 0a Notification handle = 0x0036 value: c4 09 39 4e 0a
Do I need to specify this handle specifically before using
startNotifcations
, and if so, how do I do that?Any help is welcome.
1 Attachment
-
• #14
BTW : My device is a Xiaomi BLE Thermometer type LYWSD03MMC
1 Attachment
-
• #15
Update : working now!
Reading the code from @Zakaton and @Gordon's response I added a
characteristic.handle_cccd = 0x0038;
statement.c.handle_cccd = 0x0038; return c.startNotifications();
Now the Notifications are coming through.
Device connected: A4:C1:38:4E:75:A0 public Service: ebe0ccb0-7a0a-4b0c-8a1a-6ff2997da3a6 Characteristic: ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6 C: BluetoothRemoteGATTCharacteristic: { "uuid": "ebe0ccc1-7a0a-4b0c-8a1a-6ff2997da3a6", "handle_value": 54, "handle_decl": 53, "properties": { "broadcast": false, "read": true, "writeWithoutResponse": false, "write": false, "notify": true, "indicate": false, "authenticatedSignedWrites": false } } Done! temp: 2484 Hum: 53 temp: 2487 Hum: 53 temp: 2486 Hum: 53
Thanks for the inspiration.
-
• #16
Great! I'd love to figure out why this isn't going though - it should really have been able to figure it out automatically.
-
• #17
I always think it's ME, not this time ;-)
I'm writing a port of the Bose AR Web SDK to Bangle.js. Right now I'm able to connect to the BLE device, get the service/characteristics and read/write values, but I get a
CCCD Handle not found
error when I runcharacteristic.startNotifications()
on the characteristics with thenotify
property.I looked it up and it seems to look for a
handle_cccd
property on the characteristic so I looked it up and found the cccd0x1
and assigned it to the characteristics'characteristic.handle_cccd
property, and the error stopped. However I still don't get any notifications when adding an eventListener viacharacteristic.on('characteristicvaluechanged', callback)
.