Skip to content

Commit c655ac1

Browse files
committed
Add POINTTAPI heat demand type sensor from flame indication
1 parent 27944b3 commit c655ac1

10 files changed

Lines changed: 109 additions & 0 deletions

File tree

custom_components/bosch/pointtapi_entities.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -911,6 +911,17 @@ def _appliance_status_available(data: dict[str, Any]) -> bool:
911911
) is not None
912912

913913

914+
def _heat_demand_type_state(data: dict[str, Any]) -> str | None:
915+
"""Map /heatSources/flameIndication to a stable demand-type state key."""
916+
raw = _val(data, "/heatSources/flameIndication")
917+
if not isinstance(raw, str):
918+
return None
919+
value = raw.strip().lower()
920+
if value in {"off", "ch", "dhw"}:
921+
return value
922+
return None
923+
924+
914925
# Zone /status -> HVAC action. Unknown values map to None (unknown), never to
915926
# COOLING — these appliances are heating-only.
916927
_ZONE_STATUS_ACTIONS = {
@@ -1519,6 +1530,7 @@ def _pointtapi_sensor_descriptions(
15191530
key="/system/appliance/causeCode",
15201531
translation_key="cause_code",
15211532
entity_category=EntityCategory.DIAGNOSTIC,
1533+
value_fn=_appliance_cause_code,
15221534
),
15231535
BoschPoinTTAPISensorEntityDescription(
15241536
key="/system/appliance/status",
@@ -1559,6 +1571,11 @@ def _pointtapi_sensor_descriptions(
15591571
native_unit_of_measurement="%",
15601572
icon="mdi:signal-cellular-2",
15611573
),
1574+
BoschPoinTTAPISensorEntityDescription(
1575+
key="/heatSources/flameIndication",
1576+
translation_key="heat_demand_type",
1577+
value_fn=_heat_demand_type_state,
1578+
),
15621579
BoschPoinTTAPISensorEntityDescription(
15631580
key="/heatSources/returnTemperature",
15641581
translation_key="return_temperature",

custom_components/bosch/strings.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,14 @@
157157
"actual_modulation": {
158158
"name": "Actual modulation"
159159
},
160+
"heat_demand_type": {
161+
"name": "Demand type",
162+
"state": {
163+
"off": "No demand",
164+
"ch": "Heating",
165+
"dhw": "Domestic hot water"
166+
}
167+
},
160168
"collector_temperature": {
161169
"name": "Collector temperature"
162170
},

custom_components/bosch/translations/de.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@
151151
"actual_modulation": {
152152
"name": "Aktuelle Modulationsleistung"
153153
},
154+
"heat_demand_type": {
155+
"name": "Anforderungsart",
156+
"state": {
157+
"off": "Keine Anforderung",
158+
"ch": "Heizung",
159+
"dhw": "Warmwasser"
160+
}
161+
},
154162
"gas_heating_today": {
155163
"name": "Gas Heizung heute"
156164
},

custom_components/bosch/translations/en.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,14 @@
163163
"storage_temperature": {
164164
"name": "Storage temperature"
165165
},
166+
"heat_demand_type": {
167+
"name": "Demand type",
168+
"state": {
169+
"off": "No demand",
170+
"ch": "Heating",
171+
"dhw": "Domestic hot water"
172+
}
173+
},
166174
"pump_modulation": {
167175
"name": "Pump modulation"
168176
},

custom_components/bosch/translations/fr.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@
151151
"actual_modulation": {
152152
"name": "Puissance de modulation actuelle"
153153
},
154+
"heat_demand_type": {
155+
"name": "Type de demande",
156+
"state": {
157+
"off": "Aucune demande",
158+
"ch": "Chauffage",
159+
"dhw": "Eau chaude sanitaire"
160+
}
161+
},
154162
"gas_heating_today": {
155163
"name": "Gaz chauffage aujourd'hui"
156164
},

custom_components/bosch/translations/it.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@
151151
"actual_modulation": {
152152
"name": "Potenza di modulazione attuale"
153153
},
154+
"heat_demand_type": {
155+
"name": "Tipo di richiesta",
156+
"state": {
157+
"off": "Nessuna richiesta",
158+
"ch": "Riscaldamento",
159+
"dhw": "Acqua calda sanitaria"
160+
}
161+
},
154162
"gas_heating_today": {
155163
"name": "Gas riscaldamento oggi"
156164
},

custom_components/bosch/translations/nl.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@
151151
"actual_modulation": {
152152
"name": "Huidige modulatiedruk"
153153
},
154+
"heat_demand_type": {
155+
"name": "Vraagtype",
156+
"state": {
157+
"off": "Geen vraag",
158+
"ch": "Verwarming",
159+
"dhw": "Warm tapwater"
160+
}
161+
},
154162
"gas_heating_today": {
155163
"name": "Gas verwarming vandaag"
156164
},

custom_components/bosch/translations/pl.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,14 @@
154154
"gas_heating_today": {
155155
"name": "Gaz ogrzewanie dziś"
156156
},
157+
"heat_demand_type": {
158+
"name": "Typ zapotrzebowania",
159+
"state": {
160+
"off": "Brak zapotrzebowania",
161+
"ch": "Ogrzewanie",
162+
"dhw": "Ciepła woda użytkowa"
163+
}
164+
},
157165
"gas_hot_water_today": {
158166
"name": "Gaz ciepła woda dziś"
159167
},

custom_components/bosch/translations/sk.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,14 @@
151151
"actual_modulation": {
152152
"name": "Aktuálna výkonová modulácia"
153153
},
154+
"heat_demand_type": {
155+
"name": "Typ požiadavky",
156+
"state": {
157+
"off": "Bez požiadavky",
158+
"ch": "Vykurovanie",
159+
"dhw": "Teplá úžitková voda"
160+
}
161+
},
154162
"gas_heating_today": {
155163
"name": "Plyn vykurovanie dnes"
156164
},

unittests/test_pointtapi_new_entities.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,34 @@ def test_appliance_status_sensor_maps_0h_203_to_standby(self):
344344
assert desc.attributes_fn is not None
345345
assert desc.attributes_fn(data) == {"display_code": "0H", "cause_code": 203}
346346

347+
def test_cause_code_sensor_normalizes_float_to_int(self):
348+
descs = {d.key: d for d in _pointtapi_sensor_descriptions()}
349+
desc = descs["/system/appliance/causeCode"]
350+
data = {"/system/appliance/causeCode": {"value": 201.0}}
351+
assert desc.value_fn is not None
352+
assert desc.value_fn(data) == 201
353+
354+
def test_heat_demand_type_sensor_is_described(self):
355+
descs = {d.key: d for d in _pointtapi_sensor_descriptions()}
356+
desc = descs["/heatSources/flameIndication"]
357+
assert desc.translation_key == "heat_demand_type"
358+
assert desc.value_fn is not None
359+
360+
def test_heat_demand_type_sensor_maps_known_values(self):
361+
descs = {d.key: d for d in _pointtapi_sensor_descriptions()}
362+
desc = descs["/heatSources/flameIndication"]
363+
assert desc.value_fn is not None
364+
365+
assert desc.value_fn({"/heatSources/flameIndication": {"value": "off"}}) == "off"
366+
assert desc.value_fn({"/heatSources/flameIndication": {"value": "ch"}}) == "ch"
367+
assert desc.value_fn({"/heatSources/flameIndication": {"value": "dhw"}}) == "dhw"
368+
369+
def test_heat_demand_type_sensor_returns_none_for_unknown(self):
370+
descs = {d.key: d for d in _pointtapi_sensor_descriptions()}
371+
desc = descs["/heatSources/flameIndication"]
372+
assert desc.value_fn is not None
373+
assert desc.value_fn({"/heatSources/flameIndication": {"value": "unexpected"}}) is None
374+
347375
def test_appliance_status_sensor_maps_unknown_pair_to_unknown(self):
348376
descs = {d.key: d for d in _pointtapi_sensor_descriptions()}
349377
desc = descs["/system/appliance/status"]

0 commit comments

Comments
 (0)