python-bsblan 6.1.11__py3-none-any.whl → 6.2.0__py3-none-any.whl

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.
bsblan/bsblan.py CHANGED
@@ -51,9 +51,10 @@ from .models import (
51
51
  State,
52
52
  StaticState,
53
53
  )
54
- from .utility import is_param_value_active, validate_time_format
54
+ from .utility import is_param_value_active
55
55
 
56
56
  if TYPE_CHECKING:
57
+ from datetime import datetime
57
58
  from typing import Self
58
59
 
59
60
  from aiohttp.client import ClientSession
@@ -862,24 +863,31 @@ class BSBLAN:
862
863
  time_data = {"time": data["0"]}
863
864
  return DeviceTime.model_validate(time_data)
864
865
 
865
- async def set_time(self, time_value: str) -> None:
866
+ async def set_time(self, value: datetime) -> None:
866
867
  """Set the time on the BSB-LAN device.
867
868
 
868
869
  Args:
869
- time_value (str): The time value to set in format "DD.MM.YYYY HH:MM:SS"
870
- (e.g., "13.08.2025 10:25:55").
870
+ value (datetime): The local time of the heating system. Its date and
871
+ time are written as they are, without timezone conversion.
871
872
 
872
873
  Raises:
873
- BSBLANInvalidParameterError: If the time format is invalid.
874
+ BSBLANInvalidParameterError: If the year is out of range.
875
+ BSBLANError: If the device does not accept the new time.
874
876
 
875
877
  """
876
878
  await self._ensure_device_metadata()
877
879
  self._validate_time_sync_supported()
878
- self._validate_time_format(time_value)
880
+ if not Validation.MIN_YEAR <= value.year <= Validation.MAX_YEAR:
881
+ msg = f"Invalid year: {value.year}"
882
+ raise BSBLANInvalidParameterError(msg)
883
+ # BSB-LAN 4.1 rejects a space between the date and the time
879
884
  response = await self._request(
880
- base_path="/JS", data=self._set_payload("0", time_value)
885
+ base_path="/JS",
886
+ data=self._set_payload("0", value.strftime("%d.%m.%Y_%H:%M:%S")),
881
887
  )
882
888
  logger.debug("Response for setting time: %s", response)
889
+ if response.get("0", {}).get("status") != 1:
890
+ raise BSBLANError(ErrorMsg.TIME_SYNC_FAILED)
883
891
 
884
892
  async def thermostat( # noqa: PLR0913 # pylint: disable=too-many-arguments
885
893
  self,
@@ -992,21 +1000,6 @@ class BSBLAN:
992
1000
  circuit,
993
1001
  )
994
1002
 
995
- def _validate_time_format(self, time_value: str) -> None:
996
- """Validate the time format.
997
-
998
- Args:
999
- time_value (str): The time value to validate.
1000
-
1001
- Raises:
1002
- BSBLANInvalidParameterError: If the time format is invalid.
1003
-
1004
- """
1005
- try:
1006
- validate_time_format(time_value, Validation.MIN_YEAR, Validation.MAX_YEAR)
1007
- except ValueError as err:
1008
- raise BSBLANInvalidParameterError(str(err)) from err
1009
-
1010
1003
  def _set_payload(
1011
1004
  self, parameter: str, value: str, type_: str = "1"
1012
1005
  ) -> dict[str, Any]:
bsblan/constants.py CHANGED
@@ -561,6 +561,7 @@ class ErrorMsg:
561
561
  )
562
562
  NO_HEATING_SCHEDULE_PARAMS = "No heating schedule parameters available"
563
563
  TIME_SYNC_NOT_SUPPORTED = "Time synchronization is not supported by this device"
564
+ TIME_SYNC_FAILED = "The device did not accept the new time"
564
565
  BUS_WRITE_NOT_SUPPORTED = "Writing parameters is not supported by this device"
565
566
 
566
567
 
bsblan/utility.py CHANGED
@@ -3,7 +3,6 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import logging
6
- import re
7
6
  from dataclasses import dataclass, field
8
7
  from typing import Any
9
8
 
@@ -12,65 +11,6 @@ from .constants import CircuitConfig
12
11
  logger = logging.getLogger(__name__)
13
12
 
14
13
 
15
- def validate_time_format(
16
- time_value: str,
17
- min_year: int,
18
- max_year: int,
19
- ) -> None:
20
- """Validate the BSB-LAN time format.
21
-
22
- Args:
23
- time_value: The time value to validate in format DD.MM.YYYY HH:MM:SS.
24
- min_year: Minimum valid year.
25
- max_year: Maximum valid year.
26
-
27
- Raises:
28
- ValueError: If the time format is invalid.
29
-
30
- """
31
- # BSB-LAN supports format: DD.MM.YYYY HH:MM:SS (e.g., "13.08.2025 10:25:55")
32
- pattern = r"^(\d{2})\.(\d{2})\.(\d{4}) (\d{2}):(\d{2}):(\d{2})$"
33
-
34
- match = re.match(pattern, time_value)
35
- if not match:
36
- msg = f"Invalid time format: {time_value}. Expected DD.MM.YYYY HH:MM:SS"
37
- raise ValueError(msg)
38
-
39
- day, month, year, hour, minute, second = map(int, match.groups())
40
-
41
- # Validate ranges
42
- if not (1 <= day <= 31):
43
- msg = f"Invalid day: {day}"
44
- raise ValueError(msg)
45
- if not (1 <= month <= 12):
46
- msg = f"Invalid month: {month}"
47
- raise ValueError(msg)
48
- if not (min_year <= year <= max_year):
49
- msg = f"Invalid year: {year}"
50
- raise ValueError(msg)
51
- if not (0 <= hour <= 23):
52
- msg = f"Invalid hour: {hour}"
53
- raise ValueError(msg)
54
- if not (0 <= minute <= 59):
55
- msg = f"Invalid minute: {minute}"
56
- raise ValueError(msg)
57
- if not (0 <= second <= 59):
58
- msg = f"Invalid second: {second}"
59
- raise ValueError(msg)
60
-
61
- # Additional validation for days per month
62
- if month in (4, 6, 9, 11) and day > 30:
63
- msg = f"Invalid day {day} for month {month}"
64
- raise ValueError(msg)
65
- if month == 2:
66
- # Leap year check
67
- is_leap = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)
68
- max_day = 29 if is_leap else 28
69
- if day > max_day:
70
- msg = f"Invalid day {day} for February in year {year}"
71
- raise ValueError(msg)
72
-
73
-
74
14
  def is_param_value_active(param: dict[str, Any] | None) -> bool:
75
15
  """Check whether a parameter payload carries an active value.
76
16
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: python-bsblan
3
- Version: 6.1.11
3
+ Version: 6.2.0
4
4
  Summary: Asynchronous Python client for BSBLAN API
5
5
  Project-URL: Homepage, https://github.com/liudger/python-bsblan
6
6
  Project-URL: Repository, https://github.com/liudger/python-bsblan
@@ -7,13 +7,13 @@ bsblan/_thermostat.py,sha256=Yl-AM4gJikwSQwcpYH7fHH6I1lEVggnendf28-d0IAE,6520
7
7
  bsblan/_transport.py,sha256=qNtV_8uJrfYfHlbaExPln4jCaJxqE5sypq5OHyxG8KE,8266
8
8
  bsblan/_validation.py,sha256=w93Hg5sqeJKXOozwWV4Hjh7_aR197tOpHn6LgxL1Pek,17836
9
9
  bsblan/_version.py,sha256=hpeIg9JUswHSorY3iSUERcMC1MzwM9Rpdo1wqeh5rc8,2799
10
- bsblan/bsblan.py,sha256=hyjd2xmK5TjvKzWHf765WEMs3hgTKxpTYu6QTgPewrE,49016
11
- bsblan/constants.py,sha256=rAiiwy-r9FhR1b118q80O07xeFvBjWqyRBdEj8DUcdM,26309
10
+ bsblan/bsblan.py,sha256=XOzwrThvxT6NQcaKz7BKdpeZPkZRBbgnXd8plcrU-X4,48987
11
+ bsblan/constants.py,sha256=xcL43NpsyrJ6NRJHO2x2iH9J97Dq6DsVsFn-CzpBxoo,26373
12
12
  bsblan/exceptions.py,sha256=Z9pXtVc8zhy9FTBkT8leJ1UE9zdOdLHF7pE7C4GjBmg,2795
13
13
  bsblan/models.py,sha256=UJbCoVr7_ohtKG5n_jSzoYDzBpl9y4OWj3bqGYRvf_0,23111
14
14
  bsblan/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
15
- bsblan/utility.py,sha256=5oD3f84ke_r7pTQN2jjhhgtVjLjq1Ohld3LlHN7m8xg,7421
16
- python_bsblan-6.1.11.dist-info/METADATA,sha256=zgvdwNLgAk8W5AKXXa9lDMrAFI0YTiVQ_gvo65nJGp4,9586
17
- python_bsblan-6.1.11.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
18
- python_bsblan-6.1.11.dist-info/licenses/LICENSE.md,sha256=Shv8HPcD1WbZjBPvfb5r3h_cwaPeVaUZMUqU_XQGwGw,1092
19
- python_bsblan-6.1.11.dist-info/RECORD,,
15
+ bsblan/utility.py,sha256=V5OjZieC6NpQHMKdfrUMJkjSrbrMvpnT7A5k5bQnmgM,5543
16
+ python_bsblan-6.2.0.dist-info/METADATA,sha256=DyrUwQh3bu9ueQKDpOkBipZzpIIAPo1OG-q0bn2ZFt8,9585
17
+ python_bsblan-6.2.0.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
18
+ python_bsblan-6.2.0.dist-info/licenses/LICENSE.md,sha256=Shv8HPcD1WbZjBPvfb5r3h_cwaPeVaUZMUqU_XQGwGw,1092
19
+ python_bsblan-6.2.0.dist-info/RECORD,,