I have an app that acts as a Bluetooth LE peripheral. I have a single service with four characteristics. 2 out of the 4 are read and write only, the other two are configured as notify.
If I subscribe to one of the "notify" characteristics then the app will not disconnect until I do so manually, works well.
My issue is, If I read or write to the other characteristics, and the then am inactive for around 30 seconds, the BTLE connection disconnects from the peripheral. This may be a limitation set by apple, not sure.
Anyone know of a solution to keep the peripheral active even when there aren't any subscribers and no read or write command has been received in 30 seconds??
This is a by-product of the BLE 4.0 specs. Bluetooth Low Energy is explicitly designed to not maintain a connection for long periods which is what you are describing.
The only way to bypass this (beyond subscribing to a characteristic as you have found) would be to modify the implementation of the BLE stack on the peripheral you are connecting to and removing or elongating the interval of connection to a point that you find satisfactory.
Although this may not help you either as both sides of the BLE communication negotiate these values and iOS may impose a maximum below your requested threshold.
In my case reason was in a mismatch between characteristic properties. I wrote data to a characteristic with "waiting for response" option, but characteristic was in 'without response' state.
The symptom: write callback in delegate does not work when BLE peripheral did not write a response.
Related
I've noticed that when you disconnect for a bluetooth device in an application the iOS device will continue to hold that connection for around 10 seconds. I've attempted to get around this by writing to a characteristic that causes the bluetooth module to cancel the connection with the iOS device instead but that isn't working (mostly because I changed the module and the iOS doesn't see the change because I assume the device is cached somewhere). Is there a way to make it disconnect instantly in code? I am using the swift command
manager.cancelPeripheralConnection(peripheral) currently.
Unfortunately, there isn't. The only way to tell the system to disconnect a peripheral is via the cancelPeripheralConnection method that you are already using. Yet, if you call this method it doesn't necessarily mean that the peripheral will be disconnect.
Background
On iOS the whole BLE connection management is maintained by the operating system. That means that no single application "owns" a connection. All BLE functionality is multiplexed to allow more than one application to gain access to centrals and peripherals.
For example, if you have installed a fitness application that tracks data from your heart rate sensor in the background then you can also "connect" to the heart rate sensor in your app but you will be unable to trigger a real disconnect as long as the fitness app maintains a connection.
The disconnect delay you have noticed is basically an optimization of the operating system. If no application holds a connection to the peripheral anymore it will wait for some time (to avoid unnecessary connect/disconnect cycles) and then trigger the disconnect on the bluetooth chip.
Hope that helps.
In iOS when you call the CBCentralManager method cancelPeripheralConnection(CBPeripheral), it does not always immediately terminate the connection. As Apple's documentation states:
Because other apps may still have a connection to the peripheral, canceling
a local connection does not guarantee that the underlying physical link is
immediately disconnected. From the app’s perspective, however, the
peripheral is considered disconnected, and the central manager object calls
the centralManager:didDisconnectPeripheral:error: method of its delegate
object.
If you have a need to immediately terminate a connection programmatically, say to free up the peripheral to be connected from another central device or to reset one's own security layer, then you need to follow the procedure described in the following StackOverflow thread:
iOS 6 - Bluetooth LE disconnect
which is for the app to send your own proprietary command to the peripheral that tells the peripheral to disconnect through normal means (e.g. "GAPRole_TerminateConnection" or "GAP_TerminateLinkReq" or "LL_Disconnect" or "HCI_Disconnect[_*]" with reason HCI_DISCONNECT_REMOTE_USER_TERM). This always works and is not delayed by the connection supervision timeout because it is a formal disconnection notifying the central device (i.e. iOS). The supervision timeout (up to 6 seconds in iOS; on Android the default is 20 seconds) only comes into play if the disconnection is unplanned as with going out of range or if the peripheral does a disconnect without notifying the remote device as with "LL_EXT_DisconnectImmed" (only available in some BLE peripheral implementations).
Is it possible to send only 1 iBeacon packet? I have tried using CBPeripheralManager,but since there are only 2 method to start and stop advertising, so I can't control how many packet is being broadcast.
What I want to try to do is use an iBeacon packet as a command, instead of just a broadcasting some ID. So I could send 1 iBeacon packet, and if the receiver got the message, it can send back Acknowledgement with another iBeacon packet. The intention is to avoid the pairing of bluetooth to send very simple data. The information will be linked to UUID, major, and minor of the packet.
Or are there better ways to do this than using iBeacon.
Yes, you can use iBeacon technology to send information back and forth between two iOS devices without pairing. If you have two devices, Device A and Device B, you set both of them up to range for beacons with a common ProximityUUID, say, E2C56DB5-DFFB-48D2-B060-D0F5A71096E0. And then you can exchange information in the two byte major and minor fields.
What you can't do is control the transmitter enough to send only a single iBeacon advertisement. The transmitter in iOS sends out 10 advertisement packets per second, so the best you could do is start the transmitter then stop it on a timer about 100ms later. (You probably shouldn't do this, because there is no guarantee that a single iBeacon advertising packet will be received successfully by the other device -- it may be lost due to a CRC error in the radio noise. You are probably better off letting the packet continue to transmit until you can confirm from a response from the other device that it was received.)
You can see an example of starting and stopping a transmitter on a timer in my answer here.
Of course, there may be easier and more robust ways of accomplishing what you want with built-in Bluetooth data exchange mechanisms. But that doesn't change the fact that what you propose is certainly possible.
No you can't since iBeacon is uni-direction device
I am creating a core bluetooth application and connecting to a peripheral device, is there a way for the peripheral to reject which centrals may connect to it? What if a random person scanned and found my peripheral devices broadcasted UUID and then broadcasted that UUID and tried to connect to it, how would I prevent this?
No, the iOS peripheral cannot prohibit centrals from connecting to it. However it has some tricks to disable the connection. When a dynamic characteristic is read:
return an error instead of the value of the characteristic,
don't respond to the request. This will cause the connection to stall and then break up after about 30 seconds.
Think of the advertisement as a real advertisement in the media. As many can see it as want. This is the same for iBeacons. You shouldn't rely any security on being hidden. (Wifi SSID broadcasting can be turned off but if your hotspot is not encrypted and authenticated, people with find you.)
The basic problem I'm trying to solve is as follows. I have two iOS devices, one configured as a central, and the other as a peripheral. I would like the peripheral to know if the central moves away or becomes inactive for some reason (say the device running the central is turned off).
Under normal conditions, I have it set up so that as the central moves close to the peripheral, the central can use beacon regions and ranging to inform the peripheral via a characteristic-write when it is in the immediate proximity (CLProximityImmediate), and then again when it is still in range, but far off (CLProximityFar). This works well.
However, to catch a corner condition when the central device goes from being CLProximityImmediate to some unknown state, I was planning to used periodic indications from the peripheral to which the central can respond. If there is no response to the indication, then the peripheral can assume that the central is no longer in immediate proximity. However, I am not able to find a callback or delegate method that informs the peripheral manager that the indication failed.
The method updateValue:forCharacteristic:onSubscribedCentrals: returns NO when the underlying transmit queue is full-- and NOT because the central did not respond, the way I've understood it.
Am I missing something obvious here? Is there a way for the peripheral manager to tell that the central did not receive an indication? Or is there a missing callback in CoreBluetooth for this case?
Thanks for your help!
There are two issues to let the peripheral know the location maneager lost contact with the CLBeacon:
The iBeacons are passive, advertise and transmit only devices. As in the Apple implementation there are no connection made to them from the Core Location framework. Therefore the peripheral newer knows anyone listened to their broadcast.
The CLBeacon will not expose the underlying BTLE peripheral as a CBPeripheral, so you would not be able to let the BTLE peripheral know your location monitor was in range.
Issue #2 can be resolved a rather complicated way:
Start scanning for CBPeripherals where the advertisementData contains the proximityUUID.
Make connections to that CBPeripheral and get notified of a characteristic value change.
Change a characteristic value on the peripheral frequently, so when the Central sees no more notifications after a timeout period it indicates the peripheral is out of range.
If you want to make it work for multiple iOS devices this gets way to complicated to switch between advertising and iBeacon and working as a GATT peripheral.
Although this was not explicitly stated in the question, implicitly, I was stating that the peripheral was advertising a service with a couple of characteristics. This is in addition to the explicit iBeacon advertisement, which I agree is "passive". When the central is notified of the beacon region, it discovers and writes to one of the characteristics, and the peripheral can know that a central is in range.
My fundamental question is not regarding the passive nature of the beacon, but more about how "indications" work with CoreBluetooth. I think it is fairly safe to say that if a peripheral uses updateValue:forCharacteristic:onSubscribedCentrals: to inform a central subscribed to a characteristic defined as CBCharacteristicPropertyIndicate, there is no callback defined to capture the confirmation to the indication that should come back from the central (per GAP).
One workaround to this missing API is to define a third characteristic as a "confirmation" characteristic, and impose a protocol that the central should do a dummy read on this characteristic whenever the central receives peripheral:didUpdateValueForCharacteristic: to the indication which was subscribed. That should produce a call to peripheralManager:didReceiveReadRequest: on the peripheral to confirm that the indication was received.
This is more work, and not the most elegant way to do it, but it may be the best thing to do given that there is no API for indication confirmations.
I am trying to understand BLE and GATT in more depth. My interest is in the max achievable number of reads you would able to make per second over the GATT profile.
I am aware of some of the post made on this topic before, for instance:
Bluetooth Low Energy - updating a characteristic value repeatedly
However, I am trying to explain these results looking at the BLE specification.
What is the relationship between connection events and GATT? Does each ATT read/write require a new connection event? If not, is it possible to say anything about how many ATT read/writes can be made per connection event?
Say I want to poll a BLE connected light sensor for a single byte value, what would be the max Hz I could achieve? Would it always be best to set the mininum connection interval as low a possible?
Would I be able to achieve better results using "GATT server notifications? In the BLE spec (Core_v4.0) it says that "The master initiates the beginning of each connection event". Then how are GATT server notifications implemented? I would think that would require the server to initiate a connection event.
Finally, if anybody knows about any specific iOS imposed limitations on the throughput I would be able to achieve when polling a sensor intensively, I would love to hear about it.
I can answer a portion of of those questions...
What is the relationship between connection events and GATT?
They're different levels of the protocol. You handle connections and connection events via HCI. GATT is something you use after you've connected.
Does each ATT read/write require a new connection event?
No. Once you're connected you can do multiple read/write or other GATT commands.
If not, is it possible to say anything about how many ATT read/writes can be made per connection event?
I think the best method is to actually benchmark the speed yourself. However, the whole point of BLE is a reduction in power usage at the expense of speed. If you're concerned about speed that you probably shouldn't be doing it with BLE. The whole point of notifications/indications is so you don't have to poll an attribute but only get a message when a certain event has occurred.
Say I want to poll a BLE connected light sensor for a single byte value, what would be the max Hz I could achieve? Would it always be best to set the mininum connection interval as low a possible?
See above 2 answers.
Then how are GATT server notifications implemented?
Once you've implemented a GATT connection there's 2 way communication going on between the master and slave-device. Either device can send events to the other. In order to use notifications, you set a bit on a particular attribute to say you want notifications on that information. Then, depending on how that notification works, you'll get events sent back to you whenever there's something to report. I have a feeling that a lightbulb wouldn't have any sort of notification unless there's some interface on it besides the BLE connection. I typical application would be something like a thermometer where it would send a notification every time the temperature changed by 1 degree.
Conclusion:
If you're polling attributes you're doing it wrong. But it's possible that you have to do it wrong because the device didn't properly implement notifications in the way you need and you can't modify the device. However, polling will ramp up the battery usage significantly and you'll have loss the benefit of using BLE.