Skip to content
5 changes: 2 additions & 3 deletions plugwise_usb/connection/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,9 +156,8 @@ async def _handle_stick_event(self, event: StickEvent) -> None:
if not self._queue.is_running:
self._queue.start(self._manager)
await self.initialize_stick()
elif event == StickEvent.DISCONNECTED:
if self._queue.is_running:
await self._queue.stop()
elif event == StickEvent.DISCONNECTED and self._queue.is_running:
await self._queue.stop()

async def initialize_stick(self) -> None:
"""Initialize connection to the USB-stick."""
Expand Down
35 changes: 21 additions & 14 deletions plugwise_usb/messages/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -283,27 +283,34 @@

async def _process_stick_response(self, stick_response: StickResponse) -> None:
"""Process incoming stick response."""
if self._response_future.done():
if (

Check warning on line 286 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L286

Added line #L286 was not covered by tests
self._response_future.done()
or self._seq_id is None
or self._seq_id != stick_response.seq_id
):
return
if self._seq_id is None or self._seq_id != stick_response.seq_id:

if stick_response.ack_id == StickResponseType.ACCEPT:

Check warning on line 293 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L293

Added line #L293 was not covered by tests
return

if stick_response.ack_id == StickResponseType.TIMEOUT:
self._response_timeout_expired(stick_timeout=True)
elif stick_response.ack_id == StickResponseType.FAILED:
return

Check warning on line 298 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L298

Added line #L298 was not covered by tests

if stick_response.ack_id == StickResponseType.FAILED:

Check warning on line 300 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L300

Added line #L300 was not covered by tests
self._unsubscribe_from_node()
self._seq_id = None
self._response_future.set_exception(
NodeError(f"Stick failed request {self._seq_id}")
)
elif stick_response.ack_id == StickResponseType.ACCEPT:
pass
else:
_LOGGER.debug(
"Unknown StickResponseType %s at %s for request %s",
str(stick_response.ack_id),
stick_response,
self,
)
return

Check warning on line 306 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L306

Added line #L306 was not covered by tests

_LOGGER.debug(

Check warning on line 308 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L308

Added line #L308 was not covered by tests
"Unknown StickResponseType %s at %s for request %s",
str(stick_response.ack_id),
stick_response,
self,
)

async def _send_request(self, suppress_node_errors=False) -> PlugwiseResponse | None:
"""Send request."""
Expand Down Expand Up @@ -1287,11 +1294,11 @@
self,
send_fn: Callable[[PlugwiseRequest, bool], Awaitable[PlugwiseResponse | None]],
mac: bytes,
taskId: int,
task_id: int,
) -> None:
"""Initialize NodeClearGroupMacRequest message object."""
super().__init__(send_fn, mac)
self._args.append(Int(taskId, length=2))
self._args.append(Int(task_id, length=2))

Check warning on line 1301 in plugwise_usb/messages/requests.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/messages/requests.py#L1301

Added line #L1301 was not covered by tests


class CircleSetScheduleValueRequest(PlugwiseRequest):
Expand Down
16 changes: 4 additions & 12 deletions plugwise_usb/messages/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -590,25 +590,17 @@ def __init__(self, protocol_version: str = "2.0") -> None:
"""Initialize NodeInfoResponse message object."""
super().__init__(b"0024")

self.datetime = DateTime()
self._logaddress_pointer = LogAddr(0, length=8)
if protocol_version == "1.0":
# FIXME: Define "absoluteHour" variable
self.datetime = DateTime()
if protocol_version in ("1.0", "2.0"):
# FIXME 1.0: Define "absoluteHour" variable
self._relay_state = Int(0, length=2)
self._params += [
self.datetime,
self._logaddress_pointer,
self._relay_state,
]
elif protocol_version == "2.0":
self.datetime = DateTime()
self._relay_state = Int(0, length=2)
self._params += [
self.datetime,
self._logaddress_pointer,
self._relay_state,
]
elif protocol_version == "2.3":
if protocol_version == "2.3":
# FIXME: Define "State_mask" variable
self.state_mask = Int(0, length=2)
self._params += [
Expand Down
20 changes: 10 additions & 10 deletions plugwise_usb/network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,30 +208,34 @@
await gather(*[node.disconnect() for node in self._nodes.values()])
self._is_running = False

async def node_awake_message(self, response: PlugwiseResponse) -> bool:
async def node_awake_message(self, response: PlugwiseResponse) -> None:
"""Handle NodeAwakeResponse message."""
if not isinstance(response, NodeAwakeResponse):
raise MessageError(
f"Invalid response message type ({response.__class__.__name__}) received, expected NodeAwakeResponse"
)

mac = response.mac_decoded
if self._awake_discovery.get(mac) is None:
self._awake_discovery[mac] = response.timestamp - timedelta(seconds=15)

if mac in self._nodes:
if self._awake_discovery[mac] < (
response.timestamp - timedelta(seconds=10)
):
await self._notify_node_event_subscribers(NodeEvent.AWAKE, mac)
self._awake_discovery[mac] = response.timestamp
return True
return

if (address := self._register.network_address(mac)) is None:
if self._register.scan_completed:
return True
return

Check warning on line 232 in plugwise_usb/network/__init__.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/network/__init__.py#L232

Added line #L232 was not covered by tests

_LOGGER.debug(
"Skip node awake message for %s because network registry address is unknown",
mac,
)
return True
return

Check warning on line 238 in plugwise_usb/network/__init__.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/network/__init__.py#L238

Added line #L238 was not covered by tests

if self._nodes.get(mac) is None:
if (
Expand All @@ -243,7 +247,6 @@
)
else:
_LOGGER.debug("duplicate maintenance awake discovery for %s", mac)
return True

async def node_join_available_message(self, response: PlugwiseResponse) -> bool:
"""Handle NodeJoinAvailableResponse messages."""
Expand Down Expand Up @@ -275,11 +278,8 @@
raise NodeError(f"Failed to obtain address for node {mac}")

if self._nodes.get(mac) is None:
if self._discover_sed_tasks.get(mac) is None:
self._discover_sed_tasks[mac] = create_task(
self._discover_battery_powered_node(address, mac)
)
elif self._discover_sed_tasks[mac].done():
task = self._discover_sed_tasks.get(mac)
if task is None or task.done():

Check warning on line 282 in plugwise_usb/network/__init__.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/network/__init__.py#L281-L282

Added lines #L281 - L282 were not covered by tests
self._discover_sed_tasks[mac] = create_task(
self._discover_battery_powered_node(address, mac)
)
Expand Down
1 change: 0 additions & 1 deletion plugwise_usb/network/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,6 @@ async def retrieve_network_registration(
return await self.retrieve_network_registration(address, retry=False)
return None
address = response.network_address
mac_of_node = response.registered_mac
if (mac_of_node := response.registered_mac) == "FFFFFFFFFFFFFFFF":
mac_of_node = ""
return (address, mac_of_node)
Expand Down
16 changes: 8 additions & 8 deletions plugwise_usb/nodes/celsius.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,22 +27,22 @@
"""Load and activate node features."""
if self._loaded:
return True
self._node_info.is_battery_powered = True

self._node_info.is_battery_powered = True
mac = self._node_info.mac

Check warning on line 32 in plugwise_usb/nodes/celsius.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/celsius.py#L31-L32

Added lines #L31 - L32 were not covered by tests
if self._cache_enabled:
_LOGGER.debug(
"Load Celsius node %s from cache", self._node_info.mac
)
if await self._load_from_cache():
pass
_LOGGER.debug("Loading Celsius node %s from cache", mac)
if not await self._load_from_cache():
_LOGGER.debug("Loading Celsius node %s from cache failed", mac)

Check warning on line 36 in plugwise_usb/nodes/celsius.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/celsius.py#L34-L36

Added lines #L34 - L36 were not covered by tests

self._loaded = True
self._setup_protocol(
CELSIUS_FIRMWARE_SUPPORT,
(NodeFeature.INFO, NodeFeature.TEMPERATURE),
)
if await self.initialize():
await self._loaded_callback(NodeEvent.LOADED, self.mac)
await self._loaded_callback(NodeEvent.LOADED, mac)

Check warning on line 44 in plugwise_usb/nodes/celsius.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/celsius.py#L44

Added line #L44 was not covered by tests
return True
_LOGGER.debug("Load of Celsius node %s failed", self._node_info.mac)

_LOGGER.debug("Loading of Celsius node %s failed", mac)

Check warning on line 47 in plugwise_usb/nodes/celsius.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/celsius.py#L47

Added line #L47 was not covered by tests
return False
27 changes: 14 additions & 13 deletions plugwise_usb/nodes/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
EnergyCalibrationRequest,
NodeInfoRequest,
)
from ..messages.responses import NodeInfoResponse, NodeResponse, NodeResponseType
from ..messages.responses import NodeInfoResponse, NodeResponseType
from .helpers import EnergyCalibration, raise_not_loaded
from .helpers.counter import EnergyCounters
from .helpers.firmware import CIRCLE_FIRMWARE_SUPPORT
Expand Down Expand Up @@ -532,7 +532,6 @@

async def _energy_log_records_load_from_cache(self) -> bool:
"""Load energy_log_record from cache."""
cache_data = self._get_cache(CACHE_ENERGY_COLLECTION)
if (cache_data := self._get_cache(CACHE_ENERGY_COLLECTION)) is None:
_LOGGER.warning(
"Failed to restore energy log records from cache for node %s", self.name
Expand Down Expand Up @@ -733,7 +732,6 @@
datetime.now(tz=UTC),
self._node_protocols.max,
)
node_response: NodeResponse | None = await set_clock_request.send()
if (node_response := await set_clock_request.send()) is None:
_LOGGER.warning(
"Failed to (re)set the internal clock of %s",
Expand Down Expand Up @@ -849,12 +847,14 @@
)
self._initialized = False
return False

if not self._calibration and not await self.calibration_update():
_LOGGER.debug(
"Failed to initialized node %s, no calibration", self._mac_in_str
)
self._initialized = False
return False

if (
self.skip_update(self._node_info, 30)
and await self.node_info_update() is None
Expand All @@ -869,7 +869,9 @@
)
self._initialized = False
return False
return await super().initialize()

await super().initialize()
return True

async def node_info_update(
self, node_info: NodeInfoResponse | None = None
Expand Down Expand Up @@ -1083,15 +1085,14 @@
async def get_state(self, features: tuple[NodeFeature]) -> dict[NodeFeature, Any]:
"""Update latest state for given feature."""
states: dict[NodeFeature, Any] = {}
if not self._available:
if not await self.is_online():
_LOGGER.debug(
"Node %s did not respond, unable to update state", self._mac_in_str
)
for feature in features:
states[feature] = None
states[NodeFeature.AVAILABLE] = self.available_state
return states
if not self._available and not await self.is_online():
_LOGGER.debug(

Check warning on line 1089 in plugwise_usb/nodes/circle.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/circle.py#L1089

Added line #L1089 was not covered by tests
"Node %s did not respond, unable to update state", self._mac_in_str
)
for feature in features:
states[feature] = None
states[NodeFeature.AVAILABLE] = self.available_state
return states

Check warning on line 1095 in plugwise_usb/nodes/circle.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/circle.py#L1092-L1095

Added lines #L1092 - L1095 were not covered by tests

for feature in features:
if feature not in self._features:
Expand Down
5 changes: 2 additions & 3 deletions plugwise_usb/nodes/helpers/counter.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,8 @@
"""Add pulse log."""
if self._pulse_collection.add_log(
address, slot, timestamp, pulses, import_only
):
if not import_only:
self.update()
) and not import_only:
self.update()

Check warning on line 86 in plugwise_usb/nodes/helpers/counter.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/helpers/counter.py#L86

Added line #L86 was not covered by tests

def get_pulse_logs(self) -> dict[int, dict[int, PulseLogRecord]]:
"""Return currently collected pulse logs."""
Expand Down
2 changes: 0 additions & 2 deletions plugwise_usb/nodes/helpers/pulses.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,8 +935,6 @@ def _missing_addresses_before(
):
# Use consumption interval
calc_interval_cons = timedelta(minutes=self._log_interval_consumption)
if self._log_interval_consumption == 0:
pass

if not self._log_production:
expected_timestamp = (
Expand Down
22 changes: 11 additions & 11 deletions plugwise_usb/nodes/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,14 +337,14 @@
for feature in node_features:
if (
required_version := FEATURE_SUPPORTED_AT_FIRMWARE.get(feature)
) is not None:
if (
self._node_protocols.min
<= required_version
<= self._node_protocols.max
and feature not in self._features
):
self._features += (feature,)
) is not None and (
self._node_protocols.min
<= required_version
<= self._node_protocols.max
and feature not in self._features
):
self._features += (feature,)

self._node_info.features = self._features

async def reconnect(self) -> None:
Expand Down Expand Up @@ -398,15 +398,15 @@
return False
return True

async def initialize(self) -> bool:
async def initialize(self) -> None:
"""Initialize node configuration."""
if self._initialized:
return True
return

Check warning on line 404 in plugwise_usb/nodes/node.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/node.py#L404

Added line #L404 was not covered by tests

self._initialization_delay_expired = datetime.now(tz=UTC) + timedelta(
minutes=SUPPRESS_INITIALIZATION_WARNINGS
)
self._initialized = True
return True

async def _available_update_state(
self, available: bool, timestamp: datetime | None = None
Expand Down
18 changes: 9 additions & 9 deletions plugwise_usb/nodes/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,12 +110,14 @@
"""Initialize Scan node."""
if self._initialized:
return True

self._unsubscribe_switch_group = await self._message_subscribe(
self._switch_group,
self._mac_in_bytes,
(NODE_SWITCH_GROUP_ID,),
)
return await super().initialize()
await super().initialize()
return True

async def unload(self) -> None:
"""Unload node."""
Expand Down Expand Up @@ -164,14 +166,12 @@
def _motion_from_cache(self) -> bool:
"""Load motion state from cache."""
if (cached_motion_state := self._get_cache(CACHE_MOTION_STATE)) is not None:
if cached_motion_state == "True":
if (
motion_timestamp := self._motion_timestamp_from_cache()
) is not None:
if (
datetime.now(tz=UTC) - motion_timestamp
).seconds < self._reset_timer_from_cache() * 60:
return True
if (
cached_motion_state == "True"
and (motion_timestamp := self._motion_timestamp_from_cache()) is not None
and (datetime.now(tz=UTC) - motion_timestamp).seconds < self._reset_timer_from_cache() * 60
):
return True

Check warning on line 174 in plugwise_usb/nodes/scan.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/scan.py#L174

Added line #L174 was not covered by tests
return False
return SCAN_DEFAULT_MOTION_STATE

Expand Down
Loading
Loading