Yesterday, I wrote about the basics involved in setting up a Bluetooth manager and scanning for available peripherals. The sample code left off after finding announced devices.
Last evening, I expanded this functionality to find a Mi wristband and execute a repeating vibration pattern. Today’s code is about four times longer and involves a lot more of the direct interaction with a BLE peripheral.
The changes start on finding a desired device. I looked at its peripheral.name
, an optional value associated with a CBPeripheral
. This approach is essentially the same as looking at SSIDs for WiFi. There’s not a lot of sophistication involved, and no pairing sequence. Once found, my code instructs the central manager to stop its scan (centralManager.stopScan()
) and connect()
to the matched peripheral.
At this point it’s really important that you do a few things:
- Create a strong reference to the target peripheral. I used a property. Without this, the peripheral reference deallocates, as I found to my dismay.
- Set the peripheral’s delegate, so you can monitor its callback routines, specifically
centralManager(_:, didConnect:)
. You won’t be able to start the communication chain otherwise.
For the next step, request service discovery from the delegate callback. After the peripheral connects, call discoverServices()
, and listen in peripheral(_:,didDiscoverServices:)
. At this point, the chain of command has passed from the manager that finds you the right peripheral, and moves to listening to the peripheral itself. Both components must establish delegation.
Today’s sample code uses a brute-force approach to find services, and then in the services callback, discover specific service characteristics (discoverCharacteristics(_:, for:)
) for the device.
In production code, you’d limit these calls: supply a list of only those services and the characteristics (the actual API call points) you’re interested in. My code passes nil, because there aren’t that many calls for the target device and I don’t mind the extra overhead.
Like previous steps, characteristics have their own delegate method (peripheral(_:didDiscoverCharacteristicsFor:,error:)
). Here’s where you can access and initialize specific actions that support those characteristics. I decided to use notifications to respond to the discovery of the vibration characteristic (“2A06”, an industry standard).
Notifications are short and sweet, especially for playgrounds. You won’t have to invest in designing protocols or implementing delegates. Just listen for the notification and then start doing whatever you need.
In this case, my open ended observer (it lives forever, so I don’t bother trying to save and release it) starts a vibration pattern by calling a custom type method startVibrating(degree:, delay:)
. This method writes request data to the peripheral’s characteristic, producing each vibration pattern on demand. The delay allows the vibration to repeat after an arbitrary number of seconds.
Like the peripheral, store your characteristics locally. Although they are characterized by a UUID, they aren’t meant to be built on the fly with raw UUID values — or at least not that I could find. Saving each characteristic for later reference appears to be a vital part of the set-up process.
At this point, I’ve pretty much taken this project where I need to. I can produce short and long vibration patterns, I’ve discovered the characteristic for direct vibration control (“FF05”, which appears to take a start and stop value), for testing the device (“FF0D”), and if I ever go that far, for pairing (“FF0F”).
I’m handing it off to my friend. Hopefully there’s enough functionality that he can perform buzzing-like therapy without further financial outlay.
Apparently, controlled buzzing has utility beyond (unconventional) autism therapy. There are any number of ADHD products built on the principle of re-focusing students back on-task every n minutes.
I suppose you could expand this as well with calendar integration for “take your meds” reminders or “get up and move around” ones, at a much lower price point than, for example, the full Apple Watch.
As for me, I discovered that I hate having anything on my wrists and that buzzing really gets on my nerves. I’m glad I had the opportunity to play around with this, though.
If you end up building something interesting, please drop me a line and tell me about it.