pyvlx 0.2.27__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyvlx/__init__.py +21 -0
- pyvlx/api/__init__.py +23 -0
- pyvlx/api/activate_scene.py +63 -0
- pyvlx/api/api_event.py +73 -0
- pyvlx/api/command_send.py +85 -0
- pyvlx/api/factory_default.py +34 -0
- pyvlx/api/frame_creation.py +202 -0
- pyvlx/api/frames/__init__.py +76 -0
- pyvlx/api/frames/alias_array.py +45 -0
- pyvlx/api/frames/frame.py +56 -0
- pyvlx/api/frames/frame_activate_scene.py +92 -0
- pyvlx/api/frames/frame_activation_log_updated.py +14 -0
- pyvlx/api/frames/frame_command_send.py +280 -0
- pyvlx/api/frames/frame_discover_nodes.py +64 -0
- pyvlx/api/frames/frame_error_notification.py +42 -0
- pyvlx/api/frames/frame_facory_default.py +32 -0
- pyvlx/api/frames/frame_get_all_nodes_information.py +218 -0
- pyvlx/api/frames/frame_get_limitation.py +127 -0
- pyvlx/api/frames/frame_get_local_time.py +38 -0
- pyvlx/api/frames/frame_get_network_setup.py +64 -0
- pyvlx/api/frames/frame_get_node_information.py +223 -0
- pyvlx/api/frames/frame_get_protocol_version.py +53 -0
- pyvlx/api/frames/frame_get_scene_list.py +82 -0
- pyvlx/api/frames/frame_get_state.py +47 -0
- pyvlx/api/frames/frame_get_version.py +72 -0
- pyvlx/api/frames/frame_helper.py +40 -0
- pyvlx/api/frames/frame_house_status_monitor_disable_cfm.py +14 -0
- pyvlx/api/frames/frame_house_status_monitor_disable_req.py +14 -0
- pyvlx/api/frames/frame_house_status_monitor_enable_cfm.py +14 -0
- pyvlx/api/frames/frame_house_status_monitor_enable_req.py +14 -0
- pyvlx/api/frames/frame_leave_learn_state.py +41 -0
- pyvlx/api/frames/frame_node_information_changed.py +57 -0
- pyvlx/api/frames/frame_node_state_position_changed_notification.py +84 -0
- pyvlx/api/frames/frame_password_change.py +114 -0
- pyvlx/api/frames/frame_password_enter.py +70 -0
- pyvlx/api/frames/frame_reboot.py +32 -0
- pyvlx/api/frames/frame_set_node_name.py +73 -0
- pyvlx/api/frames/frame_set_utc.py +45 -0
- pyvlx/api/frames/frame_status_request.py +212 -0
- pyvlx/api/get_all_nodes_information.py +46 -0
- pyvlx/api/get_limitation.py +64 -0
- pyvlx/api/get_local_time.py +34 -0
- pyvlx/api/get_network_setup.py +34 -0
- pyvlx/api/get_node_information.py +42 -0
- pyvlx/api/get_protocol_version.py +40 -0
- pyvlx/api/get_scene_list.py +49 -0
- pyvlx/api/get_state.py +43 -0
- pyvlx/api/get_version.py +34 -0
- pyvlx/api/house_status_monitor.py +52 -0
- pyvlx/api/leave_learn_state.py +33 -0
- pyvlx/api/password_enter.py +39 -0
- pyvlx/api/reboot.py +33 -0
- pyvlx/api/session_id.py +20 -0
- pyvlx/api/set_node_name.py +32 -0
- pyvlx/api/set_utc.py +31 -0
- pyvlx/api/status_request.py +48 -0
- pyvlx/config.py +54 -0
- pyvlx/connection.py +182 -0
- pyvlx/const.py +685 -0
- pyvlx/dataobjects.py +161 -0
- pyvlx/discovery.py +100 -0
- pyvlx/exception.py +26 -0
- pyvlx/heartbeat.py +79 -0
- pyvlx/klf200gateway.py +167 -0
- pyvlx/lightening_device.py +102 -0
- pyvlx/log.py +4 -0
- pyvlx/node.py +74 -0
- pyvlx/node_helper.py +165 -0
- pyvlx/node_updater.py +162 -0
- pyvlx/nodes.py +99 -0
- pyvlx/on_off_switch.py +44 -0
- pyvlx/opening_device.py +644 -0
- pyvlx/parameter.py +357 -0
- pyvlx/py.typed +0 -0
- pyvlx/pyvlx.py +124 -0
- pyvlx/scene.py +53 -0
- pyvlx/scenes.py +60 -0
- pyvlx/slip.py +48 -0
- pyvlx/string_helper.py +20 -0
- pyvlx-0.2.27.dist-info/METADATA +122 -0
- pyvlx-0.2.27.dist-info/RECORD +84 -0
- pyvlx-0.2.27.dist-info/WHEEL +5 -0
- pyvlx-0.2.27.dist-info/licenses/LICENSE +165 -0
- pyvlx-0.2.27.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Module for password enter frame classes."""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from pyvlx.const import Command
|
|
6
|
+
from pyvlx.exception import PyVLXException
|
|
7
|
+
from pyvlx.string_helper import bytes_to_string, string_to_bytes
|
|
8
|
+
|
|
9
|
+
from .frame import FrameBase
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class FramePasswordEnterRequest(FrameBase):
|
|
13
|
+
"""Frame for sending password enter request."""
|
|
14
|
+
|
|
15
|
+
MAX_SIZE = 32
|
|
16
|
+
PAYLOAD_LEN = 32
|
|
17
|
+
|
|
18
|
+
def __init__(self, password: Optional[str] = None):
|
|
19
|
+
"""Init Frame."""
|
|
20
|
+
super().__init__(Command.GW_PASSWORD_ENTER_REQ)
|
|
21
|
+
self.password = password
|
|
22
|
+
|
|
23
|
+
def get_payload(self) -> bytes:
|
|
24
|
+
"""Return Payload."""
|
|
25
|
+
if self.password is None:
|
|
26
|
+
raise PyVLXException("password is none")
|
|
27
|
+
if len(self.password) > self.MAX_SIZE:
|
|
28
|
+
raise PyVLXException("password is too long")
|
|
29
|
+
return string_to_bytes(self.password, self.MAX_SIZE)
|
|
30
|
+
|
|
31
|
+
def from_payload(self, payload: bytes) -> None:
|
|
32
|
+
"""Init frame from binary data."""
|
|
33
|
+
self.password = bytes_to_string(payload)
|
|
34
|
+
|
|
35
|
+
def __str__(self) -> str:
|
|
36
|
+
"""Return human readable string."""
|
|
37
|
+
password_esc = (
|
|
38
|
+
None if self.password is None else "{}****".format(self.password[:2])
|
|
39
|
+
)
|
|
40
|
+
return '<{} password="{}"/>'.format(type(self).__name__, password_esc)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class PasswordEnterConfirmationStatus(Enum):
|
|
44
|
+
"""Enum class for status of password enter confirmation."""
|
|
45
|
+
|
|
46
|
+
SUCCESSFUL = 0
|
|
47
|
+
FAILED = 1
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class FramePasswordEnterConfirmation(FrameBase):
|
|
51
|
+
"""Frame for confirmation for sent password."""
|
|
52
|
+
|
|
53
|
+
PAYLOAD_LEN = 1
|
|
54
|
+
|
|
55
|
+
def __init__(self, status: PasswordEnterConfirmationStatus = PasswordEnterConfirmationStatus.SUCCESSFUL):
|
|
56
|
+
"""Init Frame."""
|
|
57
|
+
super().__init__(Command.GW_PASSWORD_ENTER_CFM)
|
|
58
|
+
self.status = status
|
|
59
|
+
|
|
60
|
+
def get_payload(self) -> bytes:
|
|
61
|
+
"""Return Payload."""
|
|
62
|
+
return bytes([self.status.value])
|
|
63
|
+
|
|
64
|
+
def from_payload(self, payload: bytes) -> None:
|
|
65
|
+
"""Init frame from binary data."""
|
|
66
|
+
self.status = PasswordEnterConfirmationStatus(payload[0])
|
|
67
|
+
|
|
68
|
+
def __str__(self) -> str:
|
|
69
|
+
"""Return human readable string."""
|
|
70
|
+
return '<{} status="{}"/>'.format(type(self).__name__, self.status)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Module for reboot frame classes."""
|
|
2
|
+
from pyvlx.const import Command
|
|
3
|
+
|
|
4
|
+
from .frame import FrameBase
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class FrameGatewayRebootRequest(FrameBase):
|
|
8
|
+
"""Frame for requesting reboot."""
|
|
9
|
+
|
|
10
|
+
PAYLOAD_LEN = 0
|
|
11
|
+
|
|
12
|
+
def __init__(self) -> None:
|
|
13
|
+
"""Init Frame."""
|
|
14
|
+
super().__init__(Command.GW_REBOOT_REQ)
|
|
15
|
+
|
|
16
|
+
def __str__(self) -> str:
|
|
17
|
+
"""Return human readable string."""
|
|
18
|
+
return '<{}/>'.format(type(self).__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class FrameGatewayRebootConfirmation(FrameBase):
|
|
22
|
+
"""Frame for response for reboot requests."""
|
|
23
|
+
|
|
24
|
+
PAYLOAD_LEN = 0
|
|
25
|
+
|
|
26
|
+
def __init__(self) -> None:
|
|
27
|
+
"""Init Frame."""
|
|
28
|
+
super().__init__(Command.GW_REBOOT_CFM)
|
|
29
|
+
|
|
30
|
+
def __str__(self) -> str:
|
|
31
|
+
"""Return human readable string."""
|
|
32
|
+
return '<{}/>'.format(type(self).__name__)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Module for requesting change of node name."""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from pyvlx.const import Command
|
|
6
|
+
from pyvlx.string_helper import bytes_to_string, string_to_bytes
|
|
7
|
+
|
|
8
|
+
from .frame import FrameBase
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class FrameSetNodeNameRequest(FrameBase):
|
|
12
|
+
"""Frame for requesting node name change."""
|
|
13
|
+
|
|
14
|
+
PAYLOAD_LEN = 65
|
|
15
|
+
|
|
16
|
+
def __init__(self, node_id: int = 0, name: Optional[str] = None):
|
|
17
|
+
"""Init Frame."""
|
|
18
|
+
super().__init__(Command.GW_SET_NODE_NAME_REQ)
|
|
19
|
+
self.node_id = node_id
|
|
20
|
+
self.name = name
|
|
21
|
+
|
|
22
|
+
def get_payload(self) -> bytes:
|
|
23
|
+
"""Return Payload."""
|
|
24
|
+
ret = bytes([self.node_id])
|
|
25
|
+
assert self.name is not None
|
|
26
|
+
ret += string_to_bytes(self.name, 64)
|
|
27
|
+
return ret
|
|
28
|
+
|
|
29
|
+
def from_payload(self, payload: bytes) -> None:
|
|
30
|
+
"""Init frame from binary data."""
|
|
31
|
+
self.node_id = payload[0]
|
|
32
|
+
self.name = bytes_to_string(payload[1:65])
|
|
33
|
+
|
|
34
|
+
def __str__(self) -> str:
|
|
35
|
+
"""Return human readable string."""
|
|
36
|
+
return '<{} node_id="{}" name="{}"/>'.format(
|
|
37
|
+
type(self).__name__, self.node_id, self.name
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class SetNodeNameConfirmationStatus(Enum):
|
|
42
|
+
"""Enum class for status of password enter confirmation."""
|
|
43
|
+
|
|
44
|
+
OK = 0
|
|
45
|
+
ERROR_REQUEST_REJECTED = 1
|
|
46
|
+
ERROR_INVALID_SYSTEM_TABLE_INDEX = 2
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class FrameSetNodeNameConfirmation(FrameBase):
|
|
50
|
+
"""Frame for confirmation for set node name."""
|
|
51
|
+
|
|
52
|
+
PAYLOAD_LEN = 2
|
|
53
|
+
|
|
54
|
+
def __init__(self, status: SetNodeNameConfirmationStatus = SetNodeNameConfirmationStatus.OK, node_id: int = 0):
|
|
55
|
+
"""Init Frame."""
|
|
56
|
+
super().__init__(Command.GW_SET_NODE_NAME_CFM)
|
|
57
|
+
self.status = status
|
|
58
|
+
self.node_id = node_id
|
|
59
|
+
|
|
60
|
+
def get_payload(self) -> bytes:
|
|
61
|
+
"""Return Payload."""
|
|
62
|
+
return bytes([self.status.value, self.node_id])
|
|
63
|
+
|
|
64
|
+
def from_payload(self, payload: bytes) -> None:
|
|
65
|
+
"""Init frame from binary data."""
|
|
66
|
+
self.status = SetNodeNameConfirmationStatus(payload[0])
|
|
67
|
+
self.node_id = payload[1]
|
|
68
|
+
|
|
69
|
+
def __str__(self) -> str:
|
|
70
|
+
"""Return human readable string."""
|
|
71
|
+
return '<{} node_id="{}" status="{}"/>'.format(
|
|
72
|
+
type(self).__name__, self.node_id, self.status
|
|
73
|
+
)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Module for sending command to gw."""
|
|
2
|
+
import struct
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
|
|
5
|
+
from pyvlx.const import Command
|
|
6
|
+
|
|
7
|
+
from .frame import FrameBase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FrameSetUTCConfirmation(FrameBase):
|
|
11
|
+
"""Frame for confirmation for setting UTC time."""
|
|
12
|
+
|
|
13
|
+
PAYLOAD_LEN = 0
|
|
14
|
+
|
|
15
|
+
def __init__(self) -> None:
|
|
16
|
+
"""Init Frame."""
|
|
17
|
+
super().__init__(Command.GW_SET_UTC_CFM)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class FrameSetUTCRequest(FrameBase):
|
|
21
|
+
"""Frame for command for setting UTC time."""
|
|
22
|
+
|
|
23
|
+
PAYLOAD_LEN = 4
|
|
24
|
+
|
|
25
|
+
def __init__(self, timestamp: float = 0):
|
|
26
|
+
"""Init Frame."""
|
|
27
|
+
super().__init__(Command.GW_SET_UTC_REQ)
|
|
28
|
+
self.timestamp = timestamp
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def timestamp_formatted(self) -> str:
|
|
32
|
+
"""Return time as human readable string."""
|
|
33
|
+
return datetime.fromtimestamp(self.timestamp).strftime("%Y-%m-%d %H:%M:%S")
|
|
34
|
+
|
|
35
|
+
def get_payload(self) -> bytes:
|
|
36
|
+
"""Return Payload."""
|
|
37
|
+
return struct.pack(">I", self.timestamp)
|
|
38
|
+
|
|
39
|
+
def from_payload(self, payload: bytes) -> None:
|
|
40
|
+
"""Init frame from binary data."""
|
|
41
|
+
self.timestamp = struct.unpack(">I", payload[0:4])[0]
|
|
42
|
+
|
|
43
|
+
def __str__(self) -> str:
|
|
44
|
+
"""Return human readable string."""
|
|
45
|
+
return '<{} time="{}"/>'.format(type(self).__name__, self.timestamp_formatted)
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
"""Module for get node information from gateway."""
|
|
2
|
+
from enum import Enum
|
|
3
|
+
from typing import Dict, List, Optional
|
|
4
|
+
|
|
5
|
+
from pyvlx.const import (
|
|
6
|
+
Command, NodeParameter, RunStatus, StatusReply, StatusType)
|
|
7
|
+
from pyvlx.exception import PyVLXException
|
|
8
|
+
from pyvlx.parameter import Parameter
|
|
9
|
+
|
|
10
|
+
from .frame import FrameBase
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class FrameStatusRequestRequest(FrameBase):
|
|
14
|
+
"""Frame for status request request."""
|
|
15
|
+
|
|
16
|
+
PAYLOAD_LEN = 26
|
|
17
|
+
|
|
18
|
+
def __init__(self, session_id: Optional[int] = None, node_ids: Optional[List[int]] = None):
|
|
19
|
+
"""Init Frame."""
|
|
20
|
+
super().__init__(Command.GW_STATUS_REQUEST_REQ)
|
|
21
|
+
self.session_id = session_id
|
|
22
|
+
self.node_ids = node_ids if node_ids is not None else []
|
|
23
|
+
self.status_type = StatusType.REQUEST_CURRENT_POSITION
|
|
24
|
+
self.fpi1 = 254 # Request FP1 to FP7
|
|
25
|
+
self.fpi2 = 0
|
|
26
|
+
|
|
27
|
+
def get_payload(self) -> bytes:
|
|
28
|
+
"""Return Payload."""
|
|
29
|
+
assert self.session_id is not None
|
|
30
|
+
ret = bytes([self.session_id >> 8 & 255, self.session_id & 255])
|
|
31
|
+
ret += bytes([len(self.node_ids)]) # index array count
|
|
32
|
+
ret += bytes(self.node_ids) + bytes(20 - len(self.node_ids))
|
|
33
|
+
ret += bytes([self.status_type.value])
|
|
34
|
+
ret += bytes([self.fpi1])
|
|
35
|
+
ret += bytes([self.fpi2])
|
|
36
|
+
return ret
|
|
37
|
+
|
|
38
|
+
def from_payload(self, payload: bytes) -> None:
|
|
39
|
+
"""Init frame from binary data."""
|
|
40
|
+
self.session_id = payload[0] * 256 + payload[1]
|
|
41
|
+
len_node_ids = payload[2]
|
|
42
|
+
if len_node_ids > 20:
|
|
43
|
+
raise PyVLXException("command_send_request_wrong_node_length")
|
|
44
|
+
self.node_ids = []
|
|
45
|
+
for i in range(len_node_ids):
|
|
46
|
+
self.node_ids.append(payload[3] + i)
|
|
47
|
+
|
|
48
|
+
self.status_type = StatusType(payload[23])
|
|
49
|
+
self.fpi1 = payload[24]
|
|
50
|
+
self.fpi2 = payload[25]
|
|
51
|
+
|
|
52
|
+
def __str__(self) -> str:
|
|
53
|
+
"""Return human readable string."""
|
|
54
|
+
return (
|
|
55
|
+
'<{} session_id="{}" node_ids="{}" '
|
|
56
|
+
'status_type="{}" fpi1="{}" fpi2="{}"/>'.format(
|
|
57
|
+
type(self).__name__, self.session_id,
|
|
58
|
+
self.node_ids,
|
|
59
|
+
self.status_type, self.fpi1, self.fpi2
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class StatusRequestStatus(Enum):
|
|
65
|
+
"""Enum for status request status."""
|
|
66
|
+
|
|
67
|
+
REJECTED = 0
|
|
68
|
+
ACCEPTED = 1
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class FrameStatusRequestConfirmation(FrameBase):
|
|
72
|
+
"""Frame for confirmation for status request request."""
|
|
73
|
+
|
|
74
|
+
PAYLOAD_LEN = 3
|
|
75
|
+
|
|
76
|
+
def __init__(self, session_id: Optional[int] = None, status: Optional[StatusRequestStatus] = None):
|
|
77
|
+
"""Init Frame."""
|
|
78
|
+
super().__init__(Command.GW_STATUS_REQUEST_CFM)
|
|
79
|
+
self.session_id = session_id
|
|
80
|
+
self.status = status
|
|
81
|
+
|
|
82
|
+
def get_payload(self) -> bytes:
|
|
83
|
+
"""Return Payload."""
|
|
84
|
+
assert self.session_id is not None
|
|
85
|
+
ret = bytes([self.session_id >> 8 & 255, self.session_id & 255])
|
|
86
|
+
assert self.status is not None
|
|
87
|
+
ret += bytes([self.status.value])
|
|
88
|
+
return ret
|
|
89
|
+
|
|
90
|
+
def from_payload(self, payload: bytes) -> None:
|
|
91
|
+
"""Init frame from binary data."""
|
|
92
|
+
self.session_id = payload[0] * 256 + payload[1]
|
|
93
|
+
self.status = StatusRequestStatus(payload[2])
|
|
94
|
+
|
|
95
|
+
def __str__(self) -> str:
|
|
96
|
+
"""Return human readable string."""
|
|
97
|
+
return '<{} session_id="{}" status="{}"/>'.format(
|
|
98
|
+
type(self).__name__, self.session_id, self.status
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class FrameStatusRequestNotification(FrameBase):
|
|
103
|
+
"""Frame for notification of status request request."""
|
|
104
|
+
|
|
105
|
+
# PAYLOAD_LEN = 59
|
|
106
|
+
# No PAYLOAD_LEN because it is variable depending on StatusType
|
|
107
|
+
|
|
108
|
+
def __init__(self) -> None:
|
|
109
|
+
"""Init Frame."""
|
|
110
|
+
super().__init__(Command.GW_STATUS_REQUEST_NTF)
|
|
111
|
+
self.session_id = 0
|
|
112
|
+
self.status_id = 0
|
|
113
|
+
self.node_id = 0
|
|
114
|
+
self.run_status = RunStatus.EXECUTION_COMPLETED
|
|
115
|
+
self.status_reply = StatusReply.UNKNOWN_STATUS_REPLY
|
|
116
|
+
self.status_type = StatusType.REQUEST_TARGET_POSITION
|
|
117
|
+
self.status_count = 0
|
|
118
|
+
self.parameter_data: Dict[NodeParameter, Parameter] = {}
|
|
119
|
+
self.target_position = Parameter()
|
|
120
|
+
self.current_position = Parameter()
|
|
121
|
+
self.remaining_time = 0
|
|
122
|
+
self.last_master_execution_address = b''
|
|
123
|
+
self.last_command_originator = 0
|
|
124
|
+
|
|
125
|
+
def get_payload(self) -> bytes:
|
|
126
|
+
"""Return Payload."""
|
|
127
|
+
payload = bytes()
|
|
128
|
+
payload += bytes([self.session_id >> 8 & 255, self.session_id & 255])
|
|
129
|
+
payload += bytes([self.status_id])
|
|
130
|
+
payload += bytes([self.node_id])
|
|
131
|
+
payload += bytes([self.run_status.value])
|
|
132
|
+
payload += bytes([self.status_reply.value])
|
|
133
|
+
payload += bytes([self.status_type.value])
|
|
134
|
+
if self.status_type == StatusType.REQUEST_MAIN_INFO:
|
|
135
|
+
payload += bytes(self.target_position.raw)
|
|
136
|
+
payload += bytes(self.current_position.raw)
|
|
137
|
+
payload += bytes([self.remaining_time >> 8 & 255, self.remaining_time & 255])
|
|
138
|
+
payload += self.last_master_execution_address
|
|
139
|
+
payload += bytes([self.last_command_originator])
|
|
140
|
+
else:
|
|
141
|
+
payload += bytes([self.status_count])
|
|
142
|
+
keys = self.parameter_data.keys()
|
|
143
|
+
for key in keys:
|
|
144
|
+
payload += bytes([key.value])
|
|
145
|
+
payload += bytes(self.parameter_data[key].raw)
|
|
146
|
+
payload += bytes(51 - len(self.parameter_data))
|
|
147
|
+
|
|
148
|
+
return payload
|
|
149
|
+
|
|
150
|
+
def from_payload(self, payload: bytes) -> None:
|
|
151
|
+
"""Init frame from binary data."""
|
|
152
|
+
self.session_id = payload[0] * 256 + payload[1]
|
|
153
|
+
self.status_id = payload[2]
|
|
154
|
+
self.node_id = payload[3]
|
|
155
|
+
self.run_status = RunStatus(payload[4])
|
|
156
|
+
self.status_reply = StatusReply(payload[5])
|
|
157
|
+
self.status_type = StatusType(payload[6])
|
|
158
|
+
if self.status_type == StatusType.REQUEST_MAIN_INFO:
|
|
159
|
+
self.target_position = Parameter(payload[7:8])
|
|
160
|
+
self.current_position = Parameter(payload[9:10])
|
|
161
|
+
self.remaining_time = payload[11] * 256 + payload[12]
|
|
162
|
+
self.last_master_execution_address = payload[13:16]
|
|
163
|
+
self.last_command_originator = payload[17]
|
|
164
|
+
else:
|
|
165
|
+
self.status_count = payload[7]
|
|
166
|
+
for i in range(8, 8 + self.status_count*3, 3):
|
|
167
|
+
self.parameter_data.update({NodeParameter(payload[i]): Parameter(payload[i+1:i+3])})
|
|
168
|
+
|
|
169
|
+
def __str__(self) -> str:
|
|
170
|
+
"""Return human readable string."""
|
|
171
|
+
if self.status_type == StatusType.REQUEST_MAIN_INFO:
|
|
172
|
+
return (
|
|
173
|
+
'<{} session_id="{}" status_id="{}" '
|
|
174
|
+
'node_id="{}" run_status="{}" status_reply="{}" status_type="{}" target_position="{}" '
|
|
175
|
+
'current_position="{}" remaining_time="{}" last_master_execution_address="{!r}" last_command_originator="{}"/>'.format(
|
|
176
|
+
type(self).__name__,
|
|
177
|
+
self.session_id,
|
|
178
|
+
self.status_id,
|
|
179
|
+
self.node_id,
|
|
180
|
+
self.run_status,
|
|
181
|
+
self.status_reply,
|
|
182
|
+
self.status_type,
|
|
183
|
+
self.target_position,
|
|
184
|
+
self.current_position,
|
|
185
|
+
self.remaining_time,
|
|
186
|
+
self.last_master_execution_address,
|
|
187
|
+
self.last_command_originator,
|
|
188
|
+
)
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
parameter_data_str = ""
|
|
192
|
+
for key, value in self.parameter_data.items():
|
|
193
|
+
parameter_data_str += "%s: %s, " % (
|
|
194
|
+
str(key),
|
|
195
|
+
str(value),
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
return (
|
|
199
|
+
'<{} session_id="{}" status_id="{}" '
|
|
200
|
+
'node_id="{}" run_status="{}" status_reply="{}" status_type="{}" status_count="{}" '
|
|
201
|
+
'parameter_data="{}"/>'.format(
|
|
202
|
+
type(self).__name__,
|
|
203
|
+
self.session_id,
|
|
204
|
+
self.status_id,
|
|
205
|
+
self.node_id,
|
|
206
|
+
self.run_status,
|
|
207
|
+
self.status_reply,
|
|
208
|
+
self.status_type,
|
|
209
|
+
self.status_count,
|
|
210
|
+
parameter_data_str
|
|
211
|
+
)
|
|
212
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Module for retrieving node information from API."""
|
|
2
|
+
from typing import TYPE_CHECKING, List
|
|
3
|
+
|
|
4
|
+
from pyvlx.log import PYVLXLOG
|
|
5
|
+
|
|
6
|
+
from .api_event import ApiEvent
|
|
7
|
+
from .frames import (
|
|
8
|
+
FrameBase, FrameGetAllNodesInformationConfirmation,
|
|
9
|
+
FrameGetAllNodesInformationFinishedNotification,
|
|
10
|
+
FrameGetAllNodesInformationNotification,
|
|
11
|
+
FrameGetAllNodesInformationRequest)
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pyvlx import PyVLX
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GetAllNodesInformation(ApiEvent):
|
|
18
|
+
"""Class for retrieving node information from API."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, pyvlx: "PyVLX"):
|
|
21
|
+
"""Initialize SceneList class."""
|
|
22
|
+
super().__init__(pyvlx=pyvlx)
|
|
23
|
+
self.number_of_nodes = 0
|
|
24
|
+
self.success = False
|
|
25
|
+
self.notification_frames: List[FrameGetAllNodesInformationNotification] = []
|
|
26
|
+
|
|
27
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
28
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
29
|
+
if isinstance(frame, FrameGetAllNodesInformationConfirmation):
|
|
30
|
+
self.number_of_nodes = frame.number_of_nodes
|
|
31
|
+
# We are still waiting for FrameGetAllNodesInformationNotification
|
|
32
|
+
return False
|
|
33
|
+
if isinstance(frame, FrameGetAllNodesInformationNotification):
|
|
34
|
+
self.notification_frames.append(frame)
|
|
35
|
+
if isinstance(frame, FrameGetAllNodesInformationFinishedNotification):
|
|
36
|
+
if self.number_of_nodes != len(self.notification_frames):
|
|
37
|
+
PYVLXLOG.warning(
|
|
38
|
+
"Number of received scenes does not match expected number"
|
|
39
|
+
)
|
|
40
|
+
self.success = True
|
|
41
|
+
return True
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
def request_frame(self) -> FrameGetAllNodesInformationRequest:
|
|
45
|
+
"""Construct initiating frame."""
|
|
46
|
+
return FrameGetAllNodesInformationRequest()
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""Module for retrieving limitation value from API."""
|
|
2
|
+
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
|
+
|
|
5
|
+
from ..const import LimitationType, Originator
|
|
6
|
+
from ..parameter import Position
|
|
7
|
+
from .api_event import ApiEvent
|
|
8
|
+
from .frames import (
|
|
9
|
+
FrameBase, FrameGetLimitationStatus, FrameGetLimitationStatusConfirmation,
|
|
10
|
+
FrameGetLimitationStatusNotification)
|
|
11
|
+
from .session_id import get_new_session_id
|
|
12
|
+
|
|
13
|
+
if TYPE_CHECKING:
|
|
14
|
+
from pyvlx import PyVLX
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GetLimitation(ApiEvent):
|
|
18
|
+
"""Class for retrieving gateway state from API."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, pyvlx: "PyVLX", node_id: int, limitation_type: LimitationType = LimitationType.MIN_LIMITATION):
|
|
21
|
+
"""Initialize SceneList class."""
|
|
22
|
+
super().__init__(pyvlx=pyvlx)
|
|
23
|
+
self.node_id = node_id
|
|
24
|
+
self.limitation_type = limitation_type
|
|
25
|
+
self.success = False
|
|
26
|
+
self.notification_frame: Optional[FrameGetLimitationStatusNotification] = None
|
|
27
|
+
self.session_id: Optional[int] = None
|
|
28
|
+
self.min_value_raw: Optional[bytes] = None
|
|
29
|
+
self.max_value_raw: Optional[bytes] = None
|
|
30
|
+
self.originator: Optional[Originator] = None
|
|
31
|
+
self.limit_time: Optional[int] = None
|
|
32
|
+
|
|
33
|
+
@property
|
|
34
|
+
def max_value(self) -> int:
|
|
35
|
+
"""Return max value."""
|
|
36
|
+
assert self.max_value_raw is not None
|
|
37
|
+
return Position.to_percent(self.max_value_raw)
|
|
38
|
+
|
|
39
|
+
@property
|
|
40
|
+
def min_value(self) -> int:
|
|
41
|
+
"""Return min value."""
|
|
42
|
+
assert self.min_value_raw is not None
|
|
43
|
+
return Position.to_percent(self.min_value_raw)
|
|
44
|
+
|
|
45
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
46
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
47
|
+
if isinstance(frame, FrameGetLimitationStatusConfirmation):
|
|
48
|
+
return False # Wait for Notification Frame
|
|
49
|
+
if isinstance(frame, FrameGetLimitationStatusNotification):
|
|
50
|
+
if frame.session_id == self.session_id:
|
|
51
|
+
self.success = True
|
|
52
|
+
self.min_value_raw = frame.min_value
|
|
53
|
+
self.max_value_raw = frame.max_value
|
|
54
|
+
self.originator = frame.limit_originator
|
|
55
|
+
self.limit_time = frame.limit_time
|
|
56
|
+
self.notification_frame = frame
|
|
57
|
+
return True
|
|
58
|
+
return False
|
|
59
|
+
|
|
60
|
+
def request_frame(self) -> FrameGetLimitationStatus:
|
|
61
|
+
"""Construct initiating frame."""
|
|
62
|
+
self.session_id = get_new_session_id()
|
|
63
|
+
return FrameGetLimitationStatus(node_ids=[self.node_id], session_id=self.session_id,
|
|
64
|
+
limitation_type=self.limitation_type)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Module for local time firmware version from API."""
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from pyvlx.dataobjects import DtoLocalTime
|
|
5
|
+
|
|
6
|
+
from .api_event import ApiEvent
|
|
7
|
+
from .frames import (
|
|
8
|
+
FrameBase, FrameGetLocalTimeConfirmation, FrameGetLocalTimeRequest)
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from pyvlx import PyVLX
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GetLocalTime(ApiEvent):
|
|
15
|
+
"""Class for retrieving firmware version from API."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, pyvlx: "PyVLX"):
|
|
18
|
+
"""Initialize GetLocalTime class."""
|
|
19
|
+
super().__init__(pyvlx=pyvlx)
|
|
20
|
+
self.success = False
|
|
21
|
+
self.localtime = DtoLocalTime()
|
|
22
|
+
|
|
23
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
24
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
25
|
+
if not isinstance(frame, FrameGetLocalTimeConfirmation):
|
|
26
|
+
return False
|
|
27
|
+
self.localtime = frame.time
|
|
28
|
+
self.success = True
|
|
29
|
+
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
def request_frame(self) -> FrameGetLocalTimeRequest:
|
|
33
|
+
"""Construct initiating frame."""
|
|
34
|
+
return FrameGetLocalTimeRequest()
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Module for retrieving gateway state from API."""
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from pyvlx.dataobjects import DtoNetworkSetup
|
|
5
|
+
|
|
6
|
+
from .api_event import ApiEvent
|
|
7
|
+
from .frames import (
|
|
8
|
+
FrameBase, FrameGetNetworkSetupConfirmation, FrameGetNetworkSetupRequest)
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from pyvlx import PyVLX
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class GetNetworkSetup(ApiEvent):
|
|
15
|
+
"""Class for retrieving gateway state from API."""
|
|
16
|
+
|
|
17
|
+
def __init__(self, pyvlx: "PyVLX"):
|
|
18
|
+
"""Initialize GetNetworkSetup class."""
|
|
19
|
+
super().__init__(pyvlx=pyvlx)
|
|
20
|
+
self.success = False
|
|
21
|
+
self.networksetup = DtoNetworkSetup()
|
|
22
|
+
|
|
23
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
24
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
25
|
+
if not isinstance(frame, FrameGetNetworkSetupConfirmation):
|
|
26
|
+
return False
|
|
27
|
+
self.success = True
|
|
28
|
+
self.networksetup = DtoNetworkSetup(
|
|
29
|
+
frame.ipaddress, frame.gateway, frame.netmask, frame.dhcp)
|
|
30
|
+
return True
|
|
31
|
+
|
|
32
|
+
def request_frame(self) -> FrameGetNetworkSetupRequest:
|
|
33
|
+
"""Construct initiating frame."""
|
|
34
|
+
return FrameGetNetworkSetupRequest()
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Module for retrieving node information from API."""
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
|
|
4
|
+
from .api_event import ApiEvent
|
|
5
|
+
from .frames import (
|
|
6
|
+
FrameBase, FrameGetNodeInformationConfirmation,
|
|
7
|
+
FrameGetNodeInformationNotification, FrameGetNodeInformationRequest)
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from pyvlx import PyVLX
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class GetNodeInformation(ApiEvent):
|
|
14
|
+
"""Class for retrieving node informationfrom API."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, pyvlx: "PyVLX", node_id: int):
|
|
17
|
+
"""Initialize SceneList class."""
|
|
18
|
+
super().__init__(pyvlx=pyvlx)
|
|
19
|
+
self.node_id = node_id
|
|
20
|
+
self.success = False
|
|
21
|
+
self.notification_frame: Optional[FrameGetNodeInformationNotification] = None
|
|
22
|
+
|
|
23
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
24
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
25
|
+
if (
|
|
26
|
+
isinstance(frame, FrameGetNodeInformationConfirmation)
|
|
27
|
+
and frame.node_id == self.node_id
|
|
28
|
+
):
|
|
29
|
+
# We are still waiting for GetNodeInformationNotification
|
|
30
|
+
return False
|
|
31
|
+
if (
|
|
32
|
+
isinstance(frame, FrameGetNodeInformationNotification)
|
|
33
|
+
and frame.node_id == self.node_id
|
|
34
|
+
):
|
|
35
|
+
self.notification_frame = frame
|
|
36
|
+
self.success = True
|
|
37
|
+
return True
|
|
38
|
+
return False
|
|
39
|
+
|
|
40
|
+
def request_frame(self) -> FrameGetNodeInformationRequest:
|
|
41
|
+
"""Construct initiating frame."""
|
|
42
|
+
return FrameGetNodeInformationRequest(node_id=self.node_id)
|