In a previous post, I introduced my new project, sling, and listed prototypes I will be working on. In the post, I noted sub-experiences to prototype. The first one was:
- local alerts: sling hardware sends out a BTLE alert that is picked up by iPhones within range that are running the sling iPhone app. Through sound and UI, the sling app notifies the iPhone that an alert has been received. At this point, the sling app is running in foreground mode. The sling app starts updating near/far proximity information so that the person with the iPhone has a chance to come quickly to the aid of the person that set of a sling alert.
- sling hardware sends out a BTLE alert that is picked up by iPhones within range that are running the sling iPhone app. Through sound and UI, the sling app notifies the iPhone that an alert has been received.
- At this point, the sling app is running in foreground mode. The sling app starts updating near/far proximity information so that the person with the iPhone has a chance to come quickly to the aid of the person that set of a sling alert.
Source Code Location
The source code is located at this GitHub location.
Demo
The following gif image shows 1) putting a battery in the Bean 2) the notification settings UI on an iPad 3) the iPad’s display 4) the blank foreground of the sling app 5) the alert that pops up when a sling alert is received by the iPad:
This siren sound is played when an alert is displayed on the iOS device.
The Goal
The goal of this post is to explore and implement the first part of the first sub-experience – sling device sends out an alert. iPhones that are running the sling app use sound and UI to notify the iPhone’s user that an attack is in progress.
Non Goals
I will not be discussing details on iOS programming. There are great resources out there including:
- The WWDC Videos – these come out yearly after Apple’s Developers Event.
- Stanford University’s iOS development course in iTunes.
- Tutorials on Ray Wenderlich’s site.
- StackOverflow
Thanks To Those That Went Before
The ability to build these prototypes, learn, and hopefully – make a difference would not be possible even 10 years ago. It amazes me to have the opportunity to wake up every day and use these tools. Of course, these tools wouldn’t be possible without dedicated and talented people. Folks at PunchThrough – thank you for the Bean. It is an excellent way to explore Bluetooth (BLE) communications between an Arduino sketch (running on a Bean) and the iOS. Folks at Apple – many people dedicated a lot of effort and time to the iPhone – not the least the engineers who designed and built Core Bluetooth and the XCode SDK. Your work is powerful and polished. And of course Chris Gammell – I keep learning from Chris and highly recommend his Contextual Electronics course. I’m excited to learn Chris is coming out with a new format for the courses.
Parts
There are two main parts – the BLE peripheral sending out sling alerts and a smartphone app that receives the alert and notifies that there is an attack in progress. The technologies I will use include:
- an iPhone. I use an iPhone and am an Apple Developer. For these reasons, I will be using the iOS SDK and the XCode IDE to build the sling app on my iPhone. I recently upgraded to an iPhone 6 and am running iOS 8. This will be my smartphone platform for this prototype.
- After listening to an interview with the founder of Punchthrough Design on The Amp Hour podcast, I decided to use a LightBlue Bean as the BLE peripheral.
Setting Up The Bean
To keep the prototype as simple as possible, I insert the Bean’s battery when I want sling advertisements to be broadcast. I remove the battery when I want the advertisements to stop.
Setting up the bean included:
- Enabling iBeacon advertisements using the Bean Loader (see PunchThrough’s iBeacon setup link).
- Turning down the advertising interval. In the WWDC 2012 Video Session 705, at ~ 21:40, the presenter discusses the differences between discovering devices in the foreground versus the background in an iOS app, noting that discovery in the background takes longer. One thing the BLE device manufacturer can do is to shorten the advertising interval. The presenter recommends to set the interval for this situation to 20ms. Since the Bean need only be advertising when a distress activation has occurred, lowering the advertising interval should not significantly degrade the battery performance. The Bean’s default advertisement interval is 500ms (from the FAQ). As you see in the image below, I was able to set the advertisement interval to 60ms, but no smaller. I am not sure why the advertisement interval cannot be set to 20ms. Luckily 60ms was a small enough interval between advertisement packets.
- Setting the name of the Bean to SLNG using the Bean’s Arduino API.
- Setting the CBAdvertisementDataLocalNameKey to HELP. I did this using the iOSExampleapp provided by the Bean SDK. The Bean SDK is at this GitHub location. The iOSExampleApp XCode project is talked about on this GitHub page under “Getting Started & Examples.”
Screen shot of Bean iOSExampleApp Showing Config Where CBAdvertisementDataLocalNameKey is Located
The iOS App
Caution – Things to Know about BLE Communications
As I learned more about Apple’s Core Bluetooth framework as well as the behavior of BLE, I found the following areas important to understand in the design of this prototype.
BLE Device -> iOS: Foreground Vs Background Communications
The challenge of using up the iPhone’s battery seems to be a major factor in why BLE communications is different when an iOS app is in the background or foreground. Apple provides the Core Bluetooth framework to iOS apps for interacting with BLE packets.
Before I talk more about this, I want to point out an excellent StackOverflow post where this exceptional person tested background discovery and provided all with the results. This post was “learning gold” for me!
The most affected area is handling BLE advertisements. Understanding the differences became critical to receiving BLE alerts.
Apple’s Programmer’s Guide points out the states an iOS app can be in:
When launched, the app runs in the foreground. When the app is no longer on the screen, it is running either in the background or suspended mode. If the system gets desperate for more memory, the suspended app gets kicked out of memory.
Handling the case when then app is in the foreground is easy-peasy.
It gets trickier when the app runs in the background or in suspended more. After all, Apple doesn’t want the sling app to suck up all the iPhones power! If an iOS app is running in the background:
- The Core Location Framework – which I hope to use in the next post – of which an iBeacon packet is a member of – does not give the app advertisement packets when the app is in the background. In order to discover the Bean while in the background, the Core Bluetooth Framework must be used.
- scanning for bluetooth packets using Core Bluetooth happens at an unpredictable and slower rate.
iOS Apps Connecting to a BLE Peripheral
At one point in the design, I planned for the sling app to connect to the Bean peripheral. Connecting and maintaining a connection to the Bean is a “showstopper” because the BLE 4 spec specifies only one central (in this case one iOS device) can connect to a peripheral at one time. This means other Buddy Guards running the sling app would not be able to connect to the sling Bean. For this reason, the sling app uses advertisement broadcasts to detect a distress alert.
The iOS App
Note: If you have looked at my code, you’ll notice I liberally sprinkle the code with debugging lines. Why do this when XCode has a very powerful debugger? Well, I got into “bad habits” while engrossed with the Arduino IDE. But also, peppering the code with log statements gives me a feel for the flow of the code. It helps me to see how the methods actually work versus assumptions I made while reading about them. This is exploratory/throw away code. You can take out the #define LOG and #define DEBUG_LOG if you wish to remove the log statements.
If I asked 10 people to draw a picture of the sun, I will get 10 different pictures. Likewise, there are many different ways to implement this scenario. After many starts and stops, I decided the app will receive alerts (from the sling device) when running in the background (emphasis on not the foreground). Why? Core Bluetooth provides the method CBCentralManager::scanForPeripheralsWithServices. This tells Core Bluetooth the app wants to get an advertising packet for a service, many services, or all BLE services depending on the parameters passed in. As noted in the StackOverflow post, The problem happens if the advertisement was previously discovered in the foreground and then the app is put in the background. If this happens, the alert will never be seen by the app running in the background. The sling app’s main feature is to discover sling alerts. There is no UI requirement for this. iPhone owners will be texting, running some other app in the foreground, have the phone with the display of in a pocket or bag.
After creating a new single view project in XCode:
- edit info.plist to include the UIBackgroundModes key and bluetooth-central value to the info.plist. Core Bluetooth will only send an iOS app delegate callbacks when this key/value is specified. (so don’t forget like I kept doing! 🙂 ).
- add Core Bluetooth methods/call backs to sling’s appDelegate. I chose the appDelegate because it reminds me of a landing field for switching between the background and foreground. Note: a “gotcha” I ran into was how Core Bluetooth optimized its BLE cache. If the sling app scanned in the background, found the Bean, stopped scanning, and started a scan – the second time the Bean would not be discovered. I’m pretty sure this is because of the state management going on behind the scenes by Core Bluetooth. This makes sense if I think about how the foreground/background scanning work. I.e.: if the Bean is discovered when the app is in the foreground, future scans for the Bean in the background will not be received. What ended up working was:
- to prepare the iPhone/iPad after messing around: 1) delete previous builds of the app from the iPhone/iPad 2) turn BLE off and then back on the iPhone/iPad 3) launch the app and then put it in the background scan only in the background and when BLE is updated (usually a power on/power off). When the alert goes off, the next step in the sling app is to move to the foreground. Thus, the next time the app is put in the background scanning will again discover the Bean (which means Bean advertisement needs to stop after a bit – basically saying the distress call has gone out. Time to stop advertising).
- Notifications on iPhone can be displayed in different ways. How a notification is displayed can only be changed by the iPhone’s owner by going into Settings->Notifications. I changed the notification style for the sling app to the Alert style.
Alert Sound
When the iPhone running the sling app gets a sling alert, the alert pops up and a sound starts. I wanted a loud siren sound. Before I can attach the sound to the alert, I needed a sound file. I googled and found the sound file Siren_Noise-KevanGC-1337458893.wav. In order to play on the iPhone, the WAV file needs to be encoded in a format that can be played on an iOS device and then put into a CAF file. This post does a great job explaining the formats, etc. in playing sounds on an iOS device. I converted the sound file to a Linear PCM encoded CAF file from a terminal window with the command:
afconvert -f caff -d LEI16@22100 -c 1 Siren_Noise-KevanGC-1337458893.wav Siren_Noise-KevanGC-1337458893.caf
Now all that needs to be done is attach the CAF file to the notification:
UILocalNotification *slingNotification = [[UILocalNotificationalloc]init];
slingNotification.soundName= @”Siren_Noise-KevanGC-1337458893.caf”;
That’s It For Now
There is a lot more to be done to get the alerts a robust and polished experience. This prototype has taught me enough about iOS app development with Core Bluetooth and using the Bean as a prototype peripheral to feel comfortable on designing the hardware and software once the details of the experience are better understood. For example, after seeing the notification, it became clear that the identification (name, initials,..) of the person under attack should be shown in the notification.
Thanks for reading this far. Please find many things to smile about.