forked from platypush/platypush
- Added support for scan_pause
/scan_resume
on bluetooth
integration.
- Added `BluetoothDevice` as its own entity type.
This commit is contained in:
parent
1d0be5c929
commit
a3aa186ddf
7 changed files with 171 additions and 40 deletions
|
@ -0,0 +1 @@
|
||||||
|
Device.vue
|
|
@ -31,6 +31,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"bluetooth_device": {
|
||||||
|
"name": "Device",
|
||||||
|
"name_plural": "Devices",
|
||||||
|
"icon": {
|
||||||
|
"class": "fab fa-bluetooth-b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
"device": {
|
"device": {
|
||||||
"name": "Device",
|
"name": "Device",
|
||||||
"name_plural": "Devices",
|
"name_plural": "Devices",
|
||||||
|
|
24
platypush/entities/bluetooth.py
Normal file
24
platypush/entities/bluetooth.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
from sqlalchemy import Column, Integer, Boolean, ForeignKey
|
||||||
|
|
||||||
|
from platypush.common.db import Base
|
||||||
|
|
||||||
|
from .devices import Device
|
||||||
|
|
||||||
|
|
||||||
|
if 'bluetooth_device' not in Base.metadata:
|
||||||
|
|
||||||
|
class BluetoothDevice(Device):
|
||||||
|
"""
|
||||||
|
Entity that represents a Bluetooth device.
|
||||||
|
"""
|
||||||
|
|
||||||
|
__tablename__ = 'bluetooth_device'
|
||||||
|
|
||||||
|
id = Column(
|
||||||
|
Integer, ForeignKey(Device.id, ondelete='CASCADE'), primary_key=True
|
||||||
|
)
|
||||||
|
connected = Column(Boolean, default=False)
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'polymorphic_identity': __tablename__,
|
||||||
|
}
|
|
@ -5,7 +5,31 @@ from platypush.message.event import Event
|
||||||
|
|
||||||
class BluetoothEvent(Event):
|
class BluetoothEvent(Event):
|
||||||
"""
|
"""
|
||||||
Base class for Bluetooth Low-Energy device events.
|
Base class for Bluetooth events.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
class BluetoothScanPausedEvent(BluetoothEvent):
|
||||||
|
"""
|
||||||
|
Event triggered when the Bluetooth scan is paused.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, duration: Optional[float] = None, **kwargs):
|
||||||
|
super().__init__(*args, duration=duration, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class BluetoothScanResumedEvent(BluetoothEvent):
|
||||||
|
"""
|
||||||
|
Event triggered when the Bluetooth scan is resumed.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, duration: Optional[float] = None, **kwargs):
|
||||||
|
super().__init__(*args, duration=duration, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
class BluetoothDeviceEvent(BluetoothEvent):
|
||||||
|
"""
|
||||||
|
Base class for Bluetooth device events.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
@ -17,7 +41,7 @@ class BluetoothEvent(Event):
|
||||||
trusted: bool,
|
trusted: bool,
|
||||||
blocked: bool,
|
blocked: bool,
|
||||||
name: Optional[str] = None,
|
name: Optional[str] = None,
|
||||||
service_uuids: Optional[Collection[str]] = None,
|
characteristics: Optional[Collection[str]] = None,
|
||||||
**kwargs
|
**kwargs
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -27,7 +51,8 @@ class BluetoothEvent(Event):
|
||||||
:param trusted: Whether the device is trusted.
|
:param trusted: Whether the device is trusted.
|
||||||
:param blocked: Whether the device is blocked.
|
:param blocked: Whether the device is blocked.
|
||||||
:param name: The name of the device.
|
:param name: The name of the device.
|
||||||
:param service_uuids: The service UUIDs of the device.
|
:param characteristics: The UUIDs of the characteristics exposed by the
|
||||||
|
device.
|
||||||
"""
|
"""
|
||||||
super().__init__(
|
super().__init__(
|
||||||
*args,
|
*args,
|
||||||
|
@ -37,66 +62,66 @@ class BluetoothEvent(Event):
|
||||||
paired=paired,
|
paired=paired,
|
||||||
blocked=blocked,
|
blocked=blocked,
|
||||||
trusted=trusted,
|
trusted=trusted,
|
||||||
service_uuids=service_uuids or [],
|
characteristics=characteristics or [],
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceFoundEvent(BluetoothEvent):
|
class BluetoothDeviceFoundEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is discovered during a scan.
|
Event triggered when a Bluetooth device is discovered during a scan.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceLostEvent(BluetoothEvent):
|
class BluetoothDeviceLostEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a previously discovered Bluetooth device is lost.
|
Event triggered when a previously discovered Bluetooth device is lost.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceConnectedEvent(BluetoothEvent):
|
class BluetoothDeviceConnectedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is connected.
|
Event triggered when a Bluetooth device is connected.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceDisconnectedEvent(BluetoothEvent):
|
class BluetoothDeviceDisconnectedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is disconnected.
|
Event triggered when a Bluetooth device is disconnected.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDevicePairedEvent(BluetoothEvent):
|
class BluetoothDevicePairedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is paired.
|
Event triggered when a Bluetooth device is paired.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceUnpairedEvent(BluetoothEvent):
|
class BluetoothDeviceUnpairedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is unpaired.
|
Event triggered when a Bluetooth device is unpaired.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceBlockedEvent(BluetoothEvent):
|
class BluetoothDeviceBlockedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is blocked.
|
Event triggered when a Bluetooth device is blocked.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceUnblockedEvent(BluetoothEvent):
|
class BluetoothDeviceUnblockedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is unblocked.
|
Event triggered when a Bluetooth device is unblocked.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceTrustedEvent(BluetoothEvent):
|
class BluetoothDeviceTrustedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is trusted.
|
Event triggered when a Bluetooth device is trusted.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
class BluetoothDeviceUntrustedEvent(BluetoothEvent):
|
class BluetoothDeviceUntrustedEvent(BluetoothDeviceEvent):
|
||||||
"""
|
"""
|
||||||
Event triggered when a Bluetooth device is untrusted.
|
Event triggered when a Bluetooth device is untrusted.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -167,7 +167,7 @@ class AsyncRunnablePlugin(RunnablePlugin, ABC):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
self._loop: Optional[asyncio.AbstractEventLoop] = None
|
self._loop: Optional[asyncio.AbstractEventLoop] = asyncio.new_event_loop()
|
||||||
self._task: Optional[asyncio.Task] = None
|
self._task: Optional[asyncio.Task] = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -204,7 +204,6 @@ class AsyncRunnablePlugin(RunnablePlugin, ABC):
|
||||||
"""
|
"""
|
||||||
Initialize an event loop and run the listener as a task.
|
Initialize an event loop and run the listener as a task.
|
||||||
"""
|
"""
|
||||||
self._loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(self._loop)
|
asyncio.set_event_loop(self._loop)
|
||||||
|
|
||||||
self._task = self._loop.create_task(self._listen())
|
self._task = self._loop.create_task(self._listen())
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import base64
|
import base64
|
||||||
|
from asyncio import Event, ensure_future
|
||||||
from contextlib import asynccontextmanager
|
from contextlib import asynccontextmanager
|
||||||
from threading import RLock
|
from threading import RLock, Timer
|
||||||
from typing import AsyncGenerator, Collection, List, Optional, Dict, Type, Union
|
from typing import AsyncGenerator, Collection, List, Optional, Dict, Type, Union
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
|
@ -10,7 +11,7 @@ from typing_extensions import override
|
||||||
|
|
||||||
from platypush.context import get_bus, get_or_create_event_loop
|
from platypush.context import get_bus, get_or_create_event_loop
|
||||||
from platypush.entities import Entity, EntityManager
|
from platypush.entities import Entity, EntityManager
|
||||||
from platypush.entities.devices import Device
|
from platypush.entities.bluetooth import BluetoothDevice
|
||||||
from platypush.message.event.bluetooth.ble import (
|
from platypush.message.event.bluetooth.ble import (
|
||||||
BluetoothDeviceBlockedEvent,
|
BluetoothDeviceBlockedEvent,
|
||||||
BluetoothDeviceConnectedEvent,
|
BluetoothDeviceConnectedEvent,
|
||||||
|
@ -22,7 +23,9 @@ from platypush.message.event.bluetooth.ble import (
|
||||||
BluetoothDeviceUnblockedEvent,
|
BluetoothDeviceUnblockedEvent,
|
||||||
BluetoothDeviceUnpairedEvent,
|
BluetoothDeviceUnpairedEvent,
|
||||||
BluetoothDeviceUntrustedEvent,
|
BluetoothDeviceUntrustedEvent,
|
||||||
BluetoothEvent,
|
BluetoothDeviceEvent,
|
||||||
|
BluetoothScanPausedEvent,
|
||||||
|
BluetoothScanResumedEvent,
|
||||||
)
|
)
|
||||||
from platypush.plugins import AsyncRunnablePlugin, action
|
from platypush.plugins import AsyncRunnablePlugin, action
|
||||||
|
|
||||||
|
@ -52,7 +55,8 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
interface: Optional[str] = None,
|
interface: Optional[str] = None,
|
||||||
connect_timeout: float = _default_connect_timeout,
|
connect_timeout: float = _default_connect_timeout,
|
||||||
device_names: Optional[Dict[str, str]] = None,
|
device_names: Optional[Dict[str, str]] = None,
|
||||||
service_uuids: Optional[Collection[UUIDType]] = None,
|
characteristics: Optional[Collection[UUIDType]] = None,
|
||||||
|
scan_paused_on_start: bool = False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -60,7 +64,8 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
on Linux). Default: first available interface.
|
on Linux). Default: first available interface.
|
||||||
:param connect_timeout: Timeout in seconds for the connection to a
|
:param connect_timeout: Timeout in seconds for the connection to a
|
||||||
Bluetooth device. Default: 5 seconds.
|
Bluetooth device. Default: 5 seconds.
|
||||||
:param service_uuids: List of service UUIDs to discover. Default: all.
|
:param characteristics: List of service/characteristic UUIDs to
|
||||||
|
discover. Default: all.
|
||||||
:param device_names: Bluetooth address -> device name mapping. If not
|
:param device_names: Bluetooth address -> device name mapping. If not
|
||||||
specified, the device's advertised name will be used, or its
|
specified, the device's advertised name will be used, or its
|
||||||
Bluetooth address. Example:
|
Bluetooth address. Example:
|
||||||
|
@ -73,13 +78,19 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
"00:11:22:33:44:57": "Button"
|
"00:11:22:33:44:57": "Button"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:param scan_paused_on_start: If ``True``, the plugin will not the
|
||||||
|
scanning thread until :meth:`.scan_resume` is called (default:
|
||||||
|
``False``).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
self._interface = interface
|
self._interface = interface
|
||||||
self._connect_timeout = connect_timeout
|
self._connect_timeout = connect_timeout
|
||||||
self._service_uuids = service_uuids
|
self._characteristics = characteristics
|
||||||
self._scan_lock = RLock()
|
self._scan_lock = RLock()
|
||||||
|
self._scan_enabled = Event()
|
||||||
|
self._scan_controller_timer: Optional[Timer] = None
|
||||||
self._connections: Dict[str, BleakClient] = {}
|
self._connections: Dict[str, BleakClient] = {}
|
||||||
self._devices: Dict[str, BLEDevice] = {}
|
self._devices: Dict[str, BLEDevice] = {}
|
||||||
self._device_name_by_addr = device_names or {}
|
self._device_name_by_addr = device_names or {}
|
||||||
|
@ -87,6 +98,9 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
name: addr for addr, name in self._device_name_by_addr.items()
|
name: addr for addr, name in self._device_name_by_addr.items()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if not scan_paused_on_start:
|
||||||
|
self._scan_enabled.set()
|
||||||
|
|
||||||
async def _get_device(self, device: str) -> BLEDevice:
|
async def _get_device(self, device: str) -> BLEDevice:
|
||||||
"""
|
"""
|
||||||
Utility method to get a device by name or address.
|
Utility method to get a device by name or address.
|
||||||
|
@ -113,7 +127,7 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
)
|
)
|
||||||
|
|
||||||
def _post_event(
|
def _post_event(
|
||||||
self, event_type: Type[BluetoothEvent], device: BLEDevice, **kwargs
|
self, event_type: Type[BluetoothDeviceEvent], device: BLEDevice, **kwargs
|
||||||
):
|
):
|
||||||
props = device.details.get('props', {})
|
props = device.details.get('props', {})
|
||||||
get_bus().post(
|
get_bus().post(
|
||||||
|
@ -124,13 +138,13 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
paired=props.get('Paired', False),
|
paired=props.get('Paired', False),
|
||||||
blocked=props.get('Blocked', False),
|
blocked=props.get('Blocked', False),
|
||||||
trusted=props.get('Trusted', False),
|
trusted=props.get('Trusted', False),
|
||||||
service_uuids=device.metadata.get('uuids', []),
|
characteristics=device.metadata.get('uuids', []),
|
||||||
**kwargs,
|
**kwargs,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def _on_device_event(self, device: BLEDevice, _):
|
def _on_device_event(self, device: BLEDevice, _):
|
||||||
event_types: List[Type[BluetoothEvent]] = []
|
event_types: List[Type[BluetoothDeviceEvent]] = []
|
||||||
existing_device = self._devices.get(device.address)
|
existing_device = self._devices.get(device.address)
|
||||||
|
|
||||||
if existing_device:
|
if existing_device:
|
||||||
|
@ -168,6 +182,9 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
event_types.append(BluetoothDeviceFoundEvent)
|
event_types.append(BluetoothDeviceFoundEvent)
|
||||||
|
|
||||||
self._devices[device.address] = device
|
self._devices[device.address] = device
|
||||||
|
if device.name:
|
||||||
|
self._device_name_by_addr[device.address] = device.name
|
||||||
|
self._device_addr_by_name[device.name] = device.address
|
||||||
|
|
||||||
if event_types:
|
if event_types:
|
||||||
for event_type in event_types:
|
for event_type in event_types:
|
||||||
|
@ -217,7 +234,7 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
async def _scan(
|
async def _scan(
|
||||||
self,
|
self,
|
||||||
duration: Optional[float] = None,
|
duration: Optional[float] = None,
|
||||||
service_uuids: Optional[Collection[UUIDType]] = None,
|
characteristics: Optional[Collection[UUIDType]] = None,
|
||||||
publish_entities: bool = False,
|
publish_entities: bool = False,
|
||||||
) -> Collection[Entity]:
|
) -> Collection[Entity]:
|
||||||
with self._scan_lock:
|
with self._scan_lock:
|
||||||
|
@ -226,7 +243,7 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
adapter=self._interface,
|
adapter=self._interface,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
service_uuids=list(
|
service_uuids=list(
|
||||||
map(str, service_uuids or self._service_uuids or [])
|
map(str, characteristics or self._characteristics or [])
|
||||||
),
|
),
|
||||||
detection_callback=self._on_device_event,
|
detection_callback=self._on_device_event,
|
||||||
)
|
)
|
||||||
|
@ -234,29 +251,75 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
# TODO Infer type from device.metadata['manufacturer_data']
|
# TODO Infer type from device.metadata['manufacturer_data']
|
||||||
|
|
||||||
self._devices.update({dev.address: dev for dev in devices})
|
self._devices.update({dev.address: dev for dev in devices})
|
||||||
if publish_entities:
|
return (
|
||||||
entities = self.publish_entities(devices)
|
self.publish_entities(devices)
|
||||||
else:
|
if publish_entities
|
||||||
entities = self.transform_entities(devices)
|
else self.transform_entities(devices)
|
||||||
|
)
|
||||||
|
|
||||||
return entities
|
async def _scan_state_set(self, state: bool, duration: Optional[float] = None):
|
||||||
|
def timer_callback():
|
||||||
|
if state:
|
||||||
|
self.scan_pause()
|
||||||
|
else:
|
||||||
|
self.scan_resume()
|
||||||
|
|
||||||
|
self._scan_controller_timer = None
|
||||||
|
|
||||||
|
with self._scan_lock:
|
||||||
|
if not state and self._scan_enabled.is_set():
|
||||||
|
get_bus().post(BluetoothScanPausedEvent(duration=duration))
|
||||||
|
elif state and not self._scan_enabled.is_set():
|
||||||
|
get_bus().post(BluetoothScanResumedEvent(duration=duration))
|
||||||
|
|
||||||
|
if state:
|
||||||
|
self._scan_enabled.set()
|
||||||
|
else:
|
||||||
|
self._scan_enabled.clear()
|
||||||
|
|
||||||
|
if duration and not self._scan_controller_timer:
|
||||||
|
self._scan_controller_timer = Timer(duration, timer_callback)
|
||||||
|
self._scan_controller_timer.start()
|
||||||
|
|
||||||
|
@action
|
||||||
|
def scan_pause(self, duration: Optional[float] = None):
|
||||||
|
"""
|
||||||
|
Pause the scanning thread.
|
||||||
|
|
||||||
|
:param duration: For how long the scanning thread should be paused
|
||||||
|
(default: null = indefinitely).
|
||||||
|
"""
|
||||||
|
if self._loop:
|
||||||
|
ensure_future(self._scan_state_set(False, duration), loop=self._loop)
|
||||||
|
|
||||||
|
@action
|
||||||
|
def scan_resume(self, duration: Optional[float] = None):
|
||||||
|
"""
|
||||||
|
Resume the scanning thread, if inactive.
|
||||||
|
|
||||||
|
:param duration: For how long the scanning thread should be running
|
||||||
|
(default: null = indefinitely).
|
||||||
|
"""
|
||||||
|
if self._loop:
|
||||||
|
ensure_future(self._scan_state_set(True, duration), loop=self._loop)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
def scan(
|
def scan(
|
||||||
self,
|
self,
|
||||||
duration: Optional[float] = None,
|
duration: Optional[float] = None,
|
||||||
service_uuids: Optional[Collection[UUIDType]] = None,
|
characteristics: Optional[Collection[UUIDType]] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Scan for Bluetooth devices nearby.
|
Scan for Bluetooth devices nearby and return the results as a list of
|
||||||
|
entities.
|
||||||
|
|
||||||
:param duration: Scan duration in seconds (default: same as the plugin's
|
:param duration: Scan duration in seconds (default: same as the plugin's
|
||||||
`poll_interval` configuration parameter)
|
`poll_interval` configuration parameter)
|
||||||
:param service_uuids: List of service UUIDs to discover. Default: all.
|
:param characteristics: List of characteristic UUIDs to discover. Default: all.
|
||||||
"""
|
"""
|
||||||
loop = get_or_create_event_loop()
|
loop = get_or_create_event_loop()
|
||||||
loop.run_until_complete(
|
return loop.run_until_complete(
|
||||||
self._scan(duration, service_uuids, publish_entities=True)
|
self._scan(duration, characteristics, publish_entities=True)
|
||||||
)
|
)
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -319,9 +382,11 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
return self.scan().output
|
return self.scan().output
|
||||||
|
|
||||||
@override
|
@override
|
||||||
def transform_entities(self, entities: Collection[BLEDevice]) -> Collection[Device]:
|
def transform_entities(
|
||||||
|
self, entities: Collection[BLEDevice]
|
||||||
|
) -> Collection[BluetoothDevice]:
|
||||||
return [
|
return [
|
||||||
Device(
|
BluetoothDevice(
|
||||||
id=dev.address,
|
id=dev.address,
|
||||||
name=self._get_device_name(dev),
|
name=self._get_device_name(dev),
|
||||||
)
|
)
|
||||||
|
@ -333,7 +398,9 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
device_addresses = set()
|
device_addresses = set()
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
|
await self._scan_enabled.wait()
|
||||||
entities = await self._scan()
|
entities = await self._scan()
|
||||||
|
|
||||||
new_device_addresses = {e.id for e in entities}
|
new_device_addresses = {e.id for e in entities}
|
||||||
missing_device_addresses = device_addresses - new_device_addresses
|
missing_device_addresses = device_addresses - new_device_addresses
|
||||||
missing_devices = [
|
missing_devices = [
|
||||||
|
@ -348,5 +415,12 @@ class BluetoothBlePlugin(AsyncRunnablePlugin, EntityManager):
|
||||||
|
|
||||||
device_addresses = new_device_addresses
|
device_addresses = new_device_addresses
|
||||||
|
|
||||||
|
@override
|
||||||
|
def stop(self):
|
||||||
|
if self._scan_controller_timer:
|
||||||
|
self._scan_controller_timer.cancel()
|
||||||
|
|
||||||
|
super().stop()
|
||||||
|
|
||||||
|
|
||||||
# vim:sw=4:ts=4:et:
|
# vim:sw=4:ts=4:et:
|
||||||
|
|
|
@ -54,7 +54,7 @@ class SwitchbotBluetoothPlugin(BluetoothBlePlugin, EnumSwitchEntityManager):
|
||||||
}
|
}
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super().__init__(*args, service_uuids=self._uuids.values(), **kwargs)
|
super().__init__(*args, characteristics=self._uuids.values(), **kwargs)
|
||||||
|
|
||||||
async def _run(
|
async def _run(
|
||||||
self,
|
self,
|
||||||
|
|
Loading…
Reference in a new issue