Skip to content

aioble peripheral may need throttling to avoid random disconnects #596

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
PBrunot opened this issue Jan 7, 2023 · 5 comments
Open

aioble peripheral may need throttling to avoid random disconnects #596

PBrunot opened this issue Jan 7, 2023 · 5 comments

Comments

@PBrunot
Copy link

PBrunot commented Jan 7, 2023

I am using AIOBLE (latest version as per December 2022) on ESP32-C3 with Micropython 1.19 (LOLIN D32 board).
My app uses 3 BT LE services (peripheral role),:

  • a custom service for requests (with 1 write-only and 1notify-only characteristics)
  • a battery_service
  • a device_information service

I observed frequent client disconnects to client (I tested with another ESP32 and with NRFConnect app on Android).
The problem seems to happen more frequently when many requests were done in a rapid succession. In such conditions, the peripheral stopped responding, and disconnected the clients after a while (10-20s). Once the clients reconnected, everything worked again.

I was able to solve the problem after one week of testing, by imposing a minimum delay between all characteristics notifications (in my case 50 ms) : now I don't have any disconnects and everything is stable.

Concept code:

            since_last = time.ticks_ms() - __last_notification_ms
            while _MIN_BLUETOOTH_DELAY_MS > since_last > 0 and not force:
                await asyncio.sleep_ms(_MIN_BLUETOOTH_DELAY_MS - since_last)
                # Need to recheck because another transmission may have happened during await period
                since_last = time.ticks_ms() - __last_notification_ms
            data = __get_notification_data()
            __status_characteristic.write(data, True)
            __last_notification_ms = time.ticks_ms()

I guess there is a minimum delay for physical transmission over bluetooth and handling by RTOS and if we push too many notifications in a short period, something goes wrong. I wrote this issue for informing other AIOBLE users and for suggesting defining a rate limit inside the aioble library, or a warning, because this was quite difficult to troubleshoot.

@jimmo
Copy link
Member

jimmo commented Jan 17, 2023

Thanks @PBrunot

It would be worth getting to the root cause of why this causes disconnects, but yes this seems to be becoming a bit of a common gotcha. It might be possible to make the server-side char.write and char.notify detect this case and raise a "busy" exception. (i.e. it should be impossible to write Python code that causes a failure like this).

FWIW, using an L2CAP connection-oriented-channel for streaming data is a much better alternative to "streaming" notifications, because flow control is built-in.

@andrewleech
Copy link
Contributor

Is L2CAP available on esp32?

@jimmo
Copy link
Member

jimmo commented Jan 17, 2023

Is L2CAP available on esp32?

Ah, good point. Now that we've moved to synchronous events on the ESP32 there should be nothing blocking enabling it though, just needs testing.

@andrewleech
Copy link
Contributor

Awesome, yeah I thought you'd done some work in this area recently :-D

@RantyDave
Copy link

RantyDave commented Jan 30, 2024

I'm also getting these frequent (after 5-10 minutes) disconnections. I'm pushing a reasonable quantity of traffic, maybe 50-100 notifications/sec over 7 characteristics, using aioble, and receive an OSError exception (22 EINVAL). Throttling makes no difference. After some quick perusal of the code I see some references to a ring buffer - could it be that it's not dealing with this filling up correctly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants