|
@@ -10,7 +10,11 @@ from bleak.backends.device import BLEDevice
|
|
|
|
|
|
|
|
from ..const import SwitchbotModel
|
|
from ..const import SwitchbotModel
|
|
|
from ..const.lock import LockStatus
|
|
from ..const.lock import LockStatus
|
|
|
-from .device import SwitchbotEncryptedDevice, SwitchbotSequenceDevice
|
|
|
|
|
|
|
+from .device import (
|
|
|
|
|
+ SwitchbotEncryptedDevice,
|
|
|
|
|
+ SwitchbotOperationError,
|
|
|
|
|
+ SwitchbotSequenceDevice,
|
|
|
|
|
+)
|
|
|
|
|
|
|
|
COMMAND_HEADER = "57"
|
|
COMMAND_HEADER = "57"
|
|
|
COMMAND_LOCK_INFO = {
|
|
COMMAND_LOCK_INFO = {
|
|
@@ -49,6 +53,10 @@ COMMAND_LOCK = {
|
|
|
SwitchbotModel.LOCK_VISION: f"{COMMAND_HEADER}0f4e0101000000",
|
|
SwitchbotModel.LOCK_VISION: f"{COMMAND_HEADER}0f4e0101000000",
|
|
|
SwitchbotModel.LOCK_PRO_WIFI: f"{COMMAND_HEADER}0f4e0101000000",
|
|
SwitchbotModel.LOCK_PRO_WIFI: f"{COMMAND_HEADER}0f4e0101000000",
|
|
|
}
|
|
}
|
|
|
|
|
+COMMAND_HALF_LOCK = {
|
|
|
|
|
+ SwitchbotModel.LOCK_ULTRA: f"{COMMAND_HEADER}0f4e0101000008",
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
COMMAND_ENABLE_NOTIFICATIONS = {
|
|
COMMAND_ENABLE_NOTIFICATIONS = {
|
|
|
SwitchbotModel.LOCK: f"{COMMAND_HEADER}0e01001e00008101",
|
|
SwitchbotModel.LOCK: f"{COMMAND_HEADER}0e01001e00008101",
|
|
|
SwitchbotModel.LOCK_LITE: f"{COMMAND_HEADER}0e01001e00008101",
|
|
SwitchbotModel.LOCK_LITE: f"{COMMAND_HEADER}0e01001e00008101",
|
|
@@ -129,6 +137,19 @@ class SwitchbotLock(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
|
|
|
{LockStatus.UNLOCKED, LockStatus.UNLOCKING, LockStatus.NOT_FULLY_LOCKED},
|
|
{LockStatus.UNLOCKED, LockStatus.UNLOCKING, LockStatus.NOT_FULLY_LOCKED},
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
|
|
+ async def half_lock(self) -> bool:
|
|
|
|
|
+ """Send half lock command (Lock Ultra EU type only)."""
|
|
|
|
|
+ if self._model not in COMMAND_HALF_LOCK:
|
|
|
|
|
+ raise SwitchbotOperationError(
|
|
|
|
|
+ f"Half lock is not supported on {self._model}"
|
|
|
|
|
+ )
|
|
|
|
|
+ if not self.is_half_lock_calibrated():
|
|
|
|
|
+ raise SwitchbotOperationError("Half lock is not calibrated")
|
|
|
|
|
+ return await self._lock_unlock(
|
|
|
|
|
+ COMMAND_HALF_LOCK[self._model],
|
|
|
|
|
+ {LockStatus.HALF_LOCKED, LockStatus.LOCKING},
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
def _parse_basic_data(self, basic_data: bytes) -> dict[str, Any]:
|
|
def _parse_basic_data(self, basic_data: bytes) -> dict[str, Any]:
|
|
|
"""Parse basic data from lock."""
|
|
"""Parse basic data from lock."""
|
|
|
return {
|
|
return {
|
|
@@ -207,6 +228,10 @@ class SwitchbotLock(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
|
|
|
"""Return True if Night Latch is enabled on EU firmware."""
|
|
"""Return True if Night Latch is enabled on EU firmware."""
|
|
|
return self._get_adv_value("night_latch")
|
|
return self._get_adv_value("night_latch")
|
|
|
|
|
|
|
|
|
|
+ def is_half_lock_calibrated(self) -> bool | None:
|
|
|
|
|
+ """Return True if half lock position is calibrated (Lock Ultra only)."""
|
|
|
|
|
+ return self._get_adv_value("half_lock_calibration")
|
|
|
|
|
+
|
|
|
async def _get_lock_info(self) -> bytes | None:
|
|
async def _get_lock_info(self) -> bytes | None:
|
|
|
"""Return lock info of device."""
|
|
"""Return lock info of device."""
|
|
|
_data = await self._send_command(
|
|
_data = await self._send_command(
|
|
@@ -268,10 +293,13 @@ class SwitchbotLock(SwitchbotSequenceDevice, SwitchbotEncryptedDevice):
|
|
|
"status": LockStatus((data[0] & 0b01110000) >> 4),
|
|
"status": LockStatus((data[0] & 0b01110000) >> 4),
|
|
|
"unlocked_alarm": bool(data[1] & 0b00010000),
|
|
"unlocked_alarm": bool(data[1] & 0b00010000),
|
|
|
}
|
|
}
|
|
|
- return {
|
|
|
|
|
|
|
+ result = {
|
|
|
"calibration": bool(data[0] & 0b10000000),
|
|
"calibration": bool(data[0] & 0b10000000),
|
|
|
"status": LockStatus((data[0] & 0b01111000) >> 3),
|
|
"status": LockStatus((data[0] & 0b01111000) >> 3),
|
|
|
"door_open": bool(data[1] & 0b00010000),
|
|
"door_open": bool(data[1] & 0b00010000),
|
|
|
"unclosed_alarm": bool(data[5] & 0b10000000),
|
|
"unclosed_alarm": bool(data[5] & 0b10000000),
|
|
|
"unlocked_alarm": bool(data[5] & 0b01000000),
|
|
"unlocked_alarm": bool(data[5] & 0b01000000),
|
|
|
}
|
|
}
|
|
|
|
|
+ if model is SwitchbotModel.LOCK_ULTRA:
|
|
|
|
|
+ result["half_lock_calibration"] = bool(data[1] & 0b00000001)
|
|
|
|
|
+ return result
|