python-bsblan 0.5.17__tar.gz → 0.5.19__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.
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/PKG-INFO +2 -2
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/pyproject.toml +13 -13
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/src/bsblan/bsblan.py +27 -9
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/src/bsblan/exceptions.py +28 -0
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/src/bsblan/models.py +28 -16
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/README.md +0 -0
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/src/bsblan/__init__.py +0 -0
- {python_bsblan-0.5.17 → python_bsblan-0.5.19}/src/bsblan/constants.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: python-bsblan
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.19
|
|
4
4
|
Summary: Asynchronous Python client for BSBLAN
|
|
5
5
|
Home-page: https://github.com/liudger/python-bsblan
|
|
6
6
|
License: MIT
|
|
@@ -23,8 +23,8 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
|
23
23
|
Requires-Dist: aiohttp (>=3.8.1)
|
|
24
24
|
Requires-Dist: async-timeout (>=4.0.3,<5.0.0)
|
|
25
25
|
Requires-Dist: backoff (>=2.2.1,<3.0.0)
|
|
26
|
+
Requires-Dist: mashumaro (>=3.13.1,<4.0.0)
|
|
26
27
|
Requires-Dist: packaging (>=21.3)
|
|
27
|
-
Requires-Dist: pydantic (>=1.9.0)
|
|
28
28
|
Requires-Dist: yarl (>=1.7.2)
|
|
29
29
|
Project-URL: Bug Tracker, https://github.com/liudger/python-bsblan/issues
|
|
30
30
|
Project-URL: Changelog, https://github.com/liudger/python-bsblan/releases
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "python-bsblan"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.19"
|
|
4
4
|
description = "Asynchronous Python client for BSBLAN"
|
|
5
5
|
authors = ["Willem-Jan van Rootselaar <liudgervr@gmail.com>"]
|
|
6
6
|
maintainers = ["Willem-Jan van Rootselaar <liudgervr@gmail.com>"]
|
|
@@ -28,25 +28,25 @@ packages = [
|
|
|
28
28
|
python = "^3.10"
|
|
29
29
|
aiohttp = ">=3.8.1"
|
|
30
30
|
yarl = ">=1.7.2"
|
|
31
|
-
pydantic = ">=1.9.0"
|
|
32
31
|
packaging = ">=21.3"
|
|
33
32
|
backoff = "^2.2.1"
|
|
34
33
|
async-timeout = "^4.0.3"
|
|
34
|
+
mashumaro = "^3.13.1"
|
|
35
35
|
|
|
36
36
|
[tool.poetry.dev-dependencies]
|
|
37
37
|
covdefaults = "^2.3.0"
|
|
38
|
-
ruff = "^0.
|
|
39
|
-
aresponses = "^
|
|
40
|
-
black = "^
|
|
38
|
+
ruff = "^0.5.0"
|
|
39
|
+
aresponses = "^3.0.0"
|
|
40
|
+
black = "^24.0.0"
|
|
41
41
|
blacken-docs = "^1.13.0"
|
|
42
42
|
coverage = "^7.0.5"
|
|
43
|
-
flake8 = "^
|
|
43
|
+
flake8 = "^7.0.0"
|
|
44
44
|
isort = "^5.11.4"
|
|
45
45
|
mypy = "^1.0.0"
|
|
46
46
|
pre-commit = "^3.0.0"
|
|
47
47
|
pre-commit-hooks = "^4.3.0"
|
|
48
48
|
pylint = "^3.0.0"
|
|
49
|
-
pytest = "^
|
|
49
|
+
pytest = "^8.0.0"
|
|
50
50
|
pytest-asyncio = "^0.23.0"
|
|
51
51
|
pytest-cov = "^4.0.0"
|
|
52
52
|
yamllint = "^1.29.0"
|
|
@@ -54,7 +54,7 @@ pyupgrade = "^3.3.1"
|
|
|
54
54
|
flake8-simplify = "^0.21.0"
|
|
55
55
|
vulture = "^2.7"
|
|
56
56
|
darglint = "^1.8.1"
|
|
57
|
-
safety = "^
|
|
57
|
+
safety = "^3.0.0"
|
|
58
58
|
codespell = "^2.2.2"
|
|
59
59
|
bandit = "^1.7.4"
|
|
60
60
|
pytest-mock = "^3.10.0"
|
|
@@ -150,7 +150,7 @@ max-line-length=88
|
|
|
150
150
|
addopts = "--cov"
|
|
151
151
|
asyncio_mode = "auto"
|
|
152
152
|
|
|
153
|
-
[tool.ruff]
|
|
153
|
+
[tool.ruff.lint]
|
|
154
154
|
select = ["ALL"]
|
|
155
155
|
ignore = [
|
|
156
156
|
"ANN101", # Self... explanatory
|
|
@@ -161,14 +161,14 @@ ignore = [
|
|
|
161
161
|
"PLR2004", # Just annoying, not really useful
|
|
162
162
|
]
|
|
163
163
|
|
|
164
|
-
[tool.ruff.flake8-pytest-style]
|
|
164
|
+
[tool.ruff.lint.flake8-pytest-style]
|
|
165
165
|
mark-parentheses = false
|
|
166
166
|
fixture-parentheses = false
|
|
167
167
|
|
|
168
|
-
[tool.ruff.isort]
|
|
169
|
-
known-first-party = ["
|
|
168
|
+
[tool.ruff.lint.isort]
|
|
169
|
+
known-first-party = ["bsblan"]
|
|
170
170
|
|
|
171
|
-
[tool.ruff.mccabe]
|
|
171
|
+
[tool.ruff.lint.mccabe]
|
|
172
172
|
max-complexity = 25
|
|
173
173
|
|
|
174
174
|
[build-system]
|
|
@@ -33,7 +33,12 @@ from .constants import (
|
|
|
33
33
|
STATIC_VALUES_API_V3,
|
|
34
34
|
VERSION_ERROR_MSG,
|
|
35
35
|
)
|
|
36
|
-
from .exceptions import
|
|
36
|
+
from .exceptions import (
|
|
37
|
+
BSBLANConnectionError,
|
|
38
|
+
BSBLANError,
|
|
39
|
+
BSBLANInvalidParameterError,
|
|
40
|
+
BSBLANVersionError,
|
|
41
|
+
)
|
|
37
42
|
from .models import Device, Info, Sensor, State, StaticState
|
|
38
43
|
|
|
39
44
|
logging.basicConfig(level=logging.DEBUG)
|
|
@@ -97,6 +102,7 @@ class BSBLAN:
|
|
|
97
102
|
fails.
|
|
98
103
|
BSBLANError: If receiving from the BSBLAN device an unexpected
|
|
99
104
|
response.
|
|
105
|
+
|
|
100
106
|
"""
|
|
101
107
|
try:
|
|
102
108
|
version = metadata.version(__package__ or __name__)
|
|
@@ -159,6 +165,7 @@ class BSBLAN:
|
|
|
159
165
|
Returns
|
|
160
166
|
-------
|
|
161
167
|
A BSBLAN state object.
|
|
168
|
+
|
|
162
169
|
"""
|
|
163
170
|
if not self._string_circuit1 or not self._heating_params:
|
|
164
171
|
# retrieve heating circuit 1
|
|
@@ -174,7 +181,7 @@ class BSBLAN:
|
|
|
174
181
|
|
|
175
182
|
# set hvac_mode with correct value
|
|
176
183
|
data["hvac_mode"]["value"] = HVAC_MODE_DICT[int(data["hvac_mode"]["value"])]
|
|
177
|
-
return State.
|
|
184
|
+
return State.from_dict(data)
|
|
178
185
|
|
|
179
186
|
async def sensor(self) -> Sensor:
|
|
180
187
|
"""Get the sensor information from BSBLAN device.
|
|
@@ -182,6 +189,7 @@ class BSBLAN:
|
|
|
182
189
|
Returns
|
|
183
190
|
-------
|
|
184
191
|
A BSBLAN sensor object.
|
|
192
|
+
|
|
185
193
|
"""
|
|
186
194
|
if not self._sensor_params:
|
|
187
195
|
data = await self._get_dict_version()
|
|
@@ -192,7 +200,7 @@ class BSBLAN:
|
|
|
192
200
|
# retrieve sensor params so we can build the data structure
|
|
193
201
|
data = await self._request(params={"Parameter": f"{self._sensor_list}"})
|
|
194
202
|
data = dict(zip(self._sensor_params, list(data.values()), strict=True))
|
|
195
|
-
return Sensor.
|
|
203
|
+
return Sensor.from_dict(data)
|
|
196
204
|
|
|
197
205
|
async def static_values(self) -> StaticState:
|
|
198
206
|
"""Get the static information from BSBLAN device.
|
|
@@ -200,6 +208,7 @@ class BSBLAN:
|
|
|
200
208
|
Returns
|
|
201
209
|
-------
|
|
202
210
|
A BSBLAN staticState object.
|
|
211
|
+
|
|
203
212
|
"""
|
|
204
213
|
if not self._static_params:
|
|
205
214
|
data = await self._get_dict_version()
|
|
@@ -212,7 +221,7 @@ class BSBLAN:
|
|
|
212
221
|
data = dict(zip(self._static_params, list(data.values()), strict=True))
|
|
213
222
|
self._min_temp = data["min_temp"]["value"]
|
|
214
223
|
self._max_temp = data["max_temp"]["value"]
|
|
215
|
-
return StaticState.
|
|
224
|
+
return StaticState.from_dict(data)
|
|
216
225
|
|
|
217
226
|
async def _get_dict_version(self) -> dict[Any, Any]:
|
|
218
227
|
"""Get the version from device.
|
|
@@ -240,7 +249,7 @@ class BSBLAN:
|
|
|
240
249
|
"device": DEVICE_INFO_API_V3,
|
|
241
250
|
"sensor": SENSORS_API_V3,
|
|
242
251
|
}
|
|
243
|
-
raise
|
|
252
|
+
raise BSBLANVersionError(VERSION_ERROR_MSG)
|
|
244
253
|
|
|
245
254
|
async def device(self) -> Device:
|
|
246
255
|
"""Get BSBLAN device info.
|
|
@@ -251,7 +260,7 @@ class BSBLAN:
|
|
|
251
260
|
|
|
252
261
|
"""
|
|
253
262
|
device_info = await self._request(base_path="/JI")
|
|
254
|
-
return Device.
|
|
263
|
+
return Device.from_dict(device_info)
|
|
255
264
|
|
|
256
265
|
async def info(self) -> Info:
|
|
257
266
|
"""Get information about the current heating system config.
|
|
@@ -259,6 +268,7 @@ class BSBLAN:
|
|
|
259
268
|
Returns
|
|
260
269
|
-------
|
|
261
270
|
A BSBLAN info object about the heating system.
|
|
271
|
+
|
|
262
272
|
"""
|
|
263
273
|
if not self._info or not self._device_params:
|
|
264
274
|
device_dict = await self._get_dict_version()
|
|
@@ -268,7 +278,7 @@ class BSBLAN:
|
|
|
268
278
|
|
|
269
279
|
data = await self._request(params={"Parameter": f"{self._info}"})
|
|
270
280
|
data = dict(zip(self._device_params, list(data.values()), strict=True))
|
|
271
|
-
return Info.
|
|
281
|
+
return Info.from_dict(data)
|
|
272
282
|
|
|
273
283
|
async def _get_parameters(self, params: dict[Any, Any]) -> dict[Any, Any]:
|
|
274
284
|
"""Get the parameters info from BSBLAN device.
|
|
@@ -280,6 +290,7 @@ class BSBLAN:
|
|
|
280
290
|
Returns:
|
|
281
291
|
-------
|
|
282
292
|
A dict of 2 objects [str, list].
|
|
293
|
+
|
|
283
294
|
"""
|
|
284
295
|
_string_params = [*params]
|
|
285
296
|
list_params = list(params.values())
|
|
@@ -303,6 +314,7 @@ class BSBLAN:
|
|
|
303
314
|
Raises:
|
|
304
315
|
------
|
|
305
316
|
BSBLANError: The provided values are invalid.
|
|
317
|
+
|
|
306
318
|
"""
|
|
307
319
|
|
|
308
320
|
class ThermostatState( # lgtm [py/unused-local-variable]
|
|
@@ -326,14 +338,18 @@ class BSBLAN:
|
|
|
326
338
|
<= float(target_temperature)
|
|
327
339
|
<= float(self._max_temp)
|
|
328
340
|
):
|
|
329
|
-
raise
|
|
341
|
+
raise BSBLANInvalidParameterError(
|
|
342
|
+
INVALID_VALUES_ERROR_MSG + ": " + str(target_temperature),
|
|
343
|
+
)
|
|
330
344
|
state["Parameter"] = "710"
|
|
331
345
|
state["Value"] = target_temperature
|
|
332
346
|
state["Type"] = "1"
|
|
333
347
|
|
|
334
348
|
if hvac_mode is not None:
|
|
335
349
|
if hvac_mode not in HVAC_MODE_DICT_REVERSE:
|
|
336
|
-
raise
|
|
350
|
+
raise BSBLANInvalidParameterError(
|
|
351
|
+
INVALID_VALUES_ERROR_MSG + ": " + str(hvac_mode),
|
|
352
|
+
)
|
|
337
353
|
state["Parameter"] = "700"
|
|
338
354
|
state["EnumValue"] = HVAC_MODE_DICT_REVERSE[hvac_mode]
|
|
339
355
|
state["Type"] = "1"
|
|
@@ -357,6 +373,7 @@ class BSBLAN:
|
|
|
357
373
|
Returns
|
|
358
374
|
-------
|
|
359
375
|
The BSBLAN object.
|
|
376
|
+
|
|
360
377
|
"""
|
|
361
378
|
logger.debug("BSBLAN: %s", self)
|
|
362
379
|
return self
|
|
@@ -367,5 +384,6 @@ class BSBLAN:
|
|
|
367
384
|
Args:
|
|
368
385
|
----
|
|
369
386
|
*_exc_info: Exec type.
|
|
387
|
+
|
|
370
388
|
"""
|
|
371
389
|
await self.close()
|
|
@@ -17,6 +17,7 @@ class BSBLANError(Exception):
|
|
|
17
17
|
Returns:
|
|
18
18
|
-------
|
|
19
19
|
None.
|
|
20
|
+
|
|
20
21
|
"""
|
|
21
22
|
if message is not None:
|
|
22
23
|
self.message = message
|
|
@@ -29,6 +30,7 @@ class BSBLANConnectionError(BSBLANError):
|
|
|
29
30
|
Attributes
|
|
30
31
|
----------
|
|
31
32
|
response: The response received from the BSBLAN device.
|
|
33
|
+
|
|
32
34
|
"""
|
|
33
35
|
|
|
34
36
|
message = "Error occurred while connecting to BSBLAN device."
|
|
@@ -43,6 +45,32 @@ class BSBLANConnectionError(BSBLANError):
|
|
|
43
45
|
Returns:
|
|
44
46
|
-------
|
|
45
47
|
None.
|
|
48
|
+
|
|
46
49
|
"""
|
|
47
50
|
self.response = response
|
|
48
51
|
super().__init__(self.message)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class BSBLANVersionError(BSBLANError):
|
|
55
|
+
"""Raised when the BSBLAN device has an unsupported version."""
|
|
56
|
+
|
|
57
|
+
message = "The BSBLAN device has an unsupported version."
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class BSBLANInvalidParameterError(BSBLANError):
|
|
61
|
+
"""Raised when an invalid parameter is provided."""
|
|
62
|
+
|
|
63
|
+
def __init__(self, parameter: str) -> None:
|
|
64
|
+
"""Initialize a new instance of the BSBLANInvalidParameterError class.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
----
|
|
68
|
+
parameter: The invalid parameter.
|
|
69
|
+
|
|
70
|
+
Returns:
|
|
71
|
+
-------
|
|
72
|
+
None.
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
self.message = f"Invalid parameter: {parameter}"
|
|
76
|
+
super().__init__(self.message)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"""Models for BSB-Lan."""
|
|
2
|
-
from
|
|
2
|
+
from dataclasses import dataclass, field
|
|
3
3
|
|
|
4
|
+
from mashumaro.mixins.json import DataClassJSONMixin
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
@dataclass
|
|
8
|
+
class EntityInfo(DataClassJSONMixin):
|
|
6
9
|
"""Convert Data to valid keys and convert to object attributes.
|
|
7
10
|
|
|
8
11
|
This object holds info about specific objects.
|
|
@@ -11,13 +14,14 @@ class EntityInfo(BaseModel):
|
|
|
11
14
|
----------
|
|
12
15
|
name: Name attribute.
|
|
13
16
|
value: value of attribute.
|
|
17
|
+
|
|
14
18
|
"""
|
|
15
19
|
|
|
16
|
-
name: str =
|
|
17
|
-
unit: str =
|
|
18
|
-
desc: str =
|
|
19
|
-
value: str =
|
|
20
|
-
data_type: int =
|
|
20
|
+
name: str = field(metadata={"alias": "name"})
|
|
21
|
+
unit: str = field(metadata={"alias": "unit"})
|
|
22
|
+
desc: str = field(metadata={"alias": "desc"})
|
|
23
|
+
value: str = field(metadata={"alias": "value"})
|
|
24
|
+
data_type: int = field(metadata={"alias": "dataType"})
|
|
21
25
|
|
|
22
26
|
"""
|
|
23
27
|
"DataType" (
|
|
@@ -34,7 +38,8 @@ class EntityInfo(BaseModel):
|
|
|
34
38
|
"""
|
|
35
39
|
|
|
36
40
|
|
|
37
|
-
|
|
41
|
+
@dataclass
|
|
42
|
+
class State(DataClassJSONMixin):
|
|
38
43
|
"""Object that holds information about the state of a climate system.
|
|
39
44
|
|
|
40
45
|
Attributes
|
|
@@ -51,6 +56,7 @@ class State(BaseModel):
|
|
|
51
56
|
The current temperature of the climate system.
|
|
52
57
|
room1_thermostat_mode : EntityInfo
|
|
53
58
|
The thermostat mode of the climate system.
|
|
59
|
+
|
|
54
60
|
"""
|
|
55
61
|
|
|
56
62
|
hvac_mode: EntityInfo
|
|
@@ -61,21 +67,24 @@ class State(BaseModel):
|
|
|
61
67
|
room1_thermostat_mode: EntityInfo
|
|
62
68
|
|
|
63
69
|
|
|
64
|
-
|
|
70
|
+
@dataclass
|
|
71
|
+
class StaticState(DataClassJSONMixin):
|
|
65
72
|
"""Class for entities that are not changing."""
|
|
66
73
|
|
|
67
74
|
min_temp: EntityInfo
|
|
68
75
|
max_temp: EntityInfo
|
|
69
76
|
|
|
70
77
|
|
|
71
|
-
|
|
78
|
+
@dataclass
|
|
79
|
+
class Sensor(DataClassJSONMixin):
|
|
72
80
|
"""Object holds info about object for sensor climate."""
|
|
73
81
|
|
|
74
82
|
current_temperature: EntityInfo
|
|
75
83
|
outside_temperature: EntityInfo
|
|
76
84
|
|
|
77
85
|
|
|
78
|
-
|
|
86
|
+
@dataclass
|
|
87
|
+
class Device(DataClassJSONMixin):
|
|
79
88
|
"""Object holds bsblan device information.
|
|
80
89
|
|
|
81
90
|
Attributes
|
|
@@ -83,21 +92,24 @@ class Device(BaseModel):
|
|
|
83
92
|
name: Name of the device.
|
|
84
93
|
version: Firmware version of the device.
|
|
85
94
|
MAC: MAC address of the device.
|
|
95
|
+
|
|
86
96
|
"""
|
|
87
97
|
|
|
88
|
-
name: str
|
|
89
|
-
version: str
|
|
90
|
-
MAC: str
|
|
91
|
-
uptime: int
|
|
98
|
+
name: str
|
|
99
|
+
version: str
|
|
100
|
+
MAC: str # pylint: disable=invalid-name
|
|
101
|
+
uptime: int
|
|
92
102
|
|
|
93
103
|
|
|
94
|
-
|
|
104
|
+
@dataclass
|
|
105
|
+
class Info(DataClassJSONMixin):
|
|
95
106
|
"""Object holding the heatingSystem info.
|
|
96
107
|
|
|
97
108
|
Attributes
|
|
98
109
|
----------
|
|
99
110
|
name: Name of the sub-device.
|
|
100
111
|
value: type of device.
|
|
112
|
+
|
|
101
113
|
"""
|
|
102
114
|
|
|
103
115
|
device_identification: EntityInfo
|
|
File without changes
|
|
File without changes
|
|
File without changes
|