|
@@ -1,3 +1,5 @@
|
|
|
|
+import asyncio
|
|
|
|
+import logging
|
|
import time
|
|
import time
|
|
from typing import Any
|
|
from typing import Any
|
|
|
|
|
|
@@ -5,7 +7,10 @@ from bleak.backends.device import BLEDevice
|
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
|
|
|
|
|
from ..const import SwitchbotModel
|
|
from ..const import SwitchbotModel
|
|
-from .device import SwitchbotSequenceDevice
|
|
|
|
|
|
+from ..models import SwitchBotAdvertisement
|
|
|
|
+from .device import SwitchbotDevice
|
|
|
|
+
|
|
|
|
+_LOGGER = logging.getLogger(__name__)
|
|
|
|
|
|
COMMAND_HEADER = "57"
|
|
COMMAND_HEADER = "57"
|
|
COMMAND_GET_CK_IV = f"{COMMAND_HEADER}0f2103"
|
|
COMMAND_GET_CK_IV = f"{COMMAND_HEADER}0f2103"
|
|
@@ -13,10 +18,10 @@ COMMAND_TURN_OFF = f"{COMMAND_HEADER}0f70010000"
|
|
COMMAND_TURN_ON = f"{COMMAND_HEADER}0f70010100"
|
|
COMMAND_TURN_ON = f"{COMMAND_HEADER}0f70010100"
|
|
COMMAND_TOGGLE = f"{COMMAND_HEADER}0f70010200"
|
|
COMMAND_TOGGLE = f"{COMMAND_HEADER}0f70010200"
|
|
COMMAND_GET_VOLTAGE_AND_CURRENT = f"{COMMAND_HEADER}0f7106000000"
|
|
COMMAND_GET_VOLTAGE_AND_CURRENT = f"{COMMAND_HEADER}0f7106000000"
|
|
-PASSIVE_POLL_INTERVAL = 1 * 60
|
|
|
|
|
|
+PASSIVE_POLL_INTERVAL = 10 * 60
|
|
|
|
|
|
|
|
|
|
-class SwitchbotRelaySwitch(SwitchbotSequenceDevice):
|
|
|
|
|
|
+class SwitchbotRelaySwitch(SwitchbotDevice):
|
|
"""Representation of a Switchbot relay switch 1pm."""
|
|
"""Representation of a Switchbot relay switch 1pm."""
|
|
|
|
|
|
def __init__(
|
|
def __init__(
|
|
@@ -41,8 +46,30 @@ class SwitchbotRelaySwitch(SwitchbotSequenceDevice):
|
|
self._key_id = key_id
|
|
self._key_id = key_id
|
|
self._encryption_key = bytearray.fromhex(encryption_key)
|
|
self._encryption_key = bytearray.fromhex(encryption_key)
|
|
self._model: SwitchbotModel = model
|
|
self._model: SwitchbotModel = model
|
|
|
|
+ self._force_next_update = False
|
|
super().__init__(device, None, interface, **kwargs)
|
|
super().__init__(device, None, interface, **kwargs)
|
|
|
|
|
|
|
|
+ def update_from_advertisement(self, advertisement: SwitchBotAdvertisement) -> None:
|
|
|
|
+ """Update device data from advertisement."""
|
|
|
|
+ # Obtain voltage and current through command.
|
|
|
|
+ adv_data = advertisement.data["data"]
|
|
|
|
+ if previous_voltage := self._get_adv_value("voltage"):
|
|
|
|
+ adv_data["voltage"] = previous_voltage
|
|
|
|
+ if previous_current := self._get_adv_value("current"):
|
|
|
|
+ adv_data["current"] = previous_current
|
|
|
|
+ current_state = self._get_adv_value("sequence_number")
|
|
|
|
+ super().update_from_advertisement(advertisement)
|
|
|
|
+ new_state = self._get_adv_value("sequence_number")
|
|
|
|
+ _LOGGER.debug(
|
|
|
|
+ "%s: update advertisement: %s (seq before: %s) (seq after: %s)",
|
|
|
|
+ self.name,
|
|
|
|
+ advertisement,
|
|
|
|
+ current_state,
|
|
|
|
+ new_state,
|
|
|
|
+ )
|
|
|
|
+ if current_state != new_state:
|
|
|
|
+ self._force_next_update = True
|
|
|
|
+
|
|
async def update(self, interface: int | None = None) -> None:
|
|
async def update(self, interface: int | None = None) -> None:
|
|
"""Update state of device."""
|
|
"""Update state of device."""
|
|
if info := await self.get_voltage_and_current():
|
|
if info := await self.get_voltage_and_current():
|
|
@@ -56,13 +83,16 @@ class SwitchbotRelaySwitch(SwitchbotSequenceDevice):
|
|
ok = self._check_command_result(result, 0, {1})
|
|
ok = self._check_command_result(result, 0, {1})
|
|
if ok:
|
|
if ok:
|
|
return {
|
|
return {
|
|
- "voltage": (result[9] << 8) + result[10],
|
|
|
|
|
|
+ "voltage": ((result[9] << 8) + result[10]) / 10,
|
|
"current": (result[11] << 8) + result[12],
|
|
"current": (result[11] << 8) + result[12],
|
|
}
|
|
}
|
|
return None
|
|
return None
|
|
|
|
|
|
def poll_needed(self, seconds_since_last_poll: float | None) -> bool:
|
|
def poll_needed(self, seconds_since_last_poll: float | None) -> bool:
|
|
"""Return if device needs polling."""
|
|
"""Return if device needs polling."""
|
|
|
|
+ if self._force_next_update:
|
|
|
|
+ self._force_next_update = False
|
|
|
|
+ return True
|
|
if (
|
|
if (
|
|
seconds_since_last_poll is not None
|
|
seconds_since_last_poll is not None
|
|
and seconds_since_last_poll < PASSIVE_POLL_INTERVAL
|
|
and seconds_since_last_poll < PASSIVE_POLL_INTERVAL
|