Skip to content

Commit 342b1af

Browse files
authored
Merge pull request #295 from plugwise/mdi_sed2
Streamline of loading SED nodes.
2 parents b275689 + 04f44c3 commit 342b1af

File tree

10 files changed

+237
-167
lines changed

10 files changed

+237
-167
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Changelog
22

3+
## ONGOING
4+
5+
- PR [295](https://github.com/plugwise/python-plugwise-usb/pull/295): Streamline of loading function, to allow nodes to load even if temporarily offline, especially for SED nodes.
6+
37
## v0.44.8
48

59
- PR [291](https://github.com/plugwise/python-plugwise-usb/pull/291): Collect send-queue depth via PriorityQueue.qsize(), this provides a more accurate result

plugwise_usb/network/__init__.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -481,15 +481,14 @@ async def _load_node(self, mac: str) -> bool:
481481
return False
482482
if self._nodes[mac].is_loaded:
483483
return True
484-
if await self._nodes[mac].load():
485-
await self._notify_node_event_subscribers(NodeEvent.LOADED, mac)
486-
return True
487-
return False
484+
await self._nodes[mac].load()
485+
await self._notify_node_event_subscribers(NodeEvent.LOADED, mac)
486+
return True
488487

489488
async def _load_stragglers(self) -> None:
490489
"""Retry failed load operation."""
491490
await sleep(NODE_RETRY_LOAD_INTERVAL)
492-
while not self._load_discovered_nodes():
491+
while not await self._load_discovered_nodes():
493492
await sleep(NODE_RETRY_LOAD_INTERVAL)
494493

495494
async def _load_discovered_nodes(self) -> bool:

plugwise_usb/nodes/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,41 +26,47 @@ def get_plugwise_node( # noqa: PLR0911
2626
return PlugwiseCirclePlus(
2727
mac,
2828
address,
29+
node_type,
2930
controller,
3031
loaded_callback,
3132
)
3233
if node_type == NodeType.CIRCLE:
3334
return PlugwiseCircle(
3435
mac,
3536
address,
37+
node_type,
3638
controller,
3739
loaded_callback,
3840
)
3941
if node_type == NodeType.SWITCH:
4042
return PlugwiseSwitch(
4143
mac,
4244
address,
45+
node_type,
4346
controller,
4447
loaded_callback,
4548
)
4649
if node_type == NodeType.SENSE:
4750
return PlugwiseSense(
4851
mac,
4952
address,
53+
node_type,
5054
controller,
5155
loaded_callback,
5256
)
5357
if node_type == NodeType.SCAN:
5458
return PlugwiseScan(
5559
mac,
5660
address,
61+
node_type,
5762
controller,
5863
loaded_callback,
5964
)
6065
if node_type == NodeType.STEALTH:
6166
return PlugwiseStealth(
6267
mac,
6368
address,
69+
node_type,
6470
controller,
6571
loaded_callback,
6672
)

plugwise_usb/nodes/circle.py

Lines changed: 35 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,15 @@
88
from datetime import UTC, datetime
99
from functools import wraps
1010
import logging
11-
from typing import Any, TypeVar, cast
11+
from typing import Any, Final, TypeVar, cast
1212

1313
from ..api import (
1414
EnergyStatistics,
1515
NodeEvent,
1616
NodeFeature,
1717
NodeInfo,
1818
NodeInfoMessage,
19+
NodeType,
1920
PowerStatistics,
2021
RelayConfig,
2122
RelayLock,
@@ -58,6 +59,19 @@
5859
CACHE_RELAY_INIT = "relay_init"
5960
CACHE_RELAY_LOCK = "relay_lock"
6061

62+
CIRCLE_FEATURES: Final = (
63+
NodeFeature.CIRCLE,
64+
NodeFeature.RELAY,
65+
NodeFeature.RELAY_INIT,
66+
NodeFeature.RELAY_LOCK,
67+
NodeFeature.ENERGY,
68+
NodeFeature.POWER,
69+
)
70+
71+
72+
# Default firmware if not known
73+
DEFAULT_FIRMWARE: Final = datetime(2008, 8, 26, 15, 46, tzinfo=UTC)
74+
6175
FuncT = TypeVar("FuncT", bound=Callable[..., Any])
6276
_LOGGER = logging.getLogger(__name__)
6377

@@ -81,11 +95,12 @@ def __init__(
8195
self,
8296
mac: str,
8397
address: int,
98+
node_type: NodeType,
8499
controller: StickController,
85100
loaded_callback: Callable[[NodeEvent, str], Awaitable[None]],
86101
):
87102
"""Initialize base class for Sleeping End Device."""
88-
super().__init__(mac, address, controller, loaded_callback)
103+
super().__init__(mac, address, node_type, controller, loaded_callback)
89104

90105
# Relay
91106
self._relay_lock: RelayLock = RelayLock()
@@ -882,10 +897,10 @@ async def clock_synchronize(self) -> bool:
882897
return True
883898
return False
884899

885-
async def load(self) -> bool:
900+
async def load(self) -> None:
886901
"""Load and activate Circle node features."""
887902
if self._loaded:
888-
return True
903+
return
889904

890905
if self._cache_enabled:
891906
_LOGGER.debug("Loading Circle node %s from cache", self._mac_in_str)
@@ -895,37 +910,20 @@ async def load(self) -> bool:
895910
_LOGGER.debug("Retrieving Info For Circle node %s", self._mac_in_str)
896911

897912
# Check if node is online
898-
if not self._available and not await self.is_online():
899-
_LOGGER.debug(
900-
"Failed to load Circle node %s because it is not online",
901-
self._mac_in_str,
902-
)
903-
return False
904-
905-
# Get node info
906-
if await self.node_info_update() is None:
913+
if (
914+
not self._available and not await self.is_online()
915+
) or await self.node_info_update() is None:
907916
_LOGGER.debug(
908-
"Failed to load Circle node %s because it is not responding to information request",
917+
"Failed to retrieve NodeInfo for %s, loading defaults",
909918
self._mac_in_str,
910919
)
911-
return False
920+
await self._load_defaults()
912921

913-
self._loaded = True
922+
self._loaded = True
914923

915-
self._setup_protocol(
916-
CIRCLE_FIRMWARE_SUPPORT,
917-
(
918-
NodeFeature.CIRCLE,
919-
NodeFeature.RELAY,
920-
NodeFeature.RELAY_INIT,
921-
NodeFeature.RELAY_LOCK,
922-
NodeFeature.ENERGY,
923-
NodeFeature.POWER,
924-
),
925-
)
924+
self._setup_protocol(CIRCLE_FIRMWARE_SUPPORT, CIRCLE_FEATURES)
926925
await self._loaded_callback(NodeEvent.LOADED, self.mac)
927926
await self.initialize()
928-
return True
929927

930928
async def _load_from_cache(self) -> bool:
931929
"""Load states from previous cached information. Returns True if successful."""
@@ -972,6 +970,15 @@ async def _load_from_cache(self) -> bool:
972970

973971
return result
974972

973+
async def _load_defaults(self) -> None:
974+
"""Load default configuration settings."""
975+
if self._node_info.model is None:
976+
self._node_info.model = "Circle"
977+
if self._node_info.name is None:
978+
self._node_info.name = f"Circle {self._node_info.mac[-5:]}"
979+
if self._node_info.firmware is None:
980+
self._node_info.firmware = DEFAULT_FIRMWARE
981+
975982
@raise_not_loaded
976983
async def initialize(self) -> bool:
977984
"""Initialize node."""

plugwise_usb/nodes/node.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
)
4949

5050
CACHE_FIRMWARE = "firmware"
51-
CACHE_NODE_TYPE = "node_type"
5251
CACHE_HARDWARE = "hardware"
5352
CACHE_NODE_INFO_TIMESTAMP = "node_info_timestamp"
5453
CACHE_RELAY = "relay"
@@ -61,16 +60,22 @@ def __init__(
6160
self,
6261
mac: str,
6362
address: int,
63+
node_type: NodeType,
6464
controller: StickController,
6565
loaded_callback: Callable[[NodeEvent, str], Awaitable[None]],
6666
):
6767
"""Initialize Plugwise base node class."""
6868
super().__init__()
69+
self.node_type = node_type
6970
self._loaded_callback = loaded_callback
7071
self._message_subscribe = controller.subscribe_to_messages
7172
self._features: tuple[NodeFeature, ...] = NODE_FEATURES
7273
self._last_seen = datetime.now(tz=UTC)
73-
self._node_info = NodeInfo(mac, address)
74+
self._node_info = NodeInfo(
75+
mac=mac,
76+
zigbee_address=address,
77+
node_type=self.node_type,
78+
)
7479
self._ping = NetworkStatistics()
7580
self._mac_in_bytes = bytes(mac, encoding=UTF8)
7681
self._mac_in_str = mac
@@ -462,7 +467,6 @@ async def node_info_update(
462467
_LOGGER.debug("No response for node_info_update() for %s", self.mac)
463468
await self._available_update_state(False)
464469
return self._node_info
465-
466470
await self._available_update_state(True, node_info.timestamp)
467471
await self.update_node_details(node_info)
468472
return self._node_info
@@ -475,16 +479,13 @@ async def _node_info_load_from_cache(self) -> bool:
475479

476480
firmware = self._get_cache_as_datetime(CACHE_FIRMWARE)
477481
hardware = self._get_cache(CACHE_HARDWARE)
478-
node_type: NodeType | None = None
479-
if (node_type_str := self._get_cache(CACHE_NODE_TYPE)) is not None:
480-
node_type = NodeType(int(node_type_str))
481482
relay_state = self._get_cache(CACHE_RELAY) == "True"
482483
timestamp = self._get_cache_as_datetime(CACHE_NODE_INFO_TIMESTAMP)
483484
node_info = NodeInfoMessage(
484485
current_logaddress_pointer=None,
485486
firmware=firmware,
486487
hardware=hardware,
487-
node_type=node_type,
488+
node_type=self.node_type,
488489
relay_state=relay_state,
489490
timestamp=timestamp,
490491
)
@@ -509,9 +510,6 @@ async def update_node_details(
509510
complete = True
510511
if node_info.node_type is None:
511512
complete = False
512-
else:
513-
self._node_info.node_type = NodeType(node_info.node_type)
514-
self._set_cache(CACHE_NODE_TYPE, self._node_info.node_type.value)
515513

516514
if node_info.firmware is None:
517515
complete = False

0 commit comments

Comments
 (0)