Slow performance reading/writing characteristics after idling
See original GitHub issue- bleak version: 0.9.1
- Python version: 3.8.5
- Operating System: Windows 10 v2004 (build 19041.508)
Description
I’m seeing strange performance issues using Bleak to read & write GATT characteristics on a BLE device, whereby a single read or write can take some 1400-2000ms to complete. It’s strange because it appears to be somewhat dependent on the process using Bleak going idle (as in, it’s much more likely to happen if the process was idle beforehand). This is a problem as it adds a huge artificial delay onto almost every attempt to communicate briefly with the device (since in almost every case, the BLE framework was idle prior to deciding to communicate for whatever reason).
In other words, if the read/write ops are chained together (one immediately after another) then the first one often seems to take a long time (1400-2000ms typically), and the rest blast through within some 30-40ms each.
And if time.sleep()
is used prior to any read or write, even just for a handful of milliseconds, then more often than not, every subsequent read or write op will also take 1400-2000ms, not just the first one.
It’s as if something is going to sleep during idle periods and then taking ages to “wake up” again afterwards, but if it’s already “awake” then it responds instantly…
What I Did
I can’t really provide a reproducible example, but essentially, the test involves writing to a characteristic, then reading back a result from another characteristic from the same service, and doing this multiple times to read different data (the write tells the device what data we want to see in the subsequent read).
async def __gatt_performance_test(self, address):
if address in self.connected_devices:
pass
else:
await self.__connect_device(address)
sv_uuid = "" # service UUID
cc_char = "" # command characteristic UUID (what we write to)
cd_char = "" # data characteristic UUID (what we read from)
protocol_reg = "41" # data we're trying to request
firmware_reg = "37"
model_reg = "31"
# spam BLE traffic; each __write and __read measures the time taken
for i in range(0,100):
await self.__write_gatt_characteristic(address, sv_uuid, cc_char, "98"+protocol_reg) # this will typically be very slow on first iteration, but not always
# time.sleep(0.03)
await self.__read_gatt_characteristic(address, sv_uuid, cd_char) # fast if time.sleep() isn't used in between
# time.sleep(0.001)
await self.__write_gatt_characteristic(address, sv_uuid, cc_char, "98"+firmware_reg)
# time.sleep(0.03)
await self.__read_gatt_characteristic(address, sv_uuid, cd_char)
# time.sleep(0.001)
await self.__write_gatt_characteristic(address, sv_uuid, cc_char, "98"+model_reg)
# time.sleep(0.03)
await self.__read_gatt_characteristic(address, sv_uuid, cd_char)
And how the times are extracted (read_gatt_char is measured the same):
ts = time.time()
await device_client.write_gatt_char(characteristic_uuid, ba_out, True)
es = time.time() - ts # this is the time value we're looking at; anywhere from ~30ms to ~2000ms depending
Does this seem at all familiar to anyone or is it specific to my situation?
Things I’ve eliminated so far:
- Not to do with range; the device is right next to the BLE modem
- Not to do with modem hardware; tried using different modems
- Not to do with the device I’m connecting to (at least, not entirely! Via an Android app performing the same test, performance is consistently much better)
Issue Analytics
- State:
- Created 3 years ago
- Comments:9 (3 by maintainers)
Top GitHub Comments
Thanks for following up.
I would love to, but alas, I can’t make any changes to the peripheral to run such tests haha!
I did acquire a BLE sniffer and Wireshark to have a look what was going on there. Though it didn’t seem as if Windows were trying to pick the absolute fastest parameters, they do seem to fall within the window provided by the device, and it did indeed ask the device for its preferred connection parameters before issuing the
LL_CONNECTION_UPDATE_IND
request. Thereafter, the device was reliably responding within about 15ms to transmissions from the PC.On initial connection:
And a few seconds later, having gathered preferred parameters:
The data stream didn’t reveal anything (that I could see) suggesting a reason for any delays. Transmissions were promptly replied to by the device in keeping with the 15ms negotiated connection interval. But there were notable gaps in time for transmissions from the master (the PC) once connection, GATT/GAP interrogation and link negotiation were complete and communication could properly begin, which seemed to tie up with the aforementioned observations on Windows (as if Windows is just sitting there for a second or so before sending any requests to access the GATT services).
I have not managed to track down a version of Windows prior to 2004 but I have just been offered an update to 20H2, as well as (apparently) some updated Bluetooth drivers for my motherboard (though I doubt the latter will have any effect when this issue is replicated across different makes/models of BLE hardware and different Windows machines). So I’ll update all of that and have another crack at it!