|
1 | 1 | """Air-To-Water (DeviceType=1) device definition.""" |
| 2 | + |
| 3 | +import warnings |
2 | 4 | from typing import Any, Callable, Dict, List, Optional |
3 | 5 |
|
4 | 6 | from pymelcloud.device import EFFECTIVE_FLAGS, Device |
|
9 | 11 | PROPERTY_ZONE_2_TARGET_TEMPERATURE = "zone_2_target_temperature" |
10 | 12 | PROPERTY_ZONE_1_TARGET_HEAT_FLOW_TEMPERATURE = "zone_1_target_heat_flow_temperature" |
11 | 13 | PROPERTY_ZONE_2_TARGET_HEAT_FLOW_TEMPERATURE = "zone_2_target_heat_flow_temperature" |
12 | | -PROPERTY_ZONE_1_TARGET_COOL_FLOW_TEMPERATURE = "zone_1_target_heat_cool_temperature" |
13 | | -PROPERTY_ZONE_2_TARGET_COOL_FLOW_TEMPERATURE = "zone_2_target_heat_cool_temperature" |
| 14 | +PROPERTY_ZONE_1_TARGET_COOL_FLOW_TEMPERATURE = "zone_1_target_cool_flow_temperature" |
| 15 | +PROPERTY_ZONE_2_TARGET_COOL_FLOW_TEMPERATURE = "zone_2_target_cool_flow_temperature" |
14 | 16 | PROPERTY_ZONE_1_OPERATION_MODE = "zone_1_operation_mode" |
15 | 17 | PROPERTY_ZONE_2_OPERATION_MODE = "zone_2_operation_mode" |
16 | 18 |
|
| 19 | +# Deprecated aliases for backwards compatibility |
| 20 | +PROPERTY_ZONE_1_TARGET_HEAT_COOL_TEMPERATURE = "zone_1_target_heat_cool_temperature" |
| 21 | +PROPERTY_ZONE_2_TARGET_HEAT_COOL_TEMPERATURE = "zone_2_target_heat_cool_temperature" |
| 22 | + |
17 | 23 | OPERATION_MODE_AUTO = "auto" |
18 | 24 | OPERATION_MODE_FORCE_HOT_WATER = "force_hot_water" |
19 | 25 |
|
@@ -155,22 +161,52 @@ async def set_target_temperature(self, target_temperature): |
155 | 161 | await self._device.set({prop: target_temperature}) |
156 | 162 |
|
157 | 163 | @property |
158 | | - def flow_temperature(self) -> float: |
| 164 | + def flow_temperature(self) -> float | None: |
159 | 165 | """Return current flow temperature. |
160 | 166 |
|
161 | | - This value is not available in the standard state poll response. The poll |
162 | | - update frequency can be a little bit lower that expected. |
| 167 | + .. deprecated:: |
| 168 | + Use `device.flow_temperature` or `zone.zone_flow_temperature` instead. |
163 | 169 | """ |
164 | | - return self._device_conf()["Device"]["FlowTemperature"] |
| 170 | + warnings.warn( |
| 171 | + "Zone.flow_temperature is deprecated, use device.flow_temperature " |
| 172 | + "or zone.zone_flow_temperature instead", |
| 173 | + DeprecationWarning, |
| 174 | + stacklevel=2, |
| 175 | + ) |
| 176 | + return self._device_conf().get("Device", {}).get("FlowTemperature") |
165 | 177 |
|
166 | 178 | @property |
167 | | - def return_temperature(self) -> float: |
168 | | - """Return current return flow temperature. |
| 179 | + def return_temperature(self) -> float | None: |
| 180 | + """Return current return temperature. |
169 | 181 |
|
170 | | - This value is not available in the standard state poll response. The poll |
171 | | - update frequency can be a little bit lower that expected. |
| 182 | + .. deprecated:: |
| 183 | + Use `device.return_temperature` or `zone.zone_return_temperature` instead. |
172 | 184 | """ |
173 | | - return self._device_conf()["Device"]["ReturnTemperature"] |
| 185 | + warnings.warn( |
| 186 | + "Zone.return_temperature is deprecated, use device.return_temperature " |
| 187 | + "or zone.zone_return_temperature instead", |
| 188 | + DeprecationWarning, |
| 189 | + stacklevel=2, |
| 190 | + ) |
| 191 | + return self._device_conf().get("Device", {}).get("ReturnTemperature") |
| 192 | + |
| 193 | + @property |
| 194 | + def zone_flow_temperature(self) -> float | None: |
| 195 | + """Return current zone-specific flow temperature.""" |
| 196 | + return ( |
| 197 | + self._device_conf() |
| 198 | + .get("Device", {}) |
| 199 | + .get(f"FlowTemperatureZone{self.zone_index}") |
| 200 | + ) |
| 201 | + |
| 202 | + @property |
| 203 | + def zone_return_temperature(self) -> float | None: |
| 204 | + """Return current zone-specific return temperature.""" |
| 205 | + return ( |
| 206 | + self._device_conf() |
| 207 | + .get("Device", {}) |
| 208 | + .get(f"ReturnTemperatureZone{self.zone_index}") |
| 209 | + ) |
174 | 210 |
|
175 | 211 | @property |
176 | 212 | def target_flow_temperature(self) -> Optional[float]: |
@@ -309,13 +345,19 @@ def apply_write(self, state: Dict[str, Any], key: str, value: Any): |
309 | 345 | elif key == PROPERTY_ZONE_1_TARGET_HEAT_FLOW_TEMPERATURE: |
310 | 346 | state["SetHeatFlowTemperatureZone1"] = self.round_temperature(value) |
311 | 347 | flags |= 0x1000000000000 |
312 | | - elif key == PROPERTY_ZONE_1_TARGET_COOL_FLOW_TEMPERATURE: |
| 348 | + elif key in ( |
| 349 | + PROPERTY_ZONE_1_TARGET_COOL_FLOW_TEMPERATURE, |
| 350 | + PROPERTY_ZONE_1_TARGET_HEAT_COOL_TEMPERATURE, |
| 351 | + ): |
313 | 352 | state["SetCoolFlowTemperatureZone1"] = self.round_temperature(value) |
314 | 353 | flags |= 0x1000000000000 |
315 | 354 | elif key == PROPERTY_ZONE_2_TARGET_HEAT_FLOW_TEMPERATURE: |
316 | 355 | state["SetHeatFlowTemperatureZone2"] = self.round_temperature(value) |
317 | 356 | flags |= 0x1000000000000 |
318 | | - elif key == PROPERTY_ZONE_2_TARGET_COOL_FLOW_TEMPERATURE: |
| 357 | + elif key in ( |
| 358 | + PROPERTY_ZONE_2_TARGET_COOL_FLOW_TEMPERATURE, |
| 359 | + PROPERTY_ZONE_2_TARGET_HEAT_COOL_TEMPERATURE, |
| 360 | + ): |
319 | 361 | state["SetCoolFlowTemperatureZone2"] = self.round_temperature(value) |
320 | 362 | flags |= 0x1000000000000 |
321 | 363 | elif key == PROPERTY_ZONE_1_OPERATION_MODE: |
@@ -366,21 +408,131 @@ def outside_temperature(self) -> Optional[float]: |
366 | 408 | """ |
367 | 409 | return self.get_state_prop("OutdoorTemperature") |
368 | 410 |
|
| 411 | + @property |
| 412 | + def flow_temperature(self) -> Optional[float]: |
| 413 | + """Return current flow temperature of the entire system.""" |
| 414 | + return self.get_device_prop("FlowTemperature") |
| 415 | + |
| 416 | + @property |
| 417 | + def return_temperature(self) -> Optional[float]: |
| 418 | + """Return current return temperature of the entire system.""" |
| 419 | + return self.get_device_prop("ReturnTemperature") |
| 420 | + |
369 | 421 | @property |
370 | 422 | def flow_temperature_boiler(self) -> Optional[float]: |
371 | 423 | """Return flow temperature of the boiler.""" |
372 | 424 | return self.get_device_prop("FlowTemperatureBoiler") |
373 | 425 |
|
374 | 426 | @property |
375 | 427 | def return_temperature_boiler(self) -> Optional[float]: |
376 | | - """Return flow temperature of the boiler.""" |
377 | | - return self.get_device_prop("FlowTemperatureBoiler") |
| 428 | + """Return the boiler return temperature.""" |
| 429 | + return self.get_device_prop("ReturnTemperatureBoiler") |
378 | 430 |
|
379 | 431 | @property |
380 | 432 | def mixing_tank_temperature(self) -> Optional[float]: |
381 | 433 | """Return mixing tank temperature.""" |
382 | 434 | return self.get_device_prop("MixingTankWaterTemperature") |
383 | 435 |
|
| 436 | + @property |
| 437 | + def condensing_temperature(self) -> Optional[float]: |
| 438 | + """Return condensing temperature.""" |
| 439 | + return self.get_device_prop("CondensingTemperature") |
| 440 | + |
| 441 | + @property |
| 442 | + def heat_pump_frequency(self) -> Optional[int]: |
| 443 | + """Return current heat pump compressor frequency in Hz.""" |
| 444 | + return self.get_device_prop("HeatPumpFrequency") |
| 445 | + |
| 446 | + @property |
| 447 | + def demand_percentage(self) -> Optional[int]: |
| 448 | + """Return demand percentage (0-100).""" |
| 449 | + return self.get_state_prop("DemandPercentage") |
| 450 | + |
| 451 | + @property |
| 452 | + def boiler_status(self) -> Optional[bool]: |
| 453 | + """Return boiler status.""" |
| 454 | + return self.get_device_prop("BoilerStatus") |
| 455 | + |
| 456 | + @property |
| 457 | + def booster_heater1_status(self) -> Optional[bool]: |
| 458 | + """Return booster heater 1 status.""" |
| 459 | + return self.get_device_prop("BoosterHeater1Status") |
| 460 | + |
| 461 | + @property |
| 462 | + def booster_heater2_status(self) -> Optional[bool]: |
| 463 | + """Return booster heater 2 status.""" |
| 464 | + return self.get_device_prop("BoosterHeater2Status") |
| 465 | + |
| 466 | + @property |
| 467 | + def booster_heater2plus_status(self) -> Optional[bool]: |
| 468 | + """Return booster heater 2+ status.""" |
| 469 | + return self.get_device_prop("BoosterHeater2PlusStatus") |
| 470 | + |
| 471 | + @property |
| 472 | + def immersion_heater_status(self) -> Optional[bool]: |
| 473 | + """Return immersion heater status.""" |
| 474 | + return self.get_device_prop("ImmersionHeaterStatus") |
| 475 | + |
| 476 | + @property |
| 477 | + def water_pump1_status(self) -> Optional[bool]: |
| 478 | + """Return water pump 1 status.""" |
| 479 | + return self.get_device_prop("WaterPump1Status") |
| 480 | + |
| 481 | + @property |
| 482 | + def water_pump2_status(self) -> Optional[bool]: |
| 483 | + """Return water pump 2 status.""" |
| 484 | + return self.get_device_prop("WaterPump2Status") |
| 485 | + |
| 486 | + @property |
| 487 | + def water_pump3_status(self) -> Optional[bool]: |
| 488 | + """Return water pump 3 status.""" |
| 489 | + return self.get_device_prop("WaterPump3Status") |
| 490 | + |
| 491 | + @property |
| 492 | + def water_pump4_status(self) -> Optional[bool]: |
| 493 | + """Return water pump 4 status.""" |
| 494 | + return self.get_device_prop("WaterPump4Status") |
| 495 | + |
| 496 | + @property |
| 497 | + def valve_3way_status(self) -> Optional[bool]: |
| 498 | + """Return 3-way valve status.""" |
| 499 | + return self.get_device_prop("ValveStatus3Way") |
| 500 | + |
| 501 | + @property |
| 502 | + def valve_2way_status(self) -> Optional[bool]: |
| 503 | + """Return 2-way valve status.""" |
| 504 | + return self.get_device_prop("ValveStatus2Way") |
| 505 | + |
| 506 | + @property |
| 507 | + def daily_heating_energy_consumed(self) -> Optional[float]: |
| 508 | + """Return today's heating energy consumed in kWh.""" |
| 509 | + return self.get_device_prop("DailyHeatingEnergyConsumed") |
| 510 | + |
| 511 | + @property |
| 512 | + def daily_cooling_energy_consumed(self) -> Optional[float]: |
| 513 | + """Return today's cooling energy consumed in kWh.""" |
| 514 | + return self.get_device_prop("DailyCoolingEnergyConsumed") |
| 515 | + |
| 516 | + @property |
| 517 | + def daily_hot_water_energy_consumed(self) -> Optional[float]: |
| 518 | + """Return today's hot water energy consumed in kWh.""" |
| 519 | + return self.get_device_prop("DailyHotWaterEnergyConsumed") |
| 520 | + |
| 521 | + @property |
| 522 | + def daily_heating_energy_produced(self) -> Optional[float]: |
| 523 | + """Return today's heating energy produced in kWh.""" |
| 524 | + return self.get_device_prop("DailyHeatingEnergyProduced") |
| 525 | + |
| 526 | + @property |
| 527 | + def daily_cooling_energy_produced(self) -> Optional[float]: |
| 528 | + """Return today's cooling energy produced in kWh.""" |
| 529 | + return self.get_device_prop("DailyCoolingEnergyProduced") |
| 530 | + |
| 531 | + @property |
| 532 | + def daily_hot_water_energy_produced(self) -> Optional[float]: |
| 533 | + """Return today's hot water energy produced in kWh.""" |
| 534 | + return self.get_device_prop("DailyHotWaterEnergyProduced") |
| 535 | + |
384 | 536 | @property |
385 | 537 | def zones(self) -> Optional[List[Zone]]: |
386 | 538 | """Return zones controlled by this device. |
|
0 commit comments