有选择地连接到特定外围设备上的蓝牙服务

Selectively connect to bluetooth services on specific peripheral

我的(室内骑行)Smart Trainer & Crank Power Meter(单独)宣传一些服务

室内教练:

Primary - Service        - Cycling Power Service (1818)
        - Characteristic - Cycling Power

Primary - Service        - Fitness Control (FTMS)
        - Characteristic - Cycling Power
                         - Trainer Target Power (from user)

曲柄功率计:

 Primary - Service        - Cycling Power Service (1818)
         - Characteristic - Cycling Power

使用自行车功率服务 (1818),它会公布传输的功率数据,但无法控制训练器的阻力。

使用 FTMS,它可以宣传传输的功率,并有办法向它发送目标功率(训练器阻力控制)

当 CoreBluetooth 连接到我的室内训练器设备时,它(我当前的代码)会自动列出这两种服务并连接到它。 (这不是我想要的)

当我连接到室内训练器时,我当然可以删除 Cycling Power (1818) 服务,但这是不希望的,因为这会删除任何连接到仅提供循环电源服务的其他外围设备的能力

var services = [serviceHeartRateCBUUID,
                serviceCyclingSpeedAndCadenceUUID,
                serviceCyclingPowerUUID, 
                serviceFTMSUUID]

centralManager.scanForPeripherals(withServices: services)

扫描后,我连接到外围设备并发现它提供的服务(传递我感兴趣的服务列表,其中再次包括 FTMS 和 Cycling Power 服务)这样,我最终得到了 w / 2 个连接到室内训练器(而不是我想要的 1 个)

 peripheral.discoverServices(services)

提问: 我正在寻找的解决方案是能够连接到室内训练器上的 FTMS 服务,同时还能够连接到曲柄功率计。

我正在考虑的解决方法基本上是让用户能够在 FTMS 与自行车功率计之间切换 select,因此如果用户同时连接了室内训练器和曲柄功率计.

搜索 Whosebug 和 goggle 并没有给我任何有用的信息,它们都只是展示了如何连接到服务(通过在“服务”变量中列出,如上例所示)

更新 1:

func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    guard let services = peripheral.services else { return }
    
    for service in services {
      print("  >> Discover Services Found : \(service.uuid) service")
      peripheral.discoverCharacteristics(nil, for: service)
    }
  }

在 didDiscoverServices 函数中,通过服务循环找到了这两个

>> Discover Services Found : 1818 service
>> Discover Services Found : FTMS service

之后调用 peripheral.discoverCharacteristics(nil, for: service)

如何使用来自 didDiscoverServices 的信息(一旦它同时检测到 FTMS 和 1818)来实际忽略 1818?

假设功率计和室内训练器是两个独立的蓝牙设备,那么应该没有任何问题。

BLE 的工作方式是中央连接到外围设备,然后您可以发现该外围设备上的服务,然后use/not使用您喜欢的任何东西。

因此,您可以继续扫描所有您喜欢的外围设备(不管他们宣传什么),然后连接、发现 services/characteristics - 并使用任何 combination/permutation 您喜欢。

如果您有兴趣在连接到外围设备时节省一些电量,并可能清理代码,您可以有选择地发现服务 (https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518706-discoverservices) - 您基本上可以处理您的服务过滤方式。

感谢与@SJoshi 的讨论,我成功地实现了我的目标。唯一的问题是代码似乎过于复杂,需要 3 个不同的循环才能实现目标。

  func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {

    var discoveredServices = [CBUUID]()
    var btServicesOffered = [CBService?]()
    
    guard let services = peripheral.services else { return }
    print("\nThere are \(services.count) service(S) advertised namely:")
    
    for service in services {
      print("  >> \(service.uuid) service")

      // Results in discoveredServices:[1818, FTMS]
      discoveredServices.append(CBUUID(string: service.uuid.uuidString))
      btServicesOffered.append(service)
    }
  
    // Can actually remove btServicesOffered as not really used
    print("  >>>>> btServicesOffered:\(btServicesOffered)")
    
    if discoveredServices.contains(FTMS) && discoveredServices.contains(1818) {
      print("\n  >> This is a Smart Trainer advertising 2 services. Connect ONLY to FTMS")

      for service in services {
        if service.uuid == FTMS {
          print("  >> Connecting to FTMS")
          peripheral.discoverCharacteristics(nil, for: service)
        } else if service.uuid == 1818 {
          print("  >> Doing NOTHING for 1818")
        }
      }
    } else {
      for service in services {
        print("  >> Discover Services Found : \(service.uuid) service")
        peripheral.discoverCharacteristics(nil, for: service)
      }
    }
    print()
  }