BLE Reconnection Fails After GoPro Battery Removal or Extended Idle Time (Requires Manual Re-pairing)
Component What is the bug in?
- Demos (python sdk, etc) - Using WirelessGoPro / python sdk
Describe the bug I can successfully pair my gopro via ble and then connect with the WirelessGoPro (connecting and disconnecting successfully). However, if the battery is removed / changes or the camera sits idle for long enough after powering off then I cannot reconnect via ble without manually repairing.
Repro
gp0 = WirelessGoPro(
target=target0,
enable_wifi=False,
maintain_state=False,
)
await gp0.open()
Error:
Connection failed during establishment..
[org.bluez.Error.Failed] Operation already in progress
Failed to connect: ConnectFailed('BLE connection failed to establish after 1 retries with timeout 1'). Retrying #1
Failed to connect: ConnectFailed('BLE connection failed to establish after 1 retries with timeout 1'). Retrying #2
Connection failed during establishment..
[org.bluez.Error.Failed] Operation already in progress
Error while opening: BLE connection failed to establish after 5 retries with timeout 15
Failed to connect: ConnectFailed('BLE connection failed to establish after 1 retries with timeout 1'). Retrying #3
Failed to connect: ConnectFailed('BLE connection failed to establish after 1 retries with timeout 1'). Retrying #4
---------------------------------------------------------------------------
BleakDBusError Traceback (most recent call last)
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/bleak/__init__.py:615](http://localhost:9091/home/areiner/miniforge3/envs//lib/python3.10/site-packages/bleak/__init__.py#line=614), in BleakClient.connect(self, **kwargs)
606 """Connect to the specified GATT server.
607
608 Args:
(...)
613
614 """
--> 615 return await self._backend.connect(**kwargs)
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/bleak/backends/bluezdbus/client.py:254](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/bleak/backends/bluezdbus/client.py#line=253), in BleakClientBlueZDBus.connect(self, dangerous_use_bleak_cache, **kwargs)
249 raise BleakDeviceNotFoundError(
250 self.address,
251 f"Device with address {self.address} was not found. It may have been removed from BlueZ when scanning stopped.",
252 )
--> 254 assert_reply(reply)
256 self._is_connected = True
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/bleak/backends/bluezdbus/utils.py:20](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/bleak/backends/bluezdbus/utils.py#line=19), in assert_reply(reply)
19 if reply.message_type == MessageType.ERROR:
---> 20 raise BleakDBusError(reply.error_name, reply.body)
21 assert reply.message_type == MessageType.METHOD_RETURN
BleakDBusError: [org.bluez.Error.Failed] Operation already in progress
The above exception was the direct cause of the following exception:
ConnectFailed Traceback (most recent call last)
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/ble/client.py:110](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/ble/client.py#line=109), in BleClient.open(self, timeout, retries)
109 try:
--> 110 self._handle = await self._controller.connect(self._disconnected_cb, self._device, timeout=timeout)
111 break
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/ble/adapters/bleak_wrapper.py:249](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/ble/adapters/bleak_wrapper.py#line=248), in BleakWrapperController.connect(self, disconnect_cb, device, timeout)
248 logger.warning(exception)
--> 249 raise ConnectFailed("BLE", 1, 1) from exception
250 return client
ConnectFailed: BLE connection failed to establish after 1 retries with timeout 1
The above exception was the direct cause of the following exception:
ConnectFailed Traceback (most recent call last)
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py:294](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py#line=293), in WirelessGoPro.open(self, timeout, retries)
293 try:
--> 294 await self._open_ble(timeout, retries)
296 # Set current dst-aware time. Don't assert on success since some old cameras don't support this command.
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py:583](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py#line=582), in WirelessGoPro._open_ble(self, timeout, retries)
582 # Establish connection, pair, etc.
--> 583 await self._ble.open(timeout, retries)
584 # Start state maintenance
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/ble/client.py:115](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/ble/client.py#line=114), in BleClient.open(self, timeout, retries)
114 if retry == retries - 1:
--> 115 raise ConnectFailed("BLE", timeout, retries) from e
117 assert self._handle is not None
ConnectFailed: BLE connection failed to establish after 5 retries with timeout 15
During handling of the above exception, another exception occurred:
GoProNotOpened Traceback (most recent call last)
Cell In[13], line 1
----> 1 r = await gp0.open()
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py:318](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py#line=317), in WirelessGoPro.open(self, timeout, retries)
316 except Exception as e:
317 logger.error(f"Error while opening: {e}")
--> 318 await self.close()
319 raise e
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py:329](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py#line=328), in WirelessGoPro.close(self)
321 async def close(self) -> None:
322 """Safely stop the GoPro instance.
323
324 This will disconnect BLE and WiFI if applicable.
(...)
327 prevent reconnection issues because the OS has never disconnected from the previous session.
328 """
--> 329 await self._close_wifi()
330 await self._close_ble()
331 self._open = False
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py:805](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_wireless.py#line=804), in WirelessGoPro._close_wifi(self)
803 async def _close_wifi(self) -> None:
804 """Terminate the Wifi connection."""
--> 805 assert (await self.ble_command.enable_wifi_ap(enable=False)).ok
806 if hasattr(self, "_wifi"): # Corner case where instantiation fails before superclass is initialized
807 self._wifi.close()
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/api/builders.py:275](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/api/builders.py#line=274), in ble_write_command.<locals>.wrapper(wrapped, instance, _, kwargs)
273 @wrapt.decorator
274 async def wrapper(wrapped: Callable, instance: BleMessages, _: Any, kwargs: Any) -> GoProResp:
--> 275 return await instance._communicator._send_ble_message(message, rules, **(await wrapped(**kwargs) or kwargs))
File [~/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_base.py:89](http://localhost:9091/home/areiner/miniforge3/envs/zed_dev2/lib/python3.10/site-packages/open_gopro/gopro_base.py#line=88), in ensure_opened.<locals>.wrapper(wrapped, instance, args, kwargs)
86 @wrapt.decorator
87 def wrapper(wrapped: Callable, instance: GoProBase, args: Any, kwargs: Any) -> Callable:
88 if GoProMessageInterface.BLE in interface and not instance.is_ble_connected:
---> 89 raise GpException.GoProNotOpened("BLE not connected")
90 if GoProMessageInterface.HTTP in interface and not instance.is_http_connected:
91 raise GpException.GoProNotOpened("HTTP interface not connected")
GoProNotOpened: GoPro is not correctly open: BLE not connected
Screenshots If applicable, add screenshots to help explain your problem.
Hardware
- Camera: Hero13 Black etc.
- PC, Ubuntu 22.04
Additional Info
Here are some additional logs via btmon:
> HCI Event: Encryption Change (0x08) plen 4 #453 [hci1] 39.779169
Status: PIN or Key Missing (0x06)
Handle: 16
Encryption: Disabled (0x00)
< HCI Command: Disconnect (0x01|0x0006) plen 3 #454 [hci1] 39.779438
Handle: 16
Reason: Authentication Failure (0x05)
> HCI Event: Command Status (0x0f) plen 4 #455 [hci1] 39.781072
Disconnect (0x01|0x0006) ncmd 2
Status: Success (0x00)
> HCI Event: Disconnect Complete (0x05) plen 4 #456 [hci1] 39.823092
Status: Success (0x00)
Handle: 16
Reason: Connection Terminated By Local Host (0x16)
@ MGMT Event: Device Disconnected (0x000c) plen 8 {0x0001} [hci1] 39.823134
LE Address: D6:DE:15:46:94:6E (Static)
Reason: Connection terminated due to authentication failure (0x04)
@ MGMT Event: Connect Failed (0x000d) plen 8 {0x0001} [hci1] 39.843463
LE Address: D6:DE:15:46:94:6E (Static)
Status: Disconnected (0x0e)
Hey @areiner222 did you ever find a way to resolve this? I am having very similar issues.
@MRL-00 I never determined a very reliable way to reconnect... I have successfully connected via BLE + COHN up to 6 cameras but I can't get it to work consistently
@tcamise-gpsw is there a way to connect to the WirelessGoPro directly via https over COHN without connecting via BLE first?
This sounds similar to a discussion I was having in the bleak repo. I'm still trying to characterize this but at least on Windows there are situations you can get into where the OS automatically reconnects and you can thus no longer connect from bleak. Also, there is no way to "access" the existing connection.
@areiner222 about your above question about establishing without BLE...unfortunately no. The Python SDK was designed before COHN existed and not in a scalable enough way to handle any type / order of connections. I've since released the Kotlin SDK which does allow such scalable connecting and plan on refactoring the Python SDK to a similar design. But this is a fairly major effort and I'm not sure when I will get to it.
FYI the Python SDK has been updated to allow directory connecting COHN without BLE.
@MRL-00 I never determined a very reliable way to reconnect... I have successfully connected via BLE + COHN up to 6 cameras but I can't get it to work consistently
@tcamise-gpsw is there a way to connect to the WirelessGoPro directly via https over COHN without connecting via BLE first?
@tcamise-gpsw did you ever manage to find the cause of GoPros not reconnecting if they turn off or batteries are removed from them?
We still see this happening randomly with certain devices. If we connect to 4 devices on one day, then overnight the devices power off, if we try to connect to the same 4 devices the next day, 2 of them may reconnect but 2 of them appear to fail. They have to be manually put back into pairing mode before they will reconnect.
I don't think this is a Bleak issue as we are not using the Python SDK.
I recently had the same problem. I have a device with an NRF52840 chip that connects to a GoPro13. The device pairs successfully and then connects successfully for a few days. But at some point, it stops connecting. The connection doesn't work until I pair it again. I looked for the problem in my NRF52840 code and asked a question on the Nordic support forum (https://devzone.nordicsemi.com/f/nordic-q-a/124754/ble-connection-to-paired-device-failed-after-some-time). I have wireshark logs of the pairing, successful connection, and unsuccessful connection.
If the problem is with the GoPro, is there on GoPro Lab firmware version? What about other GoPro versions? In my case, the problem is only with my NRF52 device; other devices (remote control, laptop, phone) continue to connect successfully.
This falls under the same bucket as the pinned issue: #487
Basically there needs to be large investigation into how the Python SDK (and bleak) handle nongraceful reconnections.
I'll close this and follow ups can be done in #487