Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for lastSeen property #705

Merged
merged 3 commits into from
Aug 8, 2023
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
2 changes: 1 addition & 1 deletion test/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ def version_data_fixture():
"serverVersion": "test_server_version",
"homeId": "test_home_id",
"minSchemaVersion": 0,
"maxSchemaVersion": 29,
"maxSchemaVersion": 30,
}


Expand Down
22 changes: 21 additions & 1 deletion test/model/test_node.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"""Test the node model."""
import json
from copy import deepcopy
from datetime import datetime
from datetime import datetime, timezone
from unittest.mock import patch

import pytest
Expand Down Expand Up @@ -136,6 +136,26 @@ def test_from_state(client):
)
assert node.endpoints[0] != node.endpoints[0].index
assert hash(node.endpoints[0]) == hash((client.driver, node.node_id, 0))
assert node.last_seen is None
event = Event(
"statistics updated",
{
"source": "node",
"event": "statistics updated",
"nodeId": node.node_id,
"statistics": {
"commandsTX": 1,
"commandsRX": 2,
"commandsDroppedTX": 3,
"commandsDroppedRX": 4,
"timeoutResponse": 5,
"rssi": 7,
"lastSeen": "2023-07-18T15:42:34.701Z",
},
},
)
node.receive_event(event)
assert node.last_seen == datetime(2023, 7, 18, 15, 42, 34, 701000, timezone.utc)


async def test_highest_security_value(lock_schlage_be469, ring_keypad):
Expand Down
2 changes: 1 addition & 1 deletion test/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ async def test_additional_user_agent_components(client_session, url):
{
"command": "initialize",
"messageId": "initialize",
"schemaVersion": 29,
"schemaVersion": 30,
"additionalUserAgentComponents": {
"zwave-js-server-python": __version__,
"foo": "bar",
Expand Down
2 changes: 1 addition & 1 deletion test/test_dump.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ async def test_dump_additional_user_agent_components(
{
"command": "initialize",
"messageId": "initialize",
"schemaVersion": 29,
"schemaVersion": 30,
"additionalUserAgentComponents": {
"zwave-js-server-python": __version__,
"foo": "bar",
Expand Down
2 changes: 1 addition & 1 deletion test/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def test_dump_state(
assert captured.out == (
"{'type': 'version', 'driverVersion': 'test_driver_version', "
"'serverVersion': 'test_server_version', 'homeId': 'test_home_id', "
"'minSchemaVersion': 0, 'maxSchemaVersion': 29}\n"
"'minSchemaVersion': 0, 'maxSchemaVersion': 30}\n"
"{'type': 'result', 'success': True, 'result': {}, 'messageId': 'initialize'}\n"
"test_result\n"
)
Expand Down
4 changes: 2 additions & 2 deletions zwave_js_server/const/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
__version__ = metadata.version(PACKAGE_NAME)

# minimal server schema version we can handle
MIN_SERVER_SCHEMA_VERSION = 29
MIN_SERVER_SCHEMA_VERSION = 30
# max server schema version we can handle (and our code is compatible with)
MAX_SERVER_SCHEMA_VERSION = 29
MAX_SERVER_SCHEMA_VERSION = 30

VALUE_UNKNOWN = "unknown"

Expand Down
9 changes: 9 additions & 0 deletions zwave_js_server/model/node/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,13 @@ def keep_awake(self) -> bool:
"""Return whether the node is set to keep awake."""
return self.data["keepAwake"]

@property
def last_seen(self) -> datetime | None:
"""Return when the node was last seen."""
if last_seen := self.data.get("lastSeen"):
return datetime.fromisoformat(last_seen)
return None

def update(self, data: NodeDataType) -> None:
"""Update the internal state data."""
self.data = copy.deepcopy(data)
Expand Down Expand Up @@ -969,3 +976,5 @@ def handle_statistics_updated(self, event: Event) -> None:
event.data["statistics_updated"] = self._statistics = NodeStatistics(
self.client, statistics
)
if last_seen := statistics.get("lastSeen"):
self.data["lastSeen"] = last_seen
1 change: 1 addition & 0 deletions zwave_js_server/model/node/data_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,4 @@ class NodeDataType(TypedDict, total=False):
statistics: NodeStatisticsDataType
highestSecurityClass: int
isControllerNode: bool
lastSeen: str
5 changes: 5 additions & 0 deletions zwave_js_server/model/node/statistics.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from contextlib import suppress
from dataclasses import dataclass, field
from datetime import datetime
from typing import TYPE_CHECKING, TypedDict

from zwave_js_server.exceptions import RssiErrorReceived
Expand All @@ -27,6 +28,7 @@ class NodeStatisticsDataType(TypedDict, total=False):
rssi: int
lwr: RouteStatisticsDataType
nlwr: RouteStatisticsDataType
lastSeen: str


@dataclass
Expand All @@ -43,6 +45,7 @@ class NodeStatistics:
rtt: int | None = field(init=False)
lwr: RouteStatistics | None = field(init=False, default=None)
nlwr: RouteStatistics | None = field(init=False, default=None)
last_seen: datetime | None = field(init=False, default=None)

def __post_init__(self) -> None:
"""Post initialize."""
Expand All @@ -52,6 +55,8 @@ def __post_init__(self) -> None:
self.commands_dropped_tx = self.data["commandsDroppedTX"]
self.timeout_response = self.data["timeoutResponse"]
self.rtt = self.data.get("rtt")
if last_seen := self.data.get("lastSeen"):
self.last_seen = datetime.fromisoformat(last_seen)
if lwr := self.data.get("lwr"):
with suppress(ValueError):
self.lwr = RouteStatistics(self.client, lwr)
Expand Down