Skip to content

Commit

Permalink
Merge 3507f15 into 9514546
Browse files Browse the repository at this point in the history
  • Loading branch information
farmio committed Jan 4, 2021
2 parents 9514546 + 3507f15 commit 8f94d29
Show file tree
Hide file tree
Showing 28 changed files with 332 additions and 274 deletions.
2 changes: 1 addition & 1 deletion setup.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ warn_unreachable = true
implicit_reexport = true

# partly typechecked modules (extra block for better overview)
[mypy-xknx.devices.device,xknx.devices.devices,xknx.devices.travelcalculator,xknx.remote_value.remote_value]
[mypy-xknx.devices.action,xknx.devices.binary_sensor,xknx.devices.climate,xknx.devices.climate_mode,xknx.devices.device,xknx.devices.devices,xknx.devices.travelcalculator,xknx.remote_value.remote_value,xknx.remote_value.remote_value_climate_mode]
strict = true
ignore_errors = false
warn_unreachable = true
Expand Down
10 changes: 6 additions & 4 deletions test/config_tests/config_v1_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,7 +382,9 @@ def test_config_climate_operation_mode(self):
self.assertEqual(
TestConfig.xknx.devices["Office.Climate"].mode,
ClimateMode(
TestConfig.xknx, name=None, group_address_operation_mode="1/7/6"
TestConfig.xknx,
name="Office.Climate_mode",
group_address_operation_mode="1/7/6",
),
)

Expand All @@ -392,7 +394,7 @@ def test_config_climate_operation_mode2(self):
TestConfig.xknx.devices["Attic.Climate"].mode,
ClimateMode(
TestConfig.xknx,
name=None,
name="Attic.Climate_mode",
group_address_operation_mode_protection="1/7/8",
group_address_operation_mode_night="1/7/9",
group_address_operation_mode_comfort="1/7/10",
Expand All @@ -405,7 +407,7 @@ def test_config_climate_operation_mode_state(self):
TestConfig.xknx.devices["Bath.Climate"].mode,
ClimateMode(
TestConfig.xknx,
name=None,
name="Bath.Climate_mode",
group_address_operation_mode="1/7/6",
group_address_operation_mode_state="1/7/7",
),
Expand All @@ -417,7 +419,7 @@ def test_config_climate_controller_status_state(self):
TestConfig.xknx.devices["Cellar.Climate"].mode,
ClimateMode(
TestConfig.xknx,
name=None,
name="Cellar.Climate_mode",
group_address_controller_status="1/7/12",
group_address_controller_status_state="1/7/13",
),
Expand Down
3 changes: 1 addition & 2 deletions test/devices_tests/climate_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
DPTHVACMode,
DPTTemperature,
DPTValue1Count,
HVACOperationMode,
)
from xknx.dpt.dpt_hvac_mode import HVACControllerMode
from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACOperationMode
from xknx.exceptions import CouldNotParseTelegram, DeviceIllegalValue
from xknx.telegram import GroupAddress, Telegram
from xknx.telegram.apci import GroupValueRead, GroupValueWrite
Expand Down
3 changes: 2 additions & 1 deletion test/dpt_tests/dpt_hvac_mode_test.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
"""Unit test for KNX DPT HVAC Operation modes."""
import unittest

from xknx.dpt import DPTControllerStatus, DPTHVACMode, HVACOperationMode
from xknx.dpt import DPTControllerStatus, DPTHVACMode
from xknx.dpt.dpt_hvac_mode import HVACOperationMode
from xknx.exceptions import ConversionError, CouldNotParseKNXIP


Expand Down
11 changes: 2 additions & 9 deletions test/remote_value_tests/remote_value_climate_mode_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
import unittest

from xknx import XKNX
from xknx.dpt import DPTArray, DPTBinary, HVACOperationMode
from xknx.dpt.dpt_hvac_mode import HVACControllerMode
from xknx.dpt import DPTArray, DPTBinary
from xknx.dpt.dpt_hvac_mode import HVACControllerMode, HVACOperationMode
from xknx.exceptions import ConversionError, CouldNotParseTelegram
from xknx.remote_value import (
RemoteValueBinaryHeatCool,
RemoteValueBinaryOperationMode,
RemoteValueClimateMode,
)
from xknx.remote_value.remote_value_climate_mode import _RemoteValueBinaryClimateMode
from xknx.telegram import GroupAddress, Telegram
from xknx.telegram.apci import GroupValueWrite

Expand Down Expand Up @@ -137,12 +136,6 @@ def test_from_knx_unknown_operation_mode(self):
with self.assertRaises(ConversionError):
RemoteValueBinaryHeatCool(xknx, controller_mode=None)

def test_supported_operation_modes_not_implemented(self):
"""Test from_knx function with unsupported operation."""
xknx = XKNX()
with self.assertRaises(NotImplementedError):
_RemoteValueBinaryClimateMode.supported_operation_modes()

def test_to_knx_error_operation_mode(self):
"""Test to_knx function with wrong parameter."""
xknx = XKNX()
Expand Down
13 changes: 3 additions & 10 deletions test/remote_value_tests/remote_value_datetime_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,9 @@
import unittest

from xknx import XKNX
from xknx.dpt import DPTArray, DPTBinary, HVACOperationMode
from xknx.exceptions import ConversionError, CouldNotParseTelegram
from xknx.remote_value import (
RemoteValueBinaryHeatCool,
RemoteValueBinaryOperationMode,
RemoteValueClimateMode,
RemoteValueDateTime,
)
from xknx.remote_value.remote_value_climate_mode import _RemoteValueBinaryClimateMode
from xknx.telegram import GroupAddress, Telegram
from xknx.dpt import DPTArray
from xknx.exceptions import ConversionError
from xknx.remote_value import RemoteValueDateTime


class TestRemoteValueDateTime(unittest.TestCase):
Expand Down
10 changes: 0 additions & 10 deletions test/remote_value_tests/remote_value_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,6 @@ def tearDown(self):
"""Tear down test class."""
self.loop.close()

def test_warn_payload_valid(self):
"""Test for warning if payload_valid is not implemented."""
xknx = XKNX()
remote_value = RemoteValue(xknx)
with patch("logging.Logger.warning") as mock_warn:
remote_value.payload_valid(DPTBinary(0))
mock_warn.assert_called_with(
"'payload_valid()' not implemented for %s", "RemoteValue"
)

def test_info_set_uninitialized(self):
"""Test for info if RemoteValue is not initialized."""
xknx = XKNX()
Expand Down
45 changes: 31 additions & 14 deletions xknx/devices/action.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
"""Module for handling commands which may be attached to BinarySensor class."""
import logging
from typing import TYPE_CHECKING, Any, Awaitable, Callable, Optional

if TYPE_CHECKING:
from xknx.xknx import XKNX

logger = logging.getLogger("xknx.log")


class ActionBase:
"""Base Class for handling commands."""

def __init__(self, xknx, hook="on", counter=1):
def __init__(self, xknx: "XKNX", hook: str = "on", counter: Optional[int] = 1):
"""Initialize Action_Base class."""
self.xknx = xknx
self.hook = hook
self.counter = counter

def test_counter(self, counter):
def test_counter(self, counter: Optional[int]) -> bool:
"""Test if action filters for specific counter."""
if self.counter is None:
# no specific counter_filter -> always true
Expand All @@ -22,55 +26,62 @@ def test_counter(self, counter):
return True
return counter == self.counter

def test_if_applicable(self, state, counter=None):
def test_if_applicable(self, state: bool, counter: Optional[int] = None) -> bool:
"""Test if should be executed for this state and this counter number."""
if state and (self.hook == "on"):
return self.test_counter(counter)
if not state and (self.hook == "off"):
return self.test_counter(counter)
return False

async def execute(self):
async def execute(self) -> None:
"""Execute action. To be overwritten in derived classes."""
logger.info("Execute not implemented for %s", self.__class__.__name__)

def __str__(self):
def __str__(self) -> str:
"""Return object as readable string."""
return f'<ActionBase hook="{self.hook}" counter="{self.counter}"/>'

def __eq__(self, other):
def __eq__(self, other: object) -> bool:
"""Equal operator."""
return self.__dict__ == other.__dict__


class Action(ActionBase):
"""Class for handling commands."""

def __init__(self, xknx, hook="on", target=None, method=None, counter=1):
def __init__(
self,
xknx: "XKNX",
hook: str = "on",
target: Optional[str] = None,
method: Optional[str] = None,
counter: int = 1,
):
"""Initialize Action class."""
# pylint: disable=too-many-arguments
super().__init__(xknx, hook, counter)
self.target = target
self.method = method

@classmethod
def from_config(cls, xknx, config):
def from_config(cls, xknx: "XKNX", config: Any) -> "Action":
"""Initialize object from configuration structure."""
hook = config.get("hook", "on")
target = config.get("target")
method = config.get("method")
counter = config.get("counter", 1)
return cls(xknx, hook=hook, target=target, method=method, counter=counter)

async def execute(self):
async def execute(self) -> None:
"""Execute action."""
if self.target is not None:
if self.target is not None and self.method is not None:
if self.target not in self.xknx.devices:
logger.warning("Unknown device %s witin action %s.", self.target, self)
return
await self.xknx.devices[self.target].do(self.method)

def __str__(self):
def __str__(self) -> str:
"""Return object as readable string."""
return '<Action target="{}" method="{}" {}/>'.format(
self.target, self.method, super().__str__()
Expand All @@ -80,17 +91,23 @@ def __str__(self):
class ActionCallback(ActionBase):
"""Class for handling commands via callbacks."""

def __init__(self, xknx, callback, hook="on", counter=1):
def __init__(
self,
xknx: "XKNX",
callback: Callable[[], Awaitable[None]],
hook: str = "on",
counter: int = 1,
):
"""Initialize Action class."""
# pylint: disable=too-many-arguments
super().__init__(xknx, hook, counter)
self.callback = callback

async def execute(self):
async def execute(self) -> None:
"""Execute callback."""
await self.callback()

def __str__(self):
def __str__(self) -> str:
"""Return object as readable string."""
return '<ActionCallback callback="{}" {}/>'.format(
self.callback.__name__, super().__str__()
Expand Down

0 comments on commit 8f94d29

Please sign in to comment.