diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 82e88c8a..758726e2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -20,6 +20,7 @@ Changed To use the cache, call ``connect`` and ``get_services`` with the ``dangerous_use_bleak_cache`` argument to avoid services being resolved again. * The BlueZ D-Bus backend now uses ``dbus-fast`` instead of ``dbus-next`` which significantly improves performance. +* The BlueZ D-Bus backend will not avoid trying to connect to devices that are already connected. Fixes #992. Fixed ----- diff --git a/bleak/backends/bluezdbus/client.py b/bleak/backends/bluezdbus/client.py index c75813b6..94067b13 100644 --- a/bleak/backends/bluezdbus/client.py +++ b/bleak/backends/bluezdbus/client.py @@ -155,16 +155,25 @@ def on_value_changed(char_path: str, value: bytes) -> None: try: try: - async with async_timeout.timeout(timeout): - reply = await self._bus.call( - Message( - destination=defs.BLUEZ_SERVICE, - interface=defs.DEVICE_INTERFACE, - path=self._device_path, - member="Connect", + # + # The BlueZ backend does not disconnect devices when the + # application closes or crashes. This can cause problems + # when trying to reconnect to the same device. To work + # around this, we check if the device is already connected. + # + # For additional details see https://github.com/bluez/bluez/issues/89 + # + if not manager.is_connected(self._device_path): + async with async_timeout.timeout(timeout): + reply = await self._bus.call( + Message( + destination=defs.BLUEZ_SERVICE, + interface=defs.DEVICE_INTERFACE, + path=self._device_path, + member="Connect", + ) ) - ) - assert_reply(reply) + assert_reply(reply) self._is_connected = True diff --git a/bleak/backends/bluezdbus/manager.py b/bleak/backends/bluezdbus/manager.py index 6569c129..bac215fe 100644 --- a/bleak/backends/bluezdbus/manager.py +++ b/bleak/backends/bluezdbus/manager.py @@ -597,6 +597,21 @@ def get_device_name(self, device_path: str) -> str: """ return self._properties[device_path][defs.DEVICE_INTERFACE]["Name"] + def is_connected(self, device_path: str) -> bool: + """ + Gets the value of the "Connected" property for a device. + + Args: + device_path: The D-Bus object path of the device. + + Returns: + The current property value. + """ + try: + return self._properties[device_path][defs.DEVICE_INTERFACE]["Connected"] + except KeyError: + return False + async def _wait_condition( self, device_path: str, property_name: str, property_value: Any ) -> None: