Fallback logic that uses DBus to disconnect from a BT device.

This logic will be used if the connection wasn't opened by the current
process and therefore a call to DBus is required to terminate it.
This commit is contained in:
Fabio Manganiello 2023-03-24 01:57:05 +01:00
parent 913ef6f8cd
commit 2f49ddf33a
Signed by untrusted user: blacklight
GPG key ID: D90FBA7F76362774
4 changed files with 37 additions and 1 deletions

View file

@ -227,6 +227,35 @@ class BLEManager(BaseBluetoothManager):
'Error while disconnecting from %s: %s', conn.device.address, e 'Error while disconnecting from %s: %s', conn.device.address, e
) )
def _dbus_disconnect(self, device: BLEDevice):
"""
Disconnect from a device using the DBus API (only available on Linux).
This may be required if there is an active connection to the device that is not owned by the
"""
entity = self._cache.get(device.address)
assert entity, f'Unknown device: "{device.address}"'
path = device.details.get('path')
assert path, f'The device "{device.address}" has no reported system path'
assert path.startswith('/org/bluez/'), (
f'The device "{device.address}" is not a BlueZ device. Programmatic '
'system disconnection is only supported on Linux'
)
try:
import pydbus
bus = pydbus.SystemBus()
dbus_device = bus.get('org.bluez', path)
dbus_device.Disconnect()
except Exception as e:
raise AssertionError(
f'Could not disconnect from {device.address}: {e}'
) from e
if entity.connected:
entity.connected = False
self.notify(BluetoothDeviceDisconnectedEvent, entity)
@override @override
def connect( def connect(
self, self,
@ -279,7 +308,11 @@ class BLEManager(BaseBluetoothManager):
# Check if there are any active connections # Check if there are any active connections
connection = self._connections.get(dev.address, None) connection = self._connections.get(dev.address, None)
assert connection, f'No active connections to the device {device} were found' if not connection:
# If there are no active connections in this process, try to
# disconnect through the DBus API
self._dbus_disconnect(dev)
return
# Set the close event and wait for any connection thread to terminate # Set the close event and wait for any connection thread to terminate
if connection.close_event: if connection.close_event:

View file

@ -57,6 +57,7 @@ class BluetoothPlugin(RunnablePlugin, EnumSwitchEntityManager):
* **bleak** (``pip install bleak``) * **bleak** (``pip install bleak``)
* **bluetooth-numbers** (``pip install bluetooth-numbers``) * **bluetooth-numbers** (``pip install bluetooth-numbers``)
* **TheengsDecoder** (``pip install TheengsDecoder``) * **TheengsDecoder** (``pip install TheengsDecoder``)
* **pydbus** (``pip install pydbus``)
* **pybluez** (``pip install git+https://github.com/pybluez/pybluez``) * **pybluez** (``pip install git+https://github.com/pybluez/pybluez``)
* **PyOBEX** (``pip install git+https://github.com/BlackLight/PyOBEX``) * **PyOBEX** (``pip install git+https://github.com/BlackLight/PyOBEX``)

View file

@ -17,6 +17,7 @@ manifest:
- bleak - bleak
- bluetooth-numbers - bluetooth-numbers
- TheengsDecoder - TheengsDecoder
- pydbus
- git+https://github.com/pybluez/pybluez - git+https://github.com/pybluez/pybluez
- git+https://github.com/BlackLight/PyOBEX - git+https://github.com/BlackLight/PyOBEX
package: platypush.plugins.bluetooth package: platypush.plugins.bluetooth

View file

@ -178,6 +178,7 @@ setup(
'bleak', 'bleak',
'bluetooth-numbers', 'bluetooth-numbers',
'TheengsDecoder', 'TheengsDecoder',
'pydbus',
'pybluez @ https://github.com/pybluez/pybluez/tarball/master', 'pybluez @ https://github.com/pybluez/pybluez/tarball/master',
'PyOBEX @ https://github.com/BlackLight/PyOBEX/tarball/master', 'PyOBEX @ https://github.com/BlackLight/PyOBEX/tarball/master',
], ],