7

andiamo con ordine: in esecuzione OSX 10.10.4, iOS 4, Xcode 6.3.2, iPhone 6, SwiftSottoscrizione per le notifiche da un CBCharacteristic non funziona

Breve storia: ho un certo dispositivo Bluetooth LE qui dal che voglio ricevere notifiche quando i valori di un cambiamento caratteristico, ad es per input dell'utente. Cercando di iscriversi ad esso non riesce, ma produce un errore Error Domain=CBATTErrorDomain Code=10 "The attribute could not be found."

Lunga storia: Così, ho una classe BluetoothManager in cui mi metto scansione Peripherals non appena il mio $CBCentralManager.state è .PoweredOn. E 'facile, io sono anche un buon cittadino e scansione appositamente per quelli con il servizio che voglio

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

sperando che questo avrà successo, ho implementato il seguente metodo delegato:

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 
} 

Così si muove lungo, si arriva a:

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) 
} 

Yupp, questo riesce, in modo da ottenere la conferma e iniziamo a scoprire il servizio:

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

    peripheral.delegate = self 

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

che funziona anche, dal momento che il metodo delegato viene chiamato così:

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 
     } 
    } 
} 

E che ne sai: la caratteristica ottiene scoperto!

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? 
    } 
} 

Ora l'uscita della console fino a qui si presenta così:

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 

Hey! Dice updateNotification è false. Da dove viene? Perché, è il mio di callback per setNotify...:

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

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

Che cosa dà? Ho detto di essere avvisato! Perché non sta avvisando? Fissiamo un punto di interruzione in linea con il println e estrarre l'oggetto di errore:

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

OK, quindi questo mi lascia a corto di idee. Non ero in grado di trovare gli indizi pertinenti riguardo a quel codice di errore. La descrizione stessa non riesco a capire da quando ho provato a impostare la notifica per una caratteristica che ho scoperto prima, quindi lo deve esistere, giusto? Inoltre, su Android sembra possibile iscriversi per le notifiche, quindi credo di poter escludere problemi con il dispositivo ... o posso? Tutti gli indizi su questo sono veramente apprezzati!

+0

Sembra che non si possa mantenere un riferimento alla periferica. Paulw11 ha un'ottima risposta per questo http://stackoverflow.com/questions/26377470/ios-corebluetooth-centralmanagerdidconnectperipheral-didfailtoconnectperiph –

+0

No, lo sto facendo; L'ho lasciato fuori per brevità: ho degli array per periferiche nello stato scoperto, connesso e connesso e mi assicuro di mantenere la periferica nell'apposito durante l'installazione. – mss

+1

Il tuo codice sembra a posto e potrebbe essere un grande sul tuo dispositivo o su iOS. Il mio strumento ideale per i test è l'app LightBlue. Puoi usarlo per scoprire la tua periferica e i tuoi servizi e vedere se è possibile impostare una notifica sulle tue caratteristiche. – Paulw11

risposta

2

Dopo aver ricevuto ulteriori informazioni dal produttore, ho rilevato che il dispositivo è collegato e invia notifiche indipendentemente dallo stato di notifica comunicato della caratteristica. Il che significa che anche se peripheral(_, didUpdateNotificationStateForCharacteristic, error) mi sta dicendo che la Caratteristica non sta notificando, peripheral(_, didUpdateValueForCharacteristic, error) viene chiamato e consegna dati quando il dispositivo lo invia. Non avevo implementato quella richiamata in precedenza, poiché non mi aspettavo che i dati fossero inviati in questo stato.

Quindi, in sostanza, il mio problema sembra essersi risolto da solo.Tuttavia, sono ancora interessato se il comportamento del dispositivo è conforme alle specifiche Bluetooth LE o no; Non ho idea di quei bassi livelli di implementazione, ma supponiamo che Apple abbia scritto i loro documenti per qualche motivo per implicare almeno fortemente che un cambiamento nello stato della Caratteristica precederà la ricezione di qualsiasi dato.

Problemi correlati