Hi everyone ;-)
I'm currently developing an app that is synced to a BT device.
This BT device has 2 states (let's say ON and OFF though it is still powered on, like a bulb).
When I connect to the peripheral, I get 2 characteristics : a write and a read characteristic. In order to retrieve the current state, I have to send a write frame that basically ask the peripheral to give me its current state. As a response, I get a frame that contains the current peripheral state.
If I connect to the peripheral, ask the state (ON for instance), I receive ON. I turn the peripheral OFF, I receive OFF. Now I kill my app and launch it again. The app will reconnect to the peripheral, ask the current state. The response is OFF. So far so good.... I can keep on changing the peripheral state, I always retrieve the last state of the peripheral when I relaunch the app.
Now for the weird part : I do exactly the same operations, but before launching my app, I switch again the peripheral state (in the above example, it would now be ON). I launch the app, send a write frame to the peripheral, and the response is ... OFF.
One could argue that it is a peripheral issue, but fellow colleagues on Android do not have this bug, so I guess it's on my side.
Just for the record, here are my BT implementation, which is pretty straightforward.
extension BluetoothManager: CBPeripheralDelegate {
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
log("didDiscoverCharacteristicsFor \(service)")
if let characteristics = service.characteristics {
for characteristic in characteristics {
if let chara = ATACharacteristics.from(characteristic) {
switch chara {
case .write:
log("write ATACharacteristics\(characteristic)")
peripheral.setNotifyValue(true, for: characteristic)
self.characteristics.append(chara)
readStateFromBox(characteristic)
case .read:
log("read ATACharacteristics\(characteristic)")
self.characteristics.append(chara)
case .nus: ()
}
}
}
}
}
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
log("didUpdateValueFor \(characteristic)")
if let data = characteristic.value,
let validator = try? ATAFrameDecoder().decode(data) as? LuminousStatusFrameValidator {
log(" data \(data as NSData)")
updateState(from: validator)
}
}
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
log("didWriteValueFor \(characteristic)")
if let data = characteristic.value,
let validator = try? ATAFrameDecoder().decode(data) as? LuminousStatusFrameValidator {
log(" data \(data as NSData)")
updateState(from: validator)
}
}
}
Here are although the logs for both scenarios. When receiving the didWrite frame, if I get a "00" after "02a00461" it means ON, if I get a "fe", it means OFF
First the good one :
📲 centralManagerDidUpdateState poweredOn
📲 didDiscoverServices <CBPeripheral: 0x281508000, identifier = A274CD79-938C-CAEF-2CE7-D20CB5B6961F, name = ATA-000008, state = connected>
📲 didDiscoverCharacteristicsFor <CBService: 0x2831a5280, isPrimary = YES, UUID = 6E400001-B5A3-F393-E0A9-E50E24DCCA9E>
📲 read	ATACharacteristics<CBCharacteristic: 0x280006100, UUID = 6E400002-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0xC, value = (null), notifying = NO>
📲 write	ATACharacteristics<CBCharacteristic: 0x2800044e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a00461fe0000000000122903}, notifying = NO>
📲 readStateFromBox {length = 9, bytes = 0x02a50000000001a603} for <CBCharacteristic: 0x2800044e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a00461fe0000000000122903}, notifying = NO>
📲 didUpdateNotificationStateFor <CBCharacteristic: 0x2800044e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a00461fe0000000000122903}, notifying = YES>
📲 didWriteValueFor <CBCharacteristic: 0x2800044e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a00461fe0000000000122903}, notifying = YES>
📲		data {length = 13, bytes = 0x02a00461fe0000000000122903}
📲 updateState occupied
📲 acknowledge {length = 9, bytes = 0x0206a000000003a703} for Optional(<CBCharacteristic: 0x2800044e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a00461fe0000000000122903}, notifying = YES>)
and then the bug
📲 centralManagerDidUpdateState poweredOn
📲 didDiscoverServices <CBPeripheral: 0x2839885a0, identifier = A274CD79-938C-CAEF-2CE7-D20CB5B6961F, name = ATA-000008, state = connected>
📲 didDiscoverCharacteristicsFor <CBService: 0x281dd5100, isPrimary = YES, UUID = 6E400001-B5A3-F393-E0A9-E50E24DCCA9E>
📲 read	ATACharacteristics<CBCharacteristic: 0x282c88300, UUID = 6E400002-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0xC, value = (null), notifying = NO>
📲 write	ATACharacteristics<CBCharacteristic: 0x282c881e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a0046100000000000013d603}, notifying = NO>
📲 readStateFromBox {length = 9, bytes = 0x02a50000000001a603} for <CBCharacteristic: 0x282c881e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a0046100000000000013d603}, notifying = NO>
📲 didUpdateNotificationStateFor <CBCharacteristic: 0x282c881e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a0046100000000000013d603}, notifying = YES>
📲 didWriteValueFor <CBCharacteristic: 0x282c881e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a0046100000000000013d603}, notifying = YES>
📲		data {length = 13, bytes = 0x02a0046100000000000013d603}
📲 updateState free
📲 acknowledge {length = 9, bytes = 0x0206a000000003a703} for Optional(<CBCharacteristic: 0x282c881e0, UUID = 6E400003-B5A3-F393-E0A9-E50E24DCCA9E, properties = 0x10, value = {length = 13, bytes = 0x02a0046100000000000013d603}, notifying = YES>)
Is there some kind of cache on BT exchanges ? I don't know why it reacts like that.
Thanks for your help.