Skip to content

Commit 13042e0

Browse files
committed
Fix operational status unknown when running
1 parent e88046f commit 13042e0

3 files changed

Lines changed: 116 additions & 85 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ To execute the example file, first run `pip install -r requirements.txt` to inst
5555
| `cooling_supply_line_temperature` | Cooling supply line temperature in Celsius |
5656
| --- | --- |
5757
| Operational status | |
58-
| `operational_status` | Operational status of the Heat Pump or list of operational statuses (if multiple) |
58+
| `running_operational_statuses` | List of running operational statuses of the Heat Pump |
5959
| `available_operational_statuses` | List of available operational statuses |
6060
| `available_operational_statuses_map` | Dictionary mapping operational status names to their values |
6161
| `operational_status_auxiliary_heater_3kw` | Auxiliary heater status for 3kw (returns `None` if unavailable) |

ThermiaOnlineAPI/model/HeatPump.py

Lines changed: 114 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,13 @@ def __init__(self, device_data: dict, api_interface: "ThermiaAPI"):
7979

8080
self.__register_indexes = DEFAULT_REGISTER_INDEXES
8181

82+
# Precalculated data so it does not have to be updated
83+
84+
self.__operational_statuses = None
85+
self.__all_operational_statuses_map = None
86+
self.__visible_operational_statuses_map = None
87+
self.__running_operational_statuses = None
88+
8289
self.update_data()
8390

8491
def update_data(self):
@@ -106,6 +113,18 @@ def update_data(self):
106113

107114
self.__alarms = self.__api_interface.get_all_alarms(self.__device_id)
108115

116+
# Precalculate data (order is important)
117+
self.__operational_statuses = (
118+
self.__get_operational_statuses_from_operational_status()
119+
)
120+
self.__all_operational_statuses_map = (
121+
self.__get_all_operational_statuses_from_operational_status()
122+
)
123+
self.__visible_operational_statuses_map = (
124+
self.__get_all_visible_operational_statuses_from_operational_status()
125+
)
126+
self.__running_operational_statuses = self.__get_running_operational_statuses()
127+
109128
def get_register_indexes(self):
110129
return self.__register_indexes
111130

@@ -318,7 +337,7 @@ def __set_historical_data_registers(self):
318337

319338
def __get_register_from_operational_status(
320339
self, register_name: str
321-
) -> Optional[dict]:
340+
) -> Optional[Dict]:
322341
data = [
323342
d
324343
for d in self.__group_operational_status or []
@@ -403,23 +422,100 @@ def __get_operational_statuses_from_operational_status(self) -> Optional[Dict]:
403422
def __get_all_operational_statuses_from_operational_status(
404423
self,
405424
) -> Optional[ChainMap]:
406-
data = self.__get_operational_statuses_from_operational_status()
425+
data = self.__operational_statuses
407426

408427
if data is None:
409-
return None
428+
return ChainMap()
410429

411430
operation_modes_map = map(
412431
lambda values: {
413-
values.get("value"): values.get("name").split(
414-
self.__device_config["operational_status_valueNamePrefix"]
415-
)[1],
432+
values.get("value"): {
433+
"name": values.get("name").split(
434+
self.__device_config["operational_status_valueNamePrefix"]
435+
)[1],
436+
"visible": values.get("visible"),
437+
}
416438
},
417439
data,
418440
)
419441

420442
operation_modes_list = list(operation_modes_map)
421443
return ChainMap(*operation_modes_list)
422444

445+
def __get_all_visible_operational_statuses_from_operational_status(
446+
self,
447+
) -> Optional[ChainMap]:
448+
data = self.__all_operational_statuses_map
449+
450+
if data is None:
451+
return ChainMap()
452+
453+
operation_modes_map = map(
454+
lambda item: {item[0]: item[1].get("name")}
455+
if item[1].get("visible")
456+
else {},
457+
data.items(),
458+
)
459+
460+
operation_modes_list = list(filter(lambda x: x != {}, operation_modes_map))
461+
return ChainMap(*operation_modes_list)
462+
463+
def __get_running_operational_statuses(
464+
self,
465+
) -> List[str]:
466+
if self.__device_config["operational_status_register"] is None:
467+
return []
468+
469+
data = self.__get_register_from_operational_status(
470+
self.__device_config["operational_status_register"]
471+
)
472+
473+
if data is None:
474+
return []
475+
476+
current_register_value = get_dict_value_or_none(data, "registerValue")
477+
478+
data = self.__all_operational_statuses_map
479+
480+
if data is None:
481+
return []
482+
483+
data_items_list = list(data.items())
484+
485+
current_operation_mode = [
486+
value.name
487+
for key, value in data_items_list
488+
if key == current_register_value
489+
]
490+
491+
if len(current_operation_mode) == 1:
492+
return current_operation_mode
493+
494+
if (
495+
len(current_operation_mode) != 1
496+
and current_register_value > 0
497+
and len(data_items_list) > 1
498+
):
499+
# Attempt to get multiple statuses by binary sum of the values
500+
data_items_list.sort(key=lambda x: x[0], reverse=True)
501+
list_of_current_operation_modes = []
502+
503+
if self.__device_config["operational_status_minRegisterValue"] is not None:
504+
current_register_value -= int(
505+
self.__device_config["operational_status_minRegisterValue"]
506+
)
507+
508+
for key, value in data_items_list:
509+
if key <= current_register_value:
510+
current_register_value -= key
511+
if value.get("visible"):
512+
list_of_current_operation_modes.append(value.get("name"))
513+
514+
if current_register_value == 0:
515+
return list_of_current_operation_modes
516+
517+
return []
518+
423519
@property
424520
def name(self):
425521
return get_dict_value_or_none(self.__info, "name")
@@ -576,65 +672,17 @@ def cooling_supply_line_temperature(self):
576672
###########################################################################
577673

578674
@property
579-
def operational_status(self) -> Optional[Union[str, List[str]]]:
580-
if self.__device_config["operational_status_register"] is None:
581-
# Attempt to get the register from the status data
582-
self.__get_operational_statuses_from_operational_status()
583-
if self.__device_config["operational_status_register"] is None:
584-
return None
585-
586-
data = self.__get_register_from_operational_status(
587-
self.__device_config["operational_status_register"]
588-
)
675+
def running_operational_statuses(self) -> List[str]:
676+
data = self.__running_operational_statuses
589677

590678
if data is None:
591-
return None
592-
593-
current_register_value = get_dict_value_or_none(data, "registerValue")
594-
595-
data = self.__get_all_operational_statuses_from_operational_status()
596-
597-
if data is None:
598-
return None
599-
600-
data_items_list = list(data.items())
601-
602-
current_operation_mode = [
603-
name for value, name in data_items_list if value == current_register_value
604-
]
605-
606-
if len(current_operation_mode) == 0:
607-
return None
608-
609-
if (
610-
len(current_operation_mode) != 1
611-
and current_register_value > 0
612-
and len(data_items_list) > 1
613-
):
614-
# Attempt to get multiple statuses by binary sum of the values
615-
data_items_list.sort(key=lambda x: x[0], reverse=True)
616-
list_of_current_operation_modes = []
617-
618-
if self.__device_config["operational_status_minRegisterValue"] is not None:
619-
current_register_value -= int(
620-
self.__device_config["operational_status_minRegisterValue"]
621-
)
622-
623-
for value, name in data_items_list:
624-
if value <= current_register_value:
625-
current_register_value -= value
626-
list_of_current_operation_modes.append(name)
627-
628-
if current_register_value == 0:
629-
return list_of_current_operation_modes
630-
631-
return None
679+
return []
632680

633-
return current_operation_mode[0]
681+
return data
634682

635683
@property
636684
def available_operational_statuses(self) -> Optional[List[str]]:
637-
data = self.__get_all_operational_statuses_from_operational_status()
685+
data = self.__visible_operational_statuses_map
638686

639687
if data is None:
640688
return []
@@ -643,7 +691,7 @@ def available_operational_statuses(self) -> Optional[List[str]]:
643691

644692
@property
645693
def available_operational_statuses_map(self) -> Optional[ChainMap]:
646-
return self.__get_all_operational_statuses_from_operational_status()
694+
return self.__visible_operational_statuses_map
647695

648696
@property
649697
def operational_status_auxiliary_heater_3kw(self):
@@ -677,39 +725,27 @@ def operational_status_auxiliary_heater_15kw(self):
677725

678726
@property
679727
def operational_status_compressor_status(self):
680-
return self.__get_value_by_key_and_register_name_from_operational_status(
681-
"COMP_STATUS", "COMP_VALUE_COMPR"
682-
)
728+
return "COMPR" in self.running_operational_statuses
683729

684730
@property
685731
def operational_status_brine_pump_status(self):
686-
return self.__get_value_by_key_and_register_name_from_operational_status(
687-
"COMP_STATUS", "COMP_VALUE_BRINEPUMP"
688-
)
732+
return "BRINEPUMP" in self.running_operational_statuses
689733

690734
@property
691735
def operational_status_radiator_pump_status(self):
692-
return self.__get_value_by_key_and_register_name_from_operational_status(
693-
"COMP_STATUS", "COMP_VALUE_RADIATORPUMP"
694-
)
736+
return "RADIATORPUMP" in self.running_operational_statuses
695737

696738
@property
697739
def operational_status_cooling_status(self):
698-
return self.__get_value_by_key_and_register_name_from_operational_status(
699-
"COMP_STATUS", "COMP_VALUE_COOLING"
700-
)
740+
return "COOLING" in self.running_operational_statuses
701741

702742
@property
703743
def operational_status_hot_water_status(self):
704-
return self.__get_value_by_key_and_register_name_from_operational_status(
705-
"COMP_STATUS", "COMP_VALUE_HOT_WATER"
706-
)
744+
return "HOT_WATER" in self.running_operational_statuses
707745

708746
@property
709747
def operational_status_heating_status(self):
710-
return self.__get_value_by_key_and_register_name_from_operational_status(
711-
"COMP_STATUS", "COMP_VALUE_HEATING"
712-
)
748+
return "HEATING" in self.running_operational_statuses
713749

714750
@property
715751
def operational_status_integral(self):
@@ -790,11 +826,6 @@ def is_operation_mode_read_only(self):
790826
# Hot water data
791827
###########################################################################
792828

793-
# TODO: DEPRECATED, remove in next major release
794-
@property
795-
def is_hot_water_switch_available(self):
796-
return self.__group_hot_water is not None
797-
798829
@property
799830
def hot_water_switch_state(self) -> Optional[int]:
800831
return self.__group_hot_water["hot_water_switch"]

example.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@
6565
print("\n")
6666

6767
print("Operational status")
68-
print("Operational status: " + str(heat_pump.operational_status))
68+
print("Running operational statuses: " + str(heat_pump.running_operational_statuses))
6969
print(
7070
"Available operational statuses: " + str(heat_pump.available_operational_statuses)
7171
)

0 commit comments

Comments
 (0)