7

Первых вещей первыми: работаю OSX 10.10.4, IOS 4, Xcode 6.3.2, iPhone 6, SwiftПодписавшись на уведомления от в CBCharacteristic не работают

Краткая история: У меня есть определенный Bluetooth LE устройство здесь с который я хочу получать уведомления, когда значения изменения характеристик, например по пользовательскому вводу. Пытаясь подписаться на него не удастся, а дает погрешность Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found."

Длинная история: Так, у меня есть класс BluetoothManager, в котором я начала сканирования для периферийных устройств, как только мой $CBCentralManager.state является .PoweredOn. Это легко, я даже хороший гражданин и отсканировать специально для тех, кто с Услугой Я хочу

centralManager.scanForPeripheralsWithServices([ServiceUUID], options: nil) 

Надеясь это удастся, я реализован следующий метод делегата:

func centralManager(central: CBCentralManager!, didDiscoverPeripheral peripheral: CBPeripheral!, advertisementData: [NSObject : AnyObject]!, RSSI: NSNumber!) { 

    if *this is a known device* { 
     connectToPeripheral(peripheral) 
     return 
    } 

    [...] // various stuff to make something a known device, this works 
} 

Так движущуюся вдоль, мы получаем:

func connectToPeripheral(peripheral: CBPeripheral) { 
    println("connecting to \(peripheral.identifier)") 

    [...] // saving the peripheral in an array along the way so it is being retained 

    centralManager.connectPeripheral(peripheral, options: nil) 
} 

ЮПП, это удастся, так что я получаю подтверждение и начать открыть службу:

func centralManager(central: CBCentralManager!, didConnectPeripheral peripheral: CBPeripheral!) {   
    println("Connected \(peripheral.name)") 

    peripheral.delegate = self 

    println("connected to \(peripheral)") 
    peripheral.discoverServices([BluetoothConstants.MY_SERVICE_UUID]) 
} 

Который также работает, так как этот метод делегата вызывается так:

func peripheral(peripheral: CBPeripheral!, didDiscoverServices error: NSError!) { 

    if peripheral.services != nil { 
     for service in peripheral.services { 
      println("discovered service \(service)") 
      let serviceObject = service as! CBService 

      [...] // Discover the Characteristic to send controls to, this works 
      peripheral.discoverCharacteristics([BluetoothConstants.MY_CHARACTERISTIC_NOTIFICATION_UUID], forService: serviceObject) 

      [...] // Some unneccessary stuff about command caches 
     } 
    } 
} 

А что вы знаете: характерный получает обнаружил!

func peripheral(peripheral: CBPeripheral!, didDiscoverCharacteristicsForService service: CBService!, error: NSError!) { 
    for characteristic in service.characteristics { 
     let castCharacteristic = characteristic as! CBCharacteristic 

     characteristics.append(castCharacteristic) // Retaining the characteristic in an Array as well, not sure if I need to do this 

     println("discovered characteristic \(castCharacteristic)") 
     if *this is the control characteristic* { 
      println("control") 
     } else if castCharacteristic.UUID.UUIDString == BluetoothConstants.MY_CHARACTERISTIC_NOTIFICATION_UUID.UUIDString { 
      println("notification") 
      peripheral.setNotifyValue(true, forCharacteristic: castCharacteristic) 
     } else { 
      println(castCharacteristic.UUID.UUIDString) // Just in case 
     } 
     println("following properties:") 

     // Just to see what we are dealing with 
     if (castCharacteristic.properties & CBCharacteristicProperties.Broadcast) != nil { 
      println("broadcast") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.Read) != nil { 
      println("read") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.WriteWithoutResponse) != nil { 
      println("write without response") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.Write) != nil { 
      println("write") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.Notify) != nil { 
      println("notify") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.Indicate) != nil { 
      println("indicate") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.AuthenticatedSignedWrites) != nil { 
      println("authenticated signed writes ") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.ExtendedProperties) != nil { 
      println("indicate") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.NotifyEncryptionRequired) != nil { 
      println("notify encryption required") 
     } 
     if (castCharacteristic.properties & CBCharacteristicProperties.IndicateEncryptionRequired) != nil { 
      println("indicate encryption required") 
     } 

     peripheral.discoverDescriptorsForCharacteristic(castCharacteristic) // Do I need this? 
    } 
} 

Теперь вывод на консоль вплоть до здесь выглядит следующим образом:

connected to <CBPeripheral: 0x1740fc780, identifier = $FOO, name = $SomeName, state = connected> 
discovered service <CBService: 0x170272c80, isPrimary = YES, UUID = $BAR> 
[...] 
discovered characteristic <CBCharacteristic: 0x17009f220, UUID = $BARBAR properties = 0xA, value = (null), notifying = NO> 
control 
following properties: 
read 
write 
[...] 
discovered characteristic <CBCharacteristic: 0x17409d0b0, UUID = $BAZBAZ, properties = 0x1A, value = (null), notifying = NO> 
notification 
following properties: 
read 
write 
notify 
[...] 
discovered DescriptorsForCharacteristic 
[] 
updateNotification: false 

Эй! В нем говорится, что updateNotification - false. Откуда это? Почему это мой обратный вызов для setNotify...:

func peripheral(peripheral: CBPeripheral!, didUpdateNotificationStateForCharacteristic characteristic: CBCharacteristic!, error: NSError!) { 

    println("updateNotification: \(characteristic.isNotifying)") 
} 

Что это дает? Я сказал, чтобы он уведомлялся! Почему он не уведомляет? Давайте установить контрольную точку в соответствии с Println и проверить объект ошибки:

(lldb) po error 
Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found." UserInfo=0x17026eac0 {NSLocalizedDescription=The attribute could not be found.} 

ОК, так что это оставляет меня из идей. Я не смог найти соответствующие подсказки относительно этого кода ошибки. Само описание, которое я не могу понять, поскольку я пытался настроить уведомление для характеристики, которую я обнаружил ранее, следовательно, это должно существует, правда? Кроме того, на Android, возможно, подписаться на уведомления, поэтому, я думаю, я могу исключить проблемы с устройством ... или я могу? Любые подсказки по этому поводу действительно оценены!

+0

Похоже, что вы не можете сохранить ссылку на периферию. Paulw11 имеет отличный ответ для этого http://stackoverflow.com/questions/26377470/ios-corebluetooth-centralmanagerdidconnectperipheral-didfailtoconnectperiph –

+0

Нет, я делаю это; Я оставил это для краткости: у меня есть Массивы для Периферийных устройств в обнаруженном, подключающемся и подключенном состоянии и не забудьте сохранить периферийное устройство в соответствующем режиме во время настройки. – mss

+1

Ваш код выглядит хорошо, и он может быть большим на вашем устройстве или на iOS. Мой инструмент для тестирования - это приложение LightBlue. Вы можете использовать это, чтобы узнать свое периферийное устройство и службы и посмотреть, может ли он установить уведомление по вашему признаку. – Paulw11

ответ

2

Получив больше информации от производителя, я понял, что устройство подключено и отправляет уведомления независимо от состояния уведомляемого уведомления об этом признаке. Это означает, что хотя peripheral(_, didUpdateNotificationStateForCharacteristic, error) сообщает мне, что Characteristic не уведомляет, peripheral(_, didUpdateValueForCharacteristic, error) получает вызов и доставку данных, когда устройство отправляет его. Я ранее не реализовал этот обратный вызов, так как я не ожидал, что данные будут отправлены в этом состоянии.

Таким образом, моя проблема, похоже, решила сама.Тем не менее, мне все еще интересно, если поведение устройства соответствует спецификациям Bluetooth LE или нет; У меня нет понимания этих более низких уровней реализации, но предположим, что Apple по какой-то причине написала свои документы, по крайней мере, решительно подразумевая, что изменение состояния характеристики будет предшествовать приему любых данных.

3

Для меня проблема заключалась в том, что я использовал другое устройство Android в качестве периферийного устройства и нуждался в реализации дескриптора конфигурации. См. Здесь: https://stackoverflow.com/a/25508053/599743

Смежные вопросы