Skip to content
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## v1.4.2

- Improve timeout setting: set it to 30s for the Stretch, to 10s for all other devices.

## v1.4.1

- Prettying documents with Biome (CLI), fixture layout updated accordingly.
Expand Down
16 changes: 3 additions & 13 deletions plugwise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@
from __future__ import annotations

from plugwise.constants import (
DEFAULT_LEGACY_TIMEOUT,
DEFAULT_PORT,
DEFAULT_TIMEOUT,
DEFAULT_USERNAME,
DOMAIN_OBJECTS,
LOGGER,
Expand Down Expand Up @@ -47,7 +45,6 @@ def __init__(
websession: aiohttp.ClientSession,
username: str = DEFAULT_USERNAME,
port: int = DEFAULT_PORT,
timeout: float = DEFAULT_LEGACY_TIMEOUT,

) -> None:
"""Set the constructor for this class."""
Expand All @@ -57,15 +54,13 @@ def __init__(
websession,
username,
port,
timeout,
)

self._host = host
self._passwd = password
self._websession = websession
self._user = username
self._username = username
self._port = port
self._timeout = timeout

self._cooling_present = False
self._elga = False
Expand Down Expand Up @@ -130,7 +125,6 @@ async def connect(self) -> bool:
self._smile_api = SmileAPI(
self._host,
self._passwd,
self._timeout,
self._websession,
self._cooling_present,
self._elga,
Expand All @@ -149,12 +143,11 @@ async def connect(self) -> bool:
self.smile_model_id,
self.smile_name,
self.smile_type,
self._user,
self._username,
self._port,
) if not self.smile_legacy else SmileLegacyAPI(
self._host,
self._passwd,
self._timeout,
self._websession,
self._is_thermostat,
self._on_off_device,
Expand All @@ -170,7 +163,7 @@ async def connect(self) -> bool:
self.smile_name,
self.smile_type,
self.smile_zigbee_mac_address,
self._user,
self._username,
self._port,
)

Expand All @@ -196,9 +189,6 @@ async def _smile_detect(self, result: etree, dsmrmain: etree) -> None:
else:
model = await self._smile_detect_legacy(result, dsmrmain, model)

if not self.smile_legacy:
self._timeout = DEFAULT_TIMEOUT

if model == "Unknown" or self.smile_fw_version is None: # pragma: no cover
# Corner case check
LOGGER.error(
Expand Down
8 changes: 7 additions & 1 deletion plugwise/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
ANNA,
ATTR_NAME,
DATA,
DEFAULT_LEGACY_TIMEOUT,
DEFAULT_TIMEOUT,
DEFAULT_USERNAME,
DEVICE_MEASUREMENTS,
DHW_SETPOINT,
DOMAIN_OBJECTS,
Expand Down Expand Up @@ -74,9 +77,12 @@ def __init__(
websession: ClientSession | None,
username: str,
port: int,
timeout: float,
) -> None:
"""Set the constructor for this class."""
timeout = DEFAULT_TIMEOUT
if username != DEFAULT_USERNAME:
timeout = DEFAULT_LEGACY_TIMEOUT

if not websession:
aio_timeout = ClientTimeout(total=timeout)

Expand Down
1 change: 0 additions & 1 deletion plugwise/legacy/helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
version_to_model,
)

# This way of importing aiohttp is because of patch/mocking in testing (aiohttp timeouts)
from defusedxml import ElementTree as etree
from munch import Munch

Expand Down
3 changes: 0 additions & 3 deletions plugwise/legacy/smile.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ def __init__(
self,
host: str,
password: str,
timeout: float,
websession: aiohttp.ClientSession,
_is_thermostat: bool,
_on_off_device: bool,
Expand All @@ -66,7 +65,6 @@ def __init__(
websession,
username,
port,
timeout,
)
SmileLegacyData.__init__(self)

Expand All @@ -76,7 +74,6 @@ def __init__(
self._opentherm_device = _opentherm_device
self._stretch_v2 = _stretch_v2
self._target_smile = _target_smile
self._timeout = timeout
self.loc_data = loc_data
self.smile_fw_version = smile_fw_version
self.smile_hostname = smile_hostname
Expand Down
3 changes: 0 additions & 3 deletions plugwise/smile.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ def __init__(
self,
host: str,
password: str,
timeout: float,
websession: aiohttp.ClientSession,
_cooling_present: bool,
_elga: bool,
Expand Down Expand Up @@ -75,7 +74,6 @@ def __init__(
websession,
username,
port,
timeout,
)
SmileData.__init__(self)

Expand All @@ -86,7 +84,6 @@ def __init__(
self._on_off_device = _on_off_device
self._opentherm_device = _opentherm_device
self._schedule_old_states = _schedule_old_states
self._timeout = timeout
self.gateway_id = gateway_id
self.loc_data = loc_data
self.smile_fw_version = smile_fw_version
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "plugwise"
version = "1.4.1"
version = "1.4.2a0"
license = {file = "LICENSE"}
description = "Plugwise Smile (Adam/Anna/P1) and Stretch module for Python 3."
readme = "README.md"
Expand Down
35 changes: 21 additions & 14 deletions tests/test_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,6 @@ async def setup_app(
timeout=False,
raise_timeout=False,
fail_auth=False,
stretch=False,
):
"""Create mock webserver for Smile to interface with."""
app = aiohttp.web.Application()
Expand Down Expand Up @@ -279,7 +278,6 @@ async def connect(
timeout=False,
raise_timeout=False,
fail_auth=False,
stretch=False,
):
"""Connect to a smile environment and perform basic asserts."""
port = aiohttp.test_utils.unused_port()
Expand All @@ -288,7 +286,7 @@ async def connect(
)

# Happy flow
app = await self.setup_app(broken, timeout, raise_timeout, fail_auth, stretch)
app = await self.setup_app(broken, timeout, raise_timeout, fail_auth)

server = aiohttp.test_utils.TestServer(
app, port=port, scheme="http", host="127.0.0.1"
Expand Down Expand Up @@ -339,7 +337,7 @@ async def connect(
)

if not timeout:
assert smile._timeout == 30
assert smile._timeout == 10

# Connect to the smile
try:
Expand Down Expand Up @@ -367,6 +365,9 @@ async def connect_legacy(
test_password = "".join(
secrets.choice(string.ascii_lowercase) for _ in range(8)
)
user_name = pw_constants.DEFAULT_USERNAME
if stretch:
user_name = pw_constants.STRETCH

# Happy flow
app = await self.setup_legacy_app(broken, timeout, raise_timeout, fail_auth, stretch)
Expand Down Expand Up @@ -400,7 +401,7 @@ async def connect_legacy(
try:
smile = pw_smile.Smile(
host=server.host,
username=pw_constants.DEFAULT_USERNAME,
username=user_name,
password=test_password,
port=server.port,
websession=None,
Expand All @@ -413,14 +414,17 @@ async def connect_legacy(

smile = pw_smile.Smile(
host=server.host,
username=pw_constants.DEFAULT_USERNAME,
username=user_name,
password=test_password,
port=server.port,
websession=websession,
)

if not timeout:
assert smile._timeout == 30
if user_name == pw_constants.STRETCH:
assert smile._timeout == 30
else:
assert smile._timeout == 10

# Connect to the smile
try:
Expand All @@ -437,7 +441,7 @@ async def connect_legacy(

# Wrap connect for invalid connections
async def connect_wrapper(
self, raise_timeout=False, fail_auth=False, stretch=False
self, raise_timeout=False, fail_auth=False,
):
"""Wrap connect to try negative testing before positive testing."""
if fail_auth:
Expand Down Expand Up @@ -471,27 +475,27 @@ async def connect_wrapper(
_LOGGER.info(" + successfully passed XML issue handling.")

_LOGGER.info("Connecting to functioning device:")
return await self.connect(stretch=stretch)
return await self.connect()

async def connect_legacy_wrapper(
self, raise_timeout=False, fail_auth=False, stretch=False
):
"""Wrap connect to try negative testing before positive testing."""
if raise_timeout:
_LOGGER.warning("Connecting to device exceeding timeout in handling:")
return await self.connect_legacy(raise_timeout=True)
return await self.connect_legacy(raise_timeout=True, stretch=stretch)

try:
_LOGGER.warning("Connecting to device exceeding timeout in response:")
await self.connect_legacy(timeout=True)
await self.connect_legacy(timeout=True, stretch=stretch)
_LOGGER.error(" - timeout not handled") # pragma: no cover
raise self.ConnectError # pragma: no cover
except pw_exceptions.ConnectionFailedError:
_LOGGER.info(" + successfully passed timeout handling.")

try:
_LOGGER.warning("Connecting to device with missing data:")
await self.connect_legacy(broken=True)
_LOGGER.warning("Connecting to device, with missing data:")
await self.connect_legacy(broken=True, stretch=stretch)
_LOGGER.error(" - broken information not handled") # pragma: no cover
raise self.ConnectError # pragma: no cover
except pw_exceptions.InvalidXMLError:
Expand Down Expand Up @@ -552,7 +556,10 @@ async def device_test(
await smile.full_update_device()
smile.get_all_devices()
data = await smile.async_update()
assert smile._timeout == 30
if smile._username == pw_constants.STRETCH:
assert smile._timeout == 30
else:
assert smile._timeout == 10
else:
data = await smile.async_update()
assert smile._timeout == 10
Expand Down
Loading