From 302b4e967fed951797439464bd6abc9c17a148bc Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:27:49 -0500 Subject: [PATCH 1/4] Add comments to device config model for metadata --- .../fixtures/wallmote_central_scene_state.json | 6 +++++- test/model/test_node.py | 5 ++++- zwave_js_server/model/device_config.py | 18 +++++++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/test/fixtures/wallmote_central_scene_state.json b/test/fixtures/wallmote_central_scene_state.json index ba58db615..bcd775495 100644 --- a/test/fixtures/wallmote_central_scene_state.json +++ b/test/fixtures/wallmote_central_scene_state.json @@ -67,7 +67,11 @@ "inclusion": "To add the ZP3111 to the Z-Wave network (inclusion), place the Z-Wave primary controller into inclusion mode. Press the Program Switch of ZP3111 for sending the NIF. After sending NIF, Z-Wave will send the auto inclusion, otherwise, ZP3111 will go to sleep after 20 seconds.", "exclusion": "To remove the ZP3111 from the Z-Wave network (exclusion), place the Z-Wave primary controller into \u201cexclusion\u201d mode, and following its instruction to delete the ZP3111 to the controller. Press the Program Switch of ZP3111 once to be excluded.", "reset": "Remove cover to trigged tamper switch, LED flash once & send out Alarm Report. Press Program Switch 10 times within 10 seconds, ZP3111 will send the \u201cDevice Reset Locally Notification\u201d command and reset to the factory default. (Remark: This is to be used only in the case of primary controller being inoperable or otherwise unavailable.)", - "manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf" + "manual": "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf", + "comments": { + "level": "info", + "text": "test" + } }, "isEmbedded": true }, diff --git a/test/model/test_node.py b/test/model/test_node.py index 718887c86..97e12b618 100644 --- a/test/model/test_node.py +++ b/test/model/test_node.py @@ -102,7 +102,7 @@ async def test_highest_security_value(lock_schlage_be469, ring_keypad): assert ring_keypad.highest_security_class is None -async def test_device_config(wallmote_central_scene): +async def test_device_config(wallmote_central_scene, climate_radio_thermostat_ct100_plus): """Test a device config.""" node: node_pkg.Node = wallmote_central_scene @@ -143,10 +143,13 @@ async def test_device_config(wallmote_central_scene): "https://products.z-wavealliance.org/ProductManual/File?folder=&filename=MarketCertificationFiles/2479/ZP3111-5_R2_20170316.pdf" ) assert device_config.metadata.wakeup is None + assert device_config.metadata.comments == [{"level": "info", "text": "test"}] assert device_config.associations == {} assert device_config.param_information == {"_map": {}} assert device_config.supports_zwave_plus is None + assert climate_radio_thermostat_ct100_plus.device_config.metadata.comments == [] + async def test_unknown_values(cover_qubino_shutter): """Test that values that are unknown return as None.""" diff --git a/zwave_js_server/model/device_config.py b/zwave_js_server/model/device_config.py index 87fe3396d..cf295a213 100644 --- a/zwave_js_server/model/device_config.py +++ b/zwave_js_server/model/device_config.py @@ -3,7 +3,7 @@ https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceconfig """ -from typing import Dict, List, Optional, TypedDict +from typing import Dict, List, Literal, Optional, TypedDict, Union class DeviceDeviceDataType(TypedDict, total=False): @@ -56,6 +56,13 @@ def max(self) -> Optional[str]: return self.data.get("max") +class CommentDataType(TypedDict): + """Represent a device config's comment data dict type.""" + + level: Literal["info", "warning", "error"] + text: str + + class DeviceMetadataDataType(TypedDict, total=False): """Represent a device metadata data dict type.""" @@ -64,6 +71,7 @@ class DeviceMetadataDataType(TypedDict, total=False): exclusion: str reset: str manual: str + comments: Union[CommentDataType, List[CommentDataType]] class DeviceMetadata: @@ -98,6 +106,14 @@ def manual(self) -> Optional[str]: """Return manual instructions.""" return self.data.get("manual") + @property + def comments(self) -> List[CommentDataType]: + """Return list of comments about device.""" + comments = self.data.get("comments", []) + if isinstance(comments, dict): + return [CommentDataType(**comments)] + return [CommentDataType(**comment) for comment in comments] + class DeviceConfigDataType(TypedDict, total=False): """Represent a device config data dict type.""" From 6f23ce8ac0b7fad23b14bc4fdd4a168e63ce7b1c Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:29:41 -0500 Subject: [PATCH 2/4] Add comment referencing PR --- zwave_js_server/model/device_config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/zwave_js_server/model/device_config.py b/zwave_js_server/model/device_config.py index cf295a213..74df34137 100644 --- a/zwave_js_server/model/device_config.py +++ b/zwave_js_server/model/device_config.py @@ -59,6 +59,8 @@ def max(self) -> Optional[str]: class CommentDataType(TypedDict): """Represent a device config's comment data dict type.""" + # See PR for suggested meanings of each level: + # https://github.com/zwave-js/node-zwave-js/pull/3947 level: Literal["info", "warning", "error"] text: str From 3fde443f6ebc69ae58dd7eb2600390f94b3464aa Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:33:34 -0500 Subject: [PATCH 3/4] Fix typing --- test/model/test_node.py | 4 +++- zwave_js_server/model/device_config.py | 5 +++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/test/model/test_node.py b/test/model/test_node.py index 97e12b618..1e6502f96 100644 --- a/test/model/test_node.py +++ b/test/model/test_node.py @@ -102,7 +102,9 @@ async def test_highest_security_value(lock_schlage_be469, ring_keypad): assert ring_keypad.highest_security_class is None -async def test_device_config(wallmote_central_scene, climate_radio_thermostat_ct100_plus): +async def test_device_config( + wallmote_central_scene, climate_radio_thermostat_ct100_plus +): """Test a device config.""" node: node_pkg.Node = wallmote_central_scene diff --git a/zwave_js_server/model/device_config.py b/zwave_js_server/model/device_config.py index 74df34137..fd485e0b3 100644 --- a/zwave_js_server/model/device_config.py +++ b/zwave_js_server/model/device_config.py @@ -3,6 +3,7 @@ https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceconfig """ +from ctypes import cast from typing import Dict, List, Literal, Optional, TypedDict, Union @@ -113,8 +114,8 @@ def comments(self) -> List[CommentDataType]: """Return list of comments about device.""" comments = self.data.get("comments", []) if isinstance(comments, dict): - return [CommentDataType(**comments)] - return [CommentDataType(**comment) for comment in comments] + return [comments] + return comments class DeviceConfigDataType(TypedDict, total=False): From cf13627de505f019df7b4ab8c7c001fdb7ae5d92 Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Tue, 8 Feb 2022 17:33:46 -0500 Subject: [PATCH 4/4] remove unused import --- zwave_js_server/model/device_config.py | 1 - 1 file changed, 1 deletion(-) diff --git a/zwave_js_server/model/device_config.py b/zwave_js_server/model/device_config.py index fd485e0b3..116a15a96 100644 --- a/zwave_js_server/model/device_config.py +++ b/zwave_js_server/model/device_config.py @@ -3,7 +3,6 @@ https://zwave-js.github.io/node-zwave-js/#/api/node?id=deviceconfig """ -from ctypes import cast from typing import Dict, List, Literal, Optional, TypedDict, Union