|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
|
|
|
import binascii
|
|
import binascii
|
|
import logging
|
|
import logging
|
|
-import threading
|
|
+from multiprocessing import Manager, Process
|
|
import time
|
|
import time
|
|
|
|
|
|
import bluepy
|
|
import bluepy
|
|
@@ -31,7 +31,6 @@ OFF_KEY_SUFFIX = "02"
|
|
PRESS_KEY_SUFFIX = "00"
|
|
PRESS_KEY_SUFFIX = "00"
|
|
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
_LOGGER = logging.getLogger(__name__)
|
|
-CONNECT_LOCK = threading.Lock()
|
|
|
|
|
|
|
|
|
|
|
|
def _process_wohand(data) -> dict:
|
|
def _process_wohand(data) -> dict:
|
|
@@ -93,6 +92,34 @@ def _process_wosensorth(data) -> dict:
|
|
return _wosensorth_data
|
|
return _wosensorth_data
|
|
|
|
|
|
|
|
|
|
|
|
+class BLEScanner:
|
|
|
|
+ """Helper for bluepy device scanning."""
|
|
|
|
+
|
|
|
|
+ def __init__(self, scan_timeout=DEFAULT_SCAN_TIMEOUT, interface=None) -> None:
|
|
|
|
+ """Init class constructor."""
|
|
|
|
+ self._scan_timeout = scan_timeout
|
|
|
|
+ self._interface = interface
|
|
|
|
+ self._devices = None
|
|
|
|
+
|
|
|
|
+ def start(self) -> dict | None:
|
|
|
|
+ """Start scan in seperate process."""
|
|
|
|
+ with Manager() as manager:
|
|
|
|
+ _devices = manager.dict()
|
|
|
|
+ process = Process(target=self._scan, args=(_devices,))
|
|
|
|
+ process.start()
|
|
|
|
+ process.join()
|
|
|
|
+
|
|
|
|
+ return _devices.get(0, None)
|
|
|
|
+
|
|
|
|
+ def _scan(self, devices) -> dict | None:
|
|
|
|
+ """Scan for advertisement data."""
|
|
|
|
+ try:
|
|
|
|
+ devices[0] = bluepy.btle.Scanner(self._interface).scan(self._scan_timeout)
|
|
|
|
+
|
|
|
|
+ except bluepy.btle.BTLEDisconnectError:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+
|
|
class GetSwitchbotDevices:
|
|
class GetSwitchbotDevices:
|
|
"""Scan for all Switchbot devices and return by type."""
|
|
"""Scan for all Switchbot devices and return by type."""
|
|
|
|
|
|
@@ -109,7 +136,9 @@ class GetSwitchbotDevices:
|
|
devices = None
|
|
devices = None
|
|
|
|
|
|
try:
|
|
try:
|
|
- devices = bluepy.btle.Scanner(self._interface).scan(scan_timeout)
|
|
+ devices = BLEScanner(
|
|
|
|
+ scan_timeout=scan_timeout, interface=self._interface
|
|
|
|
+ ).start()
|
|
|
|
|
|
except bluepy.btle.BTLEManagementError:
|
|
except bluepy.btle.BTLEManagementError:
|
|
_LOGGER.error("Error scanning for switchbot devices", exc_info=True)
|
|
_LOGGER.error("Error scanning for switchbot devices", exc_info=True)
|
|
@@ -199,7 +228,7 @@ class GetSwitchbotDevices:
|
|
_switchbot_data = {}
|
|
_switchbot_data = {}
|
|
|
|
|
|
for item in self._all_services_data:
|
|
for item in self._all_services_data:
|
|
- if self._all_services_data[item]["mac_address"] == mac:
|
|
+ if self._all_services_data[item]["mac_address"] == mac.replace("-", ":").lower():
|
|
_switchbot_data = self._all_services_data[item]
|
|
_switchbot_data = self._all_services_data[item]
|
|
|
|
|
|
return _switchbot_data
|
|
return _switchbot_data
|
|
@@ -211,7 +240,7 @@ class SwitchbotDevice:
|
|
def __init__(self, mac, password=None, interface=None, **kwargs) -> None:
|
|
def __init__(self, mac, password=None, interface=None, **kwargs) -> None:
|
|
"""Switchbot base class constructor."""
|
|
"""Switchbot base class constructor."""
|
|
self._interface = interface
|
|
self._interface = interface
|
|
- self._mac = mac
|
|
+ self._mac = mac.replace("-", ":").lower()
|
|
self._device = None
|
|
self._device = None
|
|
self._switchbot_device_data = {}
|
|
self._switchbot_device_data = {}
|
|
self._scan_timeout = kwargs.pop("scan_timeout", DEFAULT_SCAN_TIMEOUT)
|
|
self._scan_timeout = kwargs.pop("scan_timeout", DEFAULT_SCAN_TIMEOUT)
|
|
@@ -277,14 +306,13 @@ class SwitchbotDevice:
|
|
send_success = False
|
|
send_success = False
|
|
command = self._commandkey(key)
|
|
command = self._commandkey(key)
|
|
_LOGGER.debug("Sending command to switchbot %s", command)
|
|
_LOGGER.debug("Sending command to switchbot %s", command)
|
|
- with CONNECT_LOCK:
|
|
+ try:
|
|
- try:
|
|
+ self._connect()
|
|
- self._connect()
|
|
+ send_success = self._writekey(command)
|
|
- send_success = self._writekey(command)
|
|
+ except bluepy.btle.BTLEException:
|
|
- except bluepy.btle.BTLEException:
|
|
+ _LOGGER.warning("Error talking to Switchbot", exc_info=True)
|
|
- _LOGGER.warning("Error talking to Switchbot", exc_info=True)
|
|
+ finally:
|
|
- finally:
|
|
+ self._disconnect()
|
|
- self._disconnect()
|
|
|
|
if send_success:
|
|
if send_success:
|
|
return True
|
|
return True
|
|
if retry < 1:
|
|
if retry < 1:
|
|
@@ -316,7 +344,9 @@ class SwitchbotDevice:
|
|
devices = None
|
|
devices = None
|
|
|
|
|
|
try:
|
|
try:
|
|
- devices = bluepy.btle.Scanner(_interface).scan(self._scan_timeout)
|
|
+ devices = BLEScanner(
|
|
|
|
+ scan_timeout=self._scan_timeout, interface=_interface
|
|
|
|
+ ).start()
|
|
|
|
|
|
except bluepy.btle.BTLEManagementError:
|
|
except bluepy.btle.BTLEManagementError:
|
|
_LOGGER.error("Error scanning for switchbot devices", exc_info=True)
|
|
_LOGGER.error("Error scanning for switchbot devices", exc_info=True)
|