Skip to content

Commit 1cdf109

Browse files
committed
POINTTAPI: add per-zone optimum start state sensor
- Add dynamic per-zone sensor for /zones/{id}/optimumStartState - Keep raw state value (no interpretation mapping yet) - Discover sensors from zone references to avoid ghost entities - Add translation key for all supported locales (en/de/fr/it/nl/pl/sk) - Add tests for discovery and raw-value passthrough
1 parent ceca83c commit 1cdf109

10 files changed

Lines changed: 91 additions & 0 deletions

File tree

custom_components/bosch/pointtapi_entities.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,6 +1448,24 @@ def _pointtapi_zone_assigned_program_sensor_descriptions(
14481448
)
14491449

14501450

1451+
def _pointtapi_zone_optimum_start_state_sensor_descriptions(
1452+
data: dict[str, Any] | None = None,
1453+
) -> tuple[BoschPoinTTAPISensorEntityDescription, ...]:
1454+
"""Return one raw optimum-start-state sensor per zone when advertised."""
1455+
if not data:
1456+
return ()
1457+
1458+
zone_ids = _zone_ids_with_reference(data, "optimumStartState")
1459+
return tuple(
1460+
BoschPoinTTAPISensorEntityDescription(
1461+
key=f"/zones/{zone_id}/optimumStartState",
1462+
translation_key="optimum_start_state",
1463+
entity_category=EntityCategory.DIAGNOSTIC,
1464+
)
1465+
for zone_id in zone_ids
1466+
)
1467+
1468+
14511469
def _pointtapi_electricity_average_sensor_descriptions(
14521470
data: dict[str, Any] | None = None,
14531471
) -> tuple[BoschPoinTTAPISensorEntityDescription, ...]:
@@ -1837,6 +1855,7 @@ def _pointtapi_sensor_descriptions(
18371855

18381856
descriptions.extend(_pointtapi_zone_valve_sensor_descriptions(data))
18391857
descriptions.extend(_pointtapi_zone_assigned_program_sensor_descriptions(data))
1858+
descriptions.extend(_pointtapi_zone_optimum_start_state_sensor_descriptions(data))
18401859
descriptions.extend(_pointtapi_electricity_average_sensor_descriptions(data))
18411860
descriptions.extend(_pointtapi_thermostat_valve_sensor_descriptions(data))
18421861
return tuple(descriptions)

custom_components/bosch/strings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@
229229
"assigned_program": {
230230
"name": "Assigned program"
231231
},
232+
"optimum_start_state": {
233+
"name": "Optimum start state"
234+
},
232235
"electricity_day_average": {
233236
"name": "Electricity day average"
234237
},

custom_components/bosch/translations/de.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
"assigned_program": {
159159
"name": "Zugewiesenes Programm"
160160
},
161+
"optimum_start_state": {
162+
"name": "Status optimaler Start"
163+
},
161164
"electricity_day_average": {
162165
"name": "Tagesdurchschnitt Strom"
163166
},

custom_components/bosch/translations/en.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,9 @@
229229
"assigned_program": {
230230
"name": "Assigned program"
231231
},
232+
"optimum_start_state": {
233+
"name": "Optimum start state"
234+
},
232235
"electricity_day_average": {
233236
"name": "Electricity day average"
234237
},

custom_components/bosch/translations/fr.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
"assigned_program": {
159159
"name": "Programme assigné"
160160
},
161+
"optimum_start_state": {
162+
"name": "État du démarrage optimal"
163+
},
161164
"electricity_day_average": {
162165
"name": "Moyenne journalière électricité"
163166
},

custom_components/bosch/translations/it.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
"assigned_program": {
159159
"name": "Programma assegnato"
160160
},
161+
"optimum_start_state": {
162+
"name": "Stato avvio ottimale"
163+
},
161164
"electricity_day_average": {
162165
"name": "Media giornaliera elettricità"
163166
},

custom_components/bosch/translations/nl.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
"assigned_program": {
159159
"name": "Toegewezen programma"
160160
},
161+
"optimum_start_state": {
162+
"name": "Status optimaal starten"
163+
},
161164
"electricity_day_average": {
162165
"name": "Daggemiddelde elektriciteit"
163166
},

custom_components/bosch/translations/pl.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
"assigned_program": {
159159
"name": "Przypisany program"
160160
},
161+
"optimum_start_state": {
162+
"name": "Stan optymalnego startu"
163+
},
161164
"electricity_day_average": {
162165
"name": "Średnia dzienna energii elektrycznej"
163166
},

custom_components/bosch/translations/sk.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,9 @@
158158
"assigned_program": {
159159
"name": "Priradený program"
160160
},
161+
"optimum_start_state": {
162+
"name": "Stav optimálneho štartu"
163+
},
161164
"electricity_day_average": {
162165
"name": "Denny priemer elektriny"
163166
},

unittests/test_pointtapi_new_entities.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,6 +672,54 @@ def test_zone_assigned_program_sensors_are_discovered_from_zone_paths(self):
672672
assert "/zones/zn10/assignedProgramName" in descs
673673
assert descs["/zones/zn2/assignedProgramName"].translation_key == "assigned_program"
674674

675+
def test_zone_optimum_start_state_sensors_are_discovered_from_zone_references(self):
676+
data = {
677+
"/zones/zn2": {
678+
"references": [
679+
{"id": "/zones/zn2/optimumStartState"},
680+
]
681+
},
682+
"/zones/zn1": {
683+
"references": [
684+
{"id": "/zones/zn1/optimumStartState"},
685+
]
686+
},
687+
"/zones/zn3": {
688+
"references": [
689+
{"id": "/zones/zn3/status"},
690+
]
691+
},
692+
}
693+
694+
descs = {d.key: d for d in _pointtapi_sensor_descriptions(data)}
695+
assert "/zones/zn1/optimumStartState" in descs
696+
assert "/zones/zn2/optimumStartState" in descs
697+
assert "/zones/zn3/optimumStartState" not in descs
698+
assert descs["/zones/zn1/optimumStartState"].translation_key == "optimum_start_state"
699+
700+
def test_zone_optimum_start_state_sensor_keeps_raw_value(self):
701+
data = {
702+
"/zones/zn2": {
703+
"id": "/zones/zn2",
704+
"references": [{"id": "/zones/zn2/optimumStartState"}],
705+
},
706+
"/zones/zn2/temperatureHeatingSetpoint": {"value": 20.0},
707+
"/zones/zn2/optimumStartState": {"value": "idle"},
708+
}
709+
710+
coord = _mock_coordinator(data)
711+
desc = next(
712+
d
713+
for d in _pointtapi_sensor_descriptions(data)
714+
if d.key == "/zones/zn2/optimumStartState"
715+
)
716+
ent = BoschPoinTTAPISensorEntity(coord, "entry1", "uuid1", desc)
717+
ent.async_write_ha_state = MagicMock()
718+
719+
ent._handle_coordinator_update()
720+
721+
assert ent.native_value == "idle"
722+
675723
def test_zone_assigned_program_sensor_resolves_base64_program_name(self):
676724
data = {
677725
"/zones/zn2": {"id": "/zones/zn2"},

0 commit comments

Comments
 (0)