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.
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.
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
}
}
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.
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.
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)
}
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:
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.
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.
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
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.
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.
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.