Group Group Group Group Group Group Group Group Group

raywenderlich.com Forums

Arduino Tutorial: Integrating Bluetooth LE and iOS with Swift

Learn how to control a servo wirelessly from your iPhone in this tutorial with Arduino, Bluetooth LE (low energy) and iOS.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/2164-arduino-tutorial-integrating-bluetooth-le-and-ios-with-swift

Great Tutorial. Is there an alternative shield to the “Black Widow BLE Shield”, which I can directly buy at https://www.sparkfun.com ? I’m living in Europe and would like to buy everything at one supplier because of shipping costs and customs.

Hello blackswan,

There are other BLE modules on Sparkfun, but are not drop in replacements. Some of them require other types of communications to the microcontroller other than common UART TX/RX. On this site, we actually prefer components from Sparkfun because it is a common place for hobbyist. But at the time I wrote the tutorial no suitable BLE module was available there. This was main reason I created the Black Widow and used it for this tutorial.

  • Owen

Great tutorial!
I’m looking forward to test it! I’ll try it with a BlackBoard (Arduino UNO brazilian compatible board) and a HC-08 BLE module. I’ll back when finish testing.

This code works great for Xcode 7.x. I have two apps, running on my iPhone compiled with Xcode 7.3 that work great. Here is a heads up. This evening I downloaded the Xcode 8 beta. When compiling this code I received all errors on the case statements in BT Discovery for the follow function.

func centralManagerDidUpdateState(central: CBCentralManager) {
    switch (central.state) {
    case CBCentralManagerState.PoweredOff:
        self.clearDevices()
        
    case CBCentralManagerState.Unauthorized:
        // Indicate to user that the iOS device does not support BLE.
        break
        
    case CBCentralManagerState.Unknown:
        // Wait for another event
        break
        
    case CBCentralManagerState.PoweredOn:
        self.startScanning()
        
    case CBCentralManagerState.Resetting:
        self.clearDevices()
        
    case CBCentralManagerState.Unsupported:
        break
    }
}

Yeah, until Xcode 8 becomes the real deal (i.e. out of beta) the tutorial won’t be update.
Thanks for the heads up!

Suppose I wanted to read some value from the peripheral and display it on the phone. I understand this should be simple but coming from straight C I can’t find the “right” way to do this. How is BTService supposed to update the ViewController? The path from phone to device seems clear but I can’t see the path from device to phone.

There are a couple of ways to get values from the Bluetooth device.

One way is to call peripheral?.readValueForCharacteristic(characteristic) in which the peripheral’s response will be found in the CBPeripheralDelegate callback method didUpdateValueForCharacteristic. The value of the characteristic is in ‘characteristic.value’.

The second way to get info from a peripheral is via notifications. If you want your application to receive value changes automatically (without having to poll the read command), then during initial discovery of Characteristics call peripheral.setNotifyValue(true, forCharacteristic: characteristic). And assuming that the peripheral’s GATT settings for the given characteristic allows for notifications, then didUpdateValueForCharacteristic will be called automatically each time the characteristics value changed on the peripheral.

Owen

Sorry, I should be more specific. I asked the same question on stack overflow and I got the same answer.

I understand that part and I have that working. What I don’t understand is how BTService communicates the data to the ViewController.

After reading the code several times over I noticed how you were communicating the connection status to the ViewController using NSNotificationCenter. I reused that to pass the data to the ViewController. Is there a better way to do it?

Hi lusher00,
Okay. Your question isn’t really regarding Bluetooth stuff. But more with 'what is a good way to notify a viewcontroller that a class property has changed.

Here is my 2 cents worth.

  • I like NSNotifications when I know more than one viewcontroller needs the updated values.
    -If only one vc is involved than a delegate is a nice option.
  • Another very cool option is Box & Bind!

Hope this helps,
Owen

I return to this code every few months and knock a bit more out when I have free time. I have another question that isn’t so much ble related.

Here is your code (after I allowed swift 3.0 to “adjust” it a bit (actually I think its been hacked up a bit more than that))

let data = Data(bytes: &positionValue, count: MemoryLayout<UInt8>.size)
self.peripheral?.writeValue(data, for: positionCharacteristic, type: CBCharacteristicWriteType.withResponse)

I would like to be able to pass in a formatted string rather than positionValue. This seems like it should work but even if I just print newData all I get is “12 bytes” Printing it as NSData seems to print the ascii hex values but writeValue still doesn’t like it

let tString = "Hello World!"
if let newData = tString.data(using: .utf8){
    print(newData as NSData)
    self.peripheral?.writeValue(, for: positionCharacteristic, type: CBCharacteristicWriteType.withResponse)
}

I would like to pass in a string

Hi lusher00,

Using the ‘print()’ function on an NSData is going to show the raw data bytes, not as a readable String. As you are seeing.

When you say ‘writeValue still doesn’t like it’, what do you mean? Are you getting an error or is the data just not showing up on the BLE device?

A couple catchya’s with writing data to a characteristics:

  1. Be sure the GATT datatype for the characteristic matches the type of data you want to send. If you just want to bang bytes thru then its not as critical as long as you are parsing the data properly on both sides. I don’t recommend this way, because it defeats some of the benefits of characteristics.
  2. The number of bytes indicated in the GATT for the characteristic needs to match the number that you are sending, unless it is set as a string with variable length.

Hope this helps!

changing

CBCharacteristicWriteType.withResponse

to

CBCharacteristicWriteType.withoutResponse

fixed it.

Unfortunately what I’m working with is just an XBee like drop in module with a UART on the wired side and a single characteristic on the RF side. I don’t have the option to add characteristics.

Lusher00,
Glad you found it!
Yeah, there are several different vendors for BLE modules out there. Each one with a different GATT setup.
Personally, I prefer to define GATT Characteristics as withResponse when possible to increase data change reliability, but when you can’t modify it on the module then your stuck with it. Unless you switch modules :slight_smile:

Any updates, suggestions, and or tutorials for opening this project with Xcode 8?

Hi dbenedi2,
I just updated the tutorial for Swift3/Xcode 8!
Owen

Why does the servo just sit and rattle when the slider is at the top?
Not only does this happen on my own project, but I notice it does this in your example video as well.

Thank you…

Jerry

To be honest, I don’t know why. Back when I did the project I noticed it and researched some forums about servos. Some said cheaper servos do it, others said it was because the servo was trying to find a position that was between increments. I never put an oscilloscope on the Arduino PWM output, but maybe this would show an issue. Its possible the pulse from the Arduino isn’t consistent, but only a theory.

Thanks for the reply, Owen, and thanks for the excellent tutorial.
I’ve added your updates for Swift 3 and everything is working great!

Jerry

Hi Owen

Great work by the way!

This is slightly off topic but you seem to know your stuff and I hoped I could pick your brain a little. I am looking to use the BLE module as a way to see what iOS devices are descoverable and either return their mac addresses or simply confirm that a device is in range using stored mac addresses in the arduino code.

I was thinking of something on these lines but I understand that It’s only Bluetooth 4 that is compatible with iOS.

Any help on this would be greatly appreciated.

Regards

John