dotintent / react-native-ble-plx

React Native BLE library
Apache License 2.0
3.07k stars 513 forks source link

connectedDevices ocasionally fails to return a connected device #361

Closed sydorenkos closed 5 years ago

sydorenkos commented 6 years ago

Before all - thank you so much for such a great library. I have a series of custom built smart sensors that communicate with android devices. Ocasionally manager.connectedDevices() returns an empty array, even though one sensor is still connected (the sensors have visual feedback of connection status). If I, for example, disable bluetooth on the phone - the sensor responds visually that the connections was lost. I notice that this happens in a situation when a connection atempt takes more time than normal (I am using a routine that attempts connection several times with ConnectionOptions { timeout: 2000 }, and then the promise finally rejects with an error, however even after the error gets loggeg - the sensor still get connected (one - two seconds after the error was thrown). Is there another way to check if a device is connected in such situations?

Cierpliwy commented 5 years ago

Is it happening on iOS? If so please send me logs which are visible on XCode console. You need to call https://polidea.github.io/react-native-ble-plx/#blemanagersetloglevel to enable that.

sydorenkos commented 5 years ago

Sorry - forgot to mention - it is happening on Anfdroid. I haven't checked it on iOS.

Cierpliwy commented 5 years ago

In that case, please send logs provided by logcat.

sydorenkos commented 5 years ago

Thaks for the idea - I haven't been using logcat. I will run some tests tonight and will post the logs when I 'catch' it.

sydorenkos commented 5 years ago

After three consecutive days of tests with three different boards the described problem happended only two times, on two different modules, and both times when the terminal was closed... So far no luck with the usable logcat. I also notice that it only happened when reception conditions were marginal (sensors are far away). I did get a log from the disconnection listener which returned null (supposedly the device was disconected normally), but after the last connection attempt the module, again, showed the connection status as connected.
In any case I have a couple of questions about possible steps I can take to diagnose this situation more efficiently. I use widows terminal and logcat tags BluetoothGatt:v BtGatt:v bt-btif:v - am I using the right tags? My program has a recursive function that attempts 2.5 second connections for five times, before returning a rejected promise. I am wondering if the problem is conected to this, I will definitely look into it. Using this 'hack' did improve connection reliability in situations when reception conditions are not the best. Question - Is it better to use a single call to connectToDevice with a bigger timeout parameter, to make sure the phone can connect (has more time to connect) to distant devices more reliably?

sydorenkos commented 5 years ago

After more tests I found a bug in my code that seems to (kind of) have solved the issue, at least now when a device get disconnected with cancelDeviceConnection it stays disconnected - so far no more problems like the one I described were detected. But I am still not quite sure why it was happening... In any case - the issue seems not to be connected to the library, which is great news, but I would really appreciate your take on this, if possible, at least to validate my line of thougth - if not - just close this thread.

I believe It's the way my recursive connect function was built. The sensors are used in an industrial environment with highly dynamic radio-environment. I have found that repeating connect attempts turned out to be a great way to achieve 'hussle-free' connection. I believe that the way I was resetting an attempt counter variable coupled with asyncrounous conditions created a racing condition somewhere...??? My connect method goes like this (method names are what they are, the commented out zeroCounter call is what seems to have solved the issue): attemptConnection(id) { const { manager } = this; return new Promise((resolve, reject) => { const attCon = () => { this.incrementCounter(id); this.removeSubscriptionsForDevice(id); if (this.attemptCounter[id] > this.maxAttempts) { manager.cancelDeviceConnection(id) .then(() => { this.zeroCounter(id); reject(new Error('Ran out of Attempts')); }) .catch(() => { this.zeroCounter(id); reject(new Error('Ran out of Attempts')); }); return; } manager.connectToDevice(id, { timeout: 5000 }) .then((device) => { this.subscriptions[id].push( device.onDisconnected(this.disconnectionListener.bind(this)) ); //this.zeroCounter(id); device.discoverAllServicesAndCharacteristics() .then(() => { this.zeroCounter(id); resolve(id); }) .catch(() => { attCon(); return; }); }) .catch(() => { attCon(); return; }); }; attCon(); }); } An aside - I've been doing 'torture tests' on several sensors for the last three days, creating all possible 'worst case scenario' situations. (bad connections, monitoring six dynamicly changing characteristics at the same time for each sensor, while reading and writing other characteristics, random power-offs, bad reception - you name it), plus all the tests are done on a slow Android device (on purpose) - the library has been holding rock solid in all tests - at least for our purpose, which is sending small chunks of sensor data around 10 times a second at most). Once again - thank you.

dariuszseweryn commented 5 years ago

Android does not like cancelling connections too quickly as there are some internal race conditions. See this.