react-native-ble-manager icon indicating copy to clipboard operation
react-native-ble-manager copied to clipboard

Notification error Set notification failed

Open ad7090 opened this issue 4 years ago • 7 comments
trafficstars

Version

  • "react-native-ble-manager": "7.6.1",
    
  • "react-native": "0.64.0",
  • Android :v 9 with android studio Android Studio Arctic Fox | 2020.3.1 Patch 2

Build #AI-203.7717.56.2031.7678000, built on August 27, 2021 Runtime version: 11.0.10+0-b96-7281165 x86_64 VM: OpenJDK 64-Bit Server VM by JetBrains s.r.o. macOS 11.5.2 GC: G1 Young Generation, G1 Old Generation Memory: 2048M Cores: 4 Registry: external.system.auto.import.disabled=true

Expected behaviour

I work for a startup Which sends an array string to the requests sent via the device via Bluetooth It used to work great for both Android and iOS, IOS working so great now but for Android I get it when I use " BleManager.startNotification " Error " Notification error Set notification failed "

I'll share my code :

`const App = () => { const [isScanning, setIsScanning] = useState(false) const peripherals = new Map(); const [list, setList] = useState([]);

const startScan = () => { if (!isScanning) { BleManager.scan([], 3, true).then((results) => { console.log('Scanning...'); setIsScanning(true); }).catch(err => { console.error(err); }); }
}

const handleStopScan = () => { console.log('Scan is stopped'); setIsScanning(false); }

const handleDisconnectedPeripheral = (data) => { let peripheral = peripherals.get(data.peripheral); if (peripheral) { peripheral.connected = false; peripherals.set(peripheral.id, peripheral); setList(Array.from(peripherals.values())); } console.log('Disconnected from ' + data.peripheral); }

const handleUpdateValueForCharacteristic = (data) => { console.log('Received data from ' + data.peripheral + ' characteristic ' + data.characteristic, data.value); }

const retrieveConnected = () => { BleManager.getConnectedPeripherals([]).then((results) => { if (results.length == 0) { console.log('No connected peripherals') } console.log(results); for (var i = 0; i < results.length; i++) { var peripheral = results[i]; peripheral.connected = true; peripherals.set(peripheral.id, peripheral); setList(Array.from(peripherals.values())); } }); }

const handleDiscoverPeripheral = (peripheral) => { console.log('Got ble peripheral', peripheral); if (!peripheral.name) { peripheral.name = 'NO NAME'; } peripherals.set(peripheral.id, peripheral); setList(Array.from(peripherals.values())); }

const testPeripheral = (peripheral) => { if (peripheral){ if (peripheral.connected){ BleManager.disconnect(peripheral.id); }else{ BleManager.connect(peripheral.id).then(() => { let p = peripherals.get(peripheral.id); if (p) { p.connected = true; peripherals.set(peripheral.id, p); setList(Array.from(peripherals.values())); } console.log('Connected to ' + peripheral.id);

      setTimeout(() => {

  
        BleManager.retrieveServices(peripheral.id).then((peripheralData) => {
          console.log('Retrieved peripheral services', peripheralData);
        const data = stringToBytes('@mamin#');

          let service_id =
          Platform.OS === 'ios'
            ? peripheralData.characteristics[1].service
            : peripheralData.characteristics[4].service;
        let characteristic_id =
          Platform.OS === 'ios'
            ? peripheralData.characteristics[1].characteristic
            : peripheralData.characteristics[4].characteristic;

            console.log('peripheralId~~>', peripheralData.id);
            console.log('serviceUUID~~>', service_id);
            console.log('characteristicUUID~~~~>', characteristic_id);
            
          BleManager.write(
            peripheralData.id,
            service_id,
            characteristic_id,
            data,
          )
            .then(() => {

              console.log('Write:  ----   Success --- ');
            })
            .catch(error => {
   
              console.log(error);
            });

            BleManager.startNotification(
              peripheralData.id,
              service_id,
              characteristic_id,
              1234
            )
              .then(() => {
                console.log('Started notification on ' + pair_d.id);
              
              })
              .catch(error => {
                console.log('Notification error', error);
              });

          BleManager.readRSSI(peripheral.id).then((rssi) => {
            console.log('Retrieved actual RSSI value', rssi);
            let p = peripherals.get(peripheral.id);
            if (p) {
              p.rssi = rssi;
              peripherals.set(peripheral.id, p);
              setList(Array.from(peripherals.values()));
            }                
          });                                          
        });

     
        

      }, 900);
    }).catch((error) => {
      console.log('Connection error', error);
    });
  }
}

}

useEffect(() => { BleManager.start({showAlert: false});

bleManagerEmitter.addListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
bleManagerEmitter.addListener('BleManagerStopScan', handleStopScan );
bleManagerEmitter.addListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
bleManagerEmitter.addListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );

if (Platform.OS === 'android' && Platform.Version >= 23) {
  PermissionsAndroid.check(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
      if (result) {
        console.log("Permission is OK");
      } else {
        PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION).then((result) => {
          if (result) {
            console.log("User accept");
          } else {
            console.log("User refuse");
          }
        });
      }
  });
}  

return (() => {
  console.log('unmount');
  bleManagerEmitter.removeListener('BleManagerDiscoverPeripheral', handleDiscoverPeripheral);
  bleManagerEmitter.removeListener('BleManagerStopScan', handleStopScan );
  bleManagerEmitter.removeListener('BleManagerDisconnectPeripheral', handleDisconnectedPeripheral );
  bleManagerEmitter.removeListener('BleManagerDidUpdateValueForCharacteristic', handleUpdateValueForCharacteristic );
})

}, []);

const renderItem = (item) => { const color = item.connected ? 'green' : '#fff'; return ( <TouchableHighlight onPress={() => testPeripheral(item) }> <View style={[styles.row, {backgroundColor: color}]}> <Text style={{fontSize: 12, textAlign: 'center', color: '#333333', padding: 10}}>{item.name}</Text> <Text style={{fontSize: 10, textAlign: 'center', color: '#333333', padding: 2}}>RSSI: {item.rssi}</Text> <Text style={{fontSize: 8, textAlign: 'center', color: '#333333', padding: 2, paddingBottom: 20}}>{item.id}</Text> </View> </TouchableHighlight> ); }

return ( <> <StatusBar barStyle="dark-content" /> <SafeAreaView> <ScrollView contentInsetAdjustmentBehavior="automatic" style={styles.scrollView}> {global.HermesInternal == null ? null : ( <View style={styles.engine}> <Text style={styles.footer}>Engine: Hermes</Text> </View> )} <View style={styles.body}>

        <View style={{margin: 10}}>
          <Button 
            title={'Scan Bluetooth (' + (isScanning ? 'on' : 'off') + ')'}
            onPress={() => startScan() } 
          />            
        </View>

        <View style={{margin: 10}}>
          <Button title="Retrieve connected peripherals" onPress={() => retrieveConnected() } />
        </View>

        {(list.length == 0) &&
          <View style={{flex:1, margin: 20}}>
            <Text style={{textAlign: 'center'}}>No peripherals</Text>
          </View>
        }
      
      </View>              
    </ScrollView>
    <FlatList
        data={list}
        renderItem={({ item }) => renderItem(item) }
        keyExtractor={item => item.id}
      />              
  </SafeAreaView>
</>

); };

const styles = StyleSheet.create({ scrollView: { backgroundColor: Colors.lighter, }, engine: { position: 'absolute', right: 0, }, body: { backgroundColor: Colors.white, }, sectionContainer: { marginTop: 32, paddingHorizontal: 24, }, sectionTitle: { fontSize: 24, fontWeight: '600', color: Colors.black, }, sectionDescription: { marginTop: 8, fontSize: 18, fontWeight: '400', color: Colors.dark, }, highlight: { fontWeight: '700', }, footer: { color: Colors.dark, fontSize: 12, fontWeight: '600', padding: 4, paddingRight: 12, textAlign: 'right', }, }) Screen Shot 2021-09-23 at 12 49 37 AM ;`

ad7090 avatar Sep 22 '21 21:09 ad7090

@marcosinigaglia Please save my life :(((( Thank You

ad7090 avatar Sep 22 '21 21:09 ad7090

Screen Shot 2021-09-23 at 1 51 59 AM

ad7090 avatar Sep 22 '21 22:09 ad7090

Hi @AMINDRH91 , are you sure that the characteristic can notify?

marcosinigaglia avatar Oct 01 '21 15:10 marcosinigaglia

Have close issue, but in adb logs seems like all is ok, but I catch error like set notificatoin failed for <Char UUID>

TyshkevichSergey avatar Oct 04 '21 14:10 TyshkevichSergey

No it's Open issue i did not get answer yet @TyshkevichSergey

ad7090 avatar Oct 05 '21 09:10 ad7090

Yes, It's working great on the IOS , but in the android send notification not work

ad7090 avatar Oct 05 '21 09:10 ad7090

Any progress on this?

I'm having a similar issue... It works fine in iOS, but all Android versions (we've tested 9 and 12 at this point) are giving the same issue as above.

To reiterate the problem I believe we're facing:

  • We subscribe to notifications on characteristic A
  • We try and read a value from characteristic B
  • We successfully get the value from characteristic B
  • We see an error with the notification Failed to set client characteristic notification for UUID-for-characteristic-A

mikcox avatar Apr 25 '22 19:04 mikcox

Anyone figured out why this is happening? Bump @marcosinigaglia

enchorb avatar Dec 07 '22 16:12 enchorb

I believe you need to add the listener after you start notifications for all characteristics:

setNotifyOnUpdate = async (): Promise<boolean> => {
      await this.bleManager.startNotification(this.peripheralId, <service>, <characteristicA>)
      await this.bleManager.startNotification(this.peripheralId, <service>, <characteristicB>)
     // only do this once you've started notifications for all the characteristics you want...
      bleManagerEmitter.addListener(
        "BleManagerDidUpdateValueForCharacteristic",
        this.handleUpdateValueForCharacteristic
      )
  }

Your logic to handle notifications would be in handleUpdateValueForCharacteristic().

mutablestudio avatar Mar 21 '23 09:03 mutablestudio

Is the ble server (the device your app should communicate with) is built by your company? If so, throwing a wild guess to the air here, but they might forgot, or didnt see a reason to add descriptors to their bluetooth characteristics.

Heres my reasoning:

private void setNotify(UUID serviceUUID, UUID characteristicUUID, final Boolean notify, Callback callback) {
        if (!isConnected() || gatt == null) {
            callback.invoke("Device is not connected", null);
            completedCommand();
            return;
        }

        BluetoothGattService service = gatt.getService(serviceUUID);
        final BluetoothGattCharacteristic characteristic = findNotifyCharacteristic(service, characteristicUUID);

        if (characteristic == null) {
            callback.invoke("Characteristic " + characteristicUUID + " not found");
            completedCommand();
            return;
        }

        if (!gatt.setCharacteristicNotification(characteristic, notify)) {
            callback.invoke("Failed to register notification for " + characteristicUUID);
            completedCommand();
            return;
        }

        final BluetoothGattDescriptor descriptor = characteristic
                .getDescriptor(UUIDHelper.uuidFromString(CHARACTERISTIC_NOTIFICATION_CONFIG));
        if (descriptor == null) {
            callback.invoke("Set notification failed for " + characteristicUUID);
            completedCommand();
            return;
        }

this is from Peripheral.java in this lib, as you can see, the they check if you have a descriptor, and if you don't they break the function. Im no Java developer, nor I have any deep knowlage on ble technologies, but solely from reading the code after this check it seems that descriptors are the metadata of the characteristics, and the lib uses them to know on which characteristic you've "started notifications" on. Thus, if you don't have any descriptors on the characteristics you want to start notification on, it will fail, so just verify that.

ororsatti avatar Apr 15 '24 10:04 ororsatti