troystribling / bluecap Goto Github PK
View Code? Open in Web Editor NEWiOS Bluetooth LE framework
License: MIT License
iOS Bluetooth LE framework
License: MIT License
Previous Code: Swift 2, BlueCap 0.1.0
New Code: Swift 3, BlueCap 0.2
Example Referenced: https://github.com/troystribling/BlueCap/blob/master/Examples/CentralManager/CentralManager/ViewController.swift#L132
I am currently in the middle of a migration to Swift 3, and at the same time I am updating some of my old code, and I was wondering if I could get some advice.
In my previous code, when calling .connect()
on the Peripheral, I would use the .onSuccess
syntax to handle the code to be executed after its completion.
However, looking at your (new) examples, it seems you've adopted a preferred syntax of using .flatmap()
to handle a chain of closures.
I really like this syntax, the only problem I've encountered with it is when calling .terminate()
or .reconnect()
on the Peripheral. Here is the code I will be referencing:
.flatMap { [unowned self] (peripheral, connectionEvent) -> Future<Peripheral> in
switch connectionEvent {
case .connect:
return peripheral.discoverServices([self.deviceUUID_CB])
case .timeout:
print(err_msg + "Connection Timeout, reconnecting.")
self.statusMessage(nil)
peripheral.reconnect()
case .disconnect:
print(err_msg + "Got disconnected, reconnecting.")
self.statusMessage(nil)
peripheral.reconnect()
case .forceDisconnect:
print(err_msg + "Forced Disconnect, terminating.")
self.statusMessage(nil)
case .giveUp:
print(err_msg + "Giving up, terminating.")
self.statusMessage(nil)
peripheral.terminate()
}
}
The following is obviously creating an error as not all the switch
's cases either return
or throw
.
Now I should obviously throw
when it gets to .giveUp
. But is there a way to have this closure loop when using .reconnect()
and not interrupt the closure chain by throwing or having it proceed with a return statement?
when i try and enable background it doesnt seem to be working, all the permissions are there and the code is going through and verifying everything in the library but the monitoring doesnt seem to be picking up the beacons.
if swap to events ranging that works perfectly, when i swap to All or region boundary the enter / Exit in onStateDidChange is not being called.
and in background, when the app is not in the foreground everything stops straight away.
Im i doing something worng
I haven't taken an in depth look into where the exact problem is, but it looks like the Peripheral objects that are being generated aren't being deallocated. I assume there is a strong reference cycle being created somewhere preventing them from deallocating (unless there is some buffer that stores all discovered peripherals that I'm unaware of). I created a deinit method inside both the Peripheral and Peripheral wrapper objects and neither are ever called.
I've talked with an Apple engineer about this and it's a big problem when CBPeripheral objects are never released (and Peripheral holds a strong reference to the CBPeripheral). To simplify the issue, if I just took an array and added every peripheral I discover to it, CoreBluetooth would eventually crash after discovering so many devices. I'm unsure of exactly why CoreBluetooth needs the memory released, but I've actually seen this happen in my tests.
Let me know if there's anything I can do to help.
I was reviewing the code for characteristic writes, and it looks like the code may be fragile for multiple writes in quick succession (specifically when writeValue
is called multiple times before the didWriteValueForCharacteristic
is called back for the first write). It looks like the writing
flag in CharacteristicImpl
can be set to false
even if a write may be pending. Mock example timeline:
writeData()
callwriteData()
callwriteData
completes succesfully, didWrite()
is called, sets writing
flag to false
writeData
fails, and times out. Since the writing
flag is now already false
, timeoutWrite
will NOT call writePromise.failure()
Did I miss something? It looks like iOS internally handles sequencing of multiple writes, but doesn't provide a way for the client to know which write succeeded. See for example:
Therefore, it looks like a CoreBluetooth wrapper will have to queue up write requests so that it can echo the data written in the response-- a feature that the iOS stack currently lacks.
I'm still a relative newbie, so am I missing something here? Thanks for sharing your code, and any pointers are appreciated.
As far as I can tell there is no way to add a CDMutableDescriptor to BlueCap's MutableCharacteristic class. The underlying CBMutableCharacteristic is not exposed either so there is no way to add the descriptors directly to the characteristic itself.
Hi,
Thank you so mu much for this git !
I run the peripheral example project but it shows some issues about request value.
Value of tuple type '(CBATTRequestInjectable, CBCentralInjectable)' has no member 'value'
Any help would be appreciated
i tried to read temperature from foramed devices with command 0x26 i can pairing and read info (name ,version , manufacturer) but i cann't write command 0x26 to read result
// Scaning 4 seconds for peripherals
[[LGCentralManager sharedInstance] scanForPeripheralsByInterval:10
completion:^(NSArray *peripherals)
{
// If we found any peripherals sending to test
for (LGPeripheral *per in peripherals) {
if ([per.UUIDString isEqualToString:@"2FF2DAFC-D4D5-4929-8E80-4CA23C56EEF2"]) {
const uint16_t bytes[] = {0x26};
NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
[LGUtils writeData:data
charactUUID:@"00001524-1212-efde-1523-785feabcd123"
serviceUUID:@"00001523-1212-efde-1523-785feabcd123"
peripheral:per completion:^(NSError *error) {
NSLog(@"Error : %@", error);
[LGUtils readDataFromCharactUUID:@"00001524-1212-efde-1523-785feabcd123"
serviceUUID:@"00001523-1212-efde-1523-785feabcd123"
peripheral:per
completion:^(NSData *data, NSError *error) {
NSLog(@"Data : %s Error : %@", (char *)[data bytes], error);
}];
}];
}
NSLog(@"name:%@ UUID:%@",per.name,per.UUIDString);
}
}];
As a boomerang/follow-up to troystribling/SimpleFutures#1:
BlueCap should return a richer error object type than a simple NSError. This richer object should contain more information about the failure's origin: was it a failed filter? propagation of an upstream future's failure? etc etc.
Hello everyone,
I have a concern and I think is very primary, I just downloaded this project and I was trying to test one of those examples, (CentralManager), but I take an error message immediately :
Showing Recent Issues
diff: /../Podfile.lock: No such file or directoryShowing Recent Issues
diff: /Manifest.lock: No such file or directoryShowing Recent Issues
error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
I have to say in Targets>General>Sing in, I couldn't use my Personal Team for this project.
I just wanted to ask if it's possible to help me resurrect this concern.
Hi,
first of all, let me thank you for this great tool! I currently use BlueCap to test the implementation of a characteristic that has the properties Write and Indicate. I would expect that I'm able to enable Notifications for that characteristic, but I'm not. Is this a know limitation or bug? Is there an other way to write the indication bit to the client characteristic configuration descriptor?
kind regards,
Torsten
Hey!
Hopefully you can help...
I need to know when the connection status of a peripheral is changed (either connected/disconnected).
Normally you set CBCentralManager.delegate
to receive updates when this happens, but the BlueCapKit.CentralManager
is already the delegate and implements both:
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)
These methods both update properties on the individual peripheral object but the FutureStream for the connection status is fileprivate.
Is there any way for me to be able to be notified about a peripheral connection status change? I really don't want to poll Peripheral.state
Thanks in advance :)
Hi Troy, I am unable to discover or connect to the sensors on the new CC2650 sensor tag. Is you TISensorTagServiceProfiles for the first gen or the current sensor tags? http://processors.wiki.ti.com/index.php/CC2650_SensorTag_User's_Guide
I have some C code that communicates at a low level, using the BlueZ lib, with the Bluetooth HCI on the Raspberry Pi 3, allowing it to emulate a peripheral.
I'm wondering if either my iPhone 6 or iPad Pro 10.5 has the capability to do this too. There's two parts to this:
It's still not clear to me if this would need MFI? So far as I can tell from Apple's docs, almost anything that works on Bluetooth LE is exempt, but I see contradictions to this in various posts.
Whether iOS and underlying hardware allows some of the Bluetooth modes I need
Looking at your excellent docs, I do see PeripheralManager
- however, this is at a higher abstraction than I'm used to. For instance, I have this piece of code:
bt_hci_send(BT_HCI_CMD_SET_EVENT_MASK_PAGE2);
Which sets the Raspberry Pi bluetooth module to something called connectionless slave broadcast, setting it up to listen for BT_HCI_EVT_CONN_REQUEST
from the master device, and if so commence with the synchronization train.
I know that not even all third party Bluetooth 4 chips support this mode, so wondering if iOS/BlueCap supports this? I can't see anything like it in your code, and it doesn't help Apple have an undocumented proprietary Wifi/Bluetooth chip, so far as I can tell from iFixit teardowns.
When I run the central example, I activate the scan and it says: Unsupported.
But I run it on a real device with bluetooth activated.
I'm developing my app in Swift 3.0 and added BlueCapKit using CocoaPods.
I've updated the flag 'Use Legacy Swift Language Version' to 'Yes' for BlueCap.
However I'm getting this particular issue which says Type 'CBCentralManager' does not conform to protocol 'CBCentralManagerInjectable'
And this happens due to the 'state' variable.
Here's a screenshot of the error to help you. Can you please help solve this?
There are wrong logic when called function loadRetrievedPeripheral().
Way to fix:
Peripheral.swift
Hello, i have to connect to a bluetooth device that requires a password.
How can i add it programmatically or display an input field to the user?
How Central respond a request from Peripheral ?
Please help ?
Hey, I'd love to see this lib available in Swift 3 so I can implement it in my project.
Thanks ๐
SimpleFutures.swift line 439
Future.complete(Try) -> ()
Right now I struggle with backward compat, I must run on 7.1.
Your code uses alert messages this way:
self.presentViewController(UIAlertController.alertOnError(error), animated:true, completion:nil)
with an extension to the UIAlertController.
This function returns an UIAlertController.
It does not exist on iOS7
So, I get a dyld error: Symbol not found: OBJC_CLASS$_UIAlertAction
My solution would be:
var device : UIDevice = UIDevice.currentDevice()!;
var systemVersion = device.systemVersion;
var iosVerion : Float = systemVersion.bridgeToObjectiveC().floatValue;
if(iosVerion < 8.0) {
let alert = UIAlertView()
alert.title = "Error"
alert.message = error.localizedDescription
alert.addButtonWithTitle("OK")
alert.show()
}else{
var alert : UIAlertController = UIAlertController(title: "Error",
message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style:.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}
But I can't return a UIAlertView and a UIAlertController with the same methods you use
in your code.
Suggestion, I would change all your calls to
self.presentViewController(UIAlertController.alertOnError(error), animated:true, completion:nil)
to a central notification object or something.
Suggestions?
From this: https://github.com/troystribling/BlueCap/blob/master/BlueCapKit/Central/Characteristic.swift#L321
It looks like BlueCap is hardcoded to always write with response. I'd like to be able to write without response for my application.
There are some complications implementing write without responses and sending a large amount of data. Since there are no callbacks to let you know when the write is done, the writes have to be spaced out based on the CI. I don't know of a good way to do this right now, I actually just asked this question on SO (http://stackoverflow.com/questions/33442472/ios-bluetooth-le-proper-way-to-write-without-response).
It'd be nice to be able to just pass a large chunk of data in and have the library handle the timing, but since that's not readily defined, the best way to do it for this library is probably just to enable the functionality of WriteWithoutResponse which just passes the data straight into the writeValue method and leaves the timing/write frequency up to the user's application.
(characteristic: CBCharacteristicInjectable, error: NSError?)
I have this issues from my BLE device !
Can you help ?
Hey!
When I am reading/writing to characteristics on my BLE device, I configure the device and then start getting notified for updates to a particular characteristic (so that I can monitor a button press).
Alongside this I regularly poll the battery level and signal strength of the peripheral but whenever I try to discover new services/and or characteristics, the previous services and characteristics are removed and forgotten about. This means that when the button is pressed I see the log message come through from CoreBluetooth that a characteristic was updated, but it can't find which peripheral the characteristic belongs to.
I can see references to discoveredServices.removeAll()
and discoveredCharacteristics.removeAll()
in a few places.
Is there a reason that services and characteristics are removed from the Peripheral when you try to discover new ones? I'm happy to submit a PR to resolve this if desired but wanted to check beforehand.
Thanks!
The podspec says the minimum target is 9.0 and the minimum Cocoapod version as 1.1.
https://github.com/troystribling/BlueCap#cocoapods
This example uses a target of 10.0, should probably be 9.0 to avoid confusion.
Also, the library now requires CocoaPods 1.1+.
https://github.com/troystribling/BlueCap#manual
The manual installation says 8.0, should definitely be 9.0 there.
Nothing really important here obviously, but thought I'd create a ticket so you notice it. Great library by the way.
First thanks for this great library and example app!
I'd like to use this in a project where a tvOS-App connects to its counterpart iOS-App (which serves as a remote to the TV app). As far as I can tell this doesn't support tvOS though (Carthage couldn't find a scheme for tvOS) which is a pity. Do you plan to add tvOS support and do you think there are parts that won't work or make any sense on tvOS? If so, which ones are they?
I'm willing to help getting tvOS-support done, so if there's anything I should know just tell me. :)
Thank you for your help!
Hi, I'm trying to test next_release branch but I'm new in Swift, what's the new syntaxis to create a new connection and when it's successful, it could probably be something like this? Could you give me a more complete example please?
manager.startScanning(forServiceUUIDs: [CBUUID]?).flatMap(mapping: (Peripheral) throws -> Future)
Thanks in advance
Lets say I saved the mac address locally, and I want to connect to the device without the scanning process. It will return either fail or success.
Hi Troy,
When I connected a device and passing the peripheral to new controller,it works fine but If I push another view controller, it will disconnect. So here is the scenario, from view A discovered and connected -> pass to B able to send command -> from B to C , the peripheral is being passed but it will disconnect right away.
Is there's something that was missing that I need to pass? Like the discovery future? It worked for the first pass , but always disconnect from B to C.
Thanks.
Here's an excerpt from the simple Central example:
let peripheralDiscoveredFuture = peripheralConnectFuture.flatmap {(peripheral, connectionEvent) -> Future<Peripheral> in
if peripheral.state == .Connected {
return peripheral.discoverPeripheralServices([serviceUUID])
} else {
let promise = Promise<Peripheral>()
promise.failure(CenteralError.peripheralNotConnected)
return promise.future
}
}
Two things:
CenteralError
should be CentralError
peripheralNotConnected
is not a member of the CentralError enum. There is only one member, IsScanning
.I have this error message. Why? What it means exactly?
Terminating app due to uncaught exception 'Future complete error', reason: 'Future previously completed.'
Hello,
I am wondering what the correct replacement is for WhenPowerOn/WhenPowerOff in the next_release branch.
Previously, I had:
peripheralManager!.whenPowerOff().onComplete({ _ in
Should I have this now?
peripheralManager!.whenStateChanges().onComplete(completion: { (managerState) in
if self.peripheralManager?.state == ManagerState.poweredOff {
And also, previously I had this, from the docs:
let scanningFuture = manager.whenPowerOn().flatmap {
manager.startScanningForServiceUUIDs([serviceUUID])
}
What should I have now?
Thanks
If I connect to, discover services and characteristics, notify and receive notification updates with a peripheral and I use the same central to attempt to connect and do the same with another peripheral, the state of the CentralManager is unsupported, yet if I forgo the state checking and connect anyway, it works as intended.
I am running this on an iPhone 7 Plus 256GB running iOS 10.3.2 beta 4.
Here is my code for the connection, discovery, etc.:
func connect() {
let dataUpdateFuture = self.central.whenStateChanges().flatMap { [unowned self] state -> FutureStream<Void> in
switch state {
case .poweredOn:
return self.peripheral.connect(connectionTimeout: 10.0)
case .poweredOff:
throw BLEError.poweredOff
case .unauthorized:
throw BLEError.unauthorized
case .unsupported:
throw BLEError.unsupported
case .resetting:
throw BLEError.resetting
case .unknown:
throw BLEError.unknown
}
return self.peripheral.connect(connectionTimeout: 10.0)
}.flatMap { [unowned self] () -> Future<Void> in
//Update UI
self.peripheral.startPollingRSSI(period: 0.25, capacity: 10).onSuccess { rssi in
BLE.sharedInstance.invoke(method: { $0.didUpdateRSSI?(rssi) })
}
BLE.sharedInstance.invoke(method: { $0.didGetPeripheralUUID?(self.peripheral.identifier.uuidString) })
self.uuid = self.peripheral.identifier.uuidString
print("Discovering services")
return self.peripheral.discoverServices([s2UUID], timeout: 10.0)
}.flatMap { [unowned self] () -> Future<Void> in
guard let service = self.peripheral.services(withUUID: s2UUID)?.first else {
throw AppError.serviceNotFound
}
print("Discovering characteristics")
return service.discoverCharacteristics([rawUUID], timeout: 10.0)
}.flatMap { [unowned self] () -> Future<Void> in
guard let service = self.peripheral.services(withUUID: s2UUID)?.first else {
throw BLEError.serviceNotFound
}
guard let rawCharacteristic = service.characteristics(withUUID: rawUUID)?.first else {
throw BLEError.rawDataCharacteristicNotFound
}
print("Start notifying raw characteristic")
self.rawDataCharacteristic = rawCharacteristic
return rawCharacteristic.startNotifying()
}.flatMap { [unowned self] () -> FutureStream<Data?> in
guard let rawCharacteristic = self.rawDataCharacteristic else {
throw BLEError.rawDataCharacteristicNotFound
}
print("Receiving raw characteristic notification update")
return rawCharacteristic.receiveNotificationUpdates(capacity: 30)
}
As for errors being thrown, I have to use CBErrors to catch some of them, like so:
dataUpdateFuture.onFailure { error in
print("Data update error: \(error)")
switch error {
case BLEError.serviceNotFound:
self.disconnect()
case PeripheralError.disconnected, PeripheralError.connectionTimeout, CBError.connectionTimeout, CBError.connectionFailed:
self.connect()
default:
break
}
}
I has an error with characteristics writing timeout after sending several times !
Is there any idea to improve this ?
Thanks
I've got a question about BlueCap (or perhaps it's for SimpleFutures) and its handling of onFailure
:
I've got a bunch of simple BT code strung together to discover, filter, and connect to a device. I've got onSuccess
and onFailure
blocks written for each of my calls.
Specifically, I'm scanning for all nearby devices, and using a withFilter:
block to search for a peripheral with a specific name pattern. When I reject the devices by returning false
, the onFailure
block logs, "Filter failed", as I expected.
peripheralConnectFuture.onFailure { (error) -> Void in
print("Error connecting to the device. \(error.localizedDescription)")
}
However! I'm seeing something frustrating in subsequent futures:
After my filter passes, I connect to the peripheral. I discover services in peripheralConnectFuture
:
let peripheralServicesDiscoveredFuture = peripheralConnectFuture.withFilter { (peripheral, connectionEvent) -> Bool in
โฆ
In its onFailure
block,
peripheralServicesDiscoveredFuture.onFailure { (error) -> Void in
print("Error discovering services: \(error.localizedDescription)")
}
I'm receiving a second failure callback, for devices I rejected with the withFilter
block.
Is this by design, or is this a bug?
I'm using BlueCap as a central to connect to a peripheral that has a notification characteristic. I subscribe to that characteristic and then set up notifications like so:
//Subscribe to the notification
if let service = peripheral.service(SERVICE_UUID), txCharacteristic = service.characteristic(TX_CHARACTERISTIC_UUID)
{
//Set subscription
txCharacteristic.setNotifyValue(true)
///Set up updates for the notification
let updatesFuture = txCharacteristic.recieveNotificationUpdates()
updatesFuture.onSuccess({
characteristic in
if characteristic.dataValue != nil
{
var data = [UInt8](count: characteristic.dataValue!.length, repeatedValue: 0)
characteristic.dataValue!.getBytes(&data, length: data.count)
var byteStr = ""
for byte in data
{
byteStr += String(format: "%02X ", arguments: [byte])
}
print("updatesFuture: \(byteStr): \(String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))!)")
}
})
updatesFuture.onFailure({
error in
//Error
})
}
else
{
//Error
}
I also added a log similar to the one above here: https://github.com/troystribling/BlueCap/blob/master/BlueCapKit/Central/Peripheral.swift#L529
My peripheral sends more than 20 bytes of data across a set of packets. In this case, the data it was attempting to send was 5 packets, 72 bytes.
Here are the logs from the first attempt:
1a. didUpdateValueForCharacteristic: 7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.gnos.us.central.main
2a. didUpdateValueForCharacteristic: 92 93 F9 1A 40 18 15 8A 78 D8 D3 1C 3A 66 30 E2 DC CB 66 53 : com.gnos.us.central.main
1b. updatesFuture: 7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.apple.main-thread
3a. didUpdateValueForCharacteristic: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.gnos.us.central.main
2b. updatesFuture: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
4a. didUpdateValueForCharacteristic: 29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.gnos.us.central.main
3b. updatesFuture: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
4b. updatesFuture: 29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.apple.main-thread
5a. didUpdateValueForCharacteristic: B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.gnos.us.central.main
5b. updatesFuture: B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.apple.main-thread
The data arrives correctly in the proper order, as logged by the didUpdateValueForCharacteristic logs. But when it is delivered to the future (as logged by the updateFuture logs), there is a packet missing. Packet 2a was never delivered and packet 3a was delivered twice (2b and 3b).
Here's another example of a retry of the same set of data:
1a. didUpdateValueForCharacteristic: 7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.gnos.us.central.main
2a. didUpdateValueForCharacteristic: 92 93 F9 1A 40 18 15 8A 78 D8 D3 1C 3A 66 30 E2 DC CB 66 53 : com.gnos.us.central.main
3a. didUpdateValueForCharacteristic: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.gnos.us.central.main
1b. updatesFuture: 7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.apple.main-thread
2b. updatesFuture: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
3b. updatesFuture: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
4a. didUpdateValueForCharacteristic: 29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.gnos.us.central.main
5a. didUpdateValueForCharacteristic: B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.gnos.us.central.main
4b. updatesFuture: 29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.apple.main-thread
5b. updatesFuture: B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.apple.main-thread
I suspect there is some foul play going on with how the futures manage firing data in the queues. It looks like sequential promises being delivered to a futurestream are not guaranteed to be delivered back to the result in the same order.
I'll admit I'm not well versed in futures, so it's very possible I'm just not doing something right. If that's the case, would you mind advising the proper way to get notifications delivered in the order in which they're received?
Is there any alternative to this library in Obj-C?
More of a request rather than an issue. Do you intend to add support for cocoa pods for BlueCap? It makes updates and new features / bug fixes much easier to incorporate than manually adding to projects.
Anyway to get a CBPeripheral from BlueCapKit.Peripheral? I'm using a framework to upgrade the firmware OTA and it only accepts CBPeripherals and I would prefer to not have to rewrite it or write another central using CoreBluetooth calls.
Thanks for your time.
I ran into a repeatable crash when I open my app via a push notification, and the BCCentralManager
is started in didFinishLaunchingWithOptions:
. The Optional BCCentralManager.cbCentralManager
is nil
during the didUpdateState()
callback. The problem is there is a race condition because the constructor sets the delegate to self
before assigning to self.cbCentralManager
, so if you get an event (like PoweredOn
) during initialization, the didUpdateState()
callback will happen before self.cbCentralManager
is set, and you will get a crash.
I was able to fix it by passing in nil
to the CBCentralManager
delegate constructor, then explicitly setting the delegate after initialization, e.g.:
self.centralQueue = Queue("us.gnos.blueCap.central-manager.main")
super.init()
self.cbCentralManager = CBCentralManager(delegate: nil, queue: self.centralQueue.queue)
self.poweredOn = self.cbCentralManager.state == .PoweredOn
self.startObserving()
self.cbCentralManager.delegate = self
An alternative way to fix it would be to check the Optional cbCentralManager
before using it.
I get the error mesage "Error Domain=BlueCap Code=5 "Characteristic write not supported" UserInfo={NSLocalizedDescription=Characteristic write not supported}" in the log and I don't get why.
I am not using a profile, but followed the Central (without profile) example and it seems like the writing property is not enabled.
But why is that?
How do I enable the property?
I tested this with pure CoreBluetooth before and writing to the same characteristic was not an issue.
I am talking to a UART emulation over BLE service using a Nordic nRF8001 and the library by RedBearLabs -> https://github.com/RedBearLab/nRF8001/.
// on power, start scanning. when peripheral is discovered connect and stop scanning
let manager = CentralManager.sharedInstance
let peripheralConnectFuture = manager.powerOn().flatmap {_ -> FutureStream<Peripheral> in
manager.startScanningForServiceUUIDs([self.serviceUUID], capacity:10)
}.flatmap {peripheral -> FutureStream<(Peripheral, ConnectionEvent)> in
manager.stopScanning()
return peripheral.connect(10, timeoutRetries:5, disconnectRetries:5)
}
// on .Timeout and .Disconnect try to reconnect on .Giveup terminate connection
peripheralConnectFuture.onSuccess{(peripheral, connectionEvent) in
switch connectionEvent {
case .Connect:
break
// TODO
case .Timeout:
peripheral.reconnect()
case .Disconnect:
peripheral.reconnect()
case .ForceDisconnect:
break
// TODO
case .Failed:
break
// TODO
case .GiveUp:
peripheral.terminate()
}
}
// discover services *and* characteristics
let characteristicsDiscoveredFuture = peripheralConnectFuture.flatmap {(peripheral, connectionEvent) -> Future<Peripheral> in
if peripheral.state == .Connected {
return peripheral.discoverPeripheralServices([self.serviceUUID])
} else {
let promise = Promise<Peripheral>()
promise.failure(CentralError.peripheralNotConnected)
return promise.future
}
}
let writeCharacteristicFuture = characteristicsDiscoveredFuture.flatmap {peripheral -> Future<Characteristic> in
if let service = peripheral.service(self.serviceUUID), characteristic = service.characteristic(CBUUID(string:self.rxUUID)) {
let message = WhisperParameterlessMessage(rawValue: WhisperMessageType.Nop.rawValue)
return characteristic.write(message!, timeout:20.0)
} else {
let promise = Promise<Characteristic>()
promise.failure(CentralError.rxCharacteristicsNotFound)
return promise.future
}
}
writeCharacteristicFuture.onSuccess {characteristic in
// Log
}
writeCharacteristicFuture.onFailure {error in
// Log
}
let writeCharacteristicFuture2 = writeCharacteristicFuture.flatmap { characteristic -> Future<Characteristic> in
// Log
let message = WhisperInteractiveChannelSetMessage(rawValue1: [0], rawValue2: self.kDefaultMessageParameters)
return characteristic.write(message!, timeout:20.0)
}
writeCharacteristicFuture2.onSuccess {characteristic in
// Log
}
writeCharacteristicFuture2.onFailure {error in
// Log
}
Hi, the device we create has 2 same UUID services for battery from different sources. When I use bluecap service discovery, it automatically filter out the service. So when I use other BLE app, I will able to find lets say total 5 services, but bluecap only show 4 services due to same UUID? Is it possible to remove the filter option? If so , how can I do it?
Thank you.
Hi,
I noted that the peripheral.connect tries to connect even after getting a timeout. Here is a scenario.
Maintain a peripheral connected to a central A
Run peripheral.connect(timeout: 10) on central B. B cannot connect since the connection is owned by 1.
onFailed is called after the timeout on central B
central A disconnects
Central B connects but it should not because we got a timeout
Is there a way to avoid this ?
Thanks,
Unlike in the examples where stopScanning() is called before connect(), I'd like to keep scanning for other devices after making a connection.
In didConnectPeripheral(), connectionPromise? was nil because the Peripheral in _discoveredPeripherals[] was overwritten in didDiscoverPeripheral() which always creates a new Peripheral instance.
Is it possible to keep objects in _discoveredPeripherals[] stable? Update the properties instead of replacing the object.
This will allow holding references to the Peripheral object.
I'm happy to discuss more or even coding.
Hi
I wanted to check if it is required to have MFI certification for using gatt profile, can you please clarify
EDIT PART 2 - It was due to XCode 7. Example now runs for me. Perhaps call it out a bit more in the README. Will close this issue.
EDIT - Missed the XCode 7 Requirement. Will try that now.
Been at this for a solid 8 hours now trying to get any of the examples to run. Many issues with code-signing, then I found these instructions to get past this issue.
Since then I've tried a few different ways of running the examples, but none work. I've tried:
Xcode 6.4
OSX 10.10.5
I admit that I'm not an iOS developer, but I also can run a C compiler and have built other iOS projects in the past. But this I just cannot make work. Not sure why. If there's something missing from the README, that would be helpful to add in even more detail there.
I'm working with a library right now from my chipset manufacturer, and trying to rewrite this and wrap it with the BlueCap framework, but I'm having trouble with the BLE messaging because I need to be able to setNotifyValue
for a characteristic once I've discovered it. For example, the manufacturer's library makes this call:
[self.connectedPeripheral.peripheral
setNotifyValue:YES
forCharacteristic:characteristic];
This call is made after the services and characteristics have been discovered, and is basically saying, "I've found this characteristic on my peripheral, and now I want to be notified of changes to it." However, the BlueCap library wraps setNotifyValue
into a private internal function, so when the characteristic is discovered, the initializer casts it to a CBCharacteristicInjectable
, and the internal cbCharacteristic.isNotifying
value is set to NO, and there's no way to change this after the fact, as far as I can tell. Am I missing something simple? Is there something more complex, like me needing to create a profile for the characteristics on my device? Or do I need to figure out a way to fix this and send a PR? Thanks for your help, and thanks for this awesome framework.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.