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
pyvlx/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Module for accessing KLF 200 gateway with python."""
|
|
2
|
+
|
|
3
|
+
from .discovery import VeluxDiscovery
|
|
4
|
+
from .exception import PyVLXException
|
|
5
|
+
from .klf200gateway import Klf200Gateway
|
|
6
|
+
from .lightening_device import Light, LighteningDevice
|
|
7
|
+
from .log import PYVLXLOG
|
|
8
|
+
from .node import Node
|
|
9
|
+
from .nodes import Nodes
|
|
10
|
+
from .on_off_switch import OnOffSwitch
|
|
11
|
+
from .opening_device import (
|
|
12
|
+
Awning, Blade, Blind, GarageDoor, Gate, OpeningDevice, RollerShutter,
|
|
13
|
+
Window)
|
|
14
|
+
from .parameter import (
|
|
15
|
+
CurrentIntensity, CurrentPosition, Intensity, Parameter, Position,
|
|
16
|
+
SwitchParameter, SwitchParameterOff, SwitchParameterOn, UnknownIntensity,
|
|
17
|
+
UnknownPosition)
|
|
18
|
+
# flake8: noqa
|
|
19
|
+
from .pyvlx import PyVLX
|
|
20
|
+
from .scene import Scene
|
|
21
|
+
from .scenes import Scenes
|
pyvlx/api/__init__.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Module for all KLF 200 API frames."""
|
|
2
|
+
# flake8: noqa
|
|
3
|
+
|
|
4
|
+
from .activate_scene import ActivateScene
|
|
5
|
+
from .api_event import ApiEvent
|
|
6
|
+
from .command_send import CommandSend
|
|
7
|
+
from .factory_default import FactoryDefault
|
|
8
|
+
from .get_all_nodes_information import GetAllNodesInformation
|
|
9
|
+
from .get_local_time import (
|
|
10
|
+
FrameGetLocalTimeConfirmation, FrameGetLocalTimeRequest, GetLocalTime)
|
|
11
|
+
from .get_network_setup import GetNetworkSetup
|
|
12
|
+
from .get_node_information import GetNodeInformation
|
|
13
|
+
from .get_protocol_version import GetProtocolVersion
|
|
14
|
+
from .get_scene_list import GetSceneList
|
|
15
|
+
from .get_state import GetState
|
|
16
|
+
from .get_version import GetVersion
|
|
17
|
+
from .house_status_monitor import (
|
|
18
|
+
HouseStatusMonitorDisable, HouseStatusMonitorEnable)
|
|
19
|
+
from .leave_learn_state import LeaveLearnState
|
|
20
|
+
from .password_enter import PasswordEnter
|
|
21
|
+
from .reboot import Reboot
|
|
22
|
+
from .set_node_name import SetNodeName
|
|
23
|
+
from .set_utc import SetUTC
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"""Module for retrieving scene list from API."""
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
|
+
|
|
4
|
+
from .api_event import ApiEvent
|
|
5
|
+
from .frames import (
|
|
6
|
+
ActivateSceneConfirmationStatus, FrameActivateSceneConfirmation,
|
|
7
|
+
FrameActivateSceneRequest, FrameBase,
|
|
8
|
+
FrameCommandRemainingTimeNotification, FrameCommandRunStatusNotification,
|
|
9
|
+
FrameSessionFinishedNotification)
|
|
10
|
+
from .session_id import get_new_session_id
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from pyvlx import PyVLX
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class ActivateScene(ApiEvent):
|
|
17
|
+
"""Class for activating scene via API."""
|
|
18
|
+
|
|
19
|
+
def __init__(
|
|
20
|
+
self, pyvlx: "PyVLX", scene_id: int, wait_for_completion: bool = True, timeout_in_seconds: int = 60
|
|
21
|
+
):
|
|
22
|
+
"""Initialize SceneList class."""
|
|
23
|
+
super().__init__(pyvlx=pyvlx, timeout_in_seconds=timeout_in_seconds)
|
|
24
|
+
self.success = False
|
|
25
|
+
self.scene_id = scene_id
|
|
26
|
+
self.wait_for_completion = wait_for_completion
|
|
27
|
+
self.session_id: Optional[int] = None
|
|
28
|
+
|
|
29
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
30
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
31
|
+
if (
|
|
32
|
+
isinstance(frame, FrameActivateSceneConfirmation)
|
|
33
|
+
and frame.session_id == self.session_id
|
|
34
|
+
):
|
|
35
|
+
if frame.status == ActivateSceneConfirmationStatus.ACCEPTED:
|
|
36
|
+
self.success = True
|
|
37
|
+
return not self.wait_for_completion
|
|
38
|
+
if (
|
|
39
|
+
isinstance(frame, FrameCommandRemainingTimeNotification)
|
|
40
|
+
and frame.session_id == self.session_id
|
|
41
|
+
):
|
|
42
|
+
# Ignoring FrameCommandRemainingTimeNotification
|
|
43
|
+
return False
|
|
44
|
+
if (
|
|
45
|
+
isinstance(frame, FrameCommandRunStatusNotification)
|
|
46
|
+
and frame.session_id == self.session_id
|
|
47
|
+
):
|
|
48
|
+
# At the moment I don't reall understand what the FrameCommandRunStatusNotification is good for.
|
|
49
|
+
# Ignoring these packets for now
|
|
50
|
+
return False
|
|
51
|
+
if (
|
|
52
|
+
isinstance(frame, FrameSessionFinishedNotification)
|
|
53
|
+
and frame.session_id == self.session_id
|
|
54
|
+
):
|
|
55
|
+
return True
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
def request_frame(self) -> FrameActivateSceneRequest:
|
|
59
|
+
"""Construct initiating frame."""
|
|
60
|
+
self.session_id = get_new_session_id()
|
|
61
|
+
return FrameActivateSceneRequest(
|
|
62
|
+
scene_id=self.scene_id, session_id=self.session_id
|
|
63
|
+
)
|
pyvlx/api/api_event.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Base class for waiting for a specific answer frame from velux ap.."""
|
|
2
|
+
import asyncio
|
|
3
|
+
from typing import TYPE_CHECKING, Optional
|
|
4
|
+
|
|
5
|
+
from .frames import FrameBase
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from pyvlx import PyVLX
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ApiEvent:
|
|
12
|
+
"""Base class for waiting a specific frame from API connection."""
|
|
13
|
+
|
|
14
|
+
def __init__(self, pyvlx: "PyVLX", timeout_in_seconds: int = 10):
|
|
15
|
+
"""Initialize ApiEvent."""
|
|
16
|
+
self.pyvlx = pyvlx
|
|
17
|
+
self.response_received_or_timeout = asyncio.Event()
|
|
18
|
+
|
|
19
|
+
self.success = False
|
|
20
|
+
self.timeout_in_seconds = timeout_in_seconds
|
|
21
|
+
self.timeout_callback = None
|
|
22
|
+
self.timeout_handle: Optional[asyncio.TimerHandle] = None
|
|
23
|
+
|
|
24
|
+
async def do_api_call(self) -> None:
|
|
25
|
+
"""Start. Sending and waiting for answer."""
|
|
26
|
+
# We check for connection before entering the semaphore section
|
|
27
|
+
# because otherwise we might try to connect, which calls this, and we get stuck on
|
|
28
|
+
# the semaphore.
|
|
29
|
+
await self.pyvlx.check_connected()
|
|
30
|
+
|
|
31
|
+
if self.pyvlx.get_connected():
|
|
32
|
+
async with self.pyvlx.api_call_semaphore:
|
|
33
|
+
self.pyvlx.connection.register_frame_received_cb(self.response_rec_callback)
|
|
34
|
+
await self.send_frame()
|
|
35
|
+
await self.start_timeout()
|
|
36
|
+
await self.response_received_or_timeout.wait()
|
|
37
|
+
self.response_received_or_timeout.clear()
|
|
38
|
+
await self.stop_timeout()
|
|
39
|
+
self.pyvlx.connection.unregister_frame_received_cb(self.response_rec_callback)
|
|
40
|
+
else:
|
|
41
|
+
self.success = False
|
|
42
|
+
|
|
43
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
44
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
45
|
+
raise NotImplementedError("handle_frame has to be implemented")
|
|
46
|
+
|
|
47
|
+
async def send_frame(self) -> None:
|
|
48
|
+
"""Send frame to API connection."""
|
|
49
|
+
await self.pyvlx.send_frame(self.request_frame())
|
|
50
|
+
|
|
51
|
+
def request_frame(self) -> FrameBase:
|
|
52
|
+
"""Construct initiating frame."""
|
|
53
|
+
raise NotImplementedError("send_frame has to be implemented")
|
|
54
|
+
|
|
55
|
+
async def response_rec_callback(self, frame: FrameBase) -> None:
|
|
56
|
+
"""Handle frame. Callback from internal api connection."""
|
|
57
|
+
if await self.handle_frame(frame):
|
|
58
|
+
self.response_received_or_timeout.set()
|
|
59
|
+
|
|
60
|
+
def timeout(self) -> None:
|
|
61
|
+
"""Handle timeout for not having received expected frame."""
|
|
62
|
+
self.response_received_or_timeout.set()
|
|
63
|
+
|
|
64
|
+
async def start_timeout(self) -> None:
|
|
65
|
+
"""Start timeout."""
|
|
66
|
+
self.timeout_handle = self.pyvlx.connection.loop.call_later(
|
|
67
|
+
self.timeout_in_seconds, self.timeout
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
async def stop_timeout(self) -> None:
|
|
71
|
+
"""Stop timeout."""
|
|
72
|
+
if self.timeout_handle is not None:
|
|
73
|
+
self.timeout_handle.cancel()
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""Module for retrieving scene list from API."""
|
|
2
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
3
|
+
|
|
4
|
+
from ..exception import PyVLXException
|
|
5
|
+
from ..parameter import Parameter
|
|
6
|
+
from .api_event import ApiEvent
|
|
7
|
+
from .frames import (
|
|
8
|
+
CommandSendConfirmationStatus, FrameBase,
|
|
9
|
+
FrameCommandRemainingTimeNotification, FrameCommandRunStatusNotification,
|
|
10
|
+
FrameCommandSendConfirmation, FrameCommandSendRequest,
|
|
11
|
+
FrameSessionFinishedNotification)
|
|
12
|
+
from .session_id import get_new_session_id
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from pyvlx import PyVLX
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class CommandSend(ApiEvent):
|
|
19
|
+
"""Class for sending command to API."""
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
pyvlx: "PyVLX",
|
|
24
|
+
node_id: int,
|
|
25
|
+
parameter: Parameter,
|
|
26
|
+
active_parameter: int = 0,
|
|
27
|
+
wait_for_completion: bool = True,
|
|
28
|
+
timeout_in_seconds: int = 2,
|
|
29
|
+
**functional_parameter: Any
|
|
30
|
+
):
|
|
31
|
+
"""Initialize SceneList class."""
|
|
32
|
+
super().__init__(pyvlx=pyvlx, timeout_in_seconds=timeout_in_seconds)
|
|
33
|
+
self.success = False
|
|
34
|
+
self.node_id = node_id
|
|
35
|
+
self.parameter = parameter
|
|
36
|
+
self.active_parameter = active_parameter
|
|
37
|
+
self.functional_parameter = functional_parameter
|
|
38
|
+
self.wait_for_completion = wait_for_completion
|
|
39
|
+
self.session_id: Optional[int] = None
|
|
40
|
+
|
|
41
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
42
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
43
|
+
if (
|
|
44
|
+
isinstance(frame, FrameCommandSendConfirmation)
|
|
45
|
+
and frame.session_id == self.session_id
|
|
46
|
+
):
|
|
47
|
+
if frame.status == CommandSendConfirmationStatus.ACCEPTED:
|
|
48
|
+
self.success = True
|
|
49
|
+
return not self.wait_for_completion
|
|
50
|
+
if (
|
|
51
|
+
isinstance(frame, FrameCommandRemainingTimeNotification)
|
|
52
|
+
and frame.session_id == self.session_id
|
|
53
|
+
):
|
|
54
|
+
# Ignoring FrameCommandRemainingTimeNotification
|
|
55
|
+
return False
|
|
56
|
+
if (
|
|
57
|
+
isinstance(frame, FrameCommandRunStatusNotification)
|
|
58
|
+
and frame.session_id == self.session_id
|
|
59
|
+
):
|
|
60
|
+
# At the moment I don't reall understand what the FrameCommandRunStatusNotification is good for.
|
|
61
|
+
# Ignoring these packets for now
|
|
62
|
+
return False
|
|
63
|
+
if (
|
|
64
|
+
isinstance(frame, FrameSessionFinishedNotification)
|
|
65
|
+
and frame.session_id == self.session_id
|
|
66
|
+
):
|
|
67
|
+
return True
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
async def send(self) -> None:
|
|
71
|
+
"""Send frame to KLF200."""
|
|
72
|
+
await self.do_api_call()
|
|
73
|
+
if not self.success:
|
|
74
|
+
raise PyVLXException("Unable to send command")
|
|
75
|
+
|
|
76
|
+
def request_frame(self) -> FrameCommandSendRequest:
|
|
77
|
+
"""Construct initiating frame."""
|
|
78
|
+
self.session_id = get_new_session_id()
|
|
79
|
+
return FrameCommandSendRequest(
|
|
80
|
+
node_ids=[self.node_id],
|
|
81
|
+
parameter=self.parameter,
|
|
82
|
+
active_parameter=self.active_parameter,
|
|
83
|
+
session_id=self.session_id,
|
|
84
|
+
**self.functional_parameter
|
|
85
|
+
)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Module for handling the FactoryDefault to API."""
|
|
2
|
+
from typing import TYPE_CHECKING
|
|
3
|
+
|
|
4
|
+
from pyvlx.log import PYVLXLOG
|
|
5
|
+
|
|
6
|
+
from .api_event import ApiEvent
|
|
7
|
+
from .frames import (
|
|
8
|
+
FrameBase, FrameGatewayFactoryDefaultConfirmation,
|
|
9
|
+
FrameGatewayFactoryDefaultRequest)
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from pyvlx import PyVLX
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class FactoryDefault(ApiEvent):
|
|
16
|
+
"""Class for handling Factory reset API."""
|
|
17
|
+
|
|
18
|
+
def __init__(self, pyvlx: "PyVLX"):
|
|
19
|
+
"""Initialize facotry default class."""
|
|
20
|
+
super().__init__(pyvlx=pyvlx)
|
|
21
|
+
self.pyvlx = pyvlx
|
|
22
|
+
self.success = False
|
|
23
|
+
|
|
24
|
+
async def handle_frame(self, frame: FrameBase) -> bool:
|
|
25
|
+
"""Handle incoming API frame, return True if this was the expected frame."""
|
|
26
|
+
if isinstance(frame, FrameGatewayFactoryDefaultConfirmation):
|
|
27
|
+
PYVLXLOG.warning("KLF200 is factory resetting")
|
|
28
|
+
self.success = True
|
|
29
|
+
return True
|
|
30
|
+
return False
|
|
31
|
+
|
|
32
|
+
def request_frame(self) -> FrameGatewayFactoryDefaultRequest:
|
|
33
|
+
"""Construct initiating frame."""
|
|
34
|
+
return FrameGatewayFactoryDefaultRequest()
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
"""Helper module for creating a frame out of raw data."""
|
|
2
|
+
from typing import Optional
|
|
3
|
+
|
|
4
|
+
from pyvlx.const import Command
|
|
5
|
+
from pyvlx.log import PYVLXLOG
|
|
6
|
+
|
|
7
|
+
from .frames import (
|
|
8
|
+
FrameActivateSceneConfirmation, FrameActivateSceneRequest,
|
|
9
|
+
FrameActivationLogUpdatedNotification, FrameBase,
|
|
10
|
+
FrameCommandRemainingTimeNotification, FrameCommandRunStatusNotification,
|
|
11
|
+
FrameCommandSendConfirmation, FrameCommandSendRequest,
|
|
12
|
+
FrameDiscoverNodesConfirmation, FrameDiscoverNodesNotification,
|
|
13
|
+
FrameDiscoverNodesRequest, FrameErrorNotification,
|
|
14
|
+
FrameGatewayFactoryDefaultConfirmation, FrameGatewayFactoryDefaultRequest,
|
|
15
|
+
FrameGatewayRebootConfirmation, FrameGatewayRebootRequest,
|
|
16
|
+
FrameGetAllNodesInformationConfirmation,
|
|
17
|
+
FrameGetAllNodesInformationFinishedNotification,
|
|
18
|
+
FrameGetAllNodesInformationNotification,
|
|
19
|
+
FrameGetAllNodesInformationRequest, FrameGetLimitationStatus,
|
|
20
|
+
FrameGetLimitationStatusConfirmation, FrameGetLimitationStatusNotification,
|
|
21
|
+
FrameGetLocalTimeConfirmation, FrameGetLocalTimeRequest,
|
|
22
|
+
FrameGetNetworkSetupConfirmation, FrameGetNetworkSetupRequest,
|
|
23
|
+
FrameGetNodeInformationConfirmation, FrameGetNodeInformationNotification,
|
|
24
|
+
FrameGetNodeInformationRequest, FrameGetProtocolVersionConfirmation,
|
|
25
|
+
FrameGetProtocolVersionRequest, FrameGetSceneListConfirmation,
|
|
26
|
+
FrameGetSceneListNotification, FrameGetSceneListRequest,
|
|
27
|
+
FrameGetStateConfirmation, FrameGetStateRequest,
|
|
28
|
+
FrameGetVersionConfirmation, FrameGetVersionRequest,
|
|
29
|
+
FrameHouseStatusMonitorDisableConfirmation,
|
|
30
|
+
FrameHouseStatusMonitorDisableRequest,
|
|
31
|
+
FrameHouseStatusMonitorEnableConfirmation,
|
|
32
|
+
FrameHouseStatusMonitorEnableRequest, FrameLeaveLearnStateConfirmation,
|
|
33
|
+
FrameLeaveLearnStateRequest, FrameNodeInformationChangedNotification,
|
|
34
|
+
FrameNodeStatePositionChangedNotification, FramePasswordChangeConfirmation,
|
|
35
|
+
FramePasswordChangeNotification, FramePasswordChangeRequest,
|
|
36
|
+
FramePasswordEnterConfirmation, FramePasswordEnterRequest,
|
|
37
|
+
FrameSessionFinishedNotification, FrameSetNodeNameConfirmation,
|
|
38
|
+
FrameSetNodeNameRequest, FrameSetUTCConfirmation, FrameSetUTCRequest,
|
|
39
|
+
FrameStatusRequestConfirmation, FrameStatusRequestNotification,
|
|
40
|
+
FrameStatusRequestRequest, extract_from_frame)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def frame_from_raw(raw: bytes) -> Optional[FrameBase]:
|
|
44
|
+
"""Create and return frame from raw bytes."""
|
|
45
|
+
command, payload = extract_from_frame(raw)
|
|
46
|
+
frame = create_frame(command)
|
|
47
|
+
if frame is None:
|
|
48
|
+
PYVLXLOG.warning(
|
|
49
|
+
"Command %s not implemented, raw: %s",
|
|
50
|
+
command,
|
|
51
|
+
":".join("{:02x}".format(c) for c in raw),
|
|
52
|
+
)
|
|
53
|
+
return None
|
|
54
|
+
frame.validate_payload_len(payload)
|
|
55
|
+
frame.from_payload(payload)
|
|
56
|
+
return frame
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def create_frame(command: Command) -> Optional[FrameBase]:
|
|
60
|
+
"""Create and return empty Frame from Command."""
|
|
61
|
+
# pylint: disable=too-many-branches,too-many-return-statements,too-many-statements
|
|
62
|
+
if command == Command.GW_ERROR_NTF:
|
|
63
|
+
return FrameErrorNotification()
|
|
64
|
+
if command == Command.GW_COMMAND_SEND_REQ:
|
|
65
|
+
return FrameCommandSendRequest()
|
|
66
|
+
if command == Command.GW_COMMAND_SEND_CFM:
|
|
67
|
+
return FrameCommandSendConfirmation()
|
|
68
|
+
if command == Command.GW_COMMAND_RUN_STATUS_NTF:
|
|
69
|
+
return FrameCommandRunStatusNotification()
|
|
70
|
+
if command == Command.GW_COMMAND_REMAINING_TIME_NTF:
|
|
71
|
+
return FrameCommandRemainingTimeNotification()
|
|
72
|
+
if command == Command.GW_SESSION_FINISHED_NTF:
|
|
73
|
+
return FrameSessionFinishedNotification()
|
|
74
|
+
|
|
75
|
+
if command == Command.GW_PASSWORD_ENTER_REQ:
|
|
76
|
+
return FramePasswordEnterRequest()
|
|
77
|
+
if command == Command.GW_PASSWORD_ENTER_CFM:
|
|
78
|
+
return FramePasswordEnterConfirmation()
|
|
79
|
+
|
|
80
|
+
if command == Command.GW_PASSWORD_CHANGE_REQ:
|
|
81
|
+
return FramePasswordChangeRequest()
|
|
82
|
+
if command == Command.GW_PASSWORD_CHANGE_CFM:
|
|
83
|
+
return FramePasswordChangeConfirmation()
|
|
84
|
+
if command == Command.GW_PASSWORD_CHANGE_NTF:
|
|
85
|
+
return FramePasswordChangeNotification()
|
|
86
|
+
|
|
87
|
+
if command == Command.GW_REBOOT_REQ:
|
|
88
|
+
return FrameGatewayRebootRequest()
|
|
89
|
+
if command == Command.GW_REBOOT_CFM:
|
|
90
|
+
return FrameGatewayRebootConfirmation()
|
|
91
|
+
|
|
92
|
+
if command == Command.GW_SET_FACTORY_DEFAULT_REQ:
|
|
93
|
+
return FrameGatewayFactoryDefaultRequest()
|
|
94
|
+
if command == Command.GW_SET_FACTORY_DEFAULT_CFM:
|
|
95
|
+
return FrameGatewayFactoryDefaultConfirmation()
|
|
96
|
+
|
|
97
|
+
if command == Command.GW_GET_LOCAL_TIME_REQ:
|
|
98
|
+
return FrameGetLocalTimeRequest()
|
|
99
|
+
if command == Command.GW_GET_LOCAL_TIME_CFM:
|
|
100
|
+
return FrameGetLocalTimeConfirmation()
|
|
101
|
+
|
|
102
|
+
if command == Command.GW_CS_DISCOVER_NODES_REQ:
|
|
103
|
+
return FrameDiscoverNodesRequest()
|
|
104
|
+
if command == Command.GW_CS_DISCOVER_NODES_CFM:
|
|
105
|
+
return FrameDiscoverNodesConfirmation()
|
|
106
|
+
if command == Command.GW_CS_DISCOVER_NODES_NTF:
|
|
107
|
+
return FrameDiscoverNodesNotification()
|
|
108
|
+
|
|
109
|
+
if command == Command.GW_GET_SCENE_LIST_REQ:
|
|
110
|
+
return FrameGetSceneListRequest()
|
|
111
|
+
if command == Command.GW_GET_SCENE_LIST_CFM:
|
|
112
|
+
return FrameGetSceneListConfirmation()
|
|
113
|
+
if command == Command.GW_GET_SCENE_LIST_NTF:
|
|
114
|
+
return FrameGetSceneListNotification()
|
|
115
|
+
|
|
116
|
+
if command == Command.GW_GET_NODE_INFORMATION_REQ:
|
|
117
|
+
return FrameGetNodeInformationRequest()
|
|
118
|
+
if command == Command.GW_GET_NODE_INFORMATION_CFM:
|
|
119
|
+
return FrameGetNodeInformationConfirmation()
|
|
120
|
+
if command == Command.GW_GET_NODE_INFORMATION_NTF:
|
|
121
|
+
return FrameGetNodeInformationNotification()
|
|
122
|
+
|
|
123
|
+
if command == Command.GW_GET_ALL_NODES_INFORMATION_REQ:
|
|
124
|
+
return FrameGetAllNodesInformationRequest()
|
|
125
|
+
if command == Command.GW_GET_ALL_NODES_INFORMATION_CFM:
|
|
126
|
+
return FrameGetAllNodesInformationConfirmation()
|
|
127
|
+
if command == Command.GW_GET_ALL_NODES_INFORMATION_NTF:
|
|
128
|
+
return FrameGetAllNodesInformationNotification()
|
|
129
|
+
if command == Command.GW_GET_ALL_NODES_INFORMATION_FINISHED_NTF:
|
|
130
|
+
return FrameGetAllNodesInformationFinishedNotification()
|
|
131
|
+
|
|
132
|
+
if command == Command.GW_ACTIVATE_SCENE_REQ:
|
|
133
|
+
return FrameActivateSceneRequest()
|
|
134
|
+
if command == Command.GW_ACTIVATE_SCENE_CFM:
|
|
135
|
+
return FrameActivateSceneConfirmation()
|
|
136
|
+
|
|
137
|
+
if command == Command.GW_GET_VERSION_REQ:
|
|
138
|
+
return FrameGetVersionRequest()
|
|
139
|
+
if command == Command.GW_GET_VERSION_CFM:
|
|
140
|
+
return FrameGetVersionConfirmation()
|
|
141
|
+
if command == Command.GW_GET_PROTOCOL_VERSION_REQ:
|
|
142
|
+
return FrameGetProtocolVersionRequest()
|
|
143
|
+
if command == Command.GW_GET_PROTOCOL_VERSION_CFM:
|
|
144
|
+
return FrameGetProtocolVersionConfirmation()
|
|
145
|
+
|
|
146
|
+
if command == Command.GW_SET_NODE_NAME_REQ:
|
|
147
|
+
return FrameSetNodeNameRequest()
|
|
148
|
+
if command == Command.GW_SET_NODE_NAME_CFM:
|
|
149
|
+
return FrameSetNodeNameConfirmation()
|
|
150
|
+
|
|
151
|
+
if command == Command.GW_NODE_INFORMATION_CHANGED_NTF:
|
|
152
|
+
return FrameNodeInformationChangedNotification()
|
|
153
|
+
|
|
154
|
+
if command == Command.GW_GET_STATE_REQ:
|
|
155
|
+
return FrameGetStateRequest()
|
|
156
|
+
if command == Command.GW_GET_STATE_CFM:
|
|
157
|
+
return FrameGetStateConfirmation()
|
|
158
|
+
|
|
159
|
+
if command == Command.GW_GET_LIMITATION_STATUS_REQ:
|
|
160
|
+
return FrameGetLimitationStatus()
|
|
161
|
+
if command == Command.GW_GET_LIMITATION_STATUS_CFM:
|
|
162
|
+
return FrameGetLimitationStatusConfirmation()
|
|
163
|
+
if command == Command.GW_LIMITATION_STATUS_NTF:
|
|
164
|
+
return FrameGetLimitationStatusNotification()
|
|
165
|
+
|
|
166
|
+
if command == Command.GW_GET_NETWORK_SETUP_REQ:
|
|
167
|
+
return FrameGetNetworkSetupRequest()
|
|
168
|
+
if command == Command.GW_GET_NETWORK_SETUP_CFM:
|
|
169
|
+
return FrameGetNetworkSetupConfirmation()
|
|
170
|
+
|
|
171
|
+
if command == Command.GW_SET_UTC_REQ:
|
|
172
|
+
return FrameSetUTCRequest()
|
|
173
|
+
if command == Command.GW_SET_UTC_CFM:
|
|
174
|
+
return FrameSetUTCConfirmation()
|
|
175
|
+
|
|
176
|
+
if command == Command.GW_ACTIVATION_LOG_UPDATED_NTF:
|
|
177
|
+
return FrameActivationLogUpdatedNotification()
|
|
178
|
+
|
|
179
|
+
if command == Command.GW_HOUSE_STATUS_MONITOR_ENABLE_REQ:
|
|
180
|
+
return FrameHouseStatusMonitorEnableRequest()
|
|
181
|
+
if command == Command.GW_HOUSE_STATUS_MONITOR_ENABLE_CFM:
|
|
182
|
+
return FrameHouseStatusMonitorEnableConfirmation()
|
|
183
|
+
if command == Command.GW_HOUSE_STATUS_MONITOR_DISABLE_REQ:
|
|
184
|
+
return FrameHouseStatusMonitorDisableRequest()
|
|
185
|
+
if command == Command.GW_HOUSE_STATUS_MONITOR_DISABLE_CFM:
|
|
186
|
+
return FrameHouseStatusMonitorDisableConfirmation()
|
|
187
|
+
|
|
188
|
+
if command == Command.GW_NODE_STATE_POSITION_CHANGED_NTF:
|
|
189
|
+
return FrameNodeStatePositionChangedNotification()
|
|
190
|
+
if command == Command.GW_LEAVE_LEARN_STATE_CFM:
|
|
191
|
+
return FrameLeaveLearnStateConfirmation()
|
|
192
|
+
if command == Command.GW_LEAVE_LEARN_STATE_REQ:
|
|
193
|
+
return FrameLeaveLearnStateRequest()
|
|
194
|
+
|
|
195
|
+
if command == Command.GW_STATUS_REQUEST_REQ:
|
|
196
|
+
return FrameStatusRequestRequest()
|
|
197
|
+
if command == Command.GW_STATUS_REQUEST_CFM:
|
|
198
|
+
return FrameStatusRequestConfirmation()
|
|
199
|
+
if command == Command.GW_STATUS_REQUEST_NTF:
|
|
200
|
+
return FrameStatusRequestNotification()
|
|
201
|
+
|
|
202
|
+
return None
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Module for all KLF 200 API frames."""
|
|
2
|
+
|
|
3
|
+
from .alias_array import AliasArray
|
|
4
|
+
# flake8: noqa
|
|
5
|
+
from .frame import FrameBase
|
|
6
|
+
from .frame_activate_scene import (
|
|
7
|
+
ActivateSceneConfirmationStatus, FrameActivateSceneConfirmation,
|
|
8
|
+
FrameActivateSceneRequest)
|
|
9
|
+
from .frame_activation_log_updated import FrameActivationLogUpdatedNotification
|
|
10
|
+
from .frame_command_send import (
|
|
11
|
+
CommandSendConfirmationStatus, FrameCommandRemainingTimeNotification,
|
|
12
|
+
FrameCommandRunStatusNotification, FrameCommandSendConfirmation,
|
|
13
|
+
FrameCommandSendRequest, FrameSessionFinishedNotification)
|
|
14
|
+
from .frame_discover_nodes import (
|
|
15
|
+
FrameDiscoverNodesConfirmation, FrameDiscoverNodesNotification,
|
|
16
|
+
FrameDiscoverNodesRequest)
|
|
17
|
+
from .frame_error_notification import ErrorType, FrameErrorNotification
|
|
18
|
+
from .frame_facory_default import (
|
|
19
|
+
FrameGatewayFactoryDefaultConfirmation, FrameGatewayFactoryDefaultRequest)
|
|
20
|
+
from .frame_get_all_nodes_information import (
|
|
21
|
+
FrameGetAllNodesInformationConfirmation,
|
|
22
|
+
FrameGetAllNodesInformationFinishedNotification,
|
|
23
|
+
FrameGetAllNodesInformationNotification,
|
|
24
|
+
FrameGetAllNodesInformationRequest)
|
|
25
|
+
from .frame_get_limitation import (
|
|
26
|
+
FrameGetLimitationStatus, FrameGetLimitationStatusConfirmation,
|
|
27
|
+
FrameGetLimitationStatusNotification)
|
|
28
|
+
from .frame_get_local_time import (
|
|
29
|
+
FrameGetLocalTimeConfirmation, FrameGetLocalTimeRequest)
|
|
30
|
+
from .frame_get_network_setup import (
|
|
31
|
+
DHCPParameter, FrameGetNetworkSetupConfirmation,
|
|
32
|
+
FrameGetNetworkSetupRequest)
|
|
33
|
+
from .frame_get_node_information import (
|
|
34
|
+
FrameGetNodeInformationConfirmation, FrameGetNodeInformationNotification,
|
|
35
|
+
FrameGetNodeInformationRequest)
|
|
36
|
+
from .frame_get_protocol_version import (
|
|
37
|
+
FrameGetProtocolVersionConfirmation, FrameGetProtocolVersionRequest)
|
|
38
|
+
from .frame_get_scene_list import (
|
|
39
|
+
FrameGetSceneListConfirmation, FrameGetSceneListNotification,
|
|
40
|
+
FrameGetSceneListRequest)
|
|
41
|
+
from .frame_get_state import (
|
|
42
|
+
FrameGetStateConfirmation, FrameGetStateRequest, GatewayState,
|
|
43
|
+
GatewaySubState)
|
|
44
|
+
from .frame_get_version import (
|
|
45
|
+
FrameGetVersionConfirmation, FrameGetVersionRequest)
|
|
46
|
+
from .frame_helper import calc_crc, extract_from_frame
|
|
47
|
+
from .frame_house_status_monitor_disable_cfm import (
|
|
48
|
+
FrameHouseStatusMonitorDisableConfirmation)
|
|
49
|
+
from .frame_house_status_monitor_disable_req import (
|
|
50
|
+
FrameHouseStatusMonitorDisableRequest)
|
|
51
|
+
from .frame_house_status_monitor_enable_cfm import (
|
|
52
|
+
FrameHouseStatusMonitorEnableConfirmation)
|
|
53
|
+
from .frame_house_status_monitor_enable_req import (
|
|
54
|
+
FrameHouseStatusMonitorEnableRequest)
|
|
55
|
+
from .frame_leave_learn_state import (
|
|
56
|
+
FrameLeaveLearnStateConfirmation, FrameLeaveLearnStateRequest,
|
|
57
|
+
LeaveLearnStateConfirmationStatus)
|
|
58
|
+
from .frame_node_information_changed import (
|
|
59
|
+
FrameNodeInformationChangedNotification)
|
|
60
|
+
from .frame_node_state_position_changed_notification import (
|
|
61
|
+
FrameNodeStatePositionChangedNotification)
|
|
62
|
+
from .frame_password_change import (
|
|
63
|
+
FramePasswordChangeConfirmation, FramePasswordChangeNotification,
|
|
64
|
+
FramePasswordChangeRequest, PasswordChangeConfirmationStatus)
|
|
65
|
+
from .frame_password_enter import (
|
|
66
|
+
FramePasswordEnterConfirmation, FramePasswordEnterRequest,
|
|
67
|
+
PasswordEnterConfirmationStatus)
|
|
68
|
+
from .frame_reboot import (
|
|
69
|
+
FrameGatewayRebootConfirmation, FrameGatewayRebootRequest)
|
|
70
|
+
from .frame_set_node_name import (
|
|
71
|
+
FrameSetNodeNameConfirmation, FrameSetNodeNameRequest,
|
|
72
|
+
SetNodeNameConfirmationStatus)
|
|
73
|
+
from .frame_set_utc import FrameSetUTCConfirmation, FrameSetUTCRequest
|
|
74
|
+
from .frame_status_request import (
|
|
75
|
+
FrameStatusRequestConfirmation, FrameStatusRequestNotification,
|
|
76
|
+
FrameStatusRequestRequest)
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Module for storing alias array."""
|
|
2
|
+
from typing import List, Optional, Tuple
|
|
3
|
+
|
|
4
|
+
from pyvlx.exception import PyVLXException
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AliasArray:
|
|
8
|
+
"""Object for storing alias array."""
|
|
9
|
+
|
|
10
|
+
def __init__(self, raw: Optional[bytes] = None):
|
|
11
|
+
"""Initialize alias array."""
|
|
12
|
+
self.alias_array_: List[Tuple[bytes, bytes]] = []
|
|
13
|
+
if raw is not None:
|
|
14
|
+
self.parse_raw(raw)
|
|
15
|
+
|
|
16
|
+
def __str__(self) -> str:
|
|
17
|
+
"""Return human readable string."""
|
|
18
|
+
return ", ".join(
|
|
19
|
+
"{:02x}{:02x}={:02x}{:02x}".format(c[0][0], c[0][1], c[1][0], c[1][1])
|
|
20
|
+
for c in self.alias_array_
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
def __bytes__(self) -> bytes:
|
|
24
|
+
"""Get raw bytes of alias array."""
|
|
25
|
+
ret = bytes([len(self.alias_array_)])
|
|
26
|
+
for alias in self.alias_array_:
|
|
27
|
+
ret += alias[0] + alias[1]
|
|
28
|
+
ret += bytes((5 - len(self.alias_array_)) * 4)
|
|
29
|
+
return ret
|
|
30
|
+
|
|
31
|
+
def parse_raw(self, raw: bytes) -> None:
|
|
32
|
+
"""Parse alias array from raw bytes."""
|
|
33
|
+
if not isinstance(raw, bytes):
|
|
34
|
+
raise PyVLXException("AliasArray::invalid_type_if_raw", type_raw=type(raw))
|
|
35
|
+
if len(raw) != 21:
|
|
36
|
+
raise PyVLXException("AliasArray::invalid_size", size=len(raw))
|
|
37
|
+
nbr_of_alias = raw[0]
|
|
38
|
+
if nbr_of_alias > 5:
|
|
39
|
+
raise PyVLXException(
|
|
40
|
+
"AliasArray::invalid_nbr_of_alias", nbr_of_alias=nbr_of_alias
|
|
41
|
+
)
|
|
42
|
+
for i in range(0, nbr_of_alias):
|
|
43
|
+
self.alias_array_.append(
|
|
44
|
+
(raw[i * 4 + 1 : i * 4 + 3], raw[i * 4 + 3 : i * 4 + 5])
|
|
45
|
+
)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"""Module for Frames."""
|
|
2
|
+
import struct
|
|
3
|
+
|
|
4
|
+
from pyvlx.const import Command
|
|
5
|
+
from pyvlx.exception import PyVLXException
|
|
6
|
+
|
|
7
|
+
from .frame_helper import calc_crc
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class FrameBase:
|
|
11
|
+
"""Class for Base Frame."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, command: Command):
|
|
14
|
+
"""Initialize Base Frame."""
|
|
15
|
+
self.command = command
|
|
16
|
+
|
|
17
|
+
def __bytes__(self) -> bytes:
|
|
18
|
+
"""Get raw bytes of Frame."""
|
|
19
|
+
payload = self.get_payload()
|
|
20
|
+
self.validate_payload_len(payload)
|
|
21
|
+
return self.build_frame(self.command, payload)
|
|
22
|
+
|
|
23
|
+
def validate_payload_len(self, payload: bytes) -> None:
|
|
24
|
+
"""Validate payload len."""
|
|
25
|
+
if not hasattr(self, "PAYLOAD_LEN"):
|
|
26
|
+
# No fixed payload len, e.g. within FrameGetSceneListNotification
|
|
27
|
+
return
|
|
28
|
+
# pylint: disable=no-member
|
|
29
|
+
if len(payload) != self.PAYLOAD_LEN:
|
|
30
|
+
raise PyVLXException(
|
|
31
|
+
"Invalid payload len",
|
|
32
|
+
expected_len=self.PAYLOAD_LEN,
|
|
33
|
+
current_len=len(payload),
|
|
34
|
+
frame_type=type(self).__name__,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def get_payload(self) -> bytes:
|
|
38
|
+
"""Return Payload."""
|
|
39
|
+
return b""
|
|
40
|
+
|
|
41
|
+
def from_payload(self, payload: bytes) -> None:
|
|
42
|
+
"""Init frame from binary data."""
|
|
43
|
+
|
|
44
|
+
def __str__(self) -> str:
|
|
45
|
+
"""Return human readable string."""
|
|
46
|
+
return "<{}/>".format(type(self).__name__)
|
|
47
|
+
|
|
48
|
+
@staticmethod
|
|
49
|
+
def build_frame(command: Command, payload: bytes) -> bytes:
|
|
50
|
+
"""Build raw bytes from command and payload."""
|
|
51
|
+
packet_length = 2 + len(payload) + 1
|
|
52
|
+
ret = struct.pack("BB", 0, packet_length)
|
|
53
|
+
ret += struct.pack(">H", command.value)
|
|
54
|
+
ret += payload
|
|
55
|
+
ret += struct.pack("B", calc_crc(ret))
|
|
56
|
+
return ret
|