Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions plugwise_usb/messages/requests.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def start_response_timeout(self) -> None:

def stop_response_timeout(self) -> None:
"""Stop timeout for node response."""
self._waiting_for_response = True
self._waiting_for_response = False
if self._response_timeout is not None:
self._response_timeout.cancel()

Expand Down Expand Up @@ -1231,13 +1231,13 @@ def __init__(
async def send(self) -> NodeResponse | None:
"""Send request."""
result = await self._send_request()
_LOGGER.warning("NodeSleepConfigRequest result: %s", result)
_LOGGER.debug("NodeSleepConfigRequest result: %s", result)
if isinstance(result, NodeResponse):
return result
if result is None:
return None
raise MessageError(
f"Invalid response message. Received {result.__class__.__name__}, expected NodeAckResponse"
f"Invalid response message. Received {result.__class__.__name__}, expected NodeResponse"
)

def __repr__(self) -> str:
Expand Down
6 changes: 3 additions & 3 deletions plugwise_usb/network/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ async def node_join_available_message(self, response: PlugwiseResponse) -> bool:
raise NodeError(f"Unable to add Node ({mac}): {exc}") from exc
if result:
return True

return False

async def node_rejoin_message(self, response: PlugwiseResponse) -> bool:
Expand All @@ -286,7 +286,7 @@ async def node_rejoin_message(self, response: PlugwiseResponse) -> bool:
else:
_LOGGER.debug("duplicate awake discovery for %s", mac)
return True

return False

def _unsubscribe_to_protocol_events(self) -> None:
Expand All @@ -299,7 +299,7 @@ def _unsubscribe_to_protocol_events(self) -> None:
self._unsubscribe_stick_event = None

# endregion

# region - Coordinator
async def discover_network_coordinator(self, load: bool = False) -> bool:
"""Discover the Zigbee network coordinator (Circle+/Stealth+)."""
Expand Down
6 changes: 4 additions & 2 deletions plugwise_usb/network/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,10 @@
"Unable to restore network registry because cache is not initialized"
)
return

if self._cache_restored:
return

for address, registration in self._network_cache.registrations.items():
mac, node_type = registration
if self._registry.get(address) is None:
Expand Down Expand Up @@ -259,12 +261,12 @@
try:
await request.send()
except StickError as exc:
raise NodeError("{exc}") from exc
raise NodeError(f"{exc}") from exc

Check warning on line 264 in plugwise_usb/network/registry.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/network/registry.py#L264

Added line #L264 was not covered by tests

async def unregister_node(self, mac: str) -> None:
"""Unregister node from current Plugwise network."""
if not validate_mac(mac):
raise NodeError(f"MAC '{mac}' invalid")
raise NodeError(f"MAC {mac} invalid")

Check warning on line 269 in plugwise_usb/network/registry.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/network/registry.py#L269

Added line #L269 was not covered by tests

mac_registered = False
for registration in self._registry.values():
Expand Down
4 changes: 2 additions & 2 deletions plugwise_usb/nodes/circle.py
Original file line number Diff line number Diff line change
Expand Up @@ -822,14 +822,14 @@ async def _load_from_cache(self) -> bool:
# Relay
if await self._relay_load_from_cache():
_LOGGER.debug(
"Node %s failed to load relay state from cache",
"Node %s successfully loaded relay state from cache",
self._mac_in_str,
)
# Relay init config if feature is enabled
if NodeFeature.RELAY_INIT in self._features:
if await self._relay_init_load_from_cache():
_LOGGER.debug(
"Node %s failed to load relay_init state from cache",
"Node %s successfully loaded relay_init state from cache",
self._mac_in_str,
)
return True
Expand Down
12 changes: 6 additions & 6 deletions plugwise_usb/nodes/helpers/pulses.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@
self, pulses_consumed: int, pulses_produced: int, timestamp: datetime
) -> None:
"""Update pulse counter.

Both device consumption and production counters reset after the beginning of a new hour.
"""
self._cons_pulsecounter_reset = False
Expand All @@ -287,7 +287,7 @@

if (
self._pulses_production is not None
and self._pulses_production < pulses_produced
and self._pulses_production < pulses_produced
):
self._prod_pulsecounter_reset = True
_LOGGER.debug("update_pulse_counter | production pulses reset")
Expand All @@ -313,9 +313,9 @@

def _update_rollover(self) -> None:
"""Update rollover states.

When the last found timestamp is outside the interval `_last_log_timestamp`
to `_next_log_timestamp` the pulses should not be counted as part of the
to `_next_log_timestamp` the pulses should not be counted as part of the
ongoing collection-interval.
"""
if self._log_addresses_missing is not None and self._log_addresses_missing:
Expand All @@ -341,7 +341,7 @@
next_log_timestamp: datetime | None,
is_consumption=True,
) -> bool:
"""Helper function for _update_rollover()."""
"""Detect rollover based on timestamp comparisons."""

if (
self._pulses_timestamp is not None
Expand Down Expand Up @@ -824,7 +824,7 @@
"The Circle %s does not overwrite old logged data, please reset the Circle's energy-logs via Source",
self._mac,
)
return
return None

Check warning on line 827 in plugwise_usb/nodes/helpers/pulses.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/helpers/pulses.py#L827

Added line #L827 was not covered by tests

if (
last_address == first_address
Expand Down
27 changes: 17 additions & 10 deletions plugwise_usb/nodes/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -416,7 +416,7 @@
if (
self._last_seen is not None
and timestamp is not None
and (timestamp - self._last_seen).seconds > 5
and int((timestamp - self._last_seen).total_seconds()) > 5

):
self._last_seen = timestamp
Expand Down Expand Up @@ -618,15 +618,22 @@
if (timestamp_str := self._get_cache(setting)) is not None:
data = timestamp_str.split("-")
if len(data) == 6:
return datetime(
year=int(data[0]),
month=int(data[1]),
day=int(data[2]),
hour=int(data[3]),
minute=int(data[4]),
second=int(data[5]),
tzinfo=UTC,
)
try:
return datetime(
year=int(data[0]),
month=int(data[1]),
day=int(data[2]),
hour=int(data[3]),
minute=int(data[4]),
second=int(data[5]),
tzinfo=UTC,
)
except ValueError:
_LOGGER.warning(

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

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/node.py#L631-L632

Added lines #L631 - L632 were not covered by tests
"Invalid datetime format in cache for setting %s: %s",
setting,
timestamp_str,
)
return None

def _set_cache(self, setting: str, value: Any) -> None:
Expand Down
25 changes: 17 additions & 8 deletions plugwise_usb/nodes/scan.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
# Light override
SCAN_DEFAULT_DAYLIGHT_MODE: Final = False

# Sensitivity values for motion sensor configuration
SENSITIVITY_HIGH_VALUE = 20 # 0x14
SENSITIVITY_MEDIUM_VALUE = 30 # 0x1E
SENSITIVITY_OFF_VALUE = 255 # 0xFF

# endregion


Expand Down Expand Up @@ -169,7 +174,7 @@ def _motion_from_cache(self) -> bool:
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
and int((datetime.now(tz=UTC) - motion_timestamp).total_seconds()) < self._reset_timer_from_cache() * 60
):
return True
return False
Expand Down Expand Up @@ -378,7 +383,7 @@ async def _motion_state_update(
self._set_cache(CACHE_MOTION_STATE, "False")
if self._motion_state.state is None or self._motion_state.state:
if self._reset_timer_motion_on is not None:
reset_timer = (timestamp - self._reset_timer_motion_on).seconds
reset_timer = int((timestamp - self._reset_timer_motion_on).total_seconds())
if self._motion_config.reset_timer is None:
self._motion_config = replace(
self._motion_config,
Expand Down Expand Up @@ -464,12 +469,13 @@ async def scan_configure(
daylight_mode: bool,
) -> bool:
"""Configure Scan device settings. Returns True if successful."""
# Default to medium:
sensitivity_value = 30 # b'1E'
if sensitivity_level == MotionSensitivity.HIGH:
sensitivity_value = 20 # b'14'
if sensitivity_level == MotionSensitivity.OFF:
sensitivity_value = 255 # b'FF'
sensitivity_map = {
MotionSensitivity.HIGH: SENSITIVITY_HIGH_VALUE,
MotionSensitivity.MEDIUM: SENSITIVITY_MEDIUM_VALUE,
MotionSensitivity.OFF: SENSITIVITY_OFF_VALUE,
}
# Default to medium
sensitivity_value = sensitivity_map.get(sensitivity_level, SENSITIVITY_MEDIUM_VALUE)
request = ScanConfigureRequest(
self._send,
self._mac_in_bytes,
Expand All @@ -484,17 +490,20 @@ async def scan_configure(
self._new_daylight_mode = None
_LOGGER.warning("Failed to configure scan settings for %s", self.name)
return False

if response.node_ack_type == NodeAckResponseType.SCAN_CONFIG_ACCEPTED:
await self._scan_configure_update(
motion_reset_timer, sensitivity_level, daylight_mode
)
return True

_LOGGER.warning(
"Unexpected response ack type %s for %s",
response.node_ack_type,
self.name,
)
return False

self._new_reset_timer = None
self._new_sensitivity_level = None
self._new_daylight_mode = None
Expand Down
20 changes: 10 additions & 10 deletions plugwise_usb/nodes/sed.py
Original file line number Diff line number Diff line change
Expand Up @@ -453,23 +453,23 @@ async def _configure_sed_task(self) -> bool:
self.name,
)
self._sed_config_task_scheduled = False
change_required = True
if self._new_battery_config.awake_duration is not None:
change_required = True
if self._new_battery_config.clock_interval is not None:
change_required = True
if self._new_battery_config.clock_sync is not None:
change_required = True
if self._new_battery_config.maintenance_interval is not None:
change_required = True
if self._new_battery_config.sleep_duration is not None:
change_required = False
if (
self._new_battery_config.awake_duration is not None
or self._new_battery_config.clock_interval is not None
or self._new_battery_config.clock_sync is not None
or self._new_battery_config.maintenance_interval is not None
or self._new_battery_config.sleep_duration is not None
):
change_required = True

if not change_required:
_LOGGER.debug(
"_configure_sed_task | Device %s | no change",
self.name,
)
return True

_LOGGER.debug(
"_configure_sed_task | Device %s | request change",
self.name,
Expand Down
14 changes: 10 additions & 4 deletions plugwise_usb/nodes/sense.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,10 @@
"""Load and activate Sense node features."""
if self._loaded:
return True

self._node_info.is_battery_powered = True
if self._cache_enabled:
_LOGGER.debug("Load Sense node %s from cache", self._node_info.mac)
_LOGGER.debug("Loading Sense node %s from cache", self._node_info.mac)

Check warning on line 58 in plugwise_usb/nodes/sense.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/sense.py#L58

Added line #L58 was not covered by tests
if await self._load_from_cache():
self._loaded = True
self._setup_protocol(
Expand All @@ -64,7 +65,8 @@
if await self.initialize():
await self._loaded_callback(NodeEvent.LOADED, self.mac)
return True
_LOGGER.debug("Load of Sense node %s failed", self._node_info.mac)

_LOGGER.debug("Loading of Sense node %s failed", self._node_info.mac)

Check warning on line 69 in plugwise_usb/nodes/sense.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/sense.py#L69

Added line #L69 was not covered by tests
return False

@raise_not_loaded
Expand Down Expand Up @@ -94,6 +96,7 @@
raise MessageError(
f"Invalid response message type ({response.__class__.__name__}) received, expected SenseReportResponse"
)
report_received = False

Check warning on line 99 in plugwise_usb/nodes/sense.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/sense.py#L99

Added line #L99 was not covered by tests
await self._available_update_state(True, response.timestamp)
if response.temperature.value != 65535:
self._temperature = int(
Expand All @@ -103,6 +106,8 @@
await self.publish_feature_update_to_subscribers(
NodeFeature.TEMPERATURE, self._temperature
)
report_received = True

Check warning on line 109 in plugwise_usb/nodes/sense.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/sense.py#L109

Added line #L109 was not covered by tests

if response.humidity.value != 65535:
self._humidity = int(
SENSE_HUMIDITY_MULTIPLIER * (response.humidity.value / 65536)
Expand All @@ -111,8 +116,9 @@
await self.publish_feature_update_to_subscribers(
NodeFeature.HUMIDITY, self._humidity
)
return True
return False
report_received = True

Check warning on line 119 in plugwise_usb/nodes/sense.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/sense.py#L119

Added line #L119 was not covered by tests

return report_received

Check warning on line 121 in plugwise_usb/nodes/sense.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/sense.py#L121

Added line #L121 was not covered by tests

@raise_not_loaded
async def get_state(self, features: tuple[NodeFeature]) -> dict[NodeFeature, Any]:
Expand Down
23 changes: 9 additions & 14 deletions plugwise_usb/nodes/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
super().__init__(mac, address, controller, loaded_callback)
self._switch_subscription: Callable[[], None] | None = None
self._switch_state: bool | None = None
self._switch: bool | None = None
self._switch: bool = False

async def load(self) -> bool:
"""Load and activate Switch node features."""
Expand Down Expand Up @@ -107,26 +107,21 @@
async def _switch_state_update(
self, switch_state: bool, timestamp: datetime
) -> None:
"""Process motion state update."""
"""Process switch state update."""
_LOGGER.debug(
"_switch_state_update for %s: %s -> %s",
self.name,
self._switch_state,
switch_state,
)
state_update = False
# Switch on
if switch_state:
self._set_cache(CACHE_SWITCH_STATE, "True")
if self._switch_state is None or not self._switch:
self._switch_state = True
state_update = True
else:
# Switch off
self._set_cache(CACHE_SWITCH_STATE, "False")
if self._switch is None or self._switch:
self._switch_state = False
state_update = True
# Update cache
self._set_cache(CACHE_SWITCH_STATE, str(switch_state))

Check warning on line 119 in plugwise_usb/nodes/switch.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/switch.py#L119

Added line #L119 was not covered by tests
# Check for a state change
if self._switch_state != switch_state:
self._switch_state = switch_state
state_update = True

Check warning on line 123 in plugwise_usb/nodes/switch.py

View check run for this annotation

Codecov / codecov/patch

plugwise_usb/nodes/switch.py#L121-L123

Added lines #L121 - L123 were not covered by tests

self._set_cache(CACHE_SWITCH_TIMESTAMP, timestamp)
if state_update:
self._switch = switch_state
Expand Down
Loading