Skip to content

Commit

Permalink
Added optional arguments to decoding/encoding routines, bumped versio…
Browse files Browse the repository at this point in the history
…n number
  • Loading branch information
alryaz committed May 10, 2021
1 parent cf561aa commit 1cac80f
Show file tree
Hide file tree
Showing 8 changed files with 39 additions and 17 deletions.
10 changes: 7 additions & 3 deletions hekrapi/aioudp.py
Expand Up @@ -30,6 +30,8 @@ async def main():


# Datagram protocol
from typing import Callable


class DatagramEndpointProtocol(asyncio.DatagramProtocol):
"""Datagram protocol for the endpoint high-level interface."""
Expand Down Expand Up @@ -149,7 +151,7 @@ class RemoteEndpoint(Endpoint):
It is initialized with an optional queue size for the incoming datagrams.
"""

def send(self, data):
def send(self, data, **kwargs):
"""Send a datagram to the remote host."""
super().send(data, None)

Expand All @@ -165,7 +167,7 @@ async def receive(self):
# High-level coroutines

async def open_datagram_endpoint(
host, port, *, endpoint_factory=Endpoint, remote=False, **kwargs):
host, port, *, endpoint_factory=Callable[[], Endpoint], remote=False, **kwargs):
"""Open and return a datagram endpoint.
The default endpoint factory is the Endpoint class.
Expand Down Expand Up @@ -209,10 +211,12 @@ async def open_remote_endpoint(
# Testing

try:
# noinspection PyPackageRequirements,PyUnresolvedReferences
import pytest
pytestmark = pytest.mark.asyncio
except ImportError: # pragma: no cover
pass
else:
pytestmark = pytest.mark.asyncio


async def test_standard_behavior():
Expand Down
20 changes: 12 additions & 8 deletions hekrapi/argument.py
Expand Up @@ -12,13 +12,13 @@ class Argument:
"""Argument class for HekrAPI"""

def __init__(self, name: str,
value_type: Union[Tuple[ArgumentType, ArgumentType], ArgumentType]=int,
byte_length: int=1,
variable: Optional[str]=None,
multiplier: Optional[Union[int, float]]=None,
decimals: Optional[int]=None,
value_min: Optional[Union[int, float]]=None,
value_max: Optional[Union[int, float]]=None,
value_type: Union[Tuple[ArgumentType, ArgumentType], ArgumentType] = int,
byte_length: int = 1,
variable: Optional[str] = None,
multiplier: Optional[Union[int, float]] = None,
decimals: Optional[int] = None,
value_min: Optional[Union[int, float]] = None,
value_max: Optional[Union[int, float]] = None,
):
"""Argument class constructor
Expand Down Expand Up @@ -104,4 +104,8 @@ def variable(self) -> str:
@variable.setter
def variable(self, value):
"""Setter for variable name"""
self.__variable = value
self.__variable = value


class OptionalArgument(Argument):
"""Argument that is optional in datagrams"""
6 changes: 5 additions & 1 deletion hekrapi/command.py
Expand Up @@ -3,7 +3,7 @@

from typing import List

from .argument import Argument
from .argument import Argument, OptionalArgument
from .const import FrameType
from .exceptions import HekrTypeError, HekrValueError, InvalidDataMissingKeyException, \
InvalidDataGreaterThanException, InvalidDataLessThanException
Expand Down Expand Up @@ -261,6 +261,8 @@ def encode(self, data: dict, use_variable_names: bool = False, filter_values: bo
value_input = data.get(key, None)

if value_input is None:
if isinstance(argument, OptionalArgument):
continue
raise InvalidDataMissingKeyException(data_key=key)

if argument.value_min is not None and argument.value_min > value_input:
Expand Down Expand Up @@ -300,6 +302,8 @@ def decode(self, data: bytes, use_variable_names: bool = False, filter_values: b

next_pos = current_pos + argument.byte_length
if next_pos > data_length:
if isinstance(argument, OptionalArgument):
continue
raise InvalidDataMissingKeyException(data_key=key)

value_output = int.from_bytes(data[current_pos:next_pos], byteorder='big', signed=False)
Expand Down
2 changes: 1 addition & 1 deletion hekrapi/device.py
Expand Up @@ -419,7 +419,7 @@ async def close_connection(self) -> None:

async def send_request(self, request_str: str) -> None:
_LOGGER.debug('Sending request via %s with content: %s' % (self, request_str))
self._endpoint.send(str.encode(request_str))
self._endpoint.send(str.encode(request_str), )

async def read_response(self) -> str:
_LOGGER.debug('Starting receiving on %s' % self)
Expand Down
3 changes: 3 additions & 0 deletions hekrapi/protocols/__init__.py
@@ -1 +1,4 @@
""" Protocols implemented in Python for Hekr API """
__all__ = [
"power_meter"
]
5 changes: 3 additions & 2 deletions hekrapi/protocols/power_meter.py
@@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
""" Basic protocol definition for a smart power meter """
from enum import IntEnum
from typing import Union, Any

from ..argument import Argument
from ..argument import Argument, OptionalArgument
from ..command import Command, FrameType
from ..protocol import Protocol, TO_STR, TO_FLOAT, TO_BOOL, TO_SIGNED_FLOAT

Expand Down Expand Up @@ -52,7 +53,7 @@ class SwitchState(IntEnum):
Argument("warning_current", CurrentWarning, 1, "fault_Over_I"),
Argument("delay_timer", int, 2, "tmCd_M", value_min=0, value_max=1440),
Argument("delay_enabled", TO_BOOL, 1, "tmCdO_Sw"),
Argument("warning_battery", PowerSupplyWarning, 1, "fault_SurplusDeficiency")
OptionalArgument("warning_battery", PowerSupplyWarning, 1, "fault_SurplusDeficiency"),
]),
Command(2, FrameType.SEND, "querySet", response_command_id=8),
Command(3, FrameType.SEND, "setLimit", arguments=[
Expand Down
8 changes: 7 additions & 1 deletion hekrapi/types.py
@@ -1,9 +1,15 @@
"""Types for Hekr API project."""

from typing import Tuple, Dict, Any, Union, Optional, Callable
from typing import Tuple, Dict, Any, Union, Optional, Callable, TYPE_CHECKING

from .const import DeviceResponseState

if TYPE_CHECKING:
# noinspection PyUnresolvedReferences
from .command import Command
# noinspection PyUnresolvedReferences
from .device import Device

DecodeResult = Tuple['Command', Dict[str, Any], int]
MessageID = int
DeviceID = str
Expand Down
2 changes: 1 addition & 1 deletion setup.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
from distutils.core import setup

version = 'v0.2.5'
version = 'v0.2.7'
setup(
name='hekrapi',
packages=['hekrapi', 'hekrapi.protocols'],
Expand Down

0 comments on commit 1cac80f

Please sign in to comment.