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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: python-bsblan
3
- Version: 0.5.17
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.17"
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.1.0"
39
- aresponses = "^2.1.6"
40
- black = "^23.0.0"
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 = "^6.0.0"
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 = "^7.2.1"
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 = "^2.3.4"
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 = ["wled"]
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 BSBLANConnectionError, BSBLANError
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.model_validate(data)
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.model_validate(data)
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.model_validate(data)
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 BSBLANError(VERSION_ERROR_MSG)
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.model_validate(device_info)
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.model_validate(data)
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 BSBLANError(INVALID_VALUES_ERROR_MSG)
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 BSBLANError(INVALID_VALUES_ERROR_MSG)
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 pydantic import BaseModel, Field
2
+ from dataclasses import dataclass, field
3
3
 
4
+ from mashumaro.mixins.json import DataClassJSONMixin
4
5
 
5
- class EntityInfo(BaseModel):
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 = Field(..., alias="name")
17
- unit: str = Field(..., alias="unit")
18
- desc: str = Field(..., alias="desc")
19
- value: str = Field(..., alias="value")
20
- data_type: int = Field(..., alias="dataType")
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
- class State(BaseModel):
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
- class StaticState(BaseModel):
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
- class Sensor(BaseModel):
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
- class Device(BaseModel):
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 = Field(..., alias="name")
89
- version: str = Field(..., alias="version")
90
- MAC: str = Field(..., alias="MAC")
91
- uptime: int = Field(..., alias="uptime")
98
+ name: str
99
+ version: str
100
+ MAC: str # pylint: disable=invalid-name
101
+ uptime: int
92
102
 
93
103
 
94
- class Info(BaseModel):
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