plugwise 1.4.3__tar.gz → 1.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {plugwise-1.4.3 → plugwise-1.5.0}/PKG-INFO +1 -1
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/__init__.py +29 -24
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/helper.py +3 -3
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/legacy/helper.py +3 -2
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/legacy/smile.py +2 -1
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/smile.py +2 -1
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise.egg-info/PKG-INFO +1 -1
- {plugwise-1.4.3 → plugwise-1.5.0}/pyproject.toml +1 -1
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_init.py +13 -10
- {plugwise-1.4.3 → plugwise-1.5.0}/LICENSE +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/README.md +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/common.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/constants.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/data.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/exceptions.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/legacy/data.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/py.typed +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise/util.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise.egg-info/SOURCES.txt +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise.egg-info/dependency_links.txt +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise.egg-info/requires.txt +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/plugwise.egg-info/top_level.txt +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/setup.cfg +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/setup.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_adam.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_anna.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_generic.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_legacy_anna.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_legacy_generic.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_legacy_p1.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_legacy_stretch.py +0 -0
- {plugwise-1.4.3 → plugwise-1.5.0}/tests/test_p1.py +0 -0
@@ -5,7 +5,9 @@ Plugwise backend module for Home Assistant Core.
|
|
5
5
|
from __future__ import annotations
|
6
6
|
|
7
7
|
from plugwise.constants import (
|
8
|
+
DEFAULT_LEGACY_TIMEOUT,
|
8
9
|
DEFAULT_PORT,
|
10
|
+
DEFAULT_TIMEOUT,
|
9
11
|
DEFAULT_USERNAME,
|
10
12
|
DOMAIN_OBJECTS,
|
11
13
|
LOGGER,
|
@@ -31,6 +33,7 @@ from plugwise.smile import SmileAPI
|
|
31
33
|
|
32
34
|
import aiohttp
|
33
35
|
from defusedxml import ElementTree as etree
|
36
|
+
from packaging.version import Version, parse
|
34
37
|
|
35
38
|
|
36
39
|
class Smile(SmileComm):
|
@@ -42,26 +45,25 @@ class Smile(SmileComm):
|
|
42
45
|
self,
|
43
46
|
host: str,
|
44
47
|
password: str,
|
45
|
-
timeout: int,
|
46
48
|
websession: aiohttp.ClientSession,
|
47
49
|
port: int = DEFAULT_PORT,
|
48
50
|
username: str = DEFAULT_USERNAME,
|
49
51
|
) -> None:
|
50
52
|
"""Set the constructor for this class."""
|
51
|
-
super().__init__(
|
52
|
-
host,
|
53
|
-
password,
|
54
|
-
port,
|
55
|
-
timeout,
|
56
|
-
username,
|
57
|
-
websession,
|
58
|
-
)
|
59
|
-
|
60
53
|
self._host = host
|
61
|
-
self.
|
54
|
+
self._password = password
|
62
55
|
self._port = port
|
63
|
-
self.
|
56
|
+
self._timeout = DEFAULT_LEGACY_TIMEOUT
|
57
|
+
self._username = username
|
64
58
|
self._websession = websession
|
59
|
+
super().__init__(
|
60
|
+
self._host,
|
61
|
+
self._password,
|
62
|
+
self._port,
|
63
|
+
self._timeout,
|
64
|
+
self._username,
|
65
|
+
self._websession,
|
66
|
+
)
|
65
67
|
|
66
68
|
self._cooling_present = False
|
67
69
|
self._elga = False
|
@@ -75,7 +77,7 @@ class Smile(SmileComm):
|
|
75
77
|
self._target_smile: str = NONE
|
76
78
|
self.gateway_id: str = NONE
|
77
79
|
self.loc_data: dict[str, ThermoLoc] = {}
|
78
|
-
self.smile_fw_version:
|
80
|
+
self.smile_fw_version: Version | None = None
|
79
81
|
self.smile_hostname: str = NONE
|
80
82
|
self.smile_hw_version: str | None = None
|
81
83
|
self.smile_legacy = False
|
@@ -84,10 +86,10 @@ class Smile(SmileComm):
|
|
84
86
|
self.smile_model_id: str | None = None
|
85
87
|
self.smile_name: str = NONE
|
86
88
|
self.smile_type: str = NONE
|
87
|
-
self.smile_version:
|
89
|
+
self.smile_version: Version | None = None
|
88
90
|
self.smile_zigbee_mac_address: str | None = None
|
89
91
|
|
90
|
-
async def connect(self) ->
|
92
|
+
async def connect(self) -> Version | None:
|
91
93
|
"""Connect to Plugwise device and determine its name, type and version."""
|
92
94
|
result = await self._request(DOMAIN_OBJECTS)
|
93
95
|
# Work-around for Stretch fw 2.7.18
|
@@ -125,7 +127,7 @@ class Smile(SmileComm):
|
|
125
127
|
|
126
128
|
self._smile_api = SmileAPI(
|
127
129
|
self._host,
|
128
|
-
self.
|
130
|
+
self._password,
|
129
131
|
self._request,
|
130
132
|
self._websession,
|
131
133
|
self._cooling_present,
|
@@ -146,10 +148,10 @@ class Smile(SmileComm):
|
|
146
148
|
self.smile_name,
|
147
149
|
self.smile_type,
|
148
150
|
self._port,
|
149
|
-
self.
|
151
|
+
self._username,
|
150
152
|
) if not self.smile_legacy else SmileLegacyAPI(
|
151
153
|
self._host,
|
152
|
-
self.
|
154
|
+
self._password,
|
153
155
|
self._request,
|
154
156
|
self._websession,
|
155
157
|
self._is_thermostat,
|
@@ -167,13 +169,13 @@ class Smile(SmileComm):
|
|
167
169
|
self.smile_type,
|
168
170
|
self.smile_zigbee_mac_address,
|
169
171
|
self._port,
|
170
|
-
self.
|
172
|
+
self._username,
|
171
173
|
)
|
172
174
|
|
173
175
|
# Update all endpoints on first connect
|
174
176
|
await self._smile_api.full_update_device()
|
175
177
|
|
176
|
-
return
|
178
|
+
return self.smile_version
|
177
179
|
|
178
180
|
async def _smile_detect(self, result: etree, dsmrmain: etree) -> None:
|
179
181
|
"""Helper-function for connect().
|
@@ -184,7 +186,7 @@ class Smile(SmileComm):
|
|
184
186
|
if (gateway := result.find("./gateway")) is not None:
|
185
187
|
if (v_model := gateway.find("vendor_model")) is not None:
|
186
188
|
model = v_model.text
|
187
|
-
self.smile_fw_version = gateway.find("firmware_version").text
|
189
|
+
self.smile_fw_version = parse(gateway.find("firmware_version").text)
|
188
190
|
self.smile_hw_version = gateway.find("hardware_version").text
|
189
191
|
self.smile_hostname = gateway.find("hostname").text
|
190
192
|
self.smile_mac_address = gateway.find("mac_address").text
|
@@ -200,7 +202,7 @@ class Smile(SmileComm):
|
|
200
202
|
)
|
201
203
|
raise UnsupportedDeviceError
|
202
204
|
|
203
|
-
version_major
|
205
|
+
version_major= str(self.smile_fw_version.major)
|
204
206
|
self._target_smile = f"{model}_v{version_major}"
|
205
207
|
LOGGER.debug("Plugwise identified as %s", self._target_smile)
|
206
208
|
if self._target_smile not in SMILES:
|
@@ -211,6 +213,9 @@ class Smile(SmileComm):
|
|
211
213
|
)
|
212
214
|
raise UnsupportedDeviceError
|
213
215
|
|
216
|
+
if not self.smile_legacy:
|
217
|
+
self._timeout = DEFAULT_TIMEOUT
|
218
|
+
|
214
219
|
if self._target_smile in ("smile_open_therm_v2", "smile_thermo_v3"):
|
215
220
|
LOGGER.error(
|
216
221
|
"Your Smile identified as %s needs a firmware update as it's firmware is severely outdated",
|
@@ -267,7 +272,7 @@ class Smile(SmileComm):
|
|
267
272
|
or network is not None
|
268
273
|
):
|
269
274
|
system = await self._request(SYSTEM)
|
270
|
-
self.smile_fw_version = system.find("./gateway/firmware").text
|
275
|
+
self.smile_fw_version = parse(system.find("./gateway/firmware").text)
|
271
276
|
return_model = system.find("./gateway/product").text
|
272
277
|
self.smile_hostname = system.find("./gateway/hostname").text
|
273
278
|
# If wlan0 contains data it's active, so eth0 should be checked last
|
@@ -278,7 +283,7 @@ class Smile(SmileComm):
|
|
278
283
|
# P1 legacy:
|
279
284
|
elif dsmrmain is not None:
|
280
285
|
status = await self._request(STATUS)
|
281
|
-
self.smile_fw_version = status.find("./system/version").text
|
286
|
+
self.smile_fw_version = parse(status.find("./system/version").text)
|
282
287
|
return_model = status.find("./system/product").text
|
283
288
|
self.smile_hostname = status.find("./network/hostname").text
|
284
289
|
self.smile_mac_address = status.find("./network/mac_address").text
|
@@ -62,6 +62,7 @@ from dateutil import tz
|
|
62
62
|
from dateutil.parser import parse
|
63
63
|
from defusedxml import ElementTree as etree
|
64
64
|
from munch import Munch
|
65
|
+
from packaging.version import Version
|
65
66
|
|
66
67
|
|
67
68
|
class SmileComm:
|
@@ -99,7 +100,6 @@ class SmileComm:
|
|
99
100
|
|
100
101
|
self._auth = BasicAuth(username, password=password)
|
101
102
|
self._endpoint = f"http://{host}:{str(port)}"
|
102
|
-
self._timeout = timeout
|
103
103
|
|
104
104
|
async def _request(
|
105
105
|
self,
|
@@ -250,7 +250,7 @@ class SmileHelper(SmileCommon):
|
|
250
250
|
self.gw_data: GatewayData = {}
|
251
251
|
self.gw_devices: dict[str, DeviceData] = {}
|
252
252
|
self.loc_data: dict[str, ThermoLoc]
|
253
|
-
self.smile_fw_version:
|
253
|
+
self.smile_fw_version: Version | None
|
254
254
|
self.smile_hw_version: str | None
|
255
255
|
self.smile_mac_address: str | None
|
256
256
|
self.smile_model: str
|
@@ -425,7 +425,7 @@ class SmileHelper(SmileCommon):
|
|
425
425
|
def _appl_gateway_info(self, appl: Munch, appliance: etree) -> Munch:
|
426
426
|
"""Helper-function for _appliance_info_finder()."""
|
427
427
|
self.gateway_id = appliance.attrib["id"]
|
428
|
-
appl.firmware = self.smile_fw_version
|
428
|
+
appl.firmware = str(self.smile_fw_version)
|
429
429
|
appl.hardware = self.smile_hw_version
|
430
430
|
appl.mac = self.smile_mac_address
|
431
431
|
appl.model = self.smile_model
|
@@ -44,6 +44,7 @@ from plugwise.util import (
|
|
44
44
|
# This way of importing aiohttp is because of patch/mocking in testing (aiohttp timeouts)
|
45
45
|
from defusedxml import ElementTree as etree
|
46
46
|
from munch import Munch
|
47
|
+
from packaging.version import Version
|
47
48
|
|
48
49
|
|
49
50
|
def etree_to_dict(element: etree) -> dict[str, str]:
|
@@ -81,7 +82,7 @@ class SmileLegacyHelper(SmileCommon):
|
|
81
82
|
self.gw_data: GatewayData = {}
|
82
83
|
self.gw_devices: dict[str, DeviceData] = {}
|
83
84
|
self.loc_data: dict[str, ThermoLoc]
|
84
|
-
self.smile_fw_version:
|
85
|
+
self.smile_fw_version: Version | None
|
85
86
|
self.smile_hw_version: str | None
|
86
87
|
self.smile_mac_address: str | None
|
87
88
|
self.smile_model: str
|
@@ -194,7 +195,7 @@ class SmileLegacyHelper(SmileCommon):
|
|
194
195
|
self.gw_devices[self.gateway_id] = {"dev_class": "gateway"}
|
195
196
|
self._count += 1
|
196
197
|
for key, value in {
|
197
|
-
"firmware": self.smile_fw_version,
|
198
|
+
"firmware": str(self.smile_fw_version),
|
198
199
|
"location": self._home_location,
|
199
200
|
"mac_address": self.smile_mac_address,
|
200
201
|
"model": self.smile_model,
|
@@ -29,6 +29,7 @@ from plugwise.legacy.data import SmileLegacyData
|
|
29
29
|
|
30
30
|
import aiohttp
|
31
31
|
from munch import Munch
|
32
|
+
from packaging.version import Version
|
32
33
|
|
33
34
|
|
34
35
|
class SmileLegacyAPI(SmileLegacyData):
|
@@ -48,7 +49,7 @@ class SmileLegacyAPI(SmileLegacyData):
|
|
48
49
|
_stretch_v2: bool,
|
49
50
|
_target_smile: str,
|
50
51
|
loc_data: dict[str, ThermoLoc],
|
51
|
-
smile_fw_version:
|
52
|
+
smile_fw_version: Version | None,
|
52
53
|
smile_hostname: str,
|
53
54
|
smile_hw_version: str | None,
|
54
55
|
smile_mac_address: str | None,
|
@@ -35,6 +35,7 @@ from defusedxml import ElementTree as etree
|
|
35
35
|
|
36
36
|
# Dict as class
|
37
37
|
from munch import Munch
|
38
|
+
from packaging.version import Version
|
38
39
|
|
39
40
|
|
40
41
|
class SmileAPI(SmileData):
|
@@ -57,7 +58,7 @@ class SmileAPI(SmileData):
|
|
57
58
|
_schedule_old_states: dict[str, dict[str, str]],
|
58
59
|
gateway_id: str,
|
59
60
|
loc_data: dict[str, ThermoLoc],
|
60
|
-
smile_fw_version:
|
61
|
+
smile_fw_version: Version | None,
|
61
62
|
smile_hostname: str | None,
|
62
63
|
smile_hw_version: str | None,
|
63
64
|
smile_mac_address: str | None,
|
@@ -17,6 +17,7 @@ import pytest
|
|
17
17
|
# Testing
|
18
18
|
import aiohttp
|
19
19
|
from freezegun import freeze_time
|
20
|
+
from packaging import version
|
20
21
|
|
21
22
|
pw_constants = importlib.import_module("plugwise.constants")
|
22
23
|
pw_exceptions = importlib.import_module("plugwise.exceptions")
|
@@ -322,7 +323,6 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
|
|
322
323
|
username=pw_constants.DEFAULT_USERNAME,
|
323
324
|
password=test_password,
|
324
325
|
port=server.port,
|
325
|
-
timeout=pw_constants.DEFAULT_TIMEOUT,
|
326
326
|
websession=None,
|
327
327
|
)
|
328
328
|
lack_of_websession = False
|
@@ -336,23 +336,25 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
|
|
336
336
|
username=pw_constants.DEFAULT_USERNAME,
|
337
337
|
password=test_password,
|
338
338
|
port=server.port,
|
339
|
-
timeout=pw_constants.DEFAULT_TIMEOUT,
|
340
339
|
websession=websession,
|
341
340
|
)
|
342
341
|
|
343
342
|
if not timeout:
|
344
|
-
assert smile._timeout ==
|
343
|
+
assert smile._timeout == 30
|
345
344
|
|
346
345
|
# Connect to the smile
|
346
|
+
version = None
|
347
347
|
try:
|
348
|
-
|
349
|
-
assert
|
348
|
+
version = await smile.connect()
|
349
|
+
assert version is not None
|
350
|
+
assert smile._timeout == 10
|
350
351
|
return server, smile, client
|
351
352
|
except (
|
352
353
|
pw_exceptions.ConnectionFailedError,
|
353
354
|
pw_exceptions.InvalidXMLError,
|
354
355
|
pw_exceptions.InvalidAuthentication,
|
355
356
|
) as exception:
|
357
|
+
assert version is None
|
356
358
|
await self.disconnect(server, client)
|
357
359
|
raise exception
|
358
360
|
|
@@ -405,7 +407,6 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
|
|
405
407
|
username=pw_constants.DEFAULT_USERNAME,
|
406
408
|
password=test_password,
|
407
409
|
port=server.port,
|
408
|
-
timeout=pw_constants.DEFAULT_LEGACY_TIMEOUT,
|
409
410
|
websession=None,
|
410
411
|
)
|
411
412
|
lack_of_websession = False
|
@@ -419,7 +420,6 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
|
|
419
420
|
username=pw_constants.DEFAULT_USERNAME,
|
420
421
|
password=test_password,
|
421
422
|
port=server.port,
|
422
|
-
timeout=pw_constants.DEFAULT_LEGACY_TIMEOUT,
|
423
423
|
websession=websession,
|
424
424
|
)
|
425
425
|
|
@@ -427,15 +427,18 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
|
|
427
427
|
assert smile._timeout == 30
|
428
428
|
|
429
429
|
# Connect to the smile
|
430
|
+
version = None
|
430
431
|
try:
|
431
|
-
|
432
|
-
assert
|
432
|
+
version = await smile.connect()
|
433
|
+
assert version is not None
|
434
|
+
assert smile._timeout == 30
|
433
435
|
return server, smile, client
|
434
436
|
except (
|
435
437
|
pw_exceptions.ConnectionFailedError,
|
436
438
|
pw_exceptions.InvalidXMLError,
|
437
439
|
pw_exceptions.InvalidAuthentication,
|
438
440
|
) as exception:
|
441
|
+
assert version is None
|
439
442
|
await self.disconnect(server, client)
|
440
443
|
raise exception
|
441
444
|
|
@@ -1004,7 +1007,7 @@ class TestPlugwise: # pylint: disable=attribute-defined-outside-init
|
|
1004
1007
|
if smile_version:
|
1005
1008
|
log_msg = f" # Assert version matching '{smile_version}"
|
1006
1009
|
parent_logger.info(log_msg)
|
1007
|
-
assert smile.smile_version == smile_version
|
1010
|
+
assert smile.smile_version == version.parse(smile_version)
|
1008
1011
|
log_msg = f" # Assert legacy {smile_legacy}"
|
1009
1012
|
parent_logger.info(log_msg)
|
1010
1013
|
if smile_legacy:
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|