python-bsblan 6.1.0__tar.gz → 6.1.1__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.
Files changed (127) hide show
  1. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/PKG-INFO +1 -1
  2. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/examples/control.py +23 -3
  3. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/pyproject.toml +1 -1
  4. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/bsblan.py +33 -4
  5. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/constants.py +4 -4
  6. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/models.py +7 -0
  7. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/dict_version.json +2 -2
  8. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_circuit.py +8 -8
  9. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_constants.py +4 -4
  10. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_include_parameter.py +5 -2
  11. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_static_state.py +5 -4
  12. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_temperature_validation.py +6 -1
  13. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_utility_additional.py +2 -2
  14. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.editorconfig +0 -0
  15. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.gitattributes +0 -0
  16. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/CODE_OF_CONDUCT.md +0 -0
  17. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/CONTRIBUTING.md +0 -0
  18. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/ISSUE_TEMPLATE/PULL_REQUEST_TEMPLATE.md +0 -0
  19. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  20. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  21. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/SECURITY.md +0 -0
  22. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/agents/security-reviewer.agent.md +0 -0
  23. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/copilot-instructions.md +0 -0
  24. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/hooks/run-validation-after-edits.json +0 -0
  25. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/hooks/run_validation_after_edits.sh +0 -0
  26. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/labels.yml +0 -0
  27. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/prompts/add-parameter.prompt.md +0 -0
  28. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/prompts/code-review.prompt.md +0 -0
  29. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/release-drafter.yml +0 -0
  30. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/renovate.json +0 -0
  31. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/skills/bsblan-parameters/SKILL.md +0 -0
  32. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/skills/bsblan-testing/SKILL.md +0 -0
  33. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/skills/feature-doc-updates/SKILL.md +0 -0
  34. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/auto-approve-renovate.yml +0 -0
  35. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/codeql.yaml +0 -0
  36. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/dependency-review.yaml +0 -0
  37. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/docs.yaml +0 -0
  38. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/labels.yaml +0 -0
  39. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/linting.yaml +0 -0
  40. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/lock.yaml +0 -0
  41. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/pr-labels.yaml +0 -0
  42. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/release-drafter.yaml +0 -0
  43. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/release.yaml +0 -0
  44. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/scorecard.yml +0 -0
  45. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/stale.yaml +0 -0
  46. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/tests.yaml +0 -0
  47. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/workflows/typing.yaml +0 -0
  48. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.github/zizmor.yml +0 -0
  49. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.gitignore +0 -0
  50. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.nvmrc +0 -0
  51. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.pre-commit-config.yaml +0 -0
  52. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.prettierignore +0 -0
  53. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/.yamllint +0 -0
  54. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/AGENTS.md +0 -0
  55. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/CLAUDE.md +0 -0
  56. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/LICENSE.md +0 -0
  57. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/Makefile +0 -0
  58. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/README.md +0 -0
  59. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/docs/api/client.md +0 -0
  60. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/docs/api/constants.md +0 -0
  61. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/docs/api/exceptions.md +0 -0
  62. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/docs/api/models.md +0 -0
  63. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/docs/getting-started.md +0 -0
  64. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/docs/index.md +0 -0
  65. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/examples/discovery.py +0 -0
  66. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/examples/fetch_param.py +0 -0
  67. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/examples/profile_init.py +0 -0
  68. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/examples/ruff.toml +0 -0
  69. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/examples/speed_test.py +0 -0
  70. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/mkdocs.yml +0 -0
  71. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/package-lock.json +0 -0
  72. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/package.json +0 -0
  73. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/sonar-project.properties +0 -0
  74. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/__init__.py +0 -0
  75. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/exceptions.py +0 -0
  76. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/py.typed +0 -0
  77. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/src/bsblan/utility.py +0 -0
  78. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/__init__.py +0 -0
  79. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/conftest.py +0 -0
  80. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/device.json +0 -0
  81. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/hot_water_state.json +0 -0
  82. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/info.json +0 -0
  83. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/password.txt +0 -0
  84. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/pps_device.json +0 -0
  85. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/pps_state.json +0 -0
  86. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/pps_static_values.json +0 -0
  87. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/sensor.json +0 -0
  88. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/state.json +0 -0
  89. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/state_circuit2.json +0 -0
  90. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/static_state.json +0 -0
  91. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/static_state_circuit2.json +0 -0
  92. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/thermostat_hvac.json +0 -0
  93. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/thermostat_temp.json +0 -0
  94. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/fixtures/time.json +0 -0
  95. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/ruff.toml +0 -0
  96. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_api_initialization.py +0 -0
  97. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_api_validation.py +0 -0
  98. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_auth.py +0 -0
  99. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_backoff_retry.py +0 -0
  100. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_bsblan.py +0 -0
  101. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_bsblan_edge_cases.py +0 -0
  102. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_configuration.py +0 -0
  103. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_context_manager.py +0 -0
  104. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_device.py +0 -0
  105. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_dhw_time_switch.py +0 -0
  106. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_entity_info.py +0 -0
  107. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_entity_info_ha.py +0 -0
  108. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_heating_schedule.py +0 -0
  109. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_hot_water_additional.py +0 -0
  110. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_hotwater_state.py +0 -0
  111. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_info.py +0 -0
  112. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_initialization.py +0 -0
  113. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_pps.py +0 -0
  114. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_read_parameters.py +0 -0
  115. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_reset_validation.py +0 -0
  116. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_schedule_models.py +0 -0
  117. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_sensor.py +0 -0
  118. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_set_heating_schedule.py +0 -0
  119. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_set_hot_water_schedule.py +0 -0
  120. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_set_hotwater.py +0 -0
  121. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_state.py +0 -0
  122. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_temperature_unit.py +0 -0
  123. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_thermostat.py +0 -0
  124. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_time.py +0 -0
  125. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_utility.py +0 -0
  126. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_utility_edge_cases.py +0 -0
  127. {python_bsblan-6.1.0 → python_bsblan-6.1.1}/tests/test_version_errors.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-bsblan
3
- Version: 6.1.0
3
+ Version: 6.1.1
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
@@ -192,6 +192,22 @@ def print_device_info(device: Device, info: Info) -> None:
192
192
  print_attributes("Device Information", attributes)
193
193
 
194
194
 
195
+ def _first_temperature_attribute(static_state: StaticState) -> Any:
196
+ """Return the first available temperature attribute for unit detection."""
197
+ for attribute in (
198
+ static_state.heating_protective_setpoint,
199
+ static_state.temp_reduced_setpoint,
200
+ static_state.comfort_setpoint_max,
201
+ static_state.min_temp,
202
+ static_state.max_temp,
203
+ static_state.cooling_comfort_setpoint_min,
204
+ static_state.cooling_reduced_setpoint,
205
+ ):
206
+ if attribute is not None:
207
+ return attribute
208
+ return None
209
+
210
+
195
211
  def print_static_state(static_state: StaticState) -> None:
196
212
  """Print static state information, including heating and cooling bounds.
197
213
 
@@ -200,8 +216,10 @@ def print_static_state(static_state: StaticState) -> None:
200
216
 
201
217
  """
202
218
  attributes = {
203
- "Min Temperature (heating)": get_attribute(static_state.min_temp),
204
- "Max Temperature (heating)": get_attribute(static_state.max_temp),
219
+ "Reduced Setpoint (eco/night)": get_attribute(
220
+ static_state.temp_reduced_setpoint
221
+ ),
222
+ "Comfort Setpoint Max": get_attribute(static_state.comfort_setpoint_max),
205
223
  "Heating Protective Setpoint": get_attribute(
206
224
  static_state.heating_protective_setpoint
207
225
  ),
@@ -211,7 +229,9 @@ def print_static_state(static_state: StaticState) -> None:
211
229
  "Cooling Setpoint Max (reduced)": get_attribute(
212
230
  static_state.cooling_reduced_setpoint
213
231
  ),
214
- "Temperature Unit": get_attribute(static_state.min_temp, "unit"),
232
+ "Temperature Unit": get_attribute(
233
+ _first_temperature_attribute(static_state), "unit"
234
+ ),
215
235
  }
216
236
  print_attributes("Static State", attributes)
217
237
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "python-bsblan"
3
- version = "6.1.0"
3
+ version = "6.1.1"
4
4
  description = "Asynchronous Python client for BSBLAN API"
5
5
  authors = [
6
6
  {name = "Willem-Jan van Rootselaar", email = "liudgervr@gmail.com"}
@@ -631,16 +631,45 @@ class BSBLAN:
631
631
  )
632
632
  return temp_range
633
633
 
634
- if static_values.min_temp is not None:
635
- temp_range["min"] = static_values.min_temp.value
634
+ # Prefer heating_protective_setpoint (714/1014) as the true lower bound
635
+ # for standard circuits. Fall back to min_temp for PPS circuits (15006)
636
+ # which have no separate protective setpoint. Skip sources whose value is
637
+ # inactive (BSB-LAN may return "---" which becomes value=None).
638
+ min_source = next(
639
+ (
640
+ source
641
+ for source in (
642
+ static_values.heating_protective_setpoint,
643
+ static_values.min_temp,
644
+ )
645
+ if source is not None and source.value is not None
646
+ ),
647
+ None,
648
+ )
649
+ if min_source is not None:
650
+ temp_range["min"] = min_source.value
636
651
  logger.debug(
637
652
  "Circuit %d min temp initialized: %s",
638
653
  circuit,
639
654
  temp_range["min"],
640
655
  )
641
656
 
642
- if static_values.max_temp is not None:
643
- temp_range["max"] = static_values.max_temp.value
657
+ # Prefer comfort_setpoint_max (716/1016) as the upper bound for standard
658
+ # circuits. Fall back to max_temp for PPS circuits (15007) which expose
659
+ # only a generic max. Skip sources whose value is inactive.
660
+ max_source = next(
661
+ (
662
+ source
663
+ for source in (
664
+ static_values.comfort_setpoint_max,
665
+ static_values.max_temp,
666
+ )
667
+ if source is not None and source.value is not None
668
+ ),
669
+ None,
670
+ )
671
+ if max_source is not None:
672
+ temp_range["max"] = max_source.value
644
673
  logger.debug(
645
674
  "Circuit %d max temp initialized: %s",
646
675
  circuit,
@@ -40,9 +40,9 @@ BASE_HEATING_PARAMS: Final[dict[str, str]] = {
40
40
  }
41
41
 
42
42
  BASE_STATIC_VALUES_PARAMS: Final[dict[str, str]] = {
43
- "712": "min_temp",
43
+ "712": "temp_reduced_setpoint",
44
44
  "714": "heating_protective_setpoint",
45
- "716": "max_temp",
45
+ "716": "comfort_setpoint_max",
46
46
  "905": "cooling_comfort_setpoint_min",
47
47
  "903": "cooling_reduced_setpoint",
48
48
  }
@@ -107,9 +107,9 @@ BASE_HEATING_CIRCUIT2_PARAMS: Final[dict[str, str]] = {
107
107
  }
108
108
 
109
109
  BASE_STATIC_VALUES_CIRCUIT2_PARAMS: Final[dict[str, str]] = {
110
- "1012": "min_temp",
110
+ "1012": "temp_reduced_setpoint",
111
111
  "1014": "heating_protective_setpoint",
112
- "1016": "max_temp",
112
+ "1016": "comfort_setpoint_max",
113
113
  "1205": "cooling_comfort_setpoint_min",
114
114
  "1203": "cooling_reduced_setpoint",
115
115
  }
@@ -479,8 +479,15 @@ class State(BaseModel):
479
479
  class StaticState(BaseModel):
480
480
  """Class for entities that are not changing."""
481
481
 
482
+ # 712/1012: room temperature reduced (eco/night) setpoint
483
+ temp_reduced_setpoint: EntityInfo[float] | None = None
484
+ # PPS-only lower bound (15006)
482
485
  min_temp: EntityInfo[float] | None = None
486
+ # 716/1016: comfort setpoint max upper bound
487
+ comfort_setpoint_max: EntityInfo[float] | None = None
488
+ # PPS-only upper bound (15007)
483
489
  max_temp: EntityInfo[float] | None = None
490
+ # 714/1014: frost-protection lower bound
484
491
  heating_protective_setpoint: EntityInfo[float] | None = None
485
492
  cooling_comfort_setpoint_min: EntityInfo[float] | None = None
486
493
  cooling_reduced_setpoint: EntityInfo[float] | None = None
@@ -7,9 +7,9 @@
7
7
  "8740": "current_temperature"
8
8
  },
9
9
  "staticValues": {
10
- "712": "min_temp",
10
+ "712": "temp_reduced_setpoint",
11
11
  "714": "heating_protective_setpoint",
12
- "716": "max_temp"
12
+ "716": "comfort_setpoint_max"
13
13
  },
14
14
  "device": {
15
15
  "6224": "device_identification",
@@ -225,10 +225,10 @@ async def test_static_values_circuit2(monkeypatch: Any) -> None:
225
225
  static: StaticState = await bsblan.static_values(circuit=2)
226
226
 
227
227
  assert isinstance(static, StaticState)
228
- assert static.min_temp is not None
229
- assert static.min_temp.value == 16.0
230
- assert static.max_temp is not None
231
- assert static.max_temp.value == 28.0
228
+ assert static.temp_reduced_setpoint is not None
229
+ assert static.temp_reduced_setpoint.value == 16.0
230
+ assert static.comfort_setpoint_max is not None
231
+ assert static.comfort_setpoint_max.value == 28.0
232
232
  assert static.heating_protective_setpoint is not None
233
233
  assert static.heating_protective_setpoint.value == 8.0
234
234
  assert static.cooling_comfort_setpoint_min is not None
@@ -490,7 +490,7 @@ async def test_circuit2_temp_range_initialization(
490
490
  await bsblan._initialize_temperature_range(circuit=2)
491
491
 
492
492
  assert 2 in bsblan._circuit_temp_initialized
493
- assert bsblan._circuit_temp_ranges[2]["min"] == 16.0
493
+ assert bsblan._circuit_temp_ranges[2]["min"] == 8.0
494
494
  assert bsblan._circuit_temp_ranges[2]["max"] == 28.0
495
495
  assert bsblan._circuit_temp_ranges[2]["cooling_min"] == 18.0
496
496
  assert bsblan._circuit_temp_ranges[2]["cooling_max"] == 26.0
@@ -526,11 +526,11 @@ async def test_circuit1_temp_range_uses_reduced_lower_bound(
526
526
  await bsblan._initialize_temperature_range(circuit=1)
527
527
 
528
528
  assert 1 in bsblan._circuit_temp_initialized
529
- assert bsblan._circuit_temp_ranges[1]["min"] == 17.0
529
+ assert bsblan._circuit_temp_ranges[1]["min"] == 8.0
530
530
  assert bsblan._circuit_temp_ranges[1]["max"] == 23.0
531
531
 
532
532
  with pytest.raises(BSBLANInvalidParameterError):
533
- await bsblan._validate_target_temperature("16.5", circuit=1)
533
+ await bsblan._validate_target_temperature("7.5", circuit=1)
534
534
 
535
535
 
536
536
  @pytest.mark.asyncio
@@ -584,7 +584,7 @@ async def test_thermostat_circuit2_lazy_temp_init(
584
584
 
585
585
  # Verify it was initialized
586
586
  assert 2 in bsblan._circuit_temp_initialized
587
- assert bsblan._circuit_temp_ranges[2]["min"] == 16.0
587
+ assert bsblan._circuit_temp_ranges[2]["min"] == 8.0
588
588
  assert bsblan._circuit_temp_ranges[2]["max"] == 28.0
589
589
 
590
590
 
@@ -128,14 +128,14 @@ def test_cooling_target_uses_single_base_parameter() -> None:
128
128
 
129
129
  assert config["heating"]["902"] == "target_temperature_high"
130
130
  assert config["heating_circuit2"]["1202"] == "target_temperature_high"
131
- assert config["staticValues"]["712"] == "min_temp"
131
+ assert config["staticValues"]["712"] == "temp_reduced_setpoint"
132
132
  assert config["staticValues"]["714"] == "heating_protective_setpoint"
133
- assert config["staticValues"]["716"] == "max_temp"
133
+ assert config["staticValues"]["716"] == "comfort_setpoint_max"
134
134
  assert config["staticValues"]["905"] == "cooling_comfort_setpoint_min"
135
135
  assert config["staticValues"]["903"] == "cooling_reduced_setpoint"
136
- assert config["staticValues_circuit2"]["1012"] == "min_temp"
136
+ assert config["staticValues_circuit2"]["1012"] == "temp_reduced_setpoint"
137
137
  assert config["staticValues_circuit2"]["1014"] == ("heating_protective_setpoint")
138
- assert config["staticValues_circuit2"]["1016"] == "max_temp"
138
+ assert config["staticValues_circuit2"]["1016"] == "comfort_setpoint_max"
139
139
  assert config["staticValues_circuit2"]["1205"] == ("cooling_comfort_setpoint_min")
140
140
  assert config["staticValues_circuit2"]["1203"] == "cooling_reduced_setpoint"
141
141
  assert "908" not in config["staticValues"]
@@ -407,9 +407,12 @@ async def test_static_values_with_include(monkeypatch: Any) -> None:
407
407
  request_mock: AsyncMock = AsyncMock(return_value=partial_response)
408
408
  monkeypatch.setattr(bsblan, "_request", request_mock)
409
409
 
410
- static: StaticState = await bsblan.static_values(include=["min_temp"])
410
+ static: StaticState = await bsblan.static_values(
411
+ include=["temp_reduced_setpoint"]
412
+ )
411
413
 
412
- assert static.min_temp is not None
414
+ assert static.temp_reduced_setpoint is not None
415
+ assert static.min_temp is None
413
416
  assert static.max_temp is None
414
417
 
415
418
 
@@ -40,10 +40,11 @@ async def test_sensor(monkeypatch: Any) -> None:
40
40
 
41
41
  static: StaticState = await bsblan.static_values()
42
42
  assert isinstance(static, StaticState)
43
- assert static.min_temp is not None
44
- assert static.min_temp.value == 17.0
45
- assert static.max_temp is not None
46
- assert static.max_temp.value == 23.0
43
+ assert static.temp_reduced_setpoint is not None
44
+ assert static.temp_reduced_setpoint.value == 17.0
45
+ assert static.min_temp is None
46
+ assert static.comfort_setpoint_max is not None
47
+ assert static.comfort_setpoint_max.value == 23.0
47
48
  assert static.heating_protective_setpoint is not None
48
49
  assert static.heating_protective_setpoint.value == 8.0
49
50
  assert static.cooling_comfort_setpoint_min is not None
@@ -153,8 +153,11 @@ async def test_temperature_range_min_temp_not_available(monkeypatch: Any) -> Non
153
153
  client._api_validator = APIValidator(client._api_data)
154
154
 
155
155
  # Mock static_values to return data without min_temp
156
+ # Mock static_values without protective or pps min temp
156
157
  static_values_mock = AsyncMock()
158
+ static_values_mock.return_value.heating_protective_setpoint = None
157
159
  static_values_mock.return_value.min_temp = None
160
+ static_values_mock.return_value.comfort_setpoint_max = None
158
161
  static_values_mock.return_value.max_temp = AsyncMock()
159
162
  static_values_mock.return_value.max_temp.value = "30"
160
163
  monkeypatch.setattr(client, "static_values", static_values_mock)
@@ -162,7 +165,7 @@ async def test_temperature_range_min_temp_not_available(monkeypatch: Any) -> Non
162
165
  # This should log a warning
163
166
  await client._initialize_temperature_range()
164
167
 
165
- # min_temp should remain None
168
+ # min should remain None when neither protective nor pps min is available
166
169
  temp_range = client._circuit_temp_ranges.get(1, {})
167
170
  assert temp_range.get("min") is None
168
171
 
@@ -188,8 +191,10 @@ async def test_temperature_range_max_temp_not_available(monkeypatch: Any) -> Non
188
191
 
189
192
  # Mock static_values to return data without max_temp
190
193
  static_values_mock = AsyncMock()
194
+ static_values_mock.return_value.heating_protective_setpoint = None
191
195
  static_values_mock.return_value.min_temp = AsyncMock()
192
196
  static_values_mock.return_value.min_temp.value = "10"
197
+ static_values_mock.return_value.comfort_setpoint_max = None
193
198
  static_values_mock.return_value.max_temp = None
194
199
  monkeypatch.setattr(client, "static_values", static_values_mock)
195
200
 
@@ -41,9 +41,9 @@ def fresh_api_validator() -> APIValidator:
41
41
  "710": "target_temperature",
42
42
  },
43
43
  "staticValues": {
44
- "712": "min_temp",
44
+ "712": "temp_reduced_setpoint",
45
45
  "714": "heating_protective_setpoint",
46
- "716": "max_temp",
46
+ "716": "comfort_setpoint_max",
47
47
  },
48
48
  "hot_water": {
49
49
  "8830": "dhw_actual_value_top_temperature",
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