diff --git a/pyvlx/__init__.py b/pyvlx/__init__.py index 7cfe4c4d..65fdbda4 100644 --- a/pyvlx/__init__.py +++ b/pyvlx/__init__.py @@ -15,3 +15,4 @@ from .pyvlx import PyVLX from .scene import Scene from .scenes import Scenes +from .klf200gateway import Klf200Gateway diff --git a/pyvlx/api/__init__.py b/pyvlx/api/__init__.py new file mode 100644 index 00000000..37fab54d --- /dev/null +++ b/pyvlx/api/__init__.py @@ -0,0 +1,21 @@ +"""Module for all KLF 200 API frames.""" +# flake8: noqa + +from .house_status_monitor import (house_status_monitor_enable) +from .command_send import (CommandSend) +from .get_local_time import (FrameGetLocalTimeRequest, FrameGetLocalTimeConfirmation) +from .get_state import (GetState) +from .get_network_setup import (GetNetworkSetup) +from .get_protocol_version import (GetProtocolVersion) +from .get_version import (GetVersion) +from .get_local_time import (GetLocalTime) +from .leave_learn_state import (LeaveLearnState) +from .factory_default import (FactoryDefault) +from .password_enter import (PasswordEnter) +from .set_utc import (SetUTC) +from .reboot import (Reboot) +from .activate_scene import (ActivateScene) +from .set_node_name import (SetNodeName) +from .get_all_nodes_information import (GetAllNodesInformation) +from .get_node_information import (GetNodeInformation) +from .get_scene_list import (GetSceneList) diff --git a/pyvlx/activate_scene.py b/pyvlx/api/activate_scene.py similarity index 74% rename from pyvlx/activate_scene.py rename to pyvlx/api/activate_scene.py index 65055cfd..f579c58f 100644 --- a/pyvlx/activate_scene.py +++ b/pyvlx/api/activate_scene.py @@ -11,7 +11,7 @@ class ActivateScene(ApiEvent): """Class for activating scene via API.""" def __init__( - self, pyvlx, scene_id, wait_for_completion=True, timeout_in_seconds=60 + self, pyvlx, scene_id, wait_for_completion=True, timeout_in_seconds=60 ): """Initialize SceneList class.""" super().__init__(pyvlx=pyvlx, timeout_in_seconds=timeout_in_seconds) @@ -23,28 +23,28 @@ def __init__( async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if ( - isinstance(frame, FrameActivateSceneConfirmation) - and frame.session_id == self.session_id + isinstance(frame, FrameActivateSceneConfirmation) + and frame.session_id == self.session_id ): if frame.status == ActivateSceneConfirmationStatus.ACCEPTED: self.success = True return not self.wait_for_completion if ( - isinstance(frame, FrameCommandRemainingTimeNotification) - and frame.session_id == self.session_id + isinstance(frame, FrameCommandRemainingTimeNotification) + and frame.session_id == self.session_id ): # Ignoring FrameCommandRemainingTimeNotification return False if ( - isinstance(frame, FrameCommandRunStatusNotification) - and frame.session_id == self.session_id + isinstance(frame, FrameCommandRunStatusNotification) + and frame.session_id == self.session_id ): # At the moment I don't reall understand what the FrameCommandRunStatusNotification is good for. # Ignoring these packets for now return False if ( - isinstance(frame, FrameSessionFinishedNotification) - and frame.session_id == self.session_id + isinstance(frame, FrameSessionFinishedNotification) + and frame.session_id == self.session_id ): return True return False diff --git a/pyvlx/api_event.py b/pyvlx/api/api_event.py similarity index 100% rename from pyvlx/api_event.py rename to pyvlx/api/api_event.py diff --git a/pyvlx/command_send.py b/pyvlx/api/command_send.py similarity index 69% rename from pyvlx/command_send.py rename to pyvlx/api/command_send.py index 8e358848..d047a73b 100644 --- a/pyvlx/command_send.py +++ b/pyvlx/api/command_send.py @@ -1,24 +1,24 @@ """Module for retrieving scene list from API.""" -from pyvlx.api_event import ApiEvent -from pyvlx.frames import ( +from .api_event import ApiEvent +from .frames import ( CommandSendConfirmationStatus, FrameCommandRemainingTimeNotification, FrameCommandRunStatusNotification, FrameCommandSendConfirmation, FrameCommandSendRequest, FrameSessionFinishedNotification) -from pyvlx.session_id import get_new_session_id +from .session_id import get_new_session_id class CommandSend(ApiEvent): """Class for sending command to API.""" def __init__( - self, - pyvlx, - node_id, - parameter, - active_parameter=0, - wait_for_completion=True, - timeout_in_seconds=60, - **functional_parameter + self, + pyvlx, + node_id, + parameter, + active_parameter=0, + wait_for_completion=True, + timeout_in_seconds=60, + **functional_parameter ): """Initialize SceneList class.""" super().__init__(pyvlx=pyvlx, timeout_in_seconds=timeout_in_seconds) @@ -33,28 +33,28 @@ def __init__( async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if ( - isinstance(frame, FrameCommandSendConfirmation) - and frame.session_id == self.session_id + isinstance(frame, FrameCommandSendConfirmation) + and frame.session_id == self.session_id ): if frame.status == CommandSendConfirmationStatus.ACCEPTED: self.success = True return not self.wait_for_completion if ( - isinstance(frame, FrameCommandRemainingTimeNotification) - and frame.session_id == self.session_id + isinstance(frame, FrameCommandRemainingTimeNotification) + and frame.session_id == self.session_id ): # Ignoring FrameCommandRemainingTimeNotification return False if ( - isinstance(frame, FrameCommandRunStatusNotification) - and frame.session_id == self.session_id + isinstance(frame, FrameCommandRunStatusNotification) + and frame.session_id == self.session_id ): # At the moment I don't reall understand what the FrameCommandRunStatusNotification is good for. # Ignoring these packets for now return False if ( - isinstance(frame, FrameSessionFinishedNotification) - and frame.session_id == self.session_id + isinstance(frame, FrameSessionFinishedNotification) + and frame.session_id == self.session_id ): return True return False diff --git a/pyvlx/api/factory_default.py b/pyvlx/api/factory_default.py new file mode 100644 index 00000000..858a4059 --- /dev/null +++ b/pyvlx/api/factory_default.py @@ -0,0 +1,26 @@ +"""Module for handling the FactoryDefault to API.""" +from pyvlx.log import PYVLXLOG +from .api_event import ApiEvent +from .frames import FrameGatewayFactoryDefaultConfirmation, FrameGatewayFactoryDefaultRequest + + +class FactoryDefault(ApiEvent): + """Class for handling Factory reset API.""" + + def __init__(self, pyvlx): + """Initialize facotry default class.""" + super().__init__(pyvlx=pyvlx) + self.pyvlx = pyvlx + self.success = False + + async def handle_frame(self, frame): + """Handle incoming API frame, return True if this was the expected frame.""" + if isinstance(frame, FrameGatewayFactoryDefaultConfirmation): + PYVLXLOG.warning("KLF200 is factory resetting") + self.success = True + return True + return False + + def request_frame(self): + """Construct initiating frame.""" + return FrameGatewayFactoryDefaultRequest() diff --git a/pyvlx/frame_creation.py b/pyvlx/api/frame_creation.py similarity index 78% rename from pyvlx/frame_creation.py rename to pyvlx/api/frame_creation.py index 25574599..8e4e559e 100644 --- a/pyvlx/frame_creation.py +++ b/pyvlx/api/frame_creation.py @@ -1,5 +1,7 @@ """Helper module for creating a frame out of raw data.""" -from pyvlx.frames import ( +from pyvlx.log import PYVLXLOG +from pyvlx.const import Command +from .frames import ( FrameActivateSceneConfirmation, FrameActivateSceneRequest, FrameActivationLogUpdatedNotification, FrameCommandRemainingTimeNotification, FrameCommandRunStatusNotification, @@ -21,13 +23,16 @@ FrameHouseStatusMonitorEnableConfirmation, FrameHouseStatusMonitorEnableRequest, FrameNodeInformationChangedNotification, - FrameNodeStatePositionChangedNotification, FramePasswordEnterConfirmation, - FramePasswordEnterRequest, FrameSessionFinishedNotification, + FrameNodeStatePositionChangedNotification, + FramePasswordEnterConfirmation, FramePasswordEnterRequest, + FramePasswordChangeRequest, FramePasswordChangeConfirmation, FramePasswordChangeNotification, + FrameSessionFinishedNotification, FrameSetNodeNameConfirmation, FrameSetNodeNameRequest, - FrameSetUTCConfirmation, FrameSetUTCRequest, extract_from_frame) - -from .const import Command -from .log import PYVLXLOG + FrameGetNetworkSetupConfirmation, FrameGetNetworkSetupRequest, + FrameSetUTCConfirmation, FrameSetUTCRequest, extract_from_frame, + FrameLeaveLearnStateConfirmation, FrameLeaveLearnStateRequest, + FrameGetLocalTimeConfirmation, FrameGetLocalTimeRequest, + FrameGatewayFactoryDefaultConfirmation, FrameGatewayFactoryDefaultRequest) def frame_from_raw(raw): @@ -48,7 +53,7 @@ def frame_from_raw(raw): def create_frame(command): """Create and return empty Frame from Command.""" - # pylint: disable=too-many-branches,too-many-return-statements + # pylint: disable=too-many-branches,too-many-return-statements,too-many-statements if command == Command.GW_ERROR_NTF: return FrameErrorNotification() if command == Command.GW_COMMAND_SEND_REQ: @@ -67,11 +72,28 @@ def create_frame(command): if command == Command.GW_PASSWORD_ENTER_CFM: return FramePasswordEnterConfirmation() + if command == Command.GW_PASSWORD_CHANGE_REQ: + return FramePasswordChangeRequest() + if command == Command.GW_PASSWORD_CHANGE_CFM: + return FramePasswordChangeConfirmation() + if command == Command.GW_PASSWORD_CHANGE_NTF: + return FramePasswordChangeNotification() + if command == Command.GW_REBOOT_REQ: return FrameGatewayRebootRequest() if command == Command.GW_REBOOT_CFM: return FrameGatewayRebootConfirmation() + if command == Command.GW_SET_FACTORY_DEFAULT_REQ: + return FrameGatewayFactoryDefaultRequest() + if command == Command.GW_SET_FACTORY_DEFAULT_CFM: + return FrameGatewayFactoryDefaultConfirmation() + + if command == Command.GW_GET_LOCAL_TIME_REQ: + return FrameGetLocalTimeRequest() + if command == Command.GW_GET_LOCAL_TIME_CFM: + return FrameGetLocalTimeConfirmation() + if command == Command.GW_CS_DISCOVER_NODES_REQ: return FrameDiscoverNodesRequest() if command == Command.GW_CS_DISCOVER_NODES_CFM: @@ -129,6 +151,11 @@ def create_frame(command): if command == Command.GW_GET_STATE_CFM: return FrameGetStateConfirmation() + if command == Command.GW_GET_NETWORK_SETUP_REQ: + return FrameGetNetworkSetupRequest() + if command == Command.GW_GET_NETWORK_SETUP_CFM: + return FrameGetNetworkSetupConfirmation() + if command == Command.GW_SET_UTC_REQ: return FrameSetUTCRequest() if command == Command.GW_SET_UTC_CFM: @@ -148,5 +175,9 @@ def create_frame(command): if command == Command.GW_NODE_STATE_POSITION_CHANGED_NTF: return FrameNodeStatePositionChangedNotification() + if command == Command.GW_LEAVE_LEARN_STATE_CFM: + return FrameLeaveLearnStateConfirmation() + if command == command.GW_LEAVE_LEARN_STATE_REQ: + return FrameLeaveLearnStateRequest() return None diff --git a/pyvlx/frames/__init__.py b/pyvlx/api/frames/__init__.py similarity index 77% rename from pyvlx/frames/__init__.py rename to pyvlx/api/frames/__init__.py index d8f5f9ec..41696b38 100644 --- a/pyvlx/frames/__init__.py +++ b/pyvlx/api/frames/__init__.py @@ -2,6 +2,7 @@ # flake8: noqa from .frame import FrameBase +from .alias_array import AliasArray from .frame_activate_scene import ( ActivateSceneConfirmationStatus, FrameActivateSceneConfirmation, FrameActivateSceneRequest) @@ -30,6 +31,8 @@ from .frame_get_state import ( FrameGetStateConfirmation, FrameGetStateRequest, GatewayState, GatewaySubState) +from .frame_get_network_setup import ( + FrameGetNetworkSetupConfirmation, FrameGetNetworkSetupRequest, DHCPParameter) from .frame_get_version import ( FrameGetVersionConfirmation, FrameGetVersionRequest) from .frame_helper import calc_crc, extract_from_frame @@ -53,5 +56,14 @@ from .frame_set_node_name import ( FrameSetNodeNameConfirmation, FrameSetNodeNameRequest, SetNodeNameConfirmationStatus) -from .frame_set_utc_cfm import FrameSetUTCConfirmation -from .frame_set_utc_req import FrameSetUTCRequest +from .frame_set_utc import (FrameSetUTCConfirmation, FrameSetUTCRequest) +from .frame_leave_learn_state import ( + FrameLeaveLearnStateRequest, FrameLeaveLearnStateConfirmation, + LeaveLearnStateConfirmationStatus) +from .frame_get_local_time import ( + FrameGetLocalTimeRequest, FrameGetLocalTimeConfirmation) +from .frame_facory_default import ( + FrameGatewayFactoryDefaultRequest, FrameGatewayFactoryDefaultConfirmation) +from .frame_password_change import ( + FramePasswordChangeRequest, FramePasswordChangeConfirmation, + FramePasswordChangeNotification, PasswordChangeConfirmationStatus) diff --git a/pyvlx/alias_array.py b/pyvlx/api/frames/alias_array.py similarity index 97% rename from pyvlx/alias_array.py rename to pyvlx/api/frames/alias_array.py index 6b1e245e..c08f9345 100644 --- a/pyvlx/alias_array.py +++ b/pyvlx/api/frames/alias_array.py @@ -1,5 +1,5 @@ """Module for storing alias array.""" -from .exception import PyVLXException +from pyvlx.exception import PyVLXException class AliasArray: diff --git a/pyvlx/frames/frame.py b/pyvlx/api/frames/frame.py similarity index 100% rename from pyvlx/frames/frame.py rename to pyvlx/api/frames/frame.py diff --git a/pyvlx/frames/frame_activate_scene.py b/pyvlx/api/frames/frame_activate_scene.py similarity index 83% rename from pyvlx/frames/frame_activate_scene.py rename to pyvlx/api/frames/frame_activate_scene.py index a4a4cba9..865971fc 100644 --- a/pyvlx/frames/frame_activate_scene.py +++ b/pyvlx/api/frames/frame_activate_scene.py @@ -12,11 +12,11 @@ class FrameActivateSceneRequest(FrameBase): PAYLOAD_LEN = 6 def __init__( - self, - scene_id=None, - session_id=None, - originator=Originator.USER, - velocity=Velocity.DEFAULT, + self, + scene_id=None, + session_id=None, + originator=Originator.USER, + velocity=Velocity.DEFAULT, ): """Init Frame.""" super().__init__(Command.GW_ACTIVATE_SCENE_REQ) @@ -45,8 +45,8 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.scene_id, self.session_id, self.originator, self.velocity + return '<{} scene_id="{}" session_id="{}" originator="{}" velocity="{}"/>'.format( + type(self).__name__, self.scene_id, self.session_id, self.originator, self.velocity ) @@ -82,6 +82,6 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.session_id, self.status + return '<{} session_id="{}" status="{}"/>'.format( + type(self).__name__, self.session_id, self.status ) diff --git a/pyvlx/frames/frame_activation_log_updated.py b/pyvlx/api/frames/frame_activation_log_updated.py similarity index 100% rename from pyvlx/frames/frame_activation_log_updated.py rename to pyvlx/api/frames/frame_activation_log_updated.py diff --git a/pyvlx/frames/frame_command_send.py b/pyvlx/api/frames/frame_command_send.py similarity index 81% rename from pyvlx/frames/frame_command_send.py rename to pyvlx/api/frames/frame_command_send.py index 0351dfd7..f99fdbc4 100644 --- a/pyvlx/frames/frame_command_send.py +++ b/pyvlx/api/frames/frame_command_send.py @@ -14,13 +14,13 @@ class FrameCommandSendRequest(FrameBase): PAYLOAD_LEN = 66 def __init__( - self, - node_ids=None, - parameter=Parameter(), - active_parameter=0, - session_id=None, - originator=Originator.USER, - **functional_parameter + self, + node_ids=None, + parameter=Parameter(), + active_parameter=0, + session_id=None, + originator=Originator.USER, + **functional_parameter ): """Init Frame.""" super().__init__(Command.GW_COMMAND_SEND_REQ) @@ -33,9 +33,10 @@ def __init__( self.session_id = session_id self.originator = originator self.priority = Priority.USER_LEVEL_2 - """Set the functional parameter indicator bytes in order to show which functional parameters are included in the frame. - Functional parameter dictionary will be checked for keys 'fp1' to 'fp16' - to set the appropriate indicator and the corresponding self.functional_parameter.""" + """Set the functional parameter indicator bytes in order to show which functional + parameters are included in the frame. Functional parameter dictionary will be checked + for keys 'fp1' to 'fp16' to set the appropriate indicator and the corresponding + self.functional_parameter.""" for i in range(1, 17): key = "fp%s" % (i) if key in functional_parameter: @@ -102,12 +103,13 @@ def __str__(self): str(key), Position(Parameter(bytes(value))), ) - return ''.format( - self.node_ids, - self.parameter, - functional_parameter, - self.session_id, - self.originator, + return ( + '<{} node_ids="{}" parameter="{}" functional_parameter="{}" ' + 'session_id="{}" originator="{}"/>'.format( + type(self).__name__, self.node_ids, + self.parameter, functional_parameter, + self.session_id, self.originator, + ) ) @@ -142,8 +144,8 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.session_id, self.status + return '<{} session_id="{}" status="{}"/>'.format( + type(self).__name__, self.session_id, self.status ) @@ -153,12 +155,12 @@ class FrameCommandRunStatusNotification(FrameBase): PAYLOAD_LEN = 13 def __init__( - self, - session_id=None, - status_id=None, - index_id=None, - node_parameter=None, - parameter_value=None, + self, + session_id=None, + status_id=None, + index_id=None, + node_parameter=None, + parameter_value=None, ): """Init Frame.""" super().__init__(Command.GW_COMMAND_RUN_STATUS_NTF) @@ -191,13 +193,11 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" return ( - "".format( - self.session_id, - self.status_id, - self.index_id, - self.node_parameter, - self.parameter_value, + '<{} session_id="{}" status_id="{}" ' + 'index_id="{}" node_parameter="{}" parameter_value="{}"/>'.format( + type(self).__name__, self.session_id, + self.status_id, self.index_id, + self.node_parameter, self.parameter_value ) ) @@ -233,9 +233,10 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" return ( - "".format( - self.session_id, self.index_id, self.node_parameter, self.seconds + '<{} session_id="{}" index_id="{}" ' + 'node_parameter="{}" seconds="{}"/>'.format( + type(self).__name__, self.session_id, + self.index_id, self.node_parameter, self.seconds ) ) @@ -261,6 +262,6 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.session_id + return '<{} session_id="{}"/>'.format( + type(self).__name__, self.session_id ) diff --git a/pyvlx/frames/frame_discover_nodes.py b/pyvlx/api/frames/frame_discover_nodes.py similarity index 87% rename from pyvlx/frames/frame_discover_nodes.py rename to pyvlx/api/frames/frame_discover_nodes.py index f399bee6..b505add4 100644 --- a/pyvlx/frames/frame_discover_nodes.py +++ b/pyvlx/api/frames/frame_discover_nodes.py @@ -25,7 +25,7 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format(self.node_type) + return '<{} node_type="{}"/>'.format(type(self).__name__, self.node_type) class FrameDiscoverNodesConfirmation(FrameBase): @@ -58,6 +58,7 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - ":".join("{:02x}".format(c) for c in self.payload) + return '<{} payload="{}"/>'.format( + type(self).__name__, + ':'.join('{:02x}'.format(c) for c in self.payload) ) diff --git a/pyvlx/frames/frame_error_notification.py b/pyvlx/api/frames/frame_error_notification.py similarity index 91% rename from pyvlx/frames/frame_error_notification.py rename to pyvlx/api/frames/frame_error_notification.py index e28dc6cf..f1a0e376 100644 --- a/pyvlx/frames/frame_error_notification.py +++ b/pyvlx/api/frames/frame_error_notification.py @@ -38,4 +38,4 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format(self.error_type) + return '<{} error_type="{}"/>'.format(type(self).__name__, self.error_type) diff --git a/pyvlx/api/frames/frame_facory_default.py b/pyvlx/api/frames/frame_facory_default.py new file mode 100644 index 00000000..7768f674 --- /dev/null +++ b/pyvlx/api/frames/frame_facory_default.py @@ -0,0 +1,32 @@ +"""Module for reboot frame classes.""" +from pyvlx.const import Command + +from .frame import FrameBase + + +class FrameGatewayFactoryDefaultRequest(FrameBase): + """Frame for requesting factory reset.""" + + PAYLOAD_LEN = 0 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_SET_FACTORY_DEFAULT_REQ) + + def __str__(self): + """Return human readable string.""" + return '<{}/>'.format(type(self).__name__) + + +class FrameGatewayFactoryDefaultConfirmation(FrameBase): + """Frame for response for factory reset.""" + + PAYLOAD_LEN = 0 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_SET_FACTORY_DEFAULT_CFM) + + def __str__(self): + """Return human readable string.""" + return '<{}/>'.format(type(self).__name__) diff --git a/pyvlx/frames/frame_get_all_nodes_information.py b/pyvlx/api/frames/frame_get_all_nodes_information.py similarity index 91% rename from pyvlx/frames/frame_get_all_nodes_information.py rename to pyvlx/api/frames/frame_get_all_nodes_information.py index 16e9b7bc..a4c4ef20 100644 --- a/pyvlx/frames/frame_get_all_nodes_information.py +++ b/pyvlx/api/frames/frame_get_all_nodes_information.py @@ -3,13 +3,13 @@ from datetime import datetime from enum import Enum -from pyvlx.alias_array import AliasArray from pyvlx.const import Command, NodeTypeWithSubtype, NodeVariation, Velocity from pyvlx.exception import PyVLXException from pyvlx.parameter import Parameter from pyvlx.string_helper import bytes_to_string, string_to_bytes from .frame import FrameBase +from .alias_array import AliasArray class FrameGetAllNodesInformationRequest(FrameBase): @@ -51,8 +51,8 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.status, self.number_of_nodes + return '<{} status="{}" number_of_nodes="{}"/>'.format( + type(self).__name__, self.status, self.number_of_nodes ) @@ -167,13 +167,14 @@ def timestamp_formatted(self): def __str__(self): """Return human readable string.""" return ( - "".format( + '<{} node_id="{}" order="{}" ' + 'placement="{}" name="{}" velocity="{}" node_type="{}" product_group="{}" ' + 'product_type="{}" node_variation="{}" power_mode="{}" build_number="{}" ' + 'serial_number="{}" state="{}" current_position="{}" ' + 'target="{}" current_position_fp1="{}" current_position_fp2="{}" ' + 'current_position_fp3="{}" current_position_fp4="{}" ' + 'remaining_time="{}" time="{}" alias_array="{}"/>'.format( + type(self).__name__, self.node_id, self.order, self.placement, diff --git a/pyvlx/api/frames/frame_get_local_time.py b/pyvlx/api/frames/frame_get_local_time.py new file mode 100644 index 00000000..c766e420 --- /dev/null +++ b/pyvlx/api/frames/frame_get_local_time.py @@ -0,0 +1,37 @@ +"""Module for get local time classes.""" +from pyvlx.const import Command +from pyvlx.dataobjects import DtoLocalTime +from .frame import FrameBase + + +class FrameGetLocalTimeRequest(FrameBase): + """Frame for requesting local time.""" + + PAYLOAD_LEN = 0 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_GET_LOCAL_TIME_REQ) + + +class FrameGetLocalTimeConfirmation(FrameBase): + """Frame for response for get local time requests.""" + + PAYLOAD_LEN = 15 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_GET_LOCAL_TIME_CFM) + self.time = DtoLocalTime() + + def get_payload(self): + """Return Payload.""" + return self.time.to_payload() + + def from_payload(self, payload): + """Init frame from binary data.""" + self.time.from_payload(payload) + + def __str__(self): + """Return human readable string.""" + return '<{0}>{1}'.format(type(self).__name__, self.time) diff --git a/pyvlx/api/frames/frame_get_network_setup.py b/pyvlx/api/frames/frame_get_network_setup.py new file mode 100644 index 00000000..1795b3b6 --- /dev/null +++ b/pyvlx/api/frames/frame_get_network_setup.py @@ -0,0 +1,63 @@ +"""Frames for receiving network setup from gateway.""" +from pyvlx.const import Command, DHCPParameter +from .frame import FrameBase + + +class FrameGetNetworkSetupRequest(FrameBase): + """Frame for requesting network setup.""" + + PAYLOAD_LEN = 0 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_GET_NETWORK_SETUP_REQ) + + +class FrameGetNetworkSetupConfirmation(FrameBase): + """Frame for confirmation for get network setup requests.""" + + PAYLOAD_LEN = 13 + + def __init__(self, ipaddress=bytes(4), netmask=bytes(4), gateway=bytes(4), + dhcp=DHCPParameter.DISABLE): + """Init Frame.""" + super().__init__(Command.GW_GET_NETWORK_SETUP_CFM) + self._ipaddress = ipaddress + self._netmask = netmask + self._gateway = gateway + self.dhcp = dhcp + + @property + def ipaddress(self): + """Return ipaddress as human readable string.""" + return ".".join(str(c) for c in self._ipaddress) + + @property + def netmask(self): + """Return ipaddress as human readable string.""" + return ".".join(str(c) for c in self._netmask) + + @property + def gateway(self): + """Return ipaddress as human readable string.""" + return ".".join(str(c) for c in self._gateway) + + def get_payload(self): + """Return Payload.""" + payload = self._ipaddress + payload += self._netmask + payload += self._gateway + payload += bytes(self.dhcp.value) + return payload + + def from_payload(self, payload): + """Init frame from binary data.""" + self._ipaddress = payload[0:4] + self._netmask = payload[4:8] + self._gateway = payload[8:12] + self.dhcp = DHCPParameter(payload[12]) + + def __str__(self): + """Return human readable string.""" + return '<{} ipaddress="{}" netmask="{}" gateway="{}" dhcp="{}"/>'.format( + type(self).__name__, self.ipaddress, self.netmask, self.gateway, self.dhcp) diff --git a/pyvlx/frames/frame_get_node_information.py b/pyvlx/api/frames/frame_get_node_information.py similarity index 90% rename from pyvlx/frames/frame_get_node_information.py rename to pyvlx/api/frames/frame_get_node_information.py index 7c114dfe..f27b5963 100644 --- a/pyvlx/frames/frame_get_node_information.py +++ b/pyvlx/api/frames/frame_get_node_information.py @@ -3,13 +3,13 @@ from datetime import datetime from enum import Enum -from pyvlx.alias_array import AliasArray from pyvlx.const import Command, NodeTypeWithSubtype, NodeVariation, Velocity from pyvlx.exception import PyVLXException from pyvlx.parameter import Parameter from pyvlx.string_helper import bytes_to_string, string_to_bytes from .frame import FrameBase +from .alias_array import AliasArray class FrameGetNodeInformationRequest(FrameBase): @@ -32,7 +32,7 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format(self.node_id) + return '<{} node_id="{}"/>'.format(type(self).__name__, self.node_id) class NodeInformationStatus(Enum): @@ -65,8 +65,8 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.node_id, self.status + return '<{} node_id="{}" status="{}"/>'.format( + type(self).__name__, self.node_id, self.status ) @@ -184,13 +184,14 @@ def timestamp_formatted(self): def __str__(self): """Return human readable string.""" return ( - "".format( + '<{} node_id="{}" order="{}" ' + 'placement="{}" name="{}" velocity="{}" node_type="{}" product_group="{}" ' + 'product_type="{}" node_variation="{}" power_mode="{}" build_number="{}" ' + 'serial_number="{}" state="{}" current_position="{}" ' + 'target="{}" current_position_fp1="{}" current_position_fp2="{}" ' + 'current_position_fp3="{}" current_position_fp4="{}" ' + 'remaining_time="{}" time="{}" alias_array="{}"/>'.format( + type(self).__name__, self.node_id, self.order, self.placement, diff --git a/pyvlx/frames/frame_get_protocol_version.py b/pyvlx/api/frames/frame_get_protocol_version.py similarity index 93% rename from pyvlx/frames/frame_get_protocol_version.py rename to pyvlx/api/frames/frame_get_protocol_version.py index 50f659a4..0ec9ac1b 100644 --- a/pyvlx/frames/frame_get_protocol_version.py +++ b/pyvlx/api/frames/frame_get_protocol_version.py @@ -48,6 +48,6 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return ''.format( - self.version + return '<{} version="{}"/>'.format( + type(self).__name__, self.version ) diff --git a/pyvlx/frames/frame_get_scene_list.py b/pyvlx/api/frames/frame_get_scene_list.py similarity index 90% rename from pyvlx/frames/frame_get_scene_list.py rename to pyvlx/api/frames/frame_get_scene_list.py index 1749969a..1b722b69 100644 --- a/pyvlx/frames/frame_get_scene_list.py +++ b/pyvlx/api/frames/frame_get_scene_list.py @@ -36,8 +36,8 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.count_scenes + return '<{} count_scenes="{}"/>'.format( + type(self).__name__, self.count_scenes ) @@ -75,6 +75,6 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format( - self.scenes, self.remaining_scenes + return '<{} scenes="{}" remaining_scenes="{}">'.format( + type(self).__name__, self.scenes, self.remaining_scenes ) diff --git a/pyvlx/frames/frame_get_state.py b/pyvlx/api/frames/frame_get_state.py similarity index 51% rename from pyvlx/frames/frame_get_state.py rename to pyvlx/api/frames/frame_get_state.py index f02cb927..fe685b78 100644 --- a/pyvlx/frames/frame_get_state.py +++ b/pyvlx/api/frames/frame_get_state.py @@ -1,8 +1,5 @@ """Frames for receiving state from gateway.""" -from enum import Enum - -from pyvlx.const import Command - +from pyvlx.const import Command, GatewayState, GatewaySubState from .frame import FrameBase @@ -16,39 +13,15 @@ def __init__(self): super().__init__(Command.GW_GET_STATE_REQ) -class GatewayState(Enum): - """Enum class for status if gateway.""" - - TEST_MODE = 0 - GATEWAY_MODE_NO_ACTUATOR = 1 - GATEWAY_MODE_WITH_ACTUATORS = 2 - BEACON_MODE_NOT_CONFIGURED = 3 - BEACON_MODE_CONFIGURED = 4 - - -class GatewaySubState(Enum): - """Enum class for substate if gateway.""" - - IDLE = 0x00 - PERFORMING_TASK_CONFIGURATION_SERVICE_HANDLER = 0x01 - PERFORMING_TASK_SCENE_CONFIGURATION = 0x02 - PERFORMING_TASK_INFORMATION_SERVICE_CONFIGURATION = 0x03 - PERFORMING_TASK_CONTACT_INPUT_CONFIGURATION = 0x04 - PERFORMING_TASK_COMMAND = 0x80 - PERFORMING_TASK_ACTIVATE_GROUP = 0x81 - PERFORMING_TASK_ACTIVATE_SCENE = 0x82 - RESERVED_132 = 0x84 # <-- hey @VELUX: Can you tell us what this value means? - - class FrameGetStateConfirmation(FrameBase): """Frame for confirmation for get state requests.""" PAYLOAD_LEN = 6 def __init__( - self, - gateway_state=GatewayState.TEST_MODE, - gateway_sub_state=GatewaySubState.IDLE, + self, + gateway_state=GatewayState.TEST_MODE, + gateway_sub_state=GatewaySubState.IDLE, ): """Init Frame.""" super().__init__(Command.GW_GET_STATE_CFM) @@ -68,6 +41,6 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return ''.format( - self.gateway_state, self.gateway_sub_state + return '<{} gateway_state="{}" gateway_sub_state="{}"/>'.format( + type(self).__name__, self.gateway_state, self.gateway_sub_state ) diff --git a/pyvlx/frames/frame_get_version.py b/pyvlx/api/frames/frame_get_version.py similarity index 91% rename from pyvlx/frames/frame_get_version.py rename to pyvlx/api/frames/frame_get_version.py index d835a3da..b5d0b06f 100644 --- a/pyvlx/frames/frame_get_version.py +++ b/pyvlx/api/frames/frame_get_version.py @@ -64,8 +64,7 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" return ( - ''.format( - self.software_version, self.hardware_version, self.product + '<{} software_version="{}" hardware_version="{}" product="{}"/>'.format( + type(self).__name__, self.software_version, self.hardware_version, self.product ) ) diff --git a/pyvlx/frames/frame_helper.py b/pyvlx/api/frames/frame_helper.py similarity index 94% rename from pyvlx/frames/frame_helper.py rename to pyvlx/api/frames/frame_helper.py index 39ac6d42..7df6dbe0 100644 --- a/pyvlx/frames/frame_helper.py +++ b/pyvlx/api/frames/frame_helper.py @@ -33,6 +33,6 @@ def extract_from_frame(data): payload = data[4:-1] try: command = Command(data[2] * 256 + data[3]) - except ValueError: - raise PyVLXException("could_not_extract_from_frame_command", data=data) + except ValueError as type_error: + raise PyVLXException("could_not_extract_from_frame_command", data=data) from type_error return command, payload diff --git a/pyvlx/frames/frame_house_status_monitor_disable_cfm.py b/pyvlx/api/frames/frame_house_status_monitor_disable_cfm.py similarity index 100% rename from pyvlx/frames/frame_house_status_monitor_disable_cfm.py rename to pyvlx/api/frames/frame_house_status_monitor_disable_cfm.py diff --git a/pyvlx/frames/frame_house_status_monitor_disable_req.py b/pyvlx/api/frames/frame_house_status_monitor_disable_req.py similarity index 100% rename from pyvlx/frames/frame_house_status_monitor_disable_req.py rename to pyvlx/api/frames/frame_house_status_monitor_disable_req.py diff --git a/pyvlx/frames/frame_house_status_monitor_enable_cfm.py b/pyvlx/api/frames/frame_house_status_monitor_enable_cfm.py similarity index 100% rename from pyvlx/frames/frame_house_status_monitor_enable_cfm.py rename to pyvlx/api/frames/frame_house_status_monitor_enable_cfm.py diff --git a/pyvlx/frames/frame_house_status_monitor_enable_req.py b/pyvlx/api/frames/frame_house_status_monitor_enable_req.py similarity index 100% rename from pyvlx/frames/frame_house_status_monitor_enable_req.py rename to pyvlx/api/frames/frame_house_status_monitor_enable_req.py diff --git a/pyvlx/api/frames/frame_leave_learn_state.py b/pyvlx/api/frames/frame_leave_learn_state.py new file mode 100644 index 00000000..4fc21410 --- /dev/null +++ b/pyvlx/api/frames/frame_leave_learn_state.py @@ -0,0 +1,40 @@ +"""Module for leave learn state frame classes.""" +from pyvlx.const import Command, LeaveLearnStateConfirmationStatus +from .frame import FrameBase + + +class FrameLeaveLearnStateRequest(FrameBase): + """Frame for leaving learn state request.""" + + PAYLOAD_LEN = 0 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_LEAVE_LEARN_STATE_REQ) + + def __str__(self): + """Return human readable string.""" + return '<{}/>'.format(type(self).__name__) + + +class FrameLeaveLearnStateConfirmation(FrameBase): + """Frame for confirmation for leaving learn State.""" + + PAYLOAD_LEN = 1 + + def __init__(self, status=0): + """Init Frame.""" + super().__init__(Command.GW_LEAVE_LEARN_STATE_CFM) + self.status = LeaveLearnStateConfirmationStatus(status) + + def get_payload(self): + """Return Payload.""" + return bytes([self.status.value]) + + def from_payload(self, payload): + """Init frame from binary data.""" + self.status = LeaveLearnStateConfirmationStatus(payload[0]) + + def __str__(self): + """Return human readable string.""" + return '<{} status="{}"/>'.format(type(self).__name__, self.status) diff --git a/pyvlx/frames/frame_node_information_changed.py b/pyvlx/api/frames/frame_node_information_changed.py similarity index 77% rename from pyvlx/frames/frame_node_information_changed.py rename to pyvlx/api/frames/frame_node_information_changed.py index cd5af049..48efb436 100644 --- a/pyvlx/frames/frame_node_information_changed.py +++ b/pyvlx/api/frames/frame_node_information_changed.py @@ -11,12 +11,12 @@ class FrameNodeInformationChangedNotification(FrameBase): PAYLOAD_LEN = 69 def __init__( - self, - node_id=0, - name=None, - order=0, - placement=0, - node_variation=NodeVariation.NOT_SET, + self, + node_id=0, + name=None, + order=0, + placement=0, + node_variation=NodeVariation.NOT_SET, ): """Init Frame.""" super().__init__(Command.GW_NODE_INFORMATION_CHANGED_NTF) @@ -46,8 +46,9 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" return ( - ''.format( - self.node_id, self.name, self.order, self.placement, self.node_variation + '<{} node_id="{}" name="{}" order="{}" ' + 'placement="{}" node_variation="{}"/>'.format( + type(self).__name__, self.node_id, self.name, + self.order, self.placement, self.node_variation ) ) diff --git a/pyvlx/frames/frame_node_state_position_changed_notification.py b/pyvlx/api/frames/frame_node_state_position_changed_notification.py similarity index 90% rename from pyvlx/frames/frame_node_state_position_changed_notification.py rename to pyvlx/api/frames/frame_node_state_position_changed_notification.py index f8c760f7..58c2b7b5 100644 --- a/pyvlx/frames/frame_node_state_position_changed_notification.py +++ b/pyvlx/api/frames/frame_node_state_position_changed_notification.py @@ -64,11 +64,12 @@ def timestamp_formatted(self): def __str__(self): """Return human readable string.""" return ( - "".format( + '<{} node_id="{}" ' + 'state="{}" current_position="{}" ' + 'target="{}" current_position_fp1="{}" current_position_fp2="{}" ' + 'current_position_fp3="{}" current_position_fp4="{}" ' + 'remaining_time="{}" time="{}"/>'.format( + type(self).__name__, self.node_id, self.state, self.current_position, diff --git a/pyvlx/api/frames/frame_password_change.py b/pyvlx/api/frames/frame_password_change.py new file mode 100644 index 00000000..7e40ac8c --- /dev/null +++ b/pyvlx/api/frames/frame_password_change.py @@ -0,0 +1,113 @@ +"""Module for password enter frame classes.""" +from enum import Enum + +from pyvlx.const import Command +from pyvlx.exception import PyVLXException +from pyvlx.string_helper import bytes_to_string, string_to_bytes + +from .frame import FrameBase + + +class FramePasswordChangeRequest(FrameBase): + """Frame for sending password enter request.""" + + MAX_SIZE = 32 + PAYLOAD_LEN = 64 + + def __init__(self, currentpassword=None, newpassword=None): + """Init Frame.""" + super().__init__(Command.GW_PASSWORD_CHANGE_REQ) + self.currentpassword = currentpassword + self.newpassword = newpassword + + def get_payload(self): + """Return Payload.""" + if self.currentpassword is None: + raise PyVLXException("currentpassword is none") + if self.newpassword is None: + raise PyVLXException("newpassword is none") + if len(self.currentpassword) > self.MAX_SIZE: + raise PyVLXException("currentpassword is too long") + if len(self.newpassword) > self.MAX_SIZE: + raise PyVLXException("newpassword is too long") + + return string_to_bytes(self.currentpassword, + self.MAX_SIZE)+string_to_bytes(self.newpassword, self.MAX_SIZE) + + def from_payload(self, payload): + """Init frame from binary data.""" + self.currentpassword = bytes_to_string(payload[0:32]) + self.newpassword = bytes_to_string(payload[32:]) + + def __str__(self): + """Return human readable string.""" + currentpassword_esc = ( + None if self.currentpassword is None else "{}****".format(self.currentpassword[:2]) + ) + newpassword_esc = ( + None if self.newpassword is None else "{}****".format(self.newpassword[:2]) + ) + return ('<{} currentpassword="{}" newpassword="{}"/>' + .format(type(self).__name__, currentpassword_esc, newpassword_esc)) + + +class PasswordChangeConfirmationStatus(Enum): + """Enum class for status of password change confirmation.""" + + SUCCESSFUL = 0 + FAILED = 1 + + +class FramePasswordChangeConfirmation(FrameBase): + """Frame for confirmation for sent password.""" + + PAYLOAD_LEN = 1 + + def __init__(self, status=PasswordChangeConfirmationStatus.SUCCESSFUL): + """Init Frame.""" + super().__init__(Command.GW_PASSWORD_CHANGE_CFM) + self.status = status + + def get_payload(self): + """Return Payload.""" + return bytes([self.status.value]) + + def from_payload(self, payload): + """Init frame from binary data.""" + self.status = PasswordChangeConfirmationStatus(payload[0]) + + def __str__(self): + """Return human readable string.""" + return '<{} status="{}"/>'.format(type(self).__name__, self.status) + + +class FramePasswordChangeNotification(FrameBase): + """Frame for sending password changed notification request.""" + + MAX_SIZE = 32 + PAYLOAD_LEN = 32 + + def __init__(self, newpassword=None): + """Init Frame.""" + super().__init__(Command.GW_PASSWORD_CHANGE_NTF) + self.newpassword = newpassword + + def get_payload(self): + """Return Payload.""" + if self.newpassword is None: + raise PyVLXException("newpassword is none") + if len(self.newpassword) > self.MAX_SIZE: + raise PyVLXException("newpassword is too long") + + return string_to_bytes(self.newpassword, self.MAX_SIZE) + + def from_payload(self, payload): + """Init frame from binary data.""" + self.newpassword = bytes_to_string(payload) + + def __str__(self): + """Return human readable string.""" + newpassword_esc = ( + None if self.newpassword is None else "{}****".format(self.newpassword[:2]) + ) + return '<{} newpassword="{}"/>'.format(type(self).__name__, newpassword_esc) diff --git a/pyvlx/frames/frame_password_enter.py b/pyvlx/api/frames/frame_password_enter.py similarity index 92% rename from pyvlx/frames/frame_password_enter.py rename to pyvlx/api/frames/frame_password_enter.py index e0375d0c..3ee1328d 100644 --- a/pyvlx/frames/frame_password_enter.py +++ b/pyvlx/api/frames/frame_password_enter.py @@ -36,7 +36,7 @@ def __str__(self): password_esc = ( None if self.password is None else "{}****".format(self.password[:2]) ) - return "".format(password_esc) + return '<{} password="{}"/>'.format(type(self).__name__, password_esc) class PasswordEnterConfirmationStatus(Enum): @@ -66,4 +66,4 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return "".format(self.status) + return '<{} status="{}"/>'.format(type(self).__name__, self.status) diff --git a/pyvlx/frames/frame_reboot.py b/pyvlx/api/frames/frame_reboot.py similarity index 74% rename from pyvlx/frames/frame_reboot.py rename to pyvlx/api/frames/frame_reboot.py index 26382d77..ad71e41f 100644 --- a/pyvlx/frames/frame_reboot.py +++ b/pyvlx/api/frames/frame_reboot.py @@ -5,7 +5,7 @@ class FrameGatewayRebootRequest(FrameBase): - """Frame for requesting version.""" + """Frame for requesting reboot.""" PAYLOAD_LEN = 0 @@ -15,11 +15,11 @@ def __init__(self): def __str__(self): """Return human readable string.""" - return "" + return '<{}/>'.format(type(self).__name__) class FrameGatewayRebootConfirmation(FrameBase): - """Frame for response for get version requests.""" + """Frame for response for reboot requests.""" PAYLOAD_LEN = 0 @@ -29,4 +29,4 @@ def __init__(self): def __str__(self): """Return human readable string.""" - return "" + return '<{}/>'.format(type(self).__name__) diff --git a/pyvlx/frames/frame_set_node_name.py b/pyvlx/api/frames/frame_set_node_name.py similarity index 88% rename from pyvlx/frames/frame_set_node_name.py rename to pyvlx/api/frames/frame_set_node_name.py index 32ba31d9..f7cb1f64 100644 --- a/pyvlx/frames/frame_set_node_name.py +++ b/pyvlx/api/frames/frame_set_node_name.py @@ -31,8 +31,8 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return ''.format( - self.node_id, self.name + return '<{} node_id="{}" name="{}"/>'.format( + type(self).__name__, self.node_id, self.name ) @@ -66,6 +66,6 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return ''.format( - self.node_id, self.status + return '<{} node_id="{}" status="{}"/>'.format( + type(self).__name__, self.node_id, self.status ) diff --git a/pyvlx/frames/frame_set_utc_req.py b/pyvlx/api/frames/frame_set_utc.py similarity index 70% rename from pyvlx/frames/frame_set_utc_req.py rename to pyvlx/api/frames/frame_set_utc.py index 8c9a4da9..55fbdfcc 100644 --- a/pyvlx/frames/frame_set_utc_req.py +++ b/pyvlx/api/frames/frame_set_utc.py @@ -1,14 +1,22 @@ """Module for sending command to gw.""" import struct from datetime import datetime - from pyvlx.const import Command - from .frame import FrameBase +class FrameSetUTCConfirmation(FrameBase): + """Frame for confirmation for setting UTC time.""" + + PAYLOAD_LEN = 0 + + def __init__(self): + """Init Frame.""" + super().__init__(Command.GW_SET_UTC_CFM) + + class FrameSetUTCRequest(FrameBase): - """Frame for sending command to gw.""" + """Frame for command for setting UTC time.""" PAYLOAD_LEN = 4 @@ -32,4 +40,4 @@ def from_payload(self, payload): def __str__(self): """Return human readable string.""" - return ''.format(self.timestamp_formatted) + return '<{} time="{}"/>'.format(type(self).__name__, self.timestamp_formatted) diff --git a/pyvlx/get_all_nodes_information.py b/pyvlx/api/get_all_nodes_information.py similarity index 98% rename from pyvlx/get_all_nodes_information.py rename to pyvlx/api/get_all_nodes_information.py index f4737fd3..33527a6f 100644 --- a/pyvlx/get_all_nodes_information.py +++ b/pyvlx/api/get_all_nodes_information.py @@ -1,11 +1,11 @@ """Module for retrieving node information from API.""" +from pyvlx.log import PYVLXLOG from .api_event import ApiEvent from .frames import ( FrameGetAllNodesInformationConfirmation, FrameGetAllNodesInformationFinishedNotification, FrameGetAllNodesInformationNotification, FrameGetAllNodesInformationRequest) -from .log import PYVLXLOG class GetAllNodesInformation(ApiEvent): diff --git a/pyvlx/api/get_local_time.py b/pyvlx/api/get_local_time.py new file mode 100644 index 00000000..431ee580 --- /dev/null +++ b/pyvlx/api/get_local_time.py @@ -0,0 +1,28 @@ +"""Module for local time firmware version from API.""" +from pyvlx.dataobjects import DtoLocalTime + +from .api_event import ApiEvent +from .frames import FrameGetLocalTimeConfirmation, FrameGetLocalTimeRequest + + +class GetLocalTime(ApiEvent): + """Class for retrieving firmware version from API.""" + + def __init__(self, pyvlx): + """Initialize GetLocalTime class.""" + super().__init__(pyvlx=pyvlx) + self.success = False + self.localtime = DtoLocalTime() + + async def handle_frame(self, frame): + """Handle incoming API frame, return True if this was the expected frame.""" + if not isinstance(frame, FrameGetLocalTimeConfirmation): + return False + self.localtime = frame.localtime + self.success = True + + return True + + def request_frame(self): + """Construct initiating frame.""" + return FrameGetLocalTimeRequest() diff --git a/pyvlx/api/get_network_setup.py b/pyvlx/api/get_network_setup.py new file mode 100644 index 00000000..eeff948e --- /dev/null +++ b/pyvlx/api/get_network_setup.py @@ -0,0 +1,28 @@ +"""Module for retrieving gateway state from API.""" +from pyvlx.dataobjects import DtoNetworkSetup + +from .api_event import ApiEvent +from .frames import FrameGetNetworkSetupConfirmation, FrameGetNetworkSetupRequest + + +class GetNetworkSetup(ApiEvent): + """Class for retrieving gateway state from API.""" + + def __init__(self, pyvlx): + """Initialize GetNetworkSetup class.""" + super().__init__(pyvlx=pyvlx) + self.success = False + self.networksetup = DtoNetworkSetup() + + async def handle_frame(self, frame): + """Handle incoming API frame, return True if this was the expected frame.""" + if not isinstance(frame, FrameGetNetworkSetupConfirmation): + return False + self.success = True + self.networksetup = DtoNetworkSetup( + frame.ipaddress, frame.gateway, frame.netmask, frame.dhcp) + return True + + def request_frame(self): + """Construct initiating frame.""" + return FrameGetNetworkSetupRequest() diff --git a/pyvlx/get_node_information.py b/pyvlx/api/get_node_information.py similarity index 81% rename from pyvlx/get_node_information.py rename to pyvlx/api/get_node_information.py index 47305d2b..e7fcce7d 100644 --- a/pyvlx/get_node_information.py +++ b/pyvlx/api/get_node_information.py @@ -18,14 +18,14 @@ def __init__(self, pyvlx, node_id): async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if ( - isinstance(frame, FrameGetNodeInformationConfirmation) - and frame.node_id == self.node_id + isinstance(frame, FrameGetNodeInformationConfirmation) + and frame.node_id == self.node_id ): # We are still waiting for GetNodeInformationNotification return False if ( - isinstance(frame, FrameGetNodeInformationNotification) - and frame.node_id == self.node_id + isinstance(frame, FrameGetNodeInformationNotification) + and frame.node_id == self.node_id ): self.notification_frame = frame self.success = True diff --git a/pyvlx/get_protocol_version.py b/pyvlx/api/get_protocol_version.py similarity index 63% rename from pyvlx/get_protocol_version.py rename to pyvlx/api/get_protocol_version.py index d2aaf00c..072109e1 100644 --- a/pyvlx/get_protocol_version.py +++ b/pyvlx/api/get_protocol_version.py @@ -1,4 +1,6 @@ """Module for retrieving protocol version from API.""" + +from pyvlx.dataobjects import DtoProtocolVersion from .api_event import ApiEvent from .frames import ( FrameGetProtocolVersionConfirmation, FrameGetProtocolVersionRequest) @@ -8,19 +10,24 @@ class GetProtocolVersion(ApiEvent): """Class for retrieving protocol version from API.""" def __init__(self, pyvlx): - """Initialize login class.""" + """Initialize GetProtocolVersion class.""" super().__init__(pyvlx=pyvlx) self.success = False - self.version = None + self.protocolversion = DtoProtocolVersion() async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if not isinstance(frame, FrameGetProtocolVersionConfirmation): return False - self.version = frame.version + self.protocolversion = DtoProtocolVersion(frame.major_version, frame.minor_version) self.success = True return True def request_frame(self): """Construct initiating frame.""" return FrameGetProtocolVersionRequest() + + @property + def version(self): + """Return Protocol Version as human readable string.""" + return "{}.{}".format(self.protocolversion.majorversion, self.protocolversion.minorversion) diff --git a/pyvlx/get_scene_list.py b/pyvlx/api/get_scene_list.py similarity index 98% rename from pyvlx/get_scene_list.py rename to pyvlx/api/get_scene_list.py index f6081444..a6a26649 100644 --- a/pyvlx/get_scene_list.py +++ b/pyvlx/api/get_scene_list.py @@ -1,9 +1,9 @@ """Module for retrieving scene list from API.""" +from pyvlx.log import PYVLXLOG from .api_event import ApiEvent from .frames import ( FrameGetSceneListConfirmation, FrameGetSceneListNotification, FrameGetSceneListRequest) -from .log import PYVLXLOG class GetSceneList(ApiEvent): diff --git a/pyvlx/get_state.py b/pyvlx/api/get_state.py similarity index 57% rename from pyvlx/get_state.py rename to pyvlx/api/get_state.py index 91024f55..e0eb5f05 100644 --- a/pyvlx/get_state.py +++ b/pyvlx/api/get_state.py @@ -1,4 +1,6 @@ """Module for retrieving gateway state from API.""" +from pyvlx.dataobjects import DtoState + from .api_event import ApiEvent from .frames import FrameGetStateConfirmation, FrameGetStateRequest @@ -7,21 +9,29 @@ class GetState(ApiEvent): """Class for retrieving gateway state from API.""" def __init__(self, pyvlx): - """Initialize login class.""" + """Initialize GetState class.""" super().__init__(pyvlx=pyvlx) self.success = False - self.gateway_state = None - self.gateway_sub_state = None + self.state = DtoState() async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if not isinstance(frame, FrameGetStateConfirmation): return False self.success = True - self.gateway_state = frame.gateway_state - self.gateway_sub_state = frame.gateway_sub_state + self.state = DtoState(frame.gateway_state, frame.gateway_sub_state) return True def request_frame(self): """Construct initiating frame.""" return FrameGetStateRequest() + + @property + def gateway_state(self): + """Return Gateway State as human readable string. Deprecated.""" + return self.state.gateway_state + + @property + def gateway_sub_state(self): + """Return Gateway Sub State as human readable string. Deprecated.""" + return self.state.gateway_sub_state diff --git a/pyvlx/get_version.py b/pyvlx/api/get_version.py similarity index 72% rename from pyvlx/get_version.py rename to pyvlx/api/get_version.py index fe43b45b..e3afbc85 100644 --- a/pyvlx/get_version.py +++ b/pyvlx/api/get_version.py @@ -1,4 +1,6 @@ """Module for retrieving firmware version from API.""" +from pyvlx.dataobjects import DtoVersion + from .api_event import ApiEvent from .frames import FrameGetVersionConfirmation, FrameGetVersionRequest @@ -7,16 +9,17 @@ class GetVersion(ApiEvent): """Class for retrieving firmware version from API.""" def __init__(self, pyvlx): - """Initialize login class.""" + """Initialize GetVersion class.""" super().__init__(pyvlx=pyvlx) self.success = False - self.version = None + self.version = DtoVersion() async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if not isinstance(frame, FrameGetVersionConfirmation): return False - self.version = frame.version + self.version = DtoVersion(frame.software_version, frame.hardware_version, + frame.product_group, frame.product_type) self.success = True return True diff --git a/pyvlx/house_status_monitor.py b/pyvlx/api/house_status_monitor.py similarity index 93% rename from pyvlx/house_status_monitor.py rename to pyvlx/api/house_status_monitor.py index 920c412a..1afe76a3 100644 --- a/pyvlx/house_status_monitor.py +++ b/pyvlx/api/house_status_monitor.py @@ -1,6 +1,6 @@ """Module for house status monitor.""" +from pyvlx.exception import PyVLXException from .api_event import ApiEvent -from .exception import PyVLXException from .frames import ( FrameHouseStatusMonitorDisableConfirmation, FrameHouseStatusMonitorDisableRequest, @@ -12,7 +12,7 @@ class HouseStatusMonitorEnable(ApiEvent): """Class for enabling house status monotor.""" def __init__(self, pyvlx): - """Initialize login class.""" + """Initialize HouseStatusMonitorEnable class.""" super().__init__(pyvlx=pyvlx) self.success = False @@ -32,7 +32,7 @@ class HouseStatusMonitorDisable(ApiEvent): """Class for disabling house status monotor.""" def __init__(self, pyvlx): - """Initialize login class.""" + """Initialize HouseStatusMonitorEnable class.""" super().__init__(pyvlx=pyvlx) self.success = False diff --git a/pyvlx/api/leave_learn_state.py b/pyvlx/api/leave_learn_state.py new file mode 100644 index 00000000..0bd8d265 --- /dev/null +++ b/pyvlx/api/leave_learn_state.py @@ -0,0 +1,28 @@ +"""Module for handling the login to API.""" +from pyvlx.dataobjects import DtoLeaveLearnState + +from .api_event import ApiEvent +from .frames import (FrameLeaveLearnStateRequest, + FrameLeaveLearnStateConfirmation) + + +class LeaveLearnState(ApiEvent): + """Class for handling leave learn state to API.""" + + def __init__(self, pyvlx): + """Initialize leave learn state class.""" + super().__init__(pyvlx=pyvlx) + self.status = DtoLeaveLearnState() + self.success = False + + async def handle_frame(self, frame): + """Handle incoming API frame, return True if this was the expected frame.""" + if not isinstance(frame, FrameLeaveLearnStateConfirmation): + return False + self.status = frame.status + self.success = True + return True + + def request_frame(self): + """Construct initiating frame.""" + return FrameLeaveLearnStateRequest() diff --git a/pyvlx/login.py b/pyvlx/api/password_enter.py similarity index 94% rename from pyvlx/login.py rename to pyvlx/api/password_enter.py index 65b61849..5d3fe94e 100644 --- a/pyvlx/login.py +++ b/pyvlx/api/password_enter.py @@ -1,12 +1,12 @@ """Module for handling the login to API.""" +from pyvlx.log import PYVLXLOG from .api_event import ApiEvent from .frames import ( FramePasswordEnterConfirmation, FramePasswordEnterRequest, PasswordEnterConfirmationStatus) -from .log import PYVLXLOG -class Login(ApiEvent): +class PasswordEnter(ApiEvent): """Class for handling login to API.""" def __init__(self, pyvlx, password): diff --git a/pyvlx/reboot.py b/pyvlx/api/reboot.py similarity index 74% rename from pyvlx/reboot.py rename to pyvlx/api/reboot.py index 8c969311..30b3f41f 100644 --- a/pyvlx/reboot.py +++ b/pyvlx/api/reboot.py @@ -1,22 +1,23 @@ -"""Module for handling the login to API.""" +"""Module for handling the Reboot to API.""" +from pyvlx.log import PYVLXLOG from .api_event import ApiEvent from .frames import FrameGatewayRebootConfirmation, FrameGatewayRebootRequest -from .log import PYVLXLOG class Reboot(ApiEvent): - """Class for handling login to API.""" + """Class for handling Reboot to API.""" def __init__(self, pyvlx): - """Initialize login class.""" + """Initialize Reboot class.""" super().__init__(pyvlx=pyvlx) self.pyvlx = pyvlx + self.success = False async def handle_frame(self, frame): """Handle incoming API frame, return True if this was the expected frame.""" if isinstance(frame, FrameGatewayRebootConfirmation): PYVLXLOG.warning("KLF200 is rebooting") - self.pyvlx.connection.connected = False + self.success = True return True return False diff --git a/pyvlx/session_id.py b/pyvlx/api/session_id.py similarity index 100% rename from pyvlx/session_id.py rename to pyvlx/api/session_id.py diff --git a/pyvlx/set_node_name.py b/pyvlx/api/set_node_name.py similarity index 100% rename from pyvlx/set_node_name.py rename to pyvlx/api/set_node_name.py diff --git a/pyvlx/set_utc.py b/pyvlx/api/set_utc.py similarity index 66% rename from pyvlx/set_utc.py rename to pyvlx/api/set_utc.py index d9469652..5182d808 100644 --- a/pyvlx/set_utc.py +++ b/pyvlx/api/set_utc.py @@ -1,17 +1,16 @@ """Module for setting UTC time within gateway.""" import time - from .api_event import ApiEvent -from .exception import PyVLXException from .frames import FrameSetUTCConfirmation, FrameSetUTCRequest class SetUTC(ApiEvent): """Class for setting UTC time within gateway.""" - def __init__(self, pyvlx): - """Initialize login class.""" + def __init__(self, pyvlx, timestamp=time.time()): + """Initialize SetUTC class.""" super().__init__(pyvlx=pyvlx) + self.timestamp = timestamp self.success = False async def handle_frame(self, frame): @@ -23,13 +22,5 @@ async def handle_frame(self, frame): def request_frame(self): """Construct initiating frame.""" - timestamp = int(time.time()) + timestamp = int(self.timestamp) return FrameSetUTCRequest(timestamp=timestamp) - - -async def set_utc(pyvlx): - """Enable house status monitor.""" - setutc = SetUTC(pyvlx=pyvlx) - await setutc.do_api_call() - if not setutc.success: - raise PyVLXException("Unable to set utc.") diff --git a/pyvlx/config.py b/pyvlx/config.py index 0af88c0a..748fa545 100644 --- a/pyvlx/config.py +++ b/pyvlx/config.py @@ -30,8 +30,8 @@ def read_config(self, path): self.password = doc["config"]["password"] if "port" in doc["config"]: self.port = doc["config"]["port"] - except FileNotFoundError as ex: - raise PyVLXException("file does not exist: {0}".format(ex)) + except FileNotFoundError as not_found: + raise PyVLXException("file does not exist: {0}".format(not_found)) from not_found @staticmethod def test_configuration(doc, path): diff --git a/pyvlx/connection.py b/pyvlx/connection.py index 3b45ad2a..fab5f05e 100644 --- a/pyvlx/connection.py +++ b/pyvlx/connection.py @@ -2,9 +2,10 @@ import asyncio import ssl +from .api.frame_creation import frame_from_raw +from .api.frames import FrameBase + from .exception import PyVLXException -from .frame_creation import frame_from_raw -from .frames import FrameBase from .log import PYVLXLOG from .slip import get_next_slip, is_slip, slip_pack diff --git a/pyvlx/const.py b/pyvlx/const.py index 432bbca4..08041c5a 100644 --- a/pyvlx/const.py +++ b/pyvlx/const.py @@ -28,9 +28,9 @@ class Command(Enum): GW_LEAVE_LEARN_STATE_CFM = 0x000F GW_GET_NETWORK_SETUP_REQ = 0x00E0 - GE_GET_NETWORK_SETUP_CFM = 0x00E1 + GW_GET_NETWORK_SETUP_CFM = 0x00E1 GW_SET_NETWORK_SETUP_REQ = 0x00E2 - GE_SET_NETWORK_SETUP_CFM = 0x00E3 + GW_SET_NETWORK_SETUP_CFM = 0x00E3 GW_CS_GET_SYSTEMTABLE_DATQ_REQ = 0x0100 GW_CS_GET_SYSTEMTABLE_DATA_CFM = 0x0101 @@ -219,22 +219,24 @@ class Command(Enum): GW_PASSWORD_CHANGE_REQ = 0x3002 GW_PASSWORD_CHANGE_CFM = 0x3003 - GW_PASSWORD_CHANGED_NTF = 0x3004 + GW_PASSWORD_CHANGE_NTF = 0x3004 class Originator(Enum): """Enum class for originator.""" - USER = 1 - RAIN = 2 - TIMER = 3 - UPS = 5 # UPC unit - SAAC = 8 # Stand Alone Automatic Controls - WIND = 9 - LOAD_SHEDDING = 11 - LOCAL_LIGHT = 12 - UNSPECIFIC_ENVIRONMENT_SENSOR = 13 - EMERGENCY = 255 + # pylint: disable=line-too-long + + USER = 1 # User Remote control causing action on actuator + RAIN = 2 # Rain sensor + TIMER = 3 # Timer controlled + UPS = 5 # UPC unit + SAAC = 8 # Stand Alone Automatic Controls + WIND = 9 # Wind sensor + LOAD_SHEDDING = 11 # Managers for requiring a particular electric load shed + LOCAL_LIGHT = 12 # Local light sensor + UNSPECIFIC_ENVIRONMENT_SENSOR = 13 # Used in context with commands transmitted on basis of an unknown sensor for protection of an end-product or house + EMERGENCY = 255 # Used in context with emergency or security commands class Priority(Enum): @@ -250,6 +252,14 @@ class Priority(Enum): COMFORT_LEVEL_4 = 7 +class LockPriorityLevel(Enum): + """Enum Class for Lock Priority Level.""" + + NO = 0 # Do not lock any priority level. + MIN30 = 1 # Lock one or more priority level in 30 minutes. + FOREVER = 2 # Lock one or more priority level forever + + class Velocity(Enum): """Enum class for velocity.""" @@ -263,6 +273,7 @@ class NodeTypeWithSubtype(Enum): """Enum class for node type plus sub type combined values.""" # pylint: disable=invalid-name + NO_TYPE = 0 INTERIOR_VENETIAN_BLIND = 0x0040 ROLLER_SHUTTER = 0x0080 @@ -334,3 +345,312 @@ class NodeVariation(Enum): KIP = 2 FLAT_ROOT = 3 SKY_LIGHT = 3 + + +class DHCPParameter(Enum): + """Enum class for dncp network setup of gateway.""" + + DISABLE = 0x00 + ENABLE = 0x01 + + +class GatewayState(Enum): + """Enum class for state of gateway.""" + + TEST_MODE = 0 + GATEWAY_MODE_NO_ACTUATOR = 1 + GATEWAY_MODE_WITH_ACTUATORS = 2 + BEACON_MODE_NOT_CONFIGURED = 3 + BEACON_MODE_CONFIGURED = 4 + + +class GatewaySubState(Enum): + """Enum class for substate of gateway.""" + + IDLE = 0x00 + PERFORMING_TASK_CONFIGURATION_SERVICE_HANDLER = 0x01 + PERFORMING_TASK_SCENE_CONFIGURATION = 0x02 + PERFORMING_TASK_INFORMATION_SERVICE_CONFIGURATION = 0x03 + PERFORMING_TASK_CONTACT_INPUT_CONFIGURATION = 0x04 + PERFORMING_TASK_COMMAND = 0x80 + PERFORMING_TASK_ACTIVATE_GROUP = 0x81 + PERFORMING_TASK_ACTIVATE_SCENE = 0x82 + RESERVED_132 = 0x84 # <-- hey @VELUX: Can you tell us what this value means? + + +class LeaveLearnStateConfirmationStatus(Enum): + """Enum class for status leaving Learn state.""" + + FAILED = 0 + SUCCESSFUL = 1 + + +class ErrorNumber(Enum): + """Enum class for Errornumber in GW_ERROR_NTF.""" + + UNDEFINED = 0 # Not further defined error. + WRONG_COMMAND = 1 # Unknown Command or command is not accepted at this state. + FRAME_ERROR = 2 # ERROR on Frame Structure. + BUSY = 7 # Busy. Try again later. + BAD_SYSTABLE_INDEX = 8 # Bad system table index. + NO_AUTH = 12 # Not authenticated. + + +class ControllerCopyMode(Enum): + """Enum class for Copy Controller Mode.""" + + # pylint: disable=line-too-long + + TCM = 0 # Transmitting Configuration Mode (TCM): The gateway gets key and system table from another controller. + RCM = 1 # Receiving Configuration Mode (RCM): The gateway gives key and system table to another controller. + + +class ControllerCopyStatus(Enum): + """Enum class for Copy Controller Mode.""" + + OK = 0 # OK. Data transfer to or from client controller. + FAILED_TRANSFER = 1 # Failed. Data transfer to or from client controller interrupted. + CANCELLED = 4 # Ok. Receiving configuration mode is cancelled in the client controller. + FAILED_TIMEOUT = 5 # Failed. Timeout. + FAILED_NOTREADY = 11 # Failed. Configuration service not ready. + + +class ChangeKeyStatus(Enum): + """Enum class for Key Change Status.""" + + # pylint: disable=line-too-long + + OK_CONTROLLER = 0 # Ok. Key Change in client controller. + OK_ALL = 2 # Ok. Key change in system table all nodes updated with current key. + OK_PARTIALLY = 3 # Ok. Key Change in System table. Not all nodes in system table was updated with current key. Check bit array. + OK_RECEIVED = 5 # Ok. Client controller received a key. + FAILED_NOTDISABLED = 7 # Failed. Local Stimuli not disabled in all Client System table nodes. See bit array. + FAILED_NOCONTROLLER = 9 # Failed. Not able to find a controller to get key from. + FAILED_DTSNOTREADY = 10 # Failed. DTS not ready. + FAILED_DTSERROR = 11 # Failed. DTS error. At DTS error no key change will take place. + FAILED_CSNOTREADY = 16 # Failed. CS not ready. + + +class PgcJobState(Enum): + """Enum class for Product Generic Configuration Job State.""" + + STARTED = 0 # PGC job started + ENDED = 1 # PGC job ended. Either OK or with error. + CS_BUSY = 2 # CS busy with other services + + +class PgcJobStatus(Enum): + """Enum class for Product Generic Configuration Job Status.""" + + OK = 0 # OK - PGC and CS job completed + OK_PARTIALLY = 1 # Partly success. + FAILED_PGCCS = 2 # Failed - Error in PGC/CS job. + FAILED = 3 # Failed - Too long key press or cancel of CS service. + + +class PgcJobType(Enum): + """Enum class for Product Generic Configuration Job Type.""" + + # pylint: disable=line-too-long + + RECEIVE_ONLY = 0 # Receive system copy or only get key. Short PGC button press. + RECEIVE_DISTRIBUTE = 1 # Receive key and distribute. Short PGC button press. + TRANSMIT = 2 # Transmit key (and system). Long PGC button press. + GENERATE = 3 # Generate new key and distribute or only generate new key. Very long PGC button press. + + +class DiscoverStatus(Enum): + """Enum class for Discovery status.""" + + # pylint: disable=line-too-long + + OK = 0 # OK. Discovered nodes. See bit array. + FAILED_CSNOTREADY = 5 # Failed. CS not ready. + OK_PARTIALLY = 6 # OK. Same as DISCOVER_NODES_PERFORMED but some nodes were not added to system table (e.g. System table has reached its limit). + FAILED_CSBUSY = 7 # CS busy with another task. + + +class PowerMode(Enum): + """Enum class for Acutuator power Mode.""" + + ALWAYS_ALIVE = 0 # ALWAYS_ALIVE + LOW_POWER_MODE = 1 # LOW_POWER_MODE + + +class ChangeType(Enum): + """Enum class Change Type in Group or Scene NTF.""" + + DELETED = 0 # Scene or Group deleted + MODIFIED = 1 # Information modified + + +class ContactInputAssignement(Enum): + """Enum class for Contact Input.""" + + NOT_ASSINGED = 0 # Input not assigned. + SCENE = 1 # Scene + PRODUCT_GROUP = 2 # Product group + BY_MODE = 3 # One node controlled by mode + + +class OutputID(Enum): + """Enum class for Error and Success Output ID.""" + + DONT_SEND = 0 # Don’t send any pulse. + PULSE_PORT_1 = 1 # Send pulse to output port number 1 + PULSE_PORT_2 = 2 # Send pulse to output port number 2 + PULSE_PORT_3 = 3 # Send pulse to output port number 3 + PULSE_PORT_4 = 4 # Send pulse to output port number 4 + PULSE_PORT_5 = 5 # Send pulse to output port number 5 + + +class GroupType(Enum): + """Enum class for Group Types.""" + + USER_GROUP = 0 # The group type is a user group. + ROOM = 1 # The group type is a Room. + HOUSE = 2 # The group type is a House. + ALL_GROUP = 3 # The group type is an All-group. + + +class LimitationTimer(Enum): + """Enum class for Limitation Timer.""" + + BY_SECONDS = 1 # 1=30 seconds 2=60 seconds 252=7590 seconds + UNLIMITED = 253 # unlimited + CLEAR_MASTER = 254 # clear entry for the Master + CLEAR_ALL = 255 # clear all + + +class LimitationType(Enum): + """Enum class for Limitation Types.""" + + MIN_LIMITATION = 0 # Resulting minimum limitation. + MAX_LIMITATION = 1 # Resulting maximum limitation. + + +class LockTime(Enum): + """Enum class for Lock Time.""" + + BY_SECONDS = 1 # 1=30 seconds, 2=60 seconds .. 254=7650 seconds + UNLIMITED = 255 # Unlimited time + + +class WinkTime(Enum): + """Enum class for Wink Time.""" + + STOP = 0 # Stop wink. + BY_SECONDS = 1 # 1=Wink in 1 sec., 2= Wink in 2 sec. 253=Wink in 253 sec. + BY_MANUFACTUERER = 254 # Manufacturer specific wink time. + FOREVER = 255 # Wink forever. + + +class NodeParameter(Enum): + """Enum Class for Node Parameter.""" + + MP = 0x00 # Main Parameter. + FP1 = 0x01 # Functional Parameter number 1. + FP2 = 0x02 # Functional Parameter number 2. + FP3 = 0x03 # Functional Parameter number 3. + FP4 = 0x04 # Functional Parameter number 4. + FP5 = 0x05 # Functional Parameter number 5. + FP6 = 0x06 # Functional Parameter number 6. + FP7 = 0x07 # Functional Parameter number 7. + FP8 = 0x08 # Functional Parameter number 8. + FP9 = 0x09 # Functional Parameter number 9. + FP10 = 0x0A # Functional Parameter number 10. + FP11 = 0x0B # Functional Parameter number 11. + FP12 = 0x0C # Functional Parameter number 12. + FP13 = 0x0D # Functional Parameter number 13. + FP14 = 0x0E # Functional Parameter number 14. + FP15 = 0x0F # Functional Parameter number 15. + FP16 = 0x10 # Functional Parameter number 16. + NOT_USED = 0xFF # Value to indicate Functional Parameter not used. + + +class OperatingState(Enum): + """Enum Class for operating state of the node.""" + + NON_EXECUTING = 0 + ERROR_EXECUTING = 1 + NOT_USED = 2 + WAIT_FOR_POWER = 3 + EXECUTING = 4 + DONE = 5 + UNKNOWN = 255 + + +class StatusReply(Enum): + """Enum Class for Node Status Reply.""" + + # pylint: disable=line-too-long + + UNKNOWN_STATUS_REPLY = 0x00 # Used to indicate unknown reply. + COMMAND_COMPLETED_OK = 0x01 # Indicates no errors detected. + NO_CONTACT = 0x02 # Indicates no communication to node. + MANUALLY_OPERATED = 0x03 # Indicates manually operated by a user. + BLOCKED = 0x04 # Indicates node has been blocked by an object. + WRONG_SYSTEMKEY = 0x05 # Indicates the node contains a wrong system key. + PRIORITY_LEVEL_LOCKED = 0x06 # Indicates the node is locked on this priority level. + REACHED_WRONG_POSITION = 0x07 # Indicates node has stopped in another position than expected. + ERROR_DURING_EXECUTION = 0x08 # Indicates an error has occurred during execution of command. + NO_EXECUTION = 0x09 # Indicates no movement of the node parameter. + CALIBRATING = 0x0A # Indicates the node is calibrating the parameters. + POWER_CONSUMPTION_TOO_HIGH = 0x0B # Indicates the node power consumption is too high. + POWER_CONSUMPTION_TOO_LOW = 0x0C # Indicates the node power consumption is too low. + LOCK_POSITION_OPEN = 0x0D # Indicates door lock errors. (Door open during lock command) + MOTION_TIME_TOO_LONG__COMMUNICATION_ENDED = 0x0E # Indicates the target was not reached in time. + THERMAL_PROTECTION = 0x0F # Indicates the node has gone into thermal protection mode. + PRODUCT_NOT_OPERATIONAL = 0x10 # Indicates the node is not currently operational. + FILTER_MAINTENANCE_NEEDED = 0x11 # Indicates the filter needs maintenance. + BATTERY_LEVEL = 0x12 # Indicates the battery level is low. + TARGET_MODIFIED = 0x13 # Indicates the node has modified the target value of the command. + MODE_NOT_IMPLEMENTED = 0x14 # Indicates this node does not support the mode received. + COMMAND_INCOMPATIBLE_TO_MOVEMENT = 0x15 # Indicates the node is unable to move in the right direction. + USER_ACTION = 0x16 # Indicates dead bolt is manually locked during unlock command. + DEAD_BOLT_ERROR = 0x17 # Indicates dead bolt error. + AUTOMATIC_CYCLE_ENGAGED = 0x18 # Indicates the node has gone into automatic cycle mode. + WRONG_LOAD_CONNECTED = 0x19 # Indicates wrong load on node. + COLOUR_NOT_REACHABLE = 0x1A # Indicates that node is unable to reach received colour code. + TARGET_NOT_REACHABLE = 0x1B # Indicates the node is unable to reach received target position. + BAD_INDEX_RECEIVED = 0x1C # Indicates io-protocol has received an invalid index. + COMMAND_OVERRULED = 0x1D # Indicates that the command was overruled by a new command. + NODE_WAITING_FOR_POWER = 0x1E # Indicates that the node reported waiting for power. + INFORMATION_CODE = 0xDF # Indicates an unknown error code received. (Hex code is shown on display) + PARAMETER_LIMITED = 0xE0 # Indicates the parameter was limited by an unknown device. (Same as LIMITATION_BY_UNKNOWN_DEVICE) + LIMITATION_BY_LOCAL_USER = 0xE1 # Indicates the parameter was limited by local button. + LIMITATION_BY_USER = 0xE2 # Indicates the parameter was limited by a remote control. + LIMITATION_BY_RAIN = 0xE3 # Indicates the parameter was limited by a rain sensor. + LIMITATION_BY_TIMER = 0xE4 # Indicates the parameter was limited by a timer. + LIMITATION_BY_UPS = 0xE6 # Indicates the parameter was limited by a power supply. + LIMITATION_BY_UNKNOWN_DEVICE = 0xE7 # Indicates the parameter was limited by an unknown device. (Same as PARAMETER_LIMITED) + LIMITATION_BY_SAAC = 0xEA # Indicates the parameter was limited by a standalone automatic controller. + LIMITATION_BY_WIND = 0xEB # Indicates the parameter was limited by a wind sensor. + LIMITATION_BY_MYSELF = 0xEC # Indicates the parameter was limited by the node itself. + LIMITATION_BY_AUTOMATIC_CYCLE = 0xED # Indicates the parameter was limited by an automatic cycle. + LIMITATION_BY_EMERGENCY = 0xEE # Indicates the parameter was limited by an emergency. + + +class StatusId(Enum): + """Enum Class for Status ID Reply.""" + + # pylint: disable=line-too-long + + STATUS_USER = 0x01 # The status is from a user activation. + STATUS_RAIN = 0x02 # The status is from a rain sensor activation. + STATUS_TIMER = 0x03 # The status is from a timer generated action. + STATUS_UPS = 0x05 # The status is from a UPS generated action. + STATUS_PROGRAM = 0x08 # The status is from an automatic program generated action. (SAAC) + STATUS_WIND = 0x09 # The status is from a Wind sensor generated action. + STATUS_MYSELF = 0x0A # The status is from an actuator generated action. + STATUS_AUTOMATIC_CYCLE = 0x0B # The status is from a automatic cycle generated action. + STATUS_EMERGENCY = 0x0C # The status is from an emergency or a security generated action. + STATUS_UNKNOWN = 0xFF # The status is from from an unknown command originator action. + + +class RunStatus(Enum): + """Enum Class for Node Runstatus.""" + + EXECUTION_COMPLETED = 0 # Execution is completed with no errors. + EXECUTION_FAILED = 1 # Execution has failed. (Get specifics in the following error code) + EXECUTION_ACTIVE = 2 # Execution is still active. diff --git a/pyvlx/dataobjects.py b/pyvlx/dataobjects.py new file mode 100644 index 00000000..f45e092d --- /dev/null +++ b/pyvlx/dataobjects.py @@ -0,0 +1,149 @@ +"""Module for Dataobjects.""" +from datetime import datetime +import time + + +class DtoLocalTime: + """Dataobject to hold KLF200 Time Data.""" + + def __init__(self, utctime=None, localtime=None): + """Initialize DtoLocalTime class.""" + if utctime is None: + utctime = datetime.fromtimestamp(0) + if localtime is None: + localtime = datetime.fromtimestamp(0) + self.utctime = utctime + self.localtime = localtime + + def __str__(self): + """Return human readable string.""" + return ( + '<{} utctime="{}" localtime="{}"/>'.format( + type(self).__name__, self.utctime, self.localtime) + ) + + def from_payload(self, payload): + """Build the Dto From Data.""" + self.utctime = datetime.fromtimestamp(int.from_bytes(payload[0:4], "big")) + weekday = payload[11] - 1 + if weekday == -1: + weekday = 6 + + self.localtime = datetime.fromtimestamp(time.mktime( + (int.from_bytes(payload[9:11], byteorder='big') + 1900, # Year + payload[8], # month + payload[7], # day + payload[6], # hour + payload[5], # minute + payload[4], # second + weekday, + int.from_bytes(payload[12:14], byteorder='big'), # day of year + int.from_bytes(payload[14:15], byteorder='big', signed=True)))) + + def to_payload(self): + """Build the Dto From Data.""" + payload = b'' + payload = int(self.utctime.timestamp()).to_bytes(4, byteorder='big') + payload += self.localtime.second.to_bytes(1, "big") + payload += self.localtime.minute.to_bytes(1, "big") + payload += self.localtime.hour.to_bytes(1, "big") + payload += self.localtime.day.to_bytes(1, "big") + payload += self.localtime.month.to_bytes(1, "big") + payload += (self.localtime.year - 1900).to_bytes(2, "big") + if self.localtime.weekday == 6: + payload += (0).to_bytes(1, "big") + else: + payload += (self.localtime.weekday() + 1).to_bytes(1, "big") + payload += self.localtime.timetuple().tm_yday.to_bytes(2, "big") + payload += (self.localtime.timetuple().tm_isdst).to_bytes(1, "big", signed=True) + return payload + + +class DtoNetworkSetup: + """Dataobject to hold KLF200 Network Setup.""" + + def __init__(self, ipaddress=None, gateway=None, netmask=None, dhcp=None): + """Initialize DtoNetworkSetup class.""" + self.ipaddress = ipaddress + self.gateway = gateway + self.netmask = netmask + self.dhcp = dhcp + + def __str__(self): + """Return human readable string.""" + return '<{} ipaddress="{}" gateway="{}" gateway="{}" dhcp="{}"/>'.format( + type(self).__name__, self.ipaddress, self.gateway, + self.gateway, self.dhcp + ) + + +class DtoProtocolVersion: + """KLF 200 Dataobject for Protocol version.""" + + def __init__(self, majorversion=None, minorversion=None): + """Initialize DtoProtocolVersion class.""" + self.majorversion = majorversion + self.minorversion = minorversion + + def __str__(self): + """Return human readable string.""" + return ( + '<{} majorversion="{}" minorversion="{}"/>'.format( + type(self).__name__, self.majorversion, self.minorversion + ) + ) + + +class DtoState: + """Data Object for Gateway State.""" + + def __init__(self, gateway_state=None, gateway_sub_state=None): + """Initialize DtoState class.""" + self.gateway_state = gateway_state + self.gateway_sub_state = gateway_sub_state + + def __str__(self): + """Return human readable string.""" + return ( + '<{} gateway_state="{}" gateway_sub_state="{}"/>'.format( + type(self).__name__, self.gateway_state, self.gateway_sub_state + ) + ) + + +class DtoVersion: + """Object for KLF200 Version Information.""" + + def __init__(self, + softwareversion=None, hardwareversion=None, productgroup=None, producttype=None): + """Initialize DtoVersion class.""" + self.softwareversion = softwareversion + self.hardwareversion = hardwareversion + self.productgroup = productgroup + self.producttype = producttype + + def __str__(self): + """Return human readable string.""" + return ( + '<{} softwareversion="{}" hardwareversion="{}" ' + 'productgroup="{}" producttype="{}"/>'.format( + type(self).__name__, + self.softwareversion, self.hardwareversion, self.productgroup, self.producttype + ) + ) + + +class DtoLeaveLearnState: + """Dataobject to hold KLF200 Data.""" + + def __init__(self, status=None): + """Initialize DtoLeaveLearnState class.""" + self.status = status + + def __str__(self): + """Return human readable string.""" + return ( + '<{} status="{}"/>'.format( + type(self).__name__, self.status + ) + ) diff --git a/pyvlx/exception.py b/pyvlx/exception.py index 1adacd60..cb70e6f2 100644 --- a/pyvlx/exception.py +++ b/pyvlx/exception.py @@ -20,6 +20,6 @@ def _format_parameter(self): def __str__(self): """Return object as readable string.""" - return ''.format( - self.description, self._format_parameter() + return '<{} description="{}" {}/>'.format( + type(self).__name__, self.description, self._format_parameter() ) diff --git a/pyvlx/frames/frame_set_utc_cfm.py b/pyvlx/frames/frame_set_utc_cfm.py deleted file mode 100644 index 97fbe74b..00000000 --- a/pyvlx/frames/frame_set_utc_cfm.py +++ /dev/null @@ -1,14 +0,0 @@ -"""Module for confirmation for setting UTC time.""" -from pyvlx.const import Command - -from .frame import FrameBase - - -class FrameSetUTCConfirmation(FrameBase): - """Frame for confirmation for setting UTC time.""" - - PAYLOAD_LEN = 0 - - def __init__(self): - """Init Frame.""" - super().__init__(Command.GW_SET_UTC_CFM) diff --git a/pyvlx/heartbeat.py b/pyvlx/heartbeat.py index e9e10794..005cb949 100644 --- a/pyvlx/heartbeat.py +++ b/pyvlx/heartbeat.py @@ -1,8 +1,8 @@ """Module for sending get state requests to API in regular periods.""" import asyncio +from .api import GetState from .exception import PyVLXException -from .get_state import GetState class Heartbeat: diff --git a/pyvlx/klf200gateway.py b/pyvlx/klf200gateway.py new file mode 100644 index 00000000..4e76eda3 --- /dev/null +++ b/pyvlx/klf200gateway.py @@ -0,0 +1,135 @@ +"""Module for basic klf200 gateway functions.""" + +from .api import (GetState, GetNetworkSetup, GetProtocolVersion, GetVersion, + GetLocalTime, LeaveLearnState, FactoryDefault, PasswordEnter, + SetUTC, Reboot) + +from .exception import PyVLXException + + +class Klf200Gateway: + """Class for node abstraction.""" + + def __init__(self, pyvlx): + """Initialize Node object.""" + self.pyvlx = pyvlx + self.state = None + self.network_setup = None + self.password = None + self.time = None + self.protocol_version = None + self.version = None + self.device_updated_cbs = [] + + def register_device_updated_cb(self, device_updated_cb): + """Register device updated callback.""" + self.device_updated_cbs.append(device_updated_cb) + + def unregister_device_updated_cb(self, device_updated_cb): + """Unregister device updated callback.""" + self.device_updated_cbs.remove(device_updated_cb) + + async def after_update(self): + """Execute callbacks after internal state has been changed.""" + for device_updated_cb in self.device_updated_cbs: + # pylint: disable=not-callable + await device_updated_cb(self) + + async def get_state(self): + """Retrieve state from API.""" + get_state = GetState(pyvlx=self.pyvlx) + await get_state.do_api_call() + if not get_state.success: + raise PyVLXException("Unable to retrieve state") + self.state = get_state.state + return get_state.success + + async def get_network_setup(self): + """Retrieve network setup from API.""" + get_network_setup = GetNetworkSetup(pyvlx=self.pyvlx) + await get_network_setup.do_api_call() + if not get_network_setup.success: + raise PyVLXException("Unable to retrieve network setup") + self.network_setup = get_network_setup.networksetup + return get_network_setup.success + + async def get_version(self): + """Retrieve version from API.""" + get_version = GetVersion(pyvlx=self.pyvlx) + await get_version.do_api_call() + if not get_version.success: + raise PyVLXException("Unable to retrieve version") + self.version = get_version.version + return get_version.success + + async def get_protocol_version(self): + """Retrieve protocol version from API.""" + get_protocol_version = GetProtocolVersion(pyvlx=self.pyvlx) + await get_protocol_version.do_api_call() + if not get_protocol_version.success: + raise PyVLXException("Unable to retrieve protocol version") + self.protocol_version = get_protocol_version.protocolversion + return get_protocol_version.success + + async def leave_learn_state(self): + """Leave Learn state from API.""" + leave_learn_state = LeaveLearnState(pyvlx=self.pyvlx) + await leave_learn_state.do_api_call() + if not leave_learn_state.success: + raise PyVLXException("Unable to leave learn state") + return leave_learn_state.success + + async def set_utc(self): + """Set UTC Clock.""" + setutc = SetUTC(pyvlx=self.pyvlx) + await setutc.do_api_call() + if not setutc.success: + raise PyVLXException("Unable to set utc.") + return setutc.success + + async def set_rtc_time_zone(self): + """Set the RTC Time Zone.""" + # idontwant = setrtctimezone(pyvlx=self.pyvlx) + raise PyVLXException("KLF 200 RTC Timezone Set not implemented") + # return setrtctimezone.success + + async def reboot(self): + """Reboot gateway.""" + reboot = Reboot(pyvlx=self.pyvlx) + await reboot.do_api_call() + if not reboot.success: + raise PyVLXException("Unable to reboot gateway.") + return reboot.success + + async def set_factory_default(self): + """Set Gateway to Factory Default.""" + factorydefault = FactoryDefault(pyvlx=self.pyvlx) + await factorydefault.do_api_call() + if not factorydefault.success: + raise PyVLXException("Unable to factory Default Reset gateway.") + return factorydefault.success + + async def get_local_time(self): + """Get local time from gateway.""" + getlocaltime = GetLocalTime(pyvlx=self.pyvlx) + await getlocaltime.do_api_call() + if not getlocaltime.success: + raise PyVLXException("Unable to get local time.") + self.time = getlocaltime.localtime + return getlocaltime.success + + async def password_enter(self, password): + """Get enter Password for gateway.""" + self.password = password + passwordenter = PasswordEnter(pyvlx=self.pyvlx, password=self.password) + await passwordenter.do_api_call() + if not passwordenter.success: + raise PyVLXException("Login to KLF 200 failed, check credentials") + return passwordenter.success + + def __str__(self): + """Return object as readable string.""" + return ( + '<{} state="{}" network_setup="{}" version="{}" protocol_version="{}"/>'.format( + type(self).__name__, str(self.state), str(self.network_setup), + str(self.version), str(self.protocol_version))) diff --git a/pyvlx/lightening_device.py b/pyvlx/lightening_device.py index 6ca79c26..da370d7e 100644 --- a/pyvlx/lightening_device.py +++ b/pyvlx/lightening_device.py @@ -1,5 +1,5 @@ """Module for lights.""" -from .command_send import CommandSend +from .api import CommandSend from .exception import PyVLXException from .node import Node from .parameter import Intensity diff --git a/pyvlx/node.py b/pyvlx/node.py index b3728f18..848256b3 100644 --- a/pyvlx/node.py +++ b/pyvlx/node.py @@ -5,8 +5,8 @@ be derived by other objects like window openers and roller shutters. """ +from .api import SetNodeName from .exception import PyVLXException -from .set_node_name import SetNodeName class Node: diff --git a/pyvlx/node_helper.py b/pyvlx/node_helper.py index d2583cc8..5b986339 100644 --- a/pyvlx/node_helper.py +++ b/pyvlx/node_helper.py @@ -31,8 +31,8 @@ def convert_frame_to_node(pyvlx, frame): ) if ( - frame.node_type == NodeTypeWithSubtype.ROLLER_SHUTTER - or frame.node_type == NodeTypeWithSubtype.DUAL_ROLLER_SHUTTER + frame.node_type == NodeTypeWithSubtype.ROLLER_SHUTTER + or frame.node_type == NodeTypeWithSubtype.DUAL_ROLLER_SHUTTER ): return RollerShutter( pyvlx=pyvlx, @@ -43,9 +43,9 @@ def convert_frame_to_node(pyvlx, frame): ) if ( - frame.node_type == NodeTypeWithSubtype.INTERIOR_VENETIAN_BLIND - or frame.node_type == NodeTypeWithSubtype.VERTICAL_INTERIOR_BLINDS - or frame.node_type == NodeTypeWithSubtype.INTERIOR_VENETIAN_BLIND + frame.node_type == NodeTypeWithSubtype.INTERIOR_VENETIAN_BLIND + or frame.node_type == NodeTypeWithSubtype.VERTICAL_INTERIOR_BLINDS + or frame.node_type == NodeTypeWithSubtype.INTERIOR_VENETIAN_BLIND ): return RollerShutter( pyvlx=pyvlx, @@ -56,9 +56,9 @@ def convert_frame_to_node(pyvlx, frame): # Blinds have position and orientation (inherit frame.current_position_fp3) attribute if ( - frame.node_type == NodeTypeWithSubtype.EXTERIOR_VENETIAN_BLIND - or frame.node_type == NodeTypeWithSubtype.ADJUSTABLE_SLUTS_ROLLING_SHUTTER - or frame.node_type == NodeTypeWithSubtype.LOUVER_BLIND + frame.node_type == NodeTypeWithSubtype.EXTERIOR_VENETIAN_BLIND + or frame.node_type == NodeTypeWithSubtype.ADJUSTABLE_SLUTS_ROLLING_SHUTTER + or frame.node_type == NodeTypeWithSubtype.LOUVER_BLIND ): return Blind( pyvlx=pyvlx, @@ -69,8 +69,8 @@ def convert_frame_to_node(pyvlx, frame): ) if ( - frame.node_type == NodeTypeWithSubtype.VERTICAL_EXTERIOR_AWNING - or frame.node_type == NodeTypeWithSubtype.HORIZONTAL_AWNING + frame.node_type == NodeTypeWithSubtype.VERTICAL_EXTERIOR_AWNING + or frame.node_type == NodeTypeWithSubtype.HORIZONTAL_AWNING ): return Awning( pyvlx=pyvlx, diff --git a/pyvlx/node_updater.py b/pyvlx/node_updater.py index 8e2aefe2..f4597658 100644 --- a/pyvlx/node_updater.py +++ b/pyvlx/node_updater.py @@ -1,5 +1,5 @@ """Module for updating nodes via frames.""" -from .frames import ( +from .api.frames import ( FrameGetAllNodesInformationNotification, FrameNodeStatePositionChangedNotification) from .lightening_device import LighteningDevice @@ -18,11 +18,11 @@ def __init__(self, pyvlx): async def process_frame(self, frame): """Update nodes via frame, usually received by house monitor.""" if isinstance( - frame, - ( - FrameGetAllNodesInformationNotification, - FrameNodeStatePositionChangedNotification, - ), + frame, + ( + FrameGetAllNodesInformationNotification, + FrameNodeStatePositionChangedNotification, + ), ): PYVLXLOG.debug("NodeUpdater process frame: %s", frame) if frame.node_id not in self.pyvlx.nodes: diff --git a/pyvlx/nodes.py b/pyvlx/nodes.py index 21e1f2b2..af8116d8 100644 --- a/pyvlx/nodes.py +++ b/pyvlx/nodes.py @@ -1,7 +1,6 @@ """Module for storing nodes.""" +from .api import (GetAllNodesInformation, GetNodeInformation) from .exception import PyVLXException -from .get_all_nodes_information import GetAllNodesInformation -from .get_node_information import GetNodeInformation from .node import Node from .node_helper import convert_frame_to_node diff --git a/pyvlx/on_off_switch.py b/pyvlx/on_off_switch.py index 59657e26..de3f523e 100644 --- a/pyvlx/on_off_switch.py +++ b/pyvlx/on_off_switch.py @@ -1,5 +1,5 @@ """Module for on/off switches.""" -from .command_send import CommandSend +from .api.command_send import CommandSend from .exception import PyVLXException from .node import Node from .parameter import SwitchParameter, SwitchParameterOff, SwitchParameterOn diff --git a/pyvlx/opening_device.py b/pyvlx/opening_device.py index 7ff67947..3e1cab88 100644 --- a/pyvlx/opening_device.py +++ b/pyvlx/opening_device.py @@ -1,5 +1,5 @@ """Module for window openers.""" -from .command_send import CommandSend +from .api.command_send import CommandSend from .exception import PyVLXException from .node import Node from .parameter import CurrentPosition, Parameter, Position, TargetPosition @@ -9,7 +9,7 @@ class OpeningDevice(Node): """Meta class for opening device with one main parameter for position.""" def __init__( - self, pyvlx, node_id, name, serial_number, position_parameter=Parameter() + self, pyvlx, node_id, name, serial_number, position_parameter=Parameter() ): """Initialize opening device. @@ -88,15 +88,8 @@ async def stop(self, wait_for_completion=True): def __str__(self): """Return object as readable string.""" return ( - '<{} name="{}" ' - 'node_id="{}" ' - 'serial_number="{}" ' - 'position="{}"/>'.format( - type(self).__name__, - self.name, - self.node_id, - self.serial_number, - self.position, + '<{} name="{}" node_id="{}" serial_number="{}" position="{}"/>'.format( + type(self).__name__, self.name, self.node_id, self.serial_number, self.position ) ) @@ -105,13 +98,13 @@ class Window(OpeningDevice): """Window object.""" def __init__( - self, - pyvlx, - node_id, - name, - serial_number, - position_parameter=Parameter(), - rain_sensor=False, + self, + pyvlx, + node_id, + name, + serial_number, + position_parameter=Parameter(), + rain_sensor=False, ): """Initialize Window class. @@ -138,15 +131,9 @@ def __init__( def __str__(self): """Return object as readable string.""" return ( - '<{} name="{}" ' - 'node_id="{}" rain_sensor={} ' - 'serial_number="{}" position="{}"/>'.format( - type(self).__name__, - self.name, - self.node_id, - self.rain_sensor, - self.serial_number, - self.position, + '<{} name="{}" node_id="{}" rain_sensor={} serial_number="{}" position="{}"/>'.format( + type(self).__name__, self.name, self.node_id, + self.rain_sensor, self.serial_number, self.position ) ) @@ -155,7 +142,7 @@ class Blind(OpeningDevice): """Blind objects.""" def __init__( - self, pyvlx, node_id, name, serial_number, position_parameter=Parameter() + self, pyvlx, node_id, name, serial_number, position_parameter=Parameter() ): """Initialize Blind class. @@ -183,8 +170,8 @@ async def set_position(self, position, wait_for_completion=True): Parameters: * position: Position object containing the current position. * target_position: Position object holding the target position - which allows to ajust the position while the blind is in movement - without stopping the blind (if orientation position has been changed.) + which allows to ajust the position while the blind is in movement + without stopping the blind (if orientation position has been changed.) * wait_for_completion: If set, function will return after device has reached target position. @@ -241,8 +228,8 @@ async def set_orientation(self, orientation, wait_for_completion=True): Parameters: * orientation: Position object containing the target orientation. + target_orientation: Position object holding the target orientation - which allows to ajust the orientation while the blind is in movement - without stopping the blind (if the position has been changed.) + which allows to ajust the orientation while the blind is in movement + without stopping the blind (if the position has been changed.) * wait_for_completion: If set, function will return after device has reached target position. @@ -261,7 +248,8 @@ async def set_orientation(self, orientation, wait_for_completion=True): if not command_send.success: raise PyVLXException("Unable to send command") await self.after_update() - # KLF200 always send UNKNOWN position for functional parameter, so orientation is set directly and not via GW_NODE_STATE_POSITION_CHANGED_NTF + # KLF200 always send UNKNOWN position for functional parameter, + # so orientation is set directly and not via GW_NODE_STATE_POSITION_CHANGED_NTF async def open_orientation(self, wait_for_completion=True): """Open Blind slats orientation. diff --git a/pyvlx/parameter.py b/pyvlx/parameter.py index d44395be..7df725a6 100644 --- a/pyvlx/parameter.py +++ b/pyvlx/parameter.py @@ -58,11 +58,11 @@ def from_raw(raw): if len(raw) != 2: raise PyVLXException("Position::raw_must_be_two_bytes") if ( - raw != Position.from_int(Position.CURRENT) - and raw != Position.from_int(Position.IGNORE) - and raw != Position.from_int(Position.TARGET) - and raw != Position.from_int(Position.UNKNOWN_VALUE) - and Position.to_int(raw) > Position.MAX + raw != Position.from_int(Position.CURRENT) + and raw != Position.from_int(Position.IGNORE) + and raw != Position.from_int(Position.TARGET) + and raw != Position.from_int(Position.UNKNOWN_VALUE) + and Position.to_int(raw) > Position.MAX ): raise PyVLXException("parameter::raw_exceed_limit", raw=raw) return raw diff --git a/pyvlx/pyvlx.py b/pyvlx/pyvlx.py index 96cbdd59..8b7af524 100644 --- a/pyvlx/pyvlx.py +++ b/pyvlx/pyvlx.py @@ -7,20 +7,16 @@ """ import asyncio + +from .api import house_status_monitor_enable from .config import Config from .connection import Connection -from .exception import PyVLXException -from .get_protocol_version import GetProtocolVersion -from .get_version import GetVersion from .heartbeat import Heartbeat -from .house_status_monitor import house_status_monitor_enable from .log import PYVLXLOG -from .login import Login from .node_updater import NodeUpdater from .nodes import Nodes -from .reboot import Reboot from .scenes import Scenes -from .set_utc import set_utc +from .klf200gateway import Klf200Gateway class PyVLX: @@ -39,42 +35,30 @@ def __init__(self, path=None, host=None, password=None, loop=None): self.scenes = Scenes(self) self.version = None self.protocol_version = None + self.klf200 = Klf200Gateway(pyvlx=self) async def connect(self): """Connect to KLF 200.""" PYVLXLOG.debug("Connecting to KLF 200.") await self.connection.connect() - login = Login(pyvlx=self, password=self.config.password) - await login.do_api_call() - if not login.success: - raise PyVLXException("Login to KLF 200 failed, check credentials") - await self.update_version() - await set_utc(pyvlx=self) + await self.klf200.password_enter(password=self.config.password) + await self.klf200.get_version() + await self.klf200.get_protocol_version() + PYVLXLOG.debug( + "Connected to: %s, %s", + str(self.klf200.version), + str(self.klf200.protocol_version) + ) + + await self.klf200.get_state() + await self.klf200.set_utc() + await self.klf200.get_network_setup() await house_status_monitor_enable(pyvlx=self) async def reboot_gateway(self): - """Reboot gateway.""" + """For Compatibility: Reboot the KLF 200.""" PYVLXLOG.warning("KLF 200 reboot initiated") - reboot = Reboot(pyvlx=self) - await reboot.do_api_call() - - async def update_version(self): - """Retrieve version and protocol version from API.""" - get_version = GetVersion(pyvlx=self) - await get_version.do_api_call() - if not get_version.success: - raise PyVLXException("Unable to retrieve version") - self.version = get_version.version - get_protocol_version = GetProtocolVersion(pyvlx=self) - await get_protocol_version.do_api_call() - if not get_protocol_version.success: - raise PyVLXException("Unable to retrieve protocol version") - self.protocol_version = get_protocol_version.version - PYVLXLOG.debug( - "Connected to: %s, protocol version: %s", - self.version, - self.protocol_version, - ) + await self.klf200.reboot() async def send_frame(self, frame): """Send frame to API via connection.""" diff --git a/pyvlx/scene.py b/pyvlx/scene.py index 2776df9c..a497c9f1 100644 --- a/pyvlx/scene.py +++ b/pyvlx/scene.py @@ -1,5 +1,5 @@ """Module for scene.""" -from .activate_scene import ActivateScene +from .api import ActivateScene from .exception import PyVLXException @@ -39,7 +39,9 @@ async def run(self, wait_for_completion=True): def __str__(self): """Return object as readable string.""" - return ''.format(self.name, self.scene_id) + return '<{} name="{}" id="{}"/>'.format( + type(self).__name__, self.name, self.scene_id + ) def __eq__(self, other): """Equal operator.""" diff --git a/pyvlx/scenes.py b/pyvlx/scenes.py index bcf8c46b..d98264bc 100644 --- a/pyvlx/scenes.py +++ b/pyvlx/scenes.py @@ -1,6 +1,6 @@ """Module for storing and accessing scene list.""" +from .api import GetSceneList from .exception import PyVLXException -from .get_scene_list import GetSceneList from .scene import Scene diff --git a/test/alias_array_test.py b/test/alias_array_test.py index b344bf25..8ee3d8dc 100644 --- a/test/alias_array_test.py +++ b/test/alias_array_test.py @@ -1,7 +1,7 @@ """Unit tests for AliasArray module.""" import unittest -from pyvlx.alias_array import AliasArray +from pyvlx.api.frames.alias_array import AliasArray from pyvlx.exception import PyVLXException diff --git a/test/frame_activate_scene_cfm_test.py b/test/frame_activate_scene_cfm_test.py index 26a2b995..c6ddcab1 100644 --- a/test/frame_activate_scene_cfm_test.py +++ b/test/frame_activate_scene_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameActivateSceneConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ( +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( ActivateSceneConfirmationStatus, FrameActivateSceneConfirmation) @@ -42,5 +42,5 @@ def test_str(self): ) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_activate_scene_req_test.py b/test/frame_activate_scene_req_test.py index e3a502ac..470623b9 100644 --- a/test/frame_activate_scene_req_test.py +++ b/test/frame_activate_scene_req_test.py @@ -2,8 +2,8 @@ import unittest from pyvlx.const import Originator, Priority, Velocity -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameActivateSceneRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameActivateSceneRequest class TestFrameActivateSceneRequest(unittest.TestCase): @@ -40,5 +40,6 @@ def test_str(self): ) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_activation_log_updated_ntf_test.py b/test/frame_activation_log_updated_ntf_test.py index f229a77e..d9ecc5ea 100644 --- a/test/frame_activation_log_updated_ntf_test.py +++ b/test/frame_activation_log_updated_ntf_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameActivationLogUpdatedNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameActivationLogUpdatedNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameActivationLogUpdatedNotification class TestFrameActivationLogUpdatedNotification(unittest.TestCase): diff --git a/test/frame_command_remaining_time_notification_test.py b/test/frame_command_remaining_time_notification_test.py index 1ee6fe29..ecd5603b 100644 --- a/test/frame_command_remaining_time_notification_test.py +++ b/test/frame_command_remaining_time_notification_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameCommandRemainingTimeNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameCommandRemainingTimeNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameCommandRemainingTimeNotification class TestFrameCommandRemainingTimeNotification(unittest.TestCase): @@ -33,5 +33,5 @@ def test_str(self): ) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_command_run_status_notification_test.py b/test/frame_command_run_status_notification_test.py index 2e34f6fe..43f37169 100644 --- a/test/frame_command_run_status_notification_test.py +++ b/test/frame_command_run_status_notification_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameCommandRunStatusNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameCommandRunStatusNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameCommandRunStatusNotification class TestFrameCommandRunStatusNotification(unittest.TestCase): @@ -46,5 +46,5 @@ def test_str(self): ) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_command_send_cfm_test.py b/test/frame_command_send_cfm_test.py index 67ce50b0..9da6bfd0 100644 --- a/test/frame_command_send_cfm_test.py +++ b/test/frame_command_send_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameCommandSendConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ( +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( CommandSendConfirmationStatus, FrameCommandSendConfirmation) @@ -39,5 +39,5 @@ def test_str(self): ) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_command_send_req_test.py b/test/frame_command_send_req_test.py index 86441872..dbbd9a34 100644 --- a/test/frame_command_send_req_test.py +++ b/test/frame_command_send_req_test.py @@ -3,8 +3,8 @@ from pyvlx import Position, PyVLXException from pyvlx.const import Originator -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameCommandSendRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameCommandSendRequest class TestFrameCommandSendRequest(unittest.TestCase): @@ -58,10 +58,10 @@ def test_str(self): ) self.assertEqual( str(frame), - '", + 'session_id="1000" originator="Originator.RAIN"/>', ) def test_wrong_payload(self): diff --git a/test/frame_discover_nodes_cfm_test.py b/test/frame_discover_nodes_cfm_test.py index 1d90c13c..b496b401 100644 --- a/test/frame_discover_nodes_cfm_test.py +++ b/test/frame_discover_nodes_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameDiscoverNodesConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameDiscoverNodesConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameDiscoverNodesConfirmation class TestFrameNodeDiscoverConfirmation(unittest.TestCase): diff --git a/test/frame_discover_nodes_ntf_test.py b/test/frame_discover_nodes_ntf_test.py index 8e6850a1..aab2f1f2 100644 --- a/test/frame_discover_nodes_ntf_test.py +++ b/test/frame_discover_nodes_ntf_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameDiscoverNodesNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameDiscoverNodesNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameDiscoverNodesNotification class TestFrameDiscoverNodesNotification(unittest.TestCase): @@ -46,11 +46,11 @@ def test_str(self): frame = FrameDiscoverNodesNotification() self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_discover_nodes_req_test.py b/test/frame_discover_nodes_req_test.py index cf8bd411..747d92dc 100644 --- a/test/frame_discover_nodes_req_test.py +++ b/test/frame_discover_nodes_req_test.py @@ -2,8 +2,8 @@ import unittest from pyvlx.const import NodeType -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameDiscoverNodesRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameDiscoverNodesRequest class TestFrameNodeDiscover(unittest.TestCase): @@ -31,5 +31,5 @@ def test_str(self): """Test string representation of FrameDiscoverNodesRequest.""" frame = FrameDiscoverNodesRequest(NodeType.LIGHT) self.assertEqual( - str(frame), "" + str(frame), '' ) diff --git a/test/frame_error_test.py b/test/frame_error_test.py index 7d652d0c..2a2b5949 100644 --- a/test/frame_error_test.py +++ b/test/frame_error_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameErrorNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ErrorType, FrameErrorNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ErrorType, FrameErrorNotification class TestErrorNotification(unittest.TestCase): @@ -26,5 +26,5 @@ def test_str(self): frame = FrameErrorNotification(error_type=ErrorType.ErrorOnFrameStructure) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_factory_default_cfm_test.py b/test/frame_factory_default_cfm_test.py new file mode 100644 index 00000000..57680997 --- /dev/null +++ b/test/frame_factory_default_cfm_test.py @@ -0,0 +1,28 @@ +"""Unit tests for FrameGatewayFactoryDefaultConfirmation.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGatewayFactoryDefaultConfirmation + + +class TestFrameGatewayFactoryDefaultConfirmation(unittest.TestCase): + """Test class FrameGatewayFactoryDefaultConfirmation.""" + + # pylint: disable=too-many-public-methods,invalid-name + + EXAMPLE_FRAME = b"\x00\x03\x00\x04\x07" + + def test_bytes(self): + """Test FrameGatewayFactoryDefaultConfirmation.""" + frame = FrameGatewayFactoryDefaultConfirmation() + self.assertEqual(bytes(frame), self.EXAMPLE_FRAME) + + def test_frame_from_raw(self): + """Test parse FrameGatewayFactoryDefaultConfirmation from raw.""" + frame = frame_from_raw(self.EXAMPLE_FRAME) + self.assertTrue(isinstance(frame, FrameGatewayFactoryDefaultConfirmation)) + + def test_str(self): + """Test string representation of FrameGatewayFactoryDefaultConfirmation.""" + frame = FrameGatewayFactoryDefaultConfirmation() + self.assertEqual(str(frame), "") diff --git a/test/frame_factory_default_req_test.py b/test/frame_factory_default_req_test.py new file mode 100644 index 00000000..de15e7a7 --- /dev/null +++ b/test/frame_factory_default_req_test.py @@ -0,0 +1,28 @@ +"""Unit tests for FrameGatewayFactoryDefaultRequest.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGatewayFactoryDefaultRequest + + +class TestFrameRebootRequest(unittest.TestCase): + """Test class FrameGatewayFactoryDefaultRequest.""" + + # pylint: disable=too-many-public-methods,invalid-name + + EXAMPLE_FRAME = b"\x00\x03\x00\x03\x00" + + def test_bytes(self): + """Test FrameGatewayFactoryDefaultRequest.""" + frame = FrameGatewayFactoryDefaultRequest() + self.assertEqual(bytes(frame), self.EXAMPLE_FRAME) + + def test_frame_from_raw(self): + """Test parse FrameGatewayFactoryDefaultRequest from raw.""" + frame = frame_from_raw(self.EXAMPLE_FRAME) + self.assertTrue(isinstance(frame, FrameGatewayFactoryDefaultRequest)) + + def test_str(self): + """Test string representation of FrameGatewayFactoryDefaultRequest.""" + frame = FrameGatewayFactoryDefaultRequest() + self.assertEqual(str(frame), "") diff --git a/test/frame_get_all_nodes_information_cfm_test.py b/test/frame_get_all_nodes_information_cfm_test.py index 4a9ed3be..9ed6d542 100644 --- a/test/frame_get_all_nodes_information_cfm_test.py +++ b/test/frame_get_all_nodes_information_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetAllNodesInformationConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetAllNodesInformationConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetAllNodesInformationConfirmation class TestFrameGetAllNodesInformationConfirmation(unittest.TestCase): @@ -26,5 +26,5 @@ def test_str(self): frame = FrameGetAllNodesInformationConfirmation(number_of_nodes=23) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_get_all_nodes_information_finished_ntf_test.py b/test/frame_get_all_nodes_information_finished_ntf_test.py index 49a0c54a..3a9e7bbf 100644 --- a/test/frame_get_all_nodes_information_finished_ntf_test.py +++ b/test/frame_get_all_nodes_information_finished_ntf_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetAllNodesInformationFinishedNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetAllNodesInformationFinishedNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetAllNodesInformationFinishedNotification class TestFrameGetAllNodesInformationFinishedNotification(unittest.TestCase): diff --git a/test/frame_get_all_nodes_information_ntf_test.py b/test/frame_get_all_nodes_information_ntf_test.py index 0509c320..91af3c55 100644 --- a/test/frame_get_all_nodes_information_ntf_test.py +++ b/test/frame_get_all_nodes_information_ntf_test.py @@ -2,11 +2,11 @@ import unittest from datetime import datetime -from pyvlx.alias_array import AliasArray +from pyvlx.api.frames.alias_array import AliasArray from pyvlx.const import NodeTypeWithSubtype, NodeVariation, Velocity from pyvlx.exception import PyVLXException -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetAllNodesInformationNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetAllNodesInformationNotification from pyvlx.parameter import Position @@ -89,14 +89,14 @@ def test_str(self): test_ts = datetime.fromtimestamp(50528771).strftime("%Y-%m-%d %H:%M:%S") self.assertEqual( str(frame), - "".format( + ''.format( test_ts ), ) diff --git a/test/frame_get_all_nodes_information_req_test.py b/test/frame_get_all_nodes_information_req_test.py index 73284561..2ce48593 100644 --- a/test/frame_get_all_nodes_information_req_test.py +++ b/test/frame_get_all_nodes_information_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetAllNodesInformationRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetAllNodesInformationRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetAllNodesInformationRequest class TestFrameGetAllNodesInformationRequest(unittest.TestCase): diff --git a/test/frame_get_local_time_cfm_test.py b/test/frame_get_local_time_cfm_test.py new file mode 100644 index 00000000..17baee5c --- /dev/null +++ b/test/frame_get_local_time_cfm_test.py @@ -0,0 +1,34 @@ +"""Unit tests for FrameGetLocalTimeConfirmation.""" +import unittest +from datetime import datetime, timezone + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetLocalTimeConfirmation + + +class TestFrameGetLocalTimeConfirmation(unittest.TestCase): + """Test class for FrameGetLocalTimeConfirmation.""" + + # pylint: disable=too-many-public-methods,invalid-name + + def test_bytes(self): + """Test FrameGetLocalTimeConfirmation.""" + frame = FrameGetLocalTimeConfirmation() + frame.time.localtime = datetime(2020, 12, 3, 18, 19, 19, 176900) + frame.time.utctime = datetime(2020, 12, 3, 18, 19, 19, 176900, tzinfo=timezone.utc) + self.assertEqual(bytes(frame), b"\x00\x12 \x05_\xc9,'\x13\x13\x12\x03\x0c\x00x\x04\x01R\xffg") + + def test_frame_from_raw(self): + """Test parse FrameGetLocalTimeConfirmation from raw.""" + frame = frame_from_raw(b'\x00\x12 \x05\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x007') + self.assertTrue(isinstance(frame, FrameGetLocalTimeConfirmation)) + + def test_str(self): + """Test string representation of FrameGetLocalTimeConfirmation.""" + frame = FrameGetLocalTimeConfirmation() + frame.time.localtime = datetime.strptime("2020-12-03 18:19:19.176900", "%Y-%m-%d %H:%M:%S.%f") + frame.time.utctime = datetime.strptime("2020-12-03 18:19:19.176900", "%Y-%m-%d %H:%M:%S.%f") + self.assertEqual(str(frame), '' + '') diff --git a/test/frame_get_local_time_req_test.py b/test/frame_get_local_time_req_test.py new file mode 100644 index 00000000..08714e54 --- /dev/null +++ b/test/frame_get_local_time_req_test.py @@ -0,0 +1,26 @@ +"""Unit tests for FrameGetLocalTimeRequest.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetLocalTimeRequest + + +class TestFrameGetLocalTimeRequest(unittest.TestCase): + """Test class for FrameGetLocalTimeRequest.""" + + # pylint: disable=too-many-public-methods,invalid-name + + def test_bytes(self): + """Test FrameGetLocalTimeRequest with NO_TYPE.""" + frame = FrameGetLocalTimeRequest() + self.assertEqual(bytes(frame), b"\x00\x03\x20\x04\x27") + + def test_frame_from_raw(self): + """Test parse FrameGetLocalTimeRequest from raw.""" + frame = frame_from_raw(b"\x00\x03\x20\x04\x27") + self.assertTrue(isinstance(frame, FrameGetLocalTimeRequest)) + + def test_str(self): + """Test string representation of FrameGetLocalTimeRequest.""" + frame = FrameGetLocalTimeRequest() + self.assertEqual(str(frame), "") diff --git a/test/frame_get_network_setup_cfm_test.py b/test/frame_get_network_setup_cfm_test.py new file mode 100644 index 00000000..64f5375d --- /dev/null +++ b/test/frame_get_network_setup_cfm_test.py @@ -0,0 +1,40 @@ +"""Unit tests for FrameGetNetworkSetupConfirmation.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetNetworkSetupConfirmation, DHCPParameter + + +class TestFrameGetNetworkSetupConfirmation(unittest.TestCase): + """Test class for FrameGetNetworkSetupConfirmation.""" + + # pylint: disable=too-many-public-methods,invalid-name + TESTFRAME = bytes.fromhex('001000e1c0a80de3ffffff00c0a80d0100ec') + + def test_bytes(self): + """Test FrameGetNetworkSetupConfirmation.""" + frame = FrameGetNetworkSetupConfirmation( + ipaddress=b'\xc0\xa8\r\xe3', netmask=b'\xff\xff\xff\x00', + gateway=b'\xc0\xa8\r\x01', dhcp=DHCPParameter.ENABLE) + self.assertEqual(bytes(frame), + b"\x00\x10\x00\xe1\xc0\xa8\r\xe3\xff\xff\xff\x00\xc0\xa8\r\x01\x00\xec") + + def test_frame_from_raw(self): + """Test parse FrameGetNetworkSetupConfirmation from raw.""" + frame = frame_from_raw(self.TESTFRAME) + self.assertTrue(isinstance(frame, FrameGetNetworkSetupConfirmation)) + self.assertEqual(frame.ipaddress, '192.168.13.227') + self.assertEqual(frame.netmask, '255.255.255.0') + self.assertEqual(frame.gateway, '192.168.13.1') + self.assertEqual(frame.dhcp, DHCPParameter.DISABLE) + + def test_str(self): + """Test string representation of FrameGetNetworkSetupConfirmation.""" + frame = FrameGetNetworkSetupConfirmation( + ipaddress=b'\xc0\xa8\r\xe3', netmask=b'\xff\xff\xff\x00', + gateway=b'\xc0\xa8\r\x01', dhcp=DHCPParameter.DISABLE) + self.assertEqual( + str(frame), + '', + ) diff --git a/test/frame_get_network_setup_req_test.py b/test/frame_get_network_setup_req_test.py new file mode 100644 index 00000000..c4df79f4 --- /dev/null +++ b/test/frame_get_network_setup_req_test.py @@ -0,0 +1,26 @@ +"""Unit tests for FrameGetNetworkSetupRequest.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetNetworkSetupRequest + + +class TestFrameGetNetworkSetupRequest(unittest.TestCase): + """Test class for FrameGetNetworkSetupRequest.""" + + # pylint: disable=too-many-public-methods,invalid-name + + def test_bytes(self): + """Test FrameGetNetworkSetupRequest with NO_TYPE.""" + frame = FrameGetNetworkSetupRequest() + self.assertEqual(bytes(frame), b"\x00\x03\x00\xe0\xe3") + + def test_frame_from_raw(self): + """Test parse FrameGetNetworkSetupRequest from raw.""" + frame = frame_from_raw(b"\x00\x03\x00\xe0\xe3") + self.assertTrue(isinstance(frame, FrameGetNetworkSetupRequest)) + + def test_str(self): + """Test string representation of FrameGetNetworkSetupRequest.""" + frame = FrameGetNetworkSetupRequest() + self.assertEqual(str(frame), "") diff --git a/test/frame_get_node_information_cfm_test.py b/test/frame_get_node_information_cfm_test.py index 0843f49e..7178c954 100644 --- a/test/frame_get_node_information_cfm_test.py +++ b/test/frame_get_node_information_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetNodeInformationConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetNodeInformationConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetNodeInformationConfirmation class TestFrameGetNodeInformationConfirmation(unittest.TestCase): @@ -26,5 +26,5 @@ def test_str(self): frame = FrameGetNodeInformationConfirmation(node_id=23) self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_get_node_information_ntf_test.py b/test/frame_get_node_information_ntf_test.py index 9cdddafd..ca42cec1 100644 --- a/test/frame_get_node_information_ntf_test.py +++ b/test/frame_get_node_information_ntf_test.py @@ -2,11 +2,11 @@ import unittest from datetime import datetime -from pyvlx.alias_array import AliasArray +from pyvlx.api.frames.alias_array import AliasArray from pyvlx.const import NodeTypeWithSubtype, NodeVariation, Velocity from pyvlx.exception import PyVLXException -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetNodeInformationNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetNodeInformationNotification from pyvlx.parameter import Position @@ -89,14 +89,14 @@ def test_str(self): test_ts = datetime.fromtimestamp(50528771).strftime("%Y-%m-%d %H:%M:%S") self.assertEqual( str(frame), - "".format( + ''.format( test_ts ), ) diff --git a/test/frame_get_node_information_req_test.py b/test/frame_get_node_information_req_test.py index b7aefe8e..f753041f 100644 --- a/test/frame_get_node_information_req_test.py +++ b/test/frame_get_node_information_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetNodeInformationRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetNodeInformationRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetNodeInformationRequest class TestFrameGetNodeInformationRequest(unittest.TestCase): @@ -24,4 +24,4 @@ def test_frame_from_raw(self): def test_str(self): """Test string representation of FrameGetNodeInformationRequest.""" frame = FrameGetNodeInformationRequest(node_id=23) - self.assertEqual(str(frame), "") + self.assertEqual(str(frame), '') diff --git a/test/frame_get_protocol_version_cfm_test.py b/test/frame_get_protocol_version_cfm_test.py index fbffc244..2bf26d26 100644 --- a/test/frame_get_protocol_version_cfm_test.py +++ b/test/frame_get_protocol_version_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetProtocolVersionConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetProtocolVersionConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetProtocolVersionConfirmation class TestFrameGetProtocolVersionConfirmation(unittest.TestCase): diff --git a/test/frame_get_protocol_version_req_test.py b/test/frame_get_protocol_version_req_test.py index 1604546e..032f2d54 100644 --- a/test/frame_get_protocol_version_req_test.py +++ b/test/frame_get_protocol_version_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetProtocolVersionRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetProtocolVersionRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetProtocolVersionRequest class TestFrameGetProtocolVersionRequest(unittest.TestCase): diff --git a/test/frame_get_scene_list_cfm_test.py b/test/frame_get_scene_list_cfm_test.py index 8bde6496..fb5b4832 100644 --- a/test/frame_get_scene_list_cfm_test.py +++ b/test/frame_get_scene_list_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetSceneListConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetSceneListConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetSceneListConfirmation class TestFrameGetSceneListConfirmation(unittest.TestCase): @@ -24,4 +24,4 @@ def test_frame_from_raw(self): def test_str(self): """Test string representation of FrameGetSceneListConfirmation.""" frame = FrameGetSceneListConfirmation(count_scenes=12) - self.assertEqual(str(frame), "") + self.assertEqual(str(frame), '') diff --git a/test/frame_get_scene_list_ntf_test.py b/test/frame_get_scene_list_ntf_test.py index 82f6416f..51ed8064 100644 --- a/test/frame_get_scene_list_ntf_test.py +++ b/test/frame_get_scene_list_ntf_test.py @@ -2,8 +2,8 @@ import unittest from pyvlx import PyVLXException -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetSceneListNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetSceneListNotification class TestFrameGetSceneListNotification(unittest.TestCase): @@ -80,8 +80,8 @@ def test_str(self): frame.remaining_scenes = 3 self.assertEqual( str(frame), - "", + '', ) def test_wrong_payload(self): diff --git a/test/frame_get_scene_list_req_test.py b/test/frame_get_scene_list_req_test.py index d02f154a..b69e9c8a 100644 --- a/test/frame_get_scene_list_req_test.py +++ b/test/frame_get_scene_list_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetSceneListRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetSceneListRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetSceneListRequest class TestFrameGetSceneListRequest(unittest.TestCase): diff --git a/test/frame_get_state_cfm_test.py b/test/frame_get_state_cfm_test.py index 38f54aff..8b93d8cc 100644 --- a/test/frame_get_state_cfm_test.py +++ b/test/frame_get_state_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetStateConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ( +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( FrameGetStateConfirmation, GatewayState, GatewaySubState) diff --git a/test/frame_get_state_req_test.py b/test/frame_get_state_req_test.py index 41651f8a..1474c7ab 100644 --- a/test/frame_get_state_req_test.py +++ b/test/frame_get_state_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetStateRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetStateRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetStateRequest class TestFrameGetStateRequest(unittest.TestCase): diff --git a/test/frame_get_version_cfm_test.py b/test/frame_get_version_cfm_test.py index 0ef5e406..83c91982 100644 --- a/test/frame_get_version_cfm_test.py +++ b/test/frame_get_version_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetVersionConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetVersionConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetVersionConfirmation class TestFrameGetVersionConfirmation(unittest.TestCase): @@ -34,7 +34,7 @@ def test_str(self): ) self.assertEqual( str(frame), - '', + '', ) def test_version(self): diff --git a/test/frame_get_version_req_test.py b/test/frame_get_version_req_test.py index 09a9f34e..08deac99 100644 --- a/test/frame_get_version_req_test.py +++ b/test/frame_get_version_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGetVersionRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGetVersionRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGetVersionRequest class TestFrameGetVersionRequest(unittest.TestCase): diff --git a/test/frame_gw_reboot_cfm_test.py b/test/frame_gw_reboot_cfm_test.py index c808a749..5a6e89ac 100644 --- a/test/frame_gw_reboot_cfm_test.py +++ b/test/frame_gw_reboot_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGatewayRebootConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGatewayRebootConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGatewayRebootConfirmation class TestFrameRebootConfirmation(unittest.TestCase): diff --git a/test/frame_gw_reboot_req_test.py b/test/frame_gw_reboot_req_test.py index dfbb9c96..9c9c9ed4 100644 --- a/test/frame_gw_reboot_req_test.py +++ b/test/frame_gw_reboot_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameGatewayRebootRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameGatewayRebootRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGatewayRebootRequest class TestFrameRebootRequest(unittest.TestCase): diff --git a/test/frame_helper_test.py b/test/frame_helper_test.py index 7e061ed7..808b3846 100644 --- a/test/frame_helper_test.py +++ b/test/frame_helper_test.py @@ -2,7 +2,7 @@ import unittest from pyvlx.exception import PyVLXException -from pyvlx.frames import calc_crc, extract_from_frame +from pyvlx.api.frames import calc_crc, extract_from_frame class TestFrameHelper(unittest.TestCase): diff --git a/test/frame_house_status_monitor_disable_cfm_test.py b/test/frame_house_status_monitor_disable_cfm_test.py index a4ac971d..3d816764 100644 --- a/test/frame_house_status_monitor_disable_cfm_test.py +++ b/test/frame_house_status_monitor_disable_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameHouseStatusMonitorDisableConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameHouseStatusMonitorDisableConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameHouseStatusMonitorDisableConfirmation class TestFrameHouseStatusMonitorDisableConfirmation(unittest.TestCase): diff --git a/test/frame_house_status_monitor_disable_req_test.py b/test/frame_house_status_monitor_disable_req_test.py index bf713dca..4ea50e6b 100644 --- a/test/frame_house_status_monitor_disable_req_test.py +++ b/test/frame_house_status_monitor_disable_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameHouseStatusMonitorDisableRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameHouseStatusMonitorDisableRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameHouseStatusMonitorDisableRequest class TestFrameHouseStatusMonitorDisableRequest(unittest.TestCase): diff --git a/test/frame_house_status_monitor_enable_cfm_test.py b/test/frame_house_status_monitor_enable_cfm_test.py index 76754514..1b814d9c 100644 --- a/test/frame_house_status_monitor_enable_cfm_test.py +++ b/test/frame_house_status_monitor_enable_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameHouseStatusMonitorEnableConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameHouseStatusMonitorEnableConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameHouseStatusMonitorEnableConfirmation class TestFrameHouseStatusMonitorEnableConfirmation(unittest.TestCase): diff --git a/test/frame_house_status_monitor_enable_req_test.py b/test/frame_house_status_monitor_enable_req_test.py index 0ea7745f..fa0d18a1 100644 --- a/test/frame_house_status_monitor_enable_req_test.py +++ b/test/frame_house_status_monitor_enable_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameHouseStatusMonitorEnableRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameHouseStatusMonitorEnableRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameHouseStatusMonitorEnableRequest class TestFrameHouseStatusMonitorEnableRequest(unittest.TestCase): diff --git a/test/frame_leave_learn_state_cfm_test.py b/test/frame_leave_learn_state_cfm_test.py new file mode 100644 index 00000000..61d89fc7 --- /dev/null +++ b/test/frame_leave_learn_state_cfm_test.py @@ -0,0 +1,28 @@ +"""Unit tests for FrameLeaveLearnStateConfirmation.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameLeaveLearnStateConfirmation + + +class TestFrameLeaveLearnStateConfirmation(unittest.TestCase): + """Test class FrameLeaveLearnStateConfirmation.""" + + # pylint: disable=too-many-public-methods,invalid-name + + EXAMPLE_FRAME = b"\x00\x04\x00\x0f\x00\x0b" + + def test_bytes(self): + """Test FrameLeaveLearnStateConfirmation.""" + frame = FrameLeaveLearnStateConfirmation() + self.assertEqual(bytes(frame), self.EXAMPLE_FRAME) + + def test_frame_from_raw(self): + """Test parse FrameLeaveLearnStateConfirmation from raw.""" + frame = frame_from_raw(self.EXAMPLE_FRAME) + self.assertTrue(isinstance(frame, FrameLeaveLearnStateConfirmation)) + + def test_str(self): + """Test string representation of FrameLeaveLearnStateConfirmation.""" + frame = FrameLeaveLearnStateConfirmation() + self.assertEqual(str(frame), '') diff --git a/test/frame_leave_learn_state_req_test.py b/test/frame_leave_learn_state_req_test.py new file mode 100644 index 00000000..38b785e2 --- /dev/null +++ b/test/frame_leave_learn_state_req_test.py @@ -0,0 +1,28 @@ +"""Unit tests for FrameLeaveLearnStateRequest.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameLeaveLearnStateRequest + + +class TestFrameLeaveLearnStateRequest(unittest.TestCase): + """Test class FrameLeaveLearnStateRequest.""" + + # pylint: disable=too-many-public-methods,invalid-name + + EXAMPLE_FRAME = b"\x00\x03\x00\x0e\r" + + def test_bytes(self): + """Test FrameLeaveLearnStateRequest with NO_TYPE.""" + frame = FrameLeaveLearnStateRequest() + self.assertEqual(bytes(frame), self.EXAMPLE_FRAME) + + def test_frame_from_raw(self): + """Test parse FrameLeaveLearnStateRequest from raw.""" + frame = frame_from_raw(self.EXAMPLE_FRAME) + self.assertTrue(isinstance(frame, FrameLeaveLearnStateRequest)) + + def test_str(self): + """Test string representation of FrameGetStateRequest.""" + frame = FrameLeaveLearnStateRequest() + self.assertEqual(str(frame), "") diff --git a/test/frame_node_information_changed_ntf_test.py b/test/frame_node_information_changed_ntf_test.py index 1106c323..c50f184b 100644 --- a/test/frame_node_information_changed_ntf_test.py +++ b/test/frame_node_information_changed_ntf_test.py @@ -2,8 +2,8 @@ import unittest from pyvlx.const import NodeVariation -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameNodeInformationChangedNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameNodeInformationChangedNotification class TestFrameNodeInformationChangedNotification(unittest.TestCase): @@ -44,6 +44,6 @@ def test_str(self): frame = frame_from_raw(self.EXAMPLE_FRAME) self.assertEqual( str(frame), - '', + '', ) diff --git a/test/frame_node_information_mischroe_test.py b/test/frame_node_information_mischroe_test.py index ca91428e..e9873c26 100644 --- a/test/frame_node_information_mischroe_test.py +++ b/test/frame_node_information_mischroe_test.py @@ -3,8 +3,8 @@ from datetime import datetime from pyvlx.const import NodeTypeWithSubtype, NodeVariation, Velocity -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ( +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( FrameGetAllNodesInformationNotification, FrameGetNodeInformationNotification) from pyvlx.parameter import Position diff --git a/test/frame_node_state_position_changed_ntf_test.py b/test/frame_node_state_position_changed_ntf_test.py index 5473e390..60c83608 100644 --- a/test/frame_node_state_position_changed_ntf_test.py +++ b/test/frame_node_state_position_changed_ntf_test.py @@ -3,8 +3,8 @@ from datetime import datetime from pyvlx import Position -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameNodeStatePositionChangedNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameNodeStatePositionChangedNotification class TestFrameNodeStatePositionChangedNotification(unittest.TestCase): @@ -53,10 +53,10 @@ def test_str(self): test_ts = datetime.fromtimestamp(1288634368).strftime("%Y-%m-%d %H:%M:%S") self.assertEqual( str(frame), - "".format( + ''.format( test_ts ), ) diff --git a/test/frame_password_change_cfm_test.py b/test/frame_password_change_cfm_test.py new file mode 100644 index 00000000..53048605 --- /dev/null +++ b/test/frame_password_change_cfm_test.py @@ -0,0 +1,38 @@ +"""Unit tests for FramePasswordChangeConfirmation.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( + FramePasswordChangeConfirmation, PasswordChangeConfirmationStatus) + + +class TestFramePasswordChangeConfirmation(unittest.TestCase): + """Test class for FramePasswordChangeConfirmation.""" + + # pylint: disable=too-many-public-methods,invalid-name + + def test_bytes(self): + """Test FramePasswordChangeConfirmation.""" + frame = FramePasswordChangeConfirmation() + self.assertEqual(bytes(frame), b"\x00\x040\x03\x007") + + def test_bytes_error(self): + """Test failed FramePasswordChangeConfirmation.""" + frame = FramePasswordChangeConfirmation( + status=PasswordChangeConfirmationStatus.FAILED + ) + self.assertEqual(bytes(frame), b"\x00\x040\x03\x016") + + def test_frame_from_raw(self): + """Test parse FramePasswordChangeConfirmation from raw.""" + frame = frame_from_raw(b"\x00\x040\x03\x016") + self.assertTrue(isinstance(frame, FramePasswordChangeConfirmation)) + self.assertEqual(frame.status, PasswordChangeConfirmationStatus.FAILED) + + def test_str(self): + """Test string representation of FramePasswordChangeConfirmation.""" + frame = FramePasswordChangeConfirmation() + self.assertEqual( + str(frame), + '', + ) diff --git a/test/frame_password_change_ntf_test.py b/test/frame_password_change_ntf_test.py new file mode 100644 index 00000000..36a0d0b5 --- /dev/null +++ b/test/frame_password_change_ntf_test.py @@ -0,0 +1,56 @@ +"""Unit tests for PyVLX PasswordChangeNotification.""" +import unittest + +from pyvlx.exception import PyVLXException +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FramePasswordChangeNotification + + +class TestFramePasswordChange(unittest.TestCase): + """Test class for FramePasswordChangeNotification.""" + + # pylint: disable=too-many-public-methods,invalid-name + + def test_bytes(self): + """Test FramePasswordChangeNotification.""" + frame = FramePasswordChangeNotification(newpassword="fnord") + self.assertEqual( + bytes(frame), + b"\x00#0\x04fnord\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f", + ) + + def test_bytes_long_pw(self): + """Test FramePasswordChangeNotification with long new password.""" + frame = FramePasswordChangeNotification(newpassword="x" * 32) + self.assertEqual( + bytes(frame), b"\x00#0\x04xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\x17" + ) + + def test_frame_from_raw(self): + """Test parsing FramePasswordChangeNotification from raw bytes.""" + frame = frame_from_raw( + b"\x00#0\x04fnord\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00f", + ) + self.assertTrue(isinstance(frame, FramePasswordChangeNotification)) + self.assertEqual(frame.newpassword, "fnord") + + def test_errors(self): + """Test FramePasswordChangeNotification with wrong password.""" + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeNotification()) + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeNotification(newpassword="x" * 33)) + + def test_str(self): + """Test string representation of FramePasswordChangeNotification.""" + frame = FramePasswordChangeNotification(newpassword="fnord") + self.assertEqual(str(frame), '') + + def test_str_no_password(self): + """Test string representation of FramePasswordChangeNotification with no password.""" + frame = FramePasswordChangeNotification() + self.assertEqual(str(frame), '') diff --git a/test/frame_password_change_req_test.py b/test/frame_password_change_req_test.py new file mode 100644 index 00000000..59bc0579 --- /dev/null +++ b/test/frame_password_change_req_test.py @@ -0,0 +1,83 @@ +"""Unit tests for PyVLX PasswordChangeRequest.""" +import unittest + +from pyvlx.exception import PyVLXException +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FramePasswordChangeRequest + + +class TestFramePasswordChange(unittest.TestCase): + """Test class for FramePasswordChangeRequest.""" + + # pylint: disable=too-many-public-methods,invalid-name + + def test_bytes(self): + """Test FramePasswordChangeRequest.""" + frame = FramePasswordChangeRequest(currentpassword="fnord", newpassword="bfeld") + self.assertEqual( + bytes(frame), + b"\x00C0\x02fnord\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00bfeld\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00i", + ) + + def test_bytes_long_newpw(self): + """Test FramePasswordChangeRequest with long new password.""" + frame = FramePasswordChangeRequest(currentpassword="fnord", newpassword="x" * 32) + self.assertEqual( + bytes(frame), b"\x00C0\x02fnord\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\x00" + ) + + def test_bytes_long_oldpw(self): + """Test FramePasswordChangeRequest with long old password.""" + frame = FramePasswordChangeRequest(currentpassword="x" * 32, newpassword="bfeld") + self.assertEqual( + bytes(frame), b"\x00C0\x02xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxbfeld\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18" + ) + + def test_bytes_long_bothpw(self): + """Test FramePasswordChangeRequest with long passwords.""" + frame = FramePasswordChangeRequest(currentpassword="x" * 32, newpassword="y" * 32) + self.assertEqual( + bytes(frame), b"\x00C0\x02xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyq" + ) + + def test_frame_from_raw(self): + """Test parsing FramePasswordChangeRequest from raw bytes.""" + frame = frame_from_raw( + b"\x00C0\x02fnord\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00bfeld\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" + + b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00i" + ) + self.assertTrue(isinstance(frame, FramePasswordChangeRequest)) + self.assertEqual(frame.newpassword, "bfeld") + self.assertEqual(frame.currentpassword, "fnord") + + def test_errors(self): + """Test FramePasswordChangeRequest with wrong password.""" + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeRequest()) + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeRequest(currentpassword="fnord")) + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeRequest(currentpassword="fnord", newpassword="x" * 33)) + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeRequest(newpassword="fnord", currentpassword="x" * 33)) + with self.assertRaises(PyVLXException): + bytes(FramePasswordChangeRequest(newpassword="x" * 33, currentpassword="x" * 33)) + + def test_str(self): + """Test string representation of FramePasswordChangeRequest.""" + frame = FramePasswordChangeRequest(currentpassword="fnord", newpassword="bfeld") + self.assertEqual(str(frame), '') + + def test_str_no_password(self): + """Test string representation of FramePasswordChangeRequest with no password.""" + frame = FramePasswordChangeRequest() + self.assertEqual(str(frame), '') diff --git a/test/frame_password_enter_cfm_test.py b/test/frame_password_enter_cfm_test.py index c591c042..c92fd2b8 100644 --- a/test/frame_password_enter_cfm_test.py +++ b/test/frame_password_enter_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FramePasswordEnterConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ( +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( FramePasswordEnterConfirmation, PasswordEnterConfirmationStatus) @@ -34,5 +34,5 @@ def test_str(self): frame = FramePasswordEnterConfirmation() self.assertEqual( str(frame), - "", + '', ) diff --git a/test/frame_password_enter_req_test.py b/test/frame_password_enter_req_test.py index 7b629513..c85a93e7 100644 --- a/test/frame_password_enter_req_test.py +++ b/test/frame_password_enter_req_test.py @@ -2,8 +2,8 @@ import unittest from pyvlx.exception import PyVLXException -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FramePasswordEnterRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FramePasswordEnterRequest class TestFramePasswordEnter(unittest.TestCase): @@ -54,9 +54,9 @@ def test_errors(self): def test_str(self): """Test string representation of FramePasswordEnterRequest.""" frame = FramePasswordEnterRequest(password="fnord") - self.assertEqual(str(frame), "") + self.assertEqual(str(frame), '') def test_str_no_password(self): """Test string representation of FramePasswordEnterRequest with no password.""" frame = FramePasswordEnterRequest() - self.assertEqual(str(frame), "") + self.assertEqual(str(frame), '') diff --git a/test/frame_reboot_cfm_test.py b/test/frame_reboot_cfm_test.py new file mode 100644 index 00000000..27b395c6 --- /dev/null +++ b/test/frame_reboot_cfm_test.py @@ -0,0 +1,28 @@ +"""Unit tests for FrameGatewayRebootConfirmation.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGatewayRebootConfirmation + + +class TestFrameGatewayRebootConfirmation(unittest.TestCase): + """Test class TestFrameGatewayRebootConfirmation.""" + + # pylint: disable=too-many-public-methods,invalid-name + + EXAMPLE_FRAME = b"\x00\x03\x00\x02\x01" + + def test_bytes(self): + """Test FrameGatewayRebootConfirmation with NO_TYPE.""" + frame = FrameGatewayRebootConfirmation() + self.assertEqual(bytes(frame), self.EXAMPLE_FRAME) + + def test_frame_from_raw(self): + """Test parse FrameGatewayRebootConfirmation from raw.""" + frame = frame_from_raw(self.EXAMPLE_FRAME) + self.assertTrue(isinstance(frame, FrameGatewayRebootConfirmation)) + + def test_str(self): + """Test string representation of FrameGatewayRebootConfirmation.""" + frame = FrameGatewayRebootConfirmation() + self.assertEqual(str(frame), '') diff --git a/test/frame_reboot_req_test.py b/test/frame_reboot_req_test.py new file mode 100644 index 00000000..e9f7fac2 --- /dev/null +++ b/test/frame_reboot_req_test.py @@ -0,0 +1,28 @@ +"""Unit tests for FrameGatewayRebootRequest.""" +import unittest + +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameGatewayRebootRequest + + +class TestFrameGatewayRebootRequest(unittest.TestCase): + """Test class TestFrameGatewayRebootRequest.""" + + # pylint: disable=too-many-public-methods,invalid-name + + EXAMPLE_FRAME = b"\x00\x03\x00\x01\x02" + + def test_bytes(self): + """Test FrameGatewayRebootRequest with NO_TYPE.""" + frame = FrameGatewayRebootRequest() + self.assertEqual(bytes(frame), self.EXAMPLE_FRAME) + + def test_frame_from_raw(self): + """Test parse FrameGatewayRebootRequest from raw.""" + frame = frame_from_raw(self.EXAMPLE_FRAME) + self.assertTrue(isinstance(frame, FrameGatewayRebootRequest)) + + def test_str(self): + """Test string representation of FrameGatewayRebootRequest.""" + frame = FrameGatewayRebootRequest() + self.assertEqual(str(frame), '') diff --git a/test/frame_session_finished_notification_test.py b/test/frame_session_finished_notification_test.py index 65b6bdb0..ea494826 100644 --- a/test/frame_session_finished_notification_test.py +++ b/test/frame_session_finished_notification_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameSessionFinishedNotification.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameSessionFinishedNotification +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameSessionFinishedNotification class TestFrameSessionFinishedNotification(unittest.TestCase): @@ -25,5 +25,5 @@ def test_str(self): """Test string representation of FrameSessionFinishedNotification.""" frame = FrameSessionFinishedNotification(session_id=1000) self.assertEqual( - str(frame), "" + str(frame), '' ) diff --git a/test/frame_set_node_name_cfm_test.py b/test/frame_set_node_name_cfm_test.py index 9551bbda..8844f1e8 100644 --- a/test/frame_set_node_name_cfm_test.py +++ b/test/frame_set_node_name_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameSetNodeNameConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import ( +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import ( FrameSetNodeNameConfirmation, SetNodeNameConfirmationStatus) @@ -38,5 +38,5 @@ def test_str(self): frame = FrameSetNodeNameConfirmation(node_id=23) self.assertEqual( str(frame), - '', + '', ) diff --git a/test/frame_set_node_name_req_test.py b/test/frame_set_node_name_req_test.py index 0ae62bd6..e39f19cf 100644 --- a/test/frame_set_node_name_req_test.py +++ b/test/frame_set_node_name_req_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameSetNodeNameRequest.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameSetNodeNameRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameSetNodeNameRequest class TestFrameSetNodeNameRequest(unittest.TestCase): @@ -34,5 +34,5 @@ def test_str(self): """Test string representation of FrameSetNodeNameRequest.""" frame = FrameSetNodeNameRequest(node_id=4, name="Fnord") self.assertEqual( - str(frame), '' + str(frame), '' ) diff --git a/test/frame_set_utc_cfm_test.py b/test/frame_set_utc_cfm_test.py index 140a063e..c8c3c77a 100644 --- a/test/frame_set_utc_cfm_test.py +++ b/test/frame_set_utc_cfm_test.py @@ -1,8 +1,8 @@ """Unit tests for FrameSetUTCConfirmation.""" import unittest -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameSetUTCConfirmation +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameSetUTCConfirmation class TestFrameSetUTCConfirmation(unittest.TestCase): diff --git a/test/frame_set_utc_req_test.py b/test/frame_set_utc_req_test.py index e73daaba..366b9cf4 100644 --- a/test/frame_set_utc_req_test.py +++ b/test/frame_set_utc_req_test.py @@ -2,8 +2,8 @@ import unittest from datetime import datetime -from pyvlx.frame_creation import frame_from_raw -from pyvlx.frames import FrameSetUTCRequest +from pyvlx.api.frame_creation import frame_from_raw +from pyvlx.api.frames import FrameSetUTCRequest class TestFrameSetUTCRequest(unittest.TestCase): diff --git a/test/frame_test.py b/test/frame_test.py index cb9bca6c..9a400146 100644 --- a/test/frame_test.py +++ b/test/frame_test.py @@ -3,7 +3,7 @@ from pyvlx import PyVLXException from pyvlx.const import Command -from pyvlx.frames.frame import FrameBase +from pyvlx.api.frames.frame import FrameBase class TestFrame(unittest.TestCase): diff --git a/test/node_helper_test.py b/test/node_helper_test.py index c81ab2a4..e0770c6b 100644 --- a/test/node_helper_test.py +++ b/test/node_helper_test.py @@ -4,7 +4,7 @@ from pyvlx import ( Blade, Blind, GarageDoor, Gate, Light, PyVLX, RollerShutter, Window) from pyvlx.const import NodeTypeWithSubtype -from pyvlx.frames import FrameGetNodeInformationNotification +from pyvlx.api.frames import FrameGetNodeInformationNotification from pyvlx.node_helper import convert_frame_to_node diff --git a/test/scene_test.py b/test/scene_test.py index 64812c9a..cce6c487 100644 --- a/test/scene_test.py +++ b/test/scene_test.py @@ -20,4 +20,4 @@ def test_str(self): """Test string representation of Scene object.""" pyvlx = PyVLX() scene = Scene(pyvlx, 2, "Scene 1") - self.assertEqual(str(scene), '') + self.assertEqual(str(scene), '') diff --git a/test/session_id_test.py b/test/session_id_test.py index e37c32c4..2d35183f 100644 --- a/test/session_id_test.py +++ b/test/session_id_test.py @@ -1,7 +1,7 @@ """Test for slip helper functions.""" import unittest -from pyvlx.session_id import get_new_session_id, set_session_id +from pyvlx.api.session_id import get_new_session_id, set_session_id class SessionIdSlip(unittest.TestCase):