didConnect is not called on iPad Pro, but works on iPhone - ios

I have been experiencing this strange error on my iPad Pro (iOS 11.2) where it discovers the peripheral, but couldn't connect. Been struggling with this for days now.
My iPhone on the other hand connects and collects data without any problem. Can some of you point me to what went wrong here? Any help greatly appreciated. Here is my code:
//Update: This happens on all new devices, ex. iPad Pro, Pixel XL, new
macbook pros, iPhone 7, etc. Maybe it has something to do with new
hardwares? Tested with LightBlue app.
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
//Use this snippet if the device name is advertised. Optionals are handled well here.
if let peripheralName = advertisementData[CBAdvertisementDataLocalNameKey] as? NSString {
if peripheralName as String == deviceDetails.deviceName{
print("Here I am \(peripheralName)")
//bleManager.myCentralManager.stopScan()
myPeripheral = peripheral
centralManager.stopScan()
centralManager.connect(myPeripheral, options: nil)
myPeripheral.delegate = self
// bleManager.myPeripheral = peripheral
//bleManager.myPeripheral.delegate = self //Setting the delegate for the peripheral and now we can implement the methods from this view controller
// bleManager.myCentralManager.connect(bleManager.myPeripheral!, options: nil) //Connecting to the peripheral
print("Connected to \(myPeripheral)")
} else {
//Device name not found
}
}
}
//MARK: Step 3 - Connecting to peripheral
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
print("Connection success")
peripheral.discoverServices([deviceDetails.service_UUID]) //Discovering specific service
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true)
}
I am also pasting my log data when run on iPad:
powered ON
Here I am GBStrain
Connected to Optional(<CBPeripheral: 0x1c83, identifier = <identifier>, name = GBStrain, state = connecting>)
Thanks in advance!

Related

Can't connect to BLE Peripheral in some iOS devices

BLE works fine on 7 Plus (iOS 14.4.2) and 6 (iOS 12). But on XR (14.4.2) and 11 connection stuck after centralManager.connect(peripheral, options: nil) (infinite connection)
The peripheral is in connection mode because other smartphones cannot detect it.
At first I thought that the problem was with the radio module of the peripheral device itself (NRF52), but the problem also occurred with the debug board.
Rebooting the smartphone did not help.
It's funny that the app works fine on a MacBook with an M1 chip
Part of code:
// Peripheral model
init(withPeripheral peripheral: CBPeripheral, advertisementData advertisementDictionary: [String : Any], andRSSI currentRSSI: NSNumber, using manager: CBCentralManager) {
centralManager = manager
basePeripheral = peripheral
RSSI = currentRSSI
super.init()
advertisedName = parseAdvertisementData(advertisementDictionary)
basePeripheral.delegate = self
}
public func connect() {
centralManager.delegate = self
centralManager.connect(basePeripheral, options: nil)
print("Connecting to \(advertisedName ?? "device")...")
// logs stops here
}
public func disconnect() {
centralManager.cancelPeripheralConnection(basePeripheral)
print("Cancelling connection with \(advertisedName ?? "device")...")
// triggers on VC dismiss
}
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state != .poweredOn {
print("Central Manager stated changed to \(central.state)")
}
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
if peripheral == basePeripheral {
print("Connected to \(advertisedName ?? "device")")
delegate?.peripheralDidConnect()
discoverPrimaryServices()
}
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
if peripheral == basePeripheral {
print("Disconnected from \(advertisedName ?? "device")")
delegate?.peripheralDidDisconnect()
}
}
"The peripheral is in connection mode because other smartphones cannot detect it." Did you mean that other smartphones can detect it?
Given the phones you've listed as working and not working, I would expect that your board is having trouble with Bluetooth 5 (which was first supported on the iPhone 8). The NRF52 supports BT5 (it supports 5.2), but if you've written your own firmware you may have broken the support. I'd start by making sure you're running the most vanilla code you can from Nordic.

BLE device randomly disconnecting

I'm using a BLE device and connecting it to an via using swift. When I turn it on it'll connect, disconnect, then reconnect. I have no idea why it's disconnecting in the first place, battery is at 100% and I have nothing that triggers a disconnect, anybody have an idea of what could be happening? here's a few of my functions for reference
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
kestrelPeripheral = peripheral
kestrelPeripheral.delegate = self
manager.connect(kestrelPeripheral)
manager.stopScan()
self.kestrelIsConnected = true
}
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
delegate?.didDisconnect()
cancelReading()
self.kestrelIsConnected = false
self.manager = CBCentralManager(delegate: self, queue: nil)
}
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
self.isInitialReading = false
kestrelPeripheral.discoverServices(nil)
delegate?.didConnect()
}
for more context:
func startReading() {
self.manager = CBCentralManager(delegate: self, queue: nil)
self.takeReading = true
progressHUD = ReadingProgressHUD(text: "Taking Reading")
self.vc!.view.addSubview(self.progressHUD)
}
This would start the reading of values
First, I agree with CodeBender that having a lot of devices in the area can be challenging, but several things about your code make me suspicious.
First, you're not logging anything, so it's hard to know exactly what's going on. You definitely want to log each step.
Make sure you're scanning for exactly the service you want; do not pass nil in scanForPeripherals. Similarly, do not pass nil to discoverServices.
But the most suspicious piece is here, and I'm suspecting it might be the cause:
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
...
self.manager = CBCentralManager(delegate: self, queue: nil)
...
}
You shouldn't be creating a new manager every time any peripheral disconnects. A central manager handles all the peripherals; not just one connection. You should be setting manager one time for the entire run of the program, and you should generally avoid having multiple CBCentralManager objects in the system. It's not impossible to make multiple managers work, but I've found they often get in each others' way a bit.
My suspicion is that you're connecting to more devices than you think you are, and when you disconnect from one of them, you reset your manager and disrupt the others. It may not be that, it could be a lot of things, but that's the most suspicious part of the code you've posted here.

CBPeripheral objects have always nil value for name and are in disconnected state

I am writing an app that allows me to send an image through BLE to the app of someone else.
In order to test it out properly, I would need to be able to connect to an device, but my scanned peripherals are always disconnected and have nil as value. I am uncertain as to whether I am doing this right. I have been reading through guides and I am following the right procedure so could someone point out to me what I might be doing wrong? What are the peripherals I'm detecting?
output:
<CBPeripheral: 0x165b9c90, identifier = 6B74A074-6F5B-0E3A-94EB-6E7BB890569C, name = (null), state = disconnected>
<CBPeripheral: 0x165a0940, identifier = A35AC32E-5668-BD0D-4DBC-D4BF959B9242, name = (null), state = disconnected>
<CBPeripheral: 0x166a8220, identifier = 4D9FA1A1-0090-465F-B53D-363B0F3BBD27, name = (null), state = disconnected>
Edit: Added more code
Here is my code
import Foundation
import CoreBluetooth
import UIKit
class BluetoothController: UITableViewController, CBCentralManagerDelegate, CBPeripheralManagerDelegate, CBPeripheralDelegate {
var centralManager: CBCentralManager!
var peripheralManager: CBPeripheralManager!
var service : CBMutableService!
let uuid:CBUUID = CBUUID(string: "09d921ff-b80c-47b1-bc2b-5bbaadf62010")
let charaUuid:CBUUID = CBUUID(string: "09d921ff-b80c-47b1-bc2b-5bbaadf62021")
override func viewDidLoad() {
print("Initialzing managers")
peripheralManager = CBPeripheralManager(delegate: self, queue: nil)
centralManager = CBCentralManager(delegate: self, queue: nil)
service = CBMutableService(type: uuid, primary: true) //<--Probably not causing it but without a service...
let properties: CBCharacteristicProperties = [.notify, .read, .write]
let permissions: CBAttributePermissions = [.readable, .writeable]
let characteristic = CBMutableCharacteristic(
type: charaUuid,
properties: properties,
value: nil,
permissions: permissions)
service.characteristics = [characteristic];
peripheralManager.add(service)
}
func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) {
print("peripheral state updated")
print("\(peripheral.description)")
}
func peripheralManagerDidStartAdvertising(_ peripheral: CBPeripheralManager, error: Error?)
{
print("started advertising")
}
// Check if the bluetooth is powered on
// Start looking for devices
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if central.state == .poweredOn {
print("Scanning for devices")
centralManager.scanForPeripherals(withServices: nil, options: nil)
startAdvert()
} else {
print("Bluetooth not available.")
}
}
func startAdvert(){
let advertisingData = [CBAdvertisementDataLocalNameKey:"Test Device", CBAdvertisementDataServiceUUIDsKey: uuid] as [String : Any]
peripheralManager.startAdvertising(advertisingData)
}
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber){
print(peripheral)
//didReadPeripheral(peripheral, rssi: RSSI)
}
}
As Paulw11 notes, you're not connected because you never call connect(). You're discovering random BLE devices around you that have nothing to do with your app. That's because you're scanning for all possible services:
centralManager.scanForPeripherals(withServices: nil, options: nil)
You should almost never do that. It's bad for the battery and it's rarely what you want. You want to scan for your service.
centralManager.scanForPeripherals(withServices: [uuid], options: nil)
And then when you discover other devices advertising your service, then you need to connect to them.
To #WholeCheese's comment, the details of the question didn't really relate to the nil name, but to address the question in the title, you will not see a name from advertising if the devices does not advertise a local name over BLE. This is quite common. There is not a lot of space in the advertising packet for data (roughly 30 bytes), and local names can be quite large.
If you're building a scanning app and want to display those names, you'll need to connect to the device. At that point, Core Bluetooth will read the GAP name (rather than the advertised Local Name). In most cases the GAP names should be there (it's not promised from all devices, but it generally should be there). Core Bluetooth caches a lot of information, so if you've ever connected to the device before, it is possible that peripheral.name will be filled out without connecting even if it's not advertised. But if it isn't, you'll need to connect.

Not able to scan Through CBCentral Manager with service ID for iBecon Signal

Working on iBecon signal using Core Bluetooth i am able to search with CBCentralManager scan optionn nil :-
Shared.sharedInstance.centralManager?.scanForPeripherals(withServices: nil, options:[CBCentralManagerScanOptionAllowDuplicatesKey:true])
But when i provide my desirable service ID i.e :-
Shared.sharedInstance.centralManager?.scanForPeripherals(withServices: [serviceID], options:[CBCentralManagerScanOptionAllowDuplicatesKey:true])
it never calls didDiscoverPeripheral Delegate method, I need to scan the peripheral in background mode too and according to apple documentation you need to provide service id explicitly whenever you need to scan in background mode. Anyone can help what i am doing wrong here.
I am using like this,
connect on button click event
and use CBCentralManagerDelegate, CBPeripheralDelegate Delegate
func connectDevice(sender:UIButton){
if peripheral != nil {
manager.cancelPeripheralConnection(peripheral)
manager = CBCentralManager(delegate: self, queue: nil)
}
}
func centralManagerDidUpdateState(central: CBCentralManager) {
if central.state == CBCentralManagerState.PoweredOn {
central.scanForPeripheralsWithServices(nil, options: nil)
} else {
self.showAlert(Messages().alert , message: "Bluetooth is not on.")
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
let device = (advertisementData as NSDictionary).objectForKey(CBAdvertisementDataLocalNameKey) as? NSString
print(device)
if device?.containsString(BEAN_NAME) == true {
self.manager.stopScan()
self.peripheral = peripheral
self.peripheral.delegate = self
manager.connectPeripheral(peripheral, options: nil)
}
}

didDiscoverPeripheral called very slowly

I have a question regarding CoreBluetooth programming in Mac OS X. I have some BLE beacons here that I want to detect. When I execute similar code on my iPhone, it seems to work just fine, but when I try this on my Mac, it seems to only notify of beacons in the neighbourhood every two seconds or so (or even more, but at least 2 seconds). The beacons are beaconing every 500ms, so I would expect to be notified every 500ms.
Is there someone out there who knows how I can tell Mac OS to be a little stricter with reporting the beacons?
I must say I'm quite new to Swift, so all comments on style will also be appreciated.
import Foundation
import CoreBluetooth
class CentralManagerDelegate : NSObject, CBCentralManagerDelegate {
func centralManagerDidUpdateState(central: CBCentralManager) {
if central.state == .PoweredOn {
central.scanForPeripheralsWithServices(nil, options: [CBCentralManagerScanOptionAllowDuplicatesKey : "YES"])
print("Started scanning")
}
else {
central.stopScan()
}
}
func centralManager(central: CBCentralManager, didDiscoverPeripheral peripheral: CBPeripheral, advertisementData: [String : AnyObject], RSSI: NSNumber) {
print("Beacon found with RSSI: " + RSSI.stringValue);
}
}
var _centralManagerDelegate = CentralManagerDelegate()
var _centralManager = CBCentralManager(delegate: _centralManagerDelegate, queue: dispatch_get_main_queue())
while true {
dispatch_main()
}

Resources