Closed NbrTDB closed 4 years ago
Gah... this is complex....
The Windows backend API has no dedicated disconnect function, so the only way I have found to facilitate a disconnect is by Dispose
:ing of the .NET client. I have not tested that repeatedly though...
Even with the Dispose
it takes quite some time, since the garbage collection in .NET is not guaranteed to happen when you request it to happen.
But in your example you call disconnect
on client you have already called disconnect
on. It is wrong behaviour, and it is reasonable that an error is thrown. It is not the right one, granted, but still. This SO post describes the situation pretty well. I am uncertain of why it disconnects the first time and not the second though...
I agree, an explosion of some sort would be expected for trying to disconnect from something twice in a row, so I guess the real conundrum is why the first client.disconnect()
request is rendered ineffective on a device has previously disconnected itself in an older connection session.
In the test case shown here, the problem only arises after a disconnect occurred remotely, so:
client.disconnect()
on Bleak's end seems to silently fail, no disconnect callbacks run, no errors thrown, and the device shows it is still connected even after waiting for quite some time. Then, as discussed, any further attempts to use client.disconnect()
result in AttributeErrors.After using client.disconnect()
on a device that had previously disconnected itself, I haven't tried forcing the device to disconnect itself a second time, maybe I should see what happens then?
If Microsoft implemented the Dispose pattern correctly, it should disconnect without having to wait for the garbage collector. I have had the same experience that there is some delay after calling Dispose though, so I think we can conclude that it is not a synchronous operation. (In fact, there is a new DisposeAsync pattern being introduced in .NET because of issues like this.)
Anyway, we could wait a while for a ConnectionStatusChanged event before returning from the async disconnect method to help ensure that the device had a chance to disconnect before allowing the program to move on.
Hmm... I've been trying this with a different device and it disconnects right away when calling Dispose().
I will also suggest that multiple calls to disconnect()
should be allowed. There is precedence for this, e.g. Python allows calling close()
multiple times.
Furthermore, async with BleakClient():
, will implicitly call disconnect()
at exit. So it would also raise an error if the device was disconnected inside the with block.
Yes, I agree. Multiple calls to disconnect should all yield the same True
response, without error.
I have not experienced problems with disconnecting on Windows since I added the Dispose
call on disconnect. It takes some time, granted, but it hasn't failed to disconnect. The PR is a good improvement though!
Additional disconnect calls are now allowed in the released version 0.9.0. Will close this issue for now.
Description
I've found a repeatable scenario wherein Bleak throws an AttributeError on attempting to
await client.disconnect()
a device which had previously disconnected itself and subsequently been reconnected to. I am not certain if this is a genuine issue or just a misuse of Bleak. In any case, catching the AttributeError still does not result in the ability to disconnect the device (it will just throw the same error each time).In short:
await client.disconnect()
What I Did
I put together a snippet that reproduces the problem for me; it requires a device where the BLE connection can quickly be severed on the device side and said device be ready to reconnect again quickly (other devices should work if the timings are adjusted to suit)