IOS Development: Background BLE with CBPeripheral periodically updating subscribed characteristic - ios

I'm currently trying to develop a Bluetooth IOS application that can work in background.
I methodically followed the tuts on the IOS developper website, and it works pretty fine; I'm getting stuck whenever I want to update a subscribed characteristic in background.
When my Peripheral device enters in background, I want the characteristic to periodically update, so that it send a notification to the Central device, taking advantage of the characteristic subscription mode.
Note : for now the characteristic is only a timestamp, updated every 5 seconds, in order to test if it works well
First I implemented a NSTimer, but as expected it is killed when the Peripheral app enters in background. Then I tried to establish a Background Fetch mode, but it is only possible to set a minimum refresh interval (and not warming up my application on fixed period).
Does somebody have an idea on how to proceed/overcome the problem?
Thank you!
Ps: I appologize for my English, I'm a bit rusty

Related

Best approach for continually scanning bluetooth devices on iOS as well as storing the peripheral data in background?

I am currently using CoreBluetooth to scan for peripherals. Every 30 seconds it sends its packet of information to the cloud by using a Timer. This is working good in foreground. I would like this exact operation to function seamlessly in the background too.
I have declared a CBUUID ahead of time for it seek out the designated peripheral in the background. Upon entering background mode, the scan stops functioning after 10~ seconds. How do I continually make the scan operate continue in the background?
I was looking into Bluetooth State Preservation, would this alleviate the issue? Should it also not be on the main thread?
After the packets are advertised I would like them stored in memory. I am aware the DiscoverPeripherals logs the peripherals... is it possible to log the RSSI and additional peripheral data in chronological order and have it an operation take affect per an interval? I was looking at BGProcessingTask to fire off a function in the background. Would a better approach be to use CoreData to store the memory and clear it after? Best/easy suggestion is appreicated.
I have changed the CBUUID to the right peripheral for centralManager.scanForPeripherals(withServices: [uuid], options: nil)
with uuid being the CBUUID. That seem to be allowing the peripheral to be detected in the background. It stopped logging the scan after a short period of time. Right when I put the app in background, it functions properly for a bit. I theorize it could just be calling it on the same thread and it may not be operating in the background all together. I did test this by changing the the withServices to nil, the result was that the operating was not being logged at all once I closed to the background.
I was expecting the operation to continually be scanning on the basis of the Timer every period, after the period is up it would send it the cloud just how it was doing it in the foreground.
There are lots of restrictions on iOS apps when they are not in the foreground. Once an app moves from the foreground it is suspended and can only execute in the background for specific reasons and for limited durations.
In general, anything based on a Timer will not fire when the app is not in the foreground.
Some Core Bluetooth events are delivered while your app is in the background:
Pending connect operations can complete with a corresponding delivery to your app.
Peripheral disconnections will be delivered to your app
GATT Notify/Indicate operations from a connected peripheral will be delivered to your app.
Discovery of new peripherals advertising a service that you are specifically scanning for will be delivered to your app.
It is this last behaviour that you are relying on.
While you have done the right thing by specifying the specific service you are interested in, your plans are being thwarted by the fact that Core Bluetooth will not deliver repeated discovery notifications for a particular peripheral.
When your app is in the foreground you can use the CBCentralManagerAllowDuplicatesKey option to request a discovery notification each time a peripheral advertisement is seen, even if an advertisement from that peripheral has been seen before. This option has no effect when your app is not in the background.
The best way to gather data on a periodic basis from a peripheral (whether in the background or foreground) is for that peripheral to send its data via Notify/Indicate, however you seem to be trying to scan for the existence of peripherals rather than gather specific data from them, so this may not work for you.
When one of the supported Core Bluetooth background events occurs and your app has been jettisoned, State restoration allows your app to respond after iOS relaunches your app. It will not help you in this case.
It probably isn't possible to do what you want, at least not without changing the behaviour of your peripheral.

Syncing data over BLE via iOS without App Open (or in the background)

I'm working on a device that keeps count when a door is closed. What I'd like to do is when I walk through the door, my iPhone automatically syncs the data on the device and sends that count to the server (via iPhone) without me opening the app or having it in the background. Is this possible, if so how?
Here's a diagram of what I'm thinking:
Door closes -> BLE notifies iPhone -> BLE sends count to iPhone ->
iPhone sends that value to server
All without the user (me) touching my device or opening the installed iOS application.
Your app has to be running in the background to do something, but that is OK, because Core Bluetooth background mode will take care of that for you.
First, you need to select "Uses Bluetooth accessories" background mode in your project.
Now, your program flow will be something like this:
Your user runs your app which scans for available doors and displays them to the user
Your user selects a door that they want to connect to
You save the identifier of the selected peripheral somewhere like NSUserDefaults
You connect to the peripheral
Once you get a call to the didConnectPeripheral delegate method you can read the count and update your server once you get the value
The user can now suspend your app and do something else
Eventually the peripheral will go out of range and you will get a call to didDisconnectPeripheral. In this method you immediately re-issue the connect to the peripheral.
Since you have Core Bluetooth background mode, when the peripheral is eventually seen again you will get another call to didConnectPeripheral in the background, and you can proceed as per step 5 (In this case your app is already in the background so it will just go back to suspended state after you have read the data without the user doing anything).
You update the server in step 5. This step executes regardless of whether the app is in the foreground or background. The user doesn't need to open your app.
Now eventually iOS may remove your app from the suspended state, say due to memory pressure. In order to still be able to connect to the peripheral when it is seen you need to opt in to state restoration as described in the Core Bluetooth Programming Guide
If you are up for building your own circuit board and Bluetooth LE firmware, this is pretty straightforward:
Add a contact switch that sends a voltage level change to the circuit board whenever the door opens.
Increment a counter on the microcontroller when the level changes.
Write firmware that advertises an iBeacon packet with the counter as the least significant part of the iBeacon identifier (32 bit major and minor).
A phone can then pick up this counter by using CoreLocation APIs to both monitor for the beacon (for fast background wakeups) and range for it (to read the specific identifier), then sending the counter value to the server based on the identifier read.
The advantage of using CoreLocation instead of CoreBluetooth as #paulw11 suggests in his very good answer is faster background wakeups of the app, allowing an app to reliably read the counter in the background. With CoreBluetooth, this background wakeup can be much slower, and door open events are more likely to be missed.

Background Bluetooth with iOS device

I am working on developing a bluetooth peripheral to work with my iOS device. I need to make the iOS app receive data whilst it's in background and process that data as it comes. Looking through Apple's CoreBluetooth framework, I can see how the background execution modes can be used. Now to save power, I want the iOS device to only connect to the bluetooth peripheral at a certain time (without need of user interaction). I've looked through Local Notifications on iOS and it has very limited functionality and don't think it provides what I need.
So is there anyway to wake up an app at 6pm and ask the application to start scanning for bluetooth devices? And then execute other code once device is connected? All this without user interaction.
Any suggestions would be appreciated!
Thanks!
You can't really schedule operations to occur at a specific time in iOS (aside from local notification, which as you said isn't what you need).
You can use background fetch mode to periodically allow your app to check for new data. You can set an interval (although this is only a guideline to iOS, not a strict schedule) for how often your app is woken.
When iOS calls your app delegate performFetchWithCompletionHandler method you can check the current time and decide whether you want to transfer data. If not then you can quickly return UIBackgroundFetchResultNoData. If you do get new data then you can retrieve it before returning UIBackgroundFetchResultNewData

Bluetooth low energy background

I am working on an iOS Bluetooth LE application. First I pair the IOS (central) to my bluetooth chip (peripheral)
1) Discover peripherals.
2) Connect to peripheral.
3) Getting services and characteristics.
4) Able to read data and write data from the characteristics.
5) Save the peripheral
6) Disconnect from the peripheral
When I run the app the second time, it connects to the peripheral automatically and writes and reads data from the characteristic and disconnects from it. The App works in the background for 10 minutes.
I would like to run this app in the background. That is I want to call the methods which connect, write and read values in the background every 6 hours. Is this possible? My App works in the background for only 10 minutes. Any suggestion will be of great help.
First you will need to be sure that you added:
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>bluetooth-peripheral</string>
</array>
to your Info.plist which will allow your app to run in the background.
However this will work as follows: it will allow your app to "wake up" to any bluetooth event and run methods that you like to fire when your app is getting any bluetooth activity.
So for example:
you can scan for bluetooth devices in the background and once found something that fits your criterias you can run code, as didDiscoverPeripheral fires (connect / read / write etc..).
you can be connected to a device and subscribed for notification from a specific characteristic. Once the characteristic changes value your app in the background should get a notification and didUpdateValueForCharacteristic callback will be called so again you can call methods from this point, still running in the background.
maybe you can think of other use-cases. I've mentioned these scenarios to give you an idea how you can definitely work in the background with BTLE.
These scenarios should not be limited to the 10 minutes timeframe.
However I have noticed that if you run something else in background mode (e.g: a loop) and the 10 minutes passes your app might be killed from the background so even the above mentioned callbacks will not work.
So to answer your 6 hours question: it would be possible if your BTLE device could initiate some BLE action every 6 hours to wake your app up. OTherwise I'm not sure you can start your activity from the app (ios) side.

App communicates using CoreBluetooth in background

I have worked on an app which read heart rate from server kinds of bluetooth low energy HRM(Heart Rate Monitor)by bluetooth notification.
And I have added the "App communicates using CoreBluetooth" into the app's "Background Modes".
It works fine when the app is in foreground, but when the app is in background, one of the Heart Rate Monitors is always to be disconnect with the app in sever minutes.
So I debugged the app and find that, this kind of HRM is always push notification irregularly.The interval between notifications is from 1 second to 20+ second.
I know that when the app is in background, iOS will stop the bluetooth connection if it is too long between bluetooth notifications.
So my question is: Is it possible to keep the connection when the app is in background?
Is reconnection the only way to solve my problem?
Detecting the disconnection and reconnecting to the peripheral will make your app more robust as it will handle the case where the peripheral goes out of range and then returns in addition to the case you are seeing.
When the peripheral is disconnected your centralManager:didDisconnectPeripheral method will be called on your delegate. In this method you can call connectPeripheral:options again to re-establish the connection. iOS will either do this immediately if the device is still in range or automatically later, once the device comes back into range.
Once your centralManager:didConnectPeripheral method is called you can re-establish the characteristic monitoring.
Edit Clarify that you can call connectPeripheral immediately

Resources