cordova-plugin-bluetoothle icon indicating copy to clipboard operation
cordova-plugin-bluetoothle copied to clipboard

multiple concurrent connect/discover/read causes one connect to not return, IOS 14

Open sdetweil opened this issue 2 years ago • 5 comments

I have an ionic native app, using promises to parallelize reading from multiple devices.

there are two promise loops one to get all the needed characteristics from a device

and one o wait for the gets for all the devices to complete

    readdeviceInfo(peripherals, characteristics){
      const plist=[]  // for waiting for all device operatons to complete
      const promiseList={};      // for all operations on A device to complete
      // loop thru all the devices found during scan cycle
      peripherals.forEach(peripheral=>{
       // init its promise list
        promiseList[peripheral.address]=[]        
        plist.push(new Promise((zresolve,zreject)=>{
          this.LogIt("connecting to device="+JSON.stringify(peripheral))
          // connect to this device
          BluetoothLE.connect({address: peripheral.address}).subscribe((device)=>{
            this.LogIt("connected device="+JSON.stringify(peripheral))
            // have to manually discover service/characteristics?!..
            // before we can read
            BluetoothLE.discover({address:peripheral.address}).then(()=>{
              // loop thru the characteristics we need to gt info for
              characteristics.forEach((characteristic)=>{
                //this.LogIt("processing for characteristic="+characteristic) 
                // wrap with a promise so they are all async           
                promiseList[peripheral.address].push(new Promise((resolve,reject)=>{
                  //try {
                    //this.LogIt("in promise for characteristic="+characteristic) 
                    // if this is read RSSI OR we don't have the table info yet
                    if(characteristic !== DATATABLE | this.deviceTable[peripheral.advertisement.serviceUuids[0].slice(0,8)] === undefined){
                      // execute the read
                      BluetoothLE.read(
                        {
                          "address": peripheral.address,
                          "service": peripheral.advertisement.serviceUuids[0],
                          "characteristic": characteristic                  
                        }
                      ).then((result)=>{
                        const p = peripheral
                        if(characteristic === RSSI ){
                          // handle one characteristic
                        }
                        else{
                          // handle the other characteristics                                                                 
                        } 
                        resolve();  
                      }).catch((error)=>{
                        //this.LogIt(" read error="+JSON.stringify(error)+" for characteristic="+characteristic) 
                        reject(error)                  
                      })           
                    }
                    else{
                      // array of characteristics needed might contain some we don't need right now
                      // skip it
                      resolve();   
                    }
                  //}catch(error){
                    //this.LogIt(/*peripheral.advertisement.serviceUuids[0]+*/" processing error="+JSON.stringify(error) )
                  //  peripheral
                  //} // end try/catch       
                })  // end new promise 
                )   // end push 
              })    // end loop characteristics.forEach
              this.LogIt("first promise.all waiting");
              // wait for all the operations for A device to complete
              Promise.all(promiseList[peripheral.address]).then(()=>{     
                this.LogIt("all promises for "+peripheral.address+" resolved ok")                                       
                        
                //this.LogIt("disconnecting")
                // reset the device timestamp        
                peripheral.timestamp=Date.now();                        
                BluetoothLE.disconnect({address: peripheral.address}).then(()=>{
                  this.LogIt("disconnect for "+peripheral.address+" completed, closing") 
                  BluetoothLE.close({address: peripheral.address}).then(()=>{
                    this.LogIt("close completed ok. resolve="+typeof zresolve)                                                    
                    zresolve()    // signal for the outer promise.. this device data collection done              
                  })/*.catch(error=>{
                    this.LogIt("close failed error="+JSON.stringify(error)) 
                    zreject()
                  })  */                        
                })/*.catch(error=>{
                  this.LogIt("disconnect failed error="+JSON.stringify(error)) 
                  zreject()
                })   */
              })/*.catch(error=>{ 
                 this.LogIt("Promise all 1 failed error="+JSON.stringify(error)) 
                 zreject()                 
              })  */                                                              
            })/*.catch(error=>{
              this.LogIt(" discover error="+JSON.stringify(error))
              zreject()
            })*/
          })/*.catch(error=>{
              this.LogIt(" connect error="+JSON.stringify(error)+" reject="+typeof zreject)
              zreject()
          })*/
        }))
      })        
      this.LogIt("second promise.all waiting, there are "+plist.length+" devices to process");
      // this for ALL devices reported in scan
      Promise.all(plist).then(()=>{
        this.LogIt("table="+this.flatten(this.deviceTable))   
        this.LogIt("all device info collected")
        this.LogIt("beacon handler="+this.inputBeaconStream)
       // send devices on to device handler
        if(this.shouldProcess){
          setTimeout(()=>{this.inputBeaconStream.next(peripherals)}, 10)           
        }
      }).catch(error=>{
        this.LogIt("second promise failed=" +error);
      })
   }

i've been using this code for months.. and two changes happened this week

  1. I added two more devices to be detected (6 now, up from 4)
  2. there was the IOS security upgrade, on both iPhones (7 & 7plus) to 14.8

i had to comment out all the .then() catches, as I was getting an error

undefined is not a function near f9000-090-0-9-99090-999()()()( .catch(function(

which made no sense

commented out the catches and no fatal error anywhere... weird..

anyhow..

whenever I get more than 4 devices back, one of the extras (5 or 6), the connect() never returns

sdetweil avatar Sep 19 '21 18:09 sdetweil

here is the trace (captured over socket.io to my desktop)

client sent=1632068833020 start scanning
client sent=1632068833022 scan for BluetoothLE
client sent=1632068833034 Scanning for devices (will continue to scan until you stop it)...
client sent=1632068833072 FOUND DEVICE: 00000200 info={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00000200-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-88,"name":"FacilityDevice","address":"51DAEFDD-E532-7BF1-5C9B-773641735327"}

client sent=1632068833101 FOUND DEVICE: 00010201 info={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010201-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-90,"name":"FacilityDevice","address":"7E03A35E-9F21-62AE-E345-DAC5DD6C7215"}

client sent=1632068833184 FOUND DEVICE: 00010202 info={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010202-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-78,"name":"FacilityDevice","address":"F08CDF62-C692-D913-3FC6-3249B58A254A"}

client sent=1632068833228 FOUND DEVICE: 00010203 info={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010203-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-58,"name":"FacilityDevice","address":"FF85CCC9-5925-DFB4-C2DE-A614F966D654"}

client sent=1632068833240 FOUND DEVICE: 00020202 info={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00020202-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-74,"name":"FacilityDevice","address":"9DC84DDB-DCB5-8B9D-FAD3-D76C56DB31BD"}

client sent=1632068833346 FOUND DEVICE: 00010200 info={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"isConnectable":1,"serviceData":{},"serviceUuids":["00010200-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-88,"name":"FacilityDevice","address":"0C157ABD-6AD6-BF61-0357-6A1AA843B86F"}

client sent=1632068833779 stopscan successful, streaming beacons

client sent=1632068833779 connecting to device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"isConnectable":1,"serviceData":{},"serviceUuids":["00010200-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-88,"name":"FacilityDevice","address":"0C157ABD-6AD6-BF61-0357-6A1AA843B86F","direction":322,"timestamp":1632068833347}

client sent=1632068833785 connecting to device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010203-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-58,"name":"FacilityDevice","address":"FF85CCC9-5925-DFB4-C2DE-A614F966D654","direction":322,"timestamp":1632068833229}

--------------------------------------------------------------
client sent=1632068833792 connecting to device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010201-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-90,"name":"FacilityDevice","address":"7E03A35E-9F21-62AE-E345-DAC5DD6C7215","direction":322,"timestamp":1632068833102}
------------------------------------------------------------- no response, in a prior scan this device worked ok 

client sent=1632068833796 connecting to device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00000200-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-88,"name":"FacilityDevice","address":"51DAEFDD-E532-7BF1-5C9B-773641735327","direction":322,"timestamp":1632068833073}

client sent=1632068833798 connecting to device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010202-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-78,"name":"FacilityDevice","address":"F08CDF62-C692-D913-3FC6-3249B58A254A","direction":322,"timestamp":1632068833184}

client sent=1632068833799 connecting to device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00020202-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-74,"name":"FacilityDevice","address":"9DC84DDB-DCB5-8B9D-FAD3-D76C56DB31BD","direction":322,"timestamp":1632068833241}

client sent=1632068833800 second promise.all waiting, there are 6 devices to process

client sent=1632068834134 connected device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010202-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-78,"name":"FacilityDevice","address":"F08CDF62-C692-D913-3FC6-3249B58A254A","direction":322,"timestamp":1632068833184}
client sent=1632068834751 first promise.all waiting
client sent=1632068834826 all promises for F08CDF62-C692-D913-3FC6-3249B58A254A resolved ok
client sent=1632068834864 disconnect for F08CDF62-C692-D913-3FC6-3249B58A254A completed, closing
client sent=1632068834872 close completed ok. resolve=function

client sent=1632068834135 connected device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00010203-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-58,"name":"FacilityDevice","address":"FF85CCC9-5925-DFB4-C2DE-A614F966D654","direction":322,"timestamp":1632068833229}
client sent=1632068834764 first promise.all waiting
client sent=1632068834812 all promises for FF85CCC9-5925-DFB4-C2DE-A614F966D654 resolved ok
client sent=1632068834827 disconnect for FF85CCC9-5925-DFB4-C2DE-A614F966D654 completed, closing
client sent=1632068834839 close completed ok. resolve=function

client sent=1632068834667 connected device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00020202-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-74,"name":"FacilityDevice","address":"9DC84DDB-DCB5-8B9D-FAD3-D76C56DB31BD","direction":322,"timestamp":1632068833241}
client sent=1632068835345 first promise.all waiting
client sent=1632068835404 all promises for 9DC84DDB-DCB5-8B9D-FAD3-D76C56DB31BD resolved ok
client sent=1632068835417 disconnect for 9DC84DDB-DCB5-8B9D-FAD3-D76C56DB31BD completed, closing
client sent=1632068835422 close completed ok. resolve=function


client sent=1632068836171 connected device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"isConnectable":1,"serviceData":{},"serviceUuids":["00010200-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-88,"name":"FacilityDevice","address":"0C157ABD-6AD6-BF61-0357-6A1AA843B86F","direction":322,"timestamp":1632068833347}
client sent=1632068837413 first promise.all waiting
client sent=1632068837624 all promises for 0C157ABD-6AD6-BF61-0357-6A1AA843B86F resolved ok
client sent=1632068837637 disconnect for 0C157ABD-6AD6-BF61-0357-6A1AA843B86F completed, closing
client sent=1632068837642 close completed ok. resolve=function

client sent=1632068835296 connected device={"status":"scanResult","advertisement":{"solicitedServiceUuids":[],"overflowServiceUuids":[],"localName":"FacilityDevice","isConnectable":1,"serviceData":{},"serviceUuids":["00000200-27B9-42F0-82AA-2E951747BBF9"]},"rssi":-88,"name":"FacilityDevice","address":"51DAEFDD-E532-7BF1-5C9B-773641735327","direction":322,"timestamp":1632068833073}
client sent=1632068836236 first promise.all waiting
client sent=1632068836326 all promises for 51DAEFDD-E532-7BF1-5C9B-773641735327 resolved ok
client sent=1632068836342 disconnect for 51DAEFDD-E532-7BF1-5C9B-773641735327 completed, closing
client sent=1632068836347 close completed ok. resolve=function

sdetweil avatar Sep 19 '21 19:09 sdetweil

so, I changed all my promise

.then(
       ()=>{}   // resolve handler
)
.catch(
       ()=>{}   // error handler
)

to

.then(
       ()=>{},      // resolve handler
       ()=>{}       // reject handler
)

and now everything works. ?!.. but NO promise rejects are reported, but also no weird

      undefined is not a function near f9000-090-0-9-99090-999()()()( .catch(function(

sdetweil avatar Sep 20 '21 18:09 sdetweil

still seeing occasional connect not returning. is there a timeout option?

sdetweil avatar Sep 22 '21 17:09 sdetweil

i put the .catch back on to see if the promise is failing and get the weird error

client sent=1632333894495 second promise failed=TypeError: undefined is not a function (near '...ify(e)),a()})).catch((function(e){n.LogI...')

the n.LogI is my code, inside the catch..

sdetweil avatar Sep 22 '21 18:09 sdetweil

i am back to trying to deal with connect not returning..

never mind, i re-read the doc, and it clearly says this will happen AND you the developer using this lib are responsible for setting up error recovery...

one thing I haven't seen is a disconnect while in use... does that flow on the connect subscribe? nm, see below

sdetweil avatar Oct 08 '21 21:10 sdetweil