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.
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 :
and then the bug
Is there some kind of cache on BT exchanges ? I don't know why it reacts like that.
Thanks for your help.
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.
Code Block 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 :
Code Block 📲 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
Code Block 📲 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.