iOS SWIFT - Detect peripheral turning off from central - ios

Is there any way from the Central app to detect when a peripheral for example runs out of power and consequently disconnects?
I tried using this:
func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) { bleCentralManagerDelegate?.disconnectFromDeviceBLEResult(result: true)}
But this event gets called only if the peripheral requests an actual disconnection, and does NOT get called if the peripheral randomly turns off.
Thanks

Unfortunately there isn't. A generic BLE disconnection usually has the "disconnection reason" as part of the disconnection event (see this), but this is not reliable and in any case CoreBluetooth does not directly expose this. I say "not directly expose this" because you do get the error parameter as part of the event, but this is not a direct mapping to the actual disconnection reason happening on the stack.
The only workaround you can do is if you add the intelligence yourself. In other words, when the peripheral is about to turn off or when it has very low battery, it can send that information to the central (via a GATT write/notification) to let it know that it is about to disconnect because the battery is low.
Have a look at the links below for more information:-
Understanding BLE disconnections
CoreBluetooth CBError

Is this what you're looking for?
func centralManagerDidUpdateState(_ central: CBCentralManager) {
let cState = central.state
switch cState {
case .unknown:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is .unknown")
}
case .resetting:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is .resetting")
}
case .unsupported:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is .unsupported")
}
case .unauthorized:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is .unauthorized")
}
case .poweredOff:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is .poweredOff")
}
case .poweredOn:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is .poweredOn")
}
centralManager.scanForPeripherals(withServices: servicesInterested)
#unknown default:
if ( preLogLevel == "LOGLEVEL" ) {
CSVfuncs.writeLog(">>BT central.state is Unknown Default")
}
break
// unknown default
}
}

Related

how to turn on bluetooth force fully or how to ask permission for turn on bluetooth in my ios application

func centralManagerDidUpdateState(central: CBCentralManager) {
switch (central.state)
{
case .PoweredOff:
print("off")
case .PoweredOn:
centralManager.scanForPeripheralsWithServices(nil, options: nil)
case .Resetting:
print("resetting")
case .Unauthorized:
print("unaithorized")
case .Unsupported:
print("unsupported")
case .Unknown:
print("unknown")
}
}
this code only check the status of bluetooth it can not turn on i want to turn on bluetooth at any way

Notifying iOS user that bluetooth must be turned on

I have an app that uses long-term BLE scanning in the background. I would like to detect when Bluetooth has been turned off so that I can send the user a notification saying that the apps functionality will be limited. Is this possible?
You can conform to CBCentralManagerDelegate and implement centralManagerDidUpdateState(_:) to be notified of the change in state
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
debugPrint("Scanner powered on")
break
case .poweredOff:
debugPrint("Scanner powered off")
break
case .resetting:
debugPrint("Resetting scanner")
break
case .unauthorized:
debugPrint("Unauthorized")
case .unknown:
debugPrint("unknown")
case .unsupported:
debugPrint("Scanner not supported")
}
}
Hope this helps

Check Bluetooth status - Swift 4

I have a problem with the Bluetooth in Xcode. I can’t find a great solution on how to check if Bluetooth is on or not. I want just that. I searched around the web some solution, but nothing works for me. Any idea on how to check Bluetooth? I imported the CoreBluetooth class and I made this line of code:
if CBPeripheralManager.authorizationStatus() == .denied { code }
if CBPeripheralManager.authorizationStatus() == .authorized { code }
Implement CBCentralManagerDelegate delegate for that.
var manager:CBCentralManager!
viewDidLoad() { // Or init()
manager = CBCentralManager()
manager.delegate = self
}
Delegate method :
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state {
case .poweredOn:
break
case .poweredOff:
print("Bluetooth is Off.")
break
case .resetting:
break
case .unauthorized:
break
case .unsupported:
break
case .unknown:
break
default:
break
}
}
you will need to use CBCentralManager and it provide delegate method "centralManagerDidUpdateState" https://developer.apple.com/documentation/corebluetooth/cbcentralmanager
func centralManagerDidUpdateState(_ central: CBCentralManager)
{
if central.state == .poweredOn
{
print("Searching for BLE Devices")
// Scan for peripherals if BLE is turned on
}
else
{
// Can have different conditions for all states if needed - print generic message for now, i.e. Bluetooth isn't On
print("Bluetooth switched off or not initialized")
}
}

CBCentralManager iOS10 and iOS9

So I'm migrating to iOS10 but I also need my code to run on iOS9. I'm using CoreBluetooth and CBCentralManagerDelegate. I can get my code to work for iOS10 however I need the fallback to work for iOS9 as well.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if #available(iOS 10.0, *) {
switch central.state{
case CBManagerState.unauthorized:
print("This app is not authorised to use Bluetooth low energy")
case CBManagerState.poweredOff:
print("Bluetooth is currently powered off.")
case CBManagerState.poweredOn:
print("Bluetooth is currently powered on and available to use.")
default:break
}
} else {
// Fallback on earlier versions
switch central.state{
case CBCentralManagerState.unauthorized:
print("This app is not authorised to use Bluetooth low energy")
case CBCentralManagerState.poweredOff:
print("Bluetooth is currently powered off.")
case CBCentralManagerState.poweredOn:
print("Bluetooth is currently powered on and available to use.")
default:break
}
}
}
I get the error:
Enum case 'unauthorized' is not a member of type 'CBManagerState'
On the line:
case CBCentralManagerState.unauthorized:
As well as for .poweredOff and .poweredOn.
Any ideas how I can get it to work in both cases?
You can simply omit the enumeration type name and just use the .value. This will compile without warnings and works on iOS 10 and earlier since the underlying raw values are compatible.
func centralManagerDidUpdateState(_ central: CBCentralManager) {
switch central.state{
case .unauthorized:
print("This app is not authorised to use Bluetooth low energy")
case .poweredOff:
print("Bluetooth is currently powered off.")
case .poweredOn:
print("Bluetooth is currently powered on and available to use.")
default:break
}
}
I worked around this issue on Xcode 8 with Swift 2.3 (targeting iOS 8 and above) by creating an extension property on CBCentralManager which is of the old enum type, CBCentralManagerState. I named it centralManagerState. I refer to CBCentralManager.centralManagerState where I used to refer to CBCentralManager.state.
extension CBCentralManager {
internal var centralManagerState: CBCentralManagerState {
get {
return CBCentralManagerState(rawValue: state.rawValue) ?? .Unknown
}
}
}
I got the idea from this forum thread though they hadn't posted the code yet.
I contacted Apple about this and was given the following response (paraphrasing).
Due to the changing nature of swift, the above implementation is not possible however you can use the rawValue of the enum as the state is identical between the two classes. Therefore the following will work for now:
func centralManagerDidUpdateState(_ central: CBCentralManager) {
if #available(iOS 10.0, *) {
switch central.state{
case CBManagerState.unauthorized:
print("This app is not authorised to use Bluetooth low energy")
case CBManagerState.poweredOff:
print("Bluetooth is currently powered off.")
case CBManagerState.poweredOn:
print("Bluetooth is currently powered on and available to use.")
default:break
}
} else {
// Fallback on earlier versions
switch central.state.rawValue {
case 3: // CBCentralManagerState.unauthorized :
print("This app is not authorised to use Bluetooth low energy")
case 4: // CBCentralManagerState.poweredOff:
print("Bluetooth is currently powered off.")
case 5: //CBCentralManagerState.poweredOn:
print("Bluetooth is currently powered on and available to use.")
default:break
}
}
}
func centralManagerDidUpdateState(central: CBCentralManager)
{
if #available(iOS 10.0, *)
{
switch (central.state) {
case CBManagerState.PoweredOff:
print("CBCentralManagerState.PoweredOff")
case CBManagerState.Unauthorized:
// Indicate to user that the iOS device does not support BLE.
print("CBCentralManagerState.Unauthorized")
break
case CBManagerState.Unknown:
// Wait for another event
print("CBCentralManagerState.Unknown")
break
case CBManagerState.PoweredOn:
print("CBCentralManagerState.PoweredOn")
self.centralManager!.scanForPeripheralsWithServices([CBUUID(string:TRANSFER_UUID)], options:[CBCentralManagerScanOptionAllowDuplicatesKey: false])
case CBManagerState.Resetting:
print("CBCentralManagerState.Resetting")
case CBManagerState.Unsupported:
print("CBCentralManagerState.Unsupported")
break
}
}
else
{
switch central.state.rawValue
{
case 0: // CBCentralManagerState.Unknown
print("CBCentralManagerState.Unknown")
break
case 1: // CBCentralManagerState.Resetting
print("CBCentralManagerState.Resetting")
case 2:// CBCentralManagerState.Unsupported
print("CBCentralManagerState.Unsupported")
break
case 3: // CBCentralManagerState.unauthorized
print("This app is not authorised to use Bluetooth low energy")
break
case 4: // CBCentralManagerState.poweredOff:
print("Bluetooth is currently powered off.")
case 5: //CBCentralManagerState.poweredOn:
self.centralManager!.scanForPeripheralsWithServices([CBUUID(string:TRANSFER_UUID)], options:[CBCentralManagerScanOptionAllowDuplicatesKey: false])
print("Bluetooth is currently powered on and available to use.")
default:break
}
}
}

BLE Scanning at Start in Swift

I have scanning for a single UUID working in my Swift app when attached to an IBAction: UIButton. However, I'm now trying to get it to start scanning right when the app starts (background scanning should also be working as I have it set to a single UUID).
I've tried what I think is logical:
self.centralManager?.scanForPeripheralsWithServices(arrayOfServices, options: nil)
in viewDidLoad with arrayOfServices being the UUID of course. But this doesn't seem to work.
How do I get my app to look for peripherals upon start up without being prompted with a button press?
You will need to initialize the CentralManager and wait for the centralManagerDidUpdateState call via the CBCentralManagerDelegate. Once you verify that the State is PoweredOn, you can start scanning.
func centralManagerDidUpdateState(central: CBCentralManager) {
switch central.state
{
case CBCentralManagerState.PoweredOff:
print("Powered Off")
case CBCentralManagerState.PoweredOn:
print("Powered On")
//Start Scanning Here
self.centralManager?.scanForPeripheralsWithServices(arrayOfServices, options: nil)
case CBCentralManagerState.Unsupported,
CBCentralManagerState.Resetting,
CBCentralManagerState.Unauthorized,
CBCentralManagerState.Unknown:
print("Unexpected CBCentralManager State")
fallthrough
default:
break;
}
}
Swift 3
func centralManagerDidUpdateState(_ central: CBCentralManager){
switch central.state{
case .poweredOn:
print("Power On")
central.scanForPeripherals(withServices: nil, options: nil)
break
case .poweredOff:
print("Power Off")
break
case .unsupported:
print("Power Unsupported")
break
case .resetting:
print("Power Resetting")
break
case .unauthorized:
print("Power Unauthorized")
break
case .unknown:
print("Power Unknown")
break
}
}

Resources