diff --git a/README.md b/README.md index 244ac85..8d2500f 100644 --- a/README.md +++ b/README.md @@ -89,10 +89,11 @@ To execute the example file, first run `pip install -r requirements.txt` to inst | `operation_mode` | Current operation mode of the Heat Pump | | `available_operation_modes` | List of available operation modes for the Heat Pump | | `available_operation_mode_map` | Dictionary mapping operation mode names to their values | +| `is_operation_mode_read_only` | Boolean value indicating if the Heat Pump operation mode is read-only | | --- | --- | | Hot Water data | | -| `is_operation_mode_read_only` | Boolean value indicating if the Heat Pump operation mode is read-only | -| `is_hot_water_switch_available` | Boolean value indicating if the Heat Pump has a hot water switch | +| `hot_water_switch_state` | Int value indicating the Heat Pump hot water switch state (0 or 1) or None if not available | +| `hot_water_boost_switch_state` | Int value indicating the Heat Pump hot water boost switch state (0 or 1) or None if not available | | --- | --- | | Historical data | | | `historical_data_registers` | List of available registers to use for historical data fetching | @@ -111,6 +112,7 @@ To execute the example file, first run `pip install -r requirements.txt` to inst | `set_temperature()` | Set the target temperature for the Heat Pump | | `set_operation_mode()` | Set the operation mode for the Heat Pump | | `set_hot_water_switch_state()` | Set the hot water switch state to 0 (off) or 1 (on) for the Heat Pump | +| `set_hot_water_boost_switch_state()` | Set the hot water boost switch state to 0 (off) or 1 (on) for the Heat Pump | | --- | --- | | Fetch historical data | | | `get_historical_data_for_register()` | Fetch historical data by using register name from `historical_data_registers` together with start_time and end_time of the data in Python datatime format. Returns list of dictionaries which contains data in format `{ "time": datetime, "value": int }` | diff --git a/ThermiaOnlineAPI/api/ThermiaAPI.py b/ThermiaOnlineAPI/api/ThermiaAPI.py index 3db5178..08e4243 100644 --- a/ThermiaOnlineAPI/api/ThermiaAPI.py +++ b/ThermiaOnlineAPI/api/ThermiaAPI.py @@ -12,6 +12,9 @@ REG_GROUP_OPERATIONAL_STATUS, REG_GROUP_OPERATIONAL_TIME, REG_GROUP_TEMPERATURES, + REG_HOT_WATER_STATUS, + REG_HOT_WATER_BOOST, + REG_OPERATIONMODE, THERMIA_API_CONFIG_URLS_BY_API_TYPE, THERMIA_AZURE_AUTH_URL, THERMIA_AZURE_AUTH_CLIENT_ID_AND_SCOPE, @@ -202,7 +205,7 @@ def get_group_operational_operation(self, device: ThermiaHeatPump): device.id, REG_GROUP_OPERATIONAL_OPERATION ) - data = [d for d in register_data if d["registerName"] == "REG_OPERATIONMODE"] + data = [d for d in register_data if d["registerName"] == REG_OPERATIONMODE] if len(data) != 1: # Operation mode not supported @@ -244,26 +247,66 @@ def get_group_operational_operation(self, device: ThermiaHeatPump): return None - def get_group_hot_water(self, device: ThermiaHeatPump): - register_data = self.__get_register_group(device.id, REG_GROUP_HOT_WATER) + def __get_switch_register_index_and_value_from_group_by_register_name( + self, register_group: list, register_name: str + ): + default_return_object = { + "registerIndex": None, + "registerValue": None, + } + + switch_data_list = [ + d for d in register_group if d["registerName"] == register_name + ] - data = [d for d in register_data if d["registerName"] == "REG_HOT_WATER_STATUS"] + if len(switch_data_list) != 1: + # Switch not supported + return default_return_object - if len(data) == 0: - # Hot water switch not supported - return None + switch_data: dict = switch_data_list[0] - data = data[0] + register_value = switch_data.get("registerValue") - device.set_register_index_hot_water_switch(data["registerIndex"]) + if not register_value: + return default_return_object - current_switch_state = int(data.get("registerValue")) - switch_states_data = data.get("valueNames") + # Validate that register is a switch + switch_states_data = switch_data.get("valueNames") - if switch_states_data is not None and len(switch_states_data) == 2: - return current_switch_state + if not switch_states_data or len(switch_states_data) != 2: + return default_return_object - return None + return { + "registerIndex": switch_data["registerIndex"], + "registerValue": int(register_value), + } + + def get_group_hot_water(self, device: ThermiaHeatPump) -> dict[str, int | None]: + register_data = self.__get_register_group(device.id, REG_GROUP_HOT_WATER) + + hot_water_switch_data = ( + self.__get_switch_register_index_and_value_from_group_by_register_name( + register_data, REG_HOT_WATER_STATUS + ) + ) + hot_water_boost_switch_data = ( + self.__get_switch_register_index_and_value_from_group_by_register_name( + register_data, REG_HOT_WATER_BOOST + ) + ) + + device.set_register_index_hot_water_switch( + hot_water_switch_data["registerIndex"] + ) + + device.set_register_index_hot_water_boost_switch( + hot_water_boost_switch_data["registerIndex"] + ) + + return { + "hot_water_switch": hot_water_switch_data["registerValue"], + "hot_water_boost_switch": hot_water_boost_switch_data["registerValue"], + } def set_temperature(self, device: ThermiaHeatPump, temperature): device_temperature_register_index = device.get_register_indexes()["temperature"] @@ -312,18 +355,26 @@ def set_operation_mode(self, device: ThermiaHeatPump, mode): def set_hot_water_switch_state( self, device: ThermiaHeatPump, state: int ): # 0 - off, 1 - on - device_hot_water_switch_state_register_index = device.get_register_indexes()[ - "hot_water_switch" - ] - if device_hot_water_switch_state_register_index is None: + register_index = device.get_register_indexes()["hot_water_switch"] + if register_index is None: _LOGGER.error( "Error setting device's hot water switch state. No hot water switch register index." ) return - self.__set_register_value( - device, device_hot_water_switch_state_register_index, state - ) + self.__set_register_value(device, register_index, state) + + def set_hot_water_boost_switch_state( + self, device: ThermiaHeatPump, state: int + ): # 0 - off, 1 - on + register_index = device.get_register_indexes()["hot_water_boost_switch"] + if register_index is None: + _LOGGER.error( + "Error setting device's hot water boost switch state. No hot water boost switch register index." + ) + return + + self.__set_register_value(device, register_index, state) def get_register_group_json(self, device_id: str, register_group: str) -> list: return self.__get_register_group(device_id, register_group) diff --git a/ThermiaOnlineAPI/const.py b/ThermiaOnlineAPI/const.py index 23809b6..92a0517 100644 --- a/ThermiaOnlineAPI/const.py +++ b/ThermiaOnlineAPI/const.py @@ -65,6 +65,26 @@ REG_COOL_SENSOR_SUPPLY = "REG_COOL_SENSOR_SUPPLY" REG_ACTUAL_POOL_TEMP = "REG_ACTUAL_POOL_TEMP" +############################################################################### +# Operational operation registers +############################################################################### + +REG_OPERATIONMODE = "REG_OPERATIONMODE" + +############################################################################### +# Operational status registers +############################################################################### + +REG_OPERATIONAL_STATUS_PRIO1 = "REG_OPERATIONAL_STATUS_PRIO1" +REG_INTEGRAL_LSD = "REG_INTEGRAL_LSD" + +############################################################################### +# Hot water registers +############################################################################### + +REG_HOT_WATER_STATUS = "REG_HOT_WATER_STATUS" +REG_HOT_WATER_BOOST = "REG_HOT_WATER_BOOST" + ############################################################################### # Operational time registers ############################################################################### diff --git a/ThermiaOnlineAPI/model/HeatPump.py b/ThermiaOnlineAPI/model/HeatPump.py index 2c2b620..a33c801 100644 --- a/ThermiaOnlineAPI/model/HeatPump.py +++ b/ThermiaOnlineAPI/model/HeatPump.py @@ -15,6 +15,8 @@ REG_DESIRED_SUPPLY_LINE, REG_DESIRED_SUPPLY_LINE_TEMP, REG_DESIRED_SYS_SUPPLY_LINE_TEMP, + REG_INTEGRAL_LSD, + REG_OPERATIONAL_STATUS_PRIO1, REG_OPER_DATA_RETURN, REG_OPER_DATA_SUPPLY_MA_SA, REG_OPER_TIME_COMPRESSOR, @@ -36,6 +38,7 @@ "temperature": None, "operation_mode": None, "hot_water_switch": None, + "hot_water_boost_switch": None, } @@ -55,7 +58,10 @@ def __init__(self, device_data: dict, api_interface: "ThermiaAPI"): self.__group_operational_status = None self.__group_operational_time = None self.__group_operational_operation = None - self.__group_hot_water = None + self.__group_hot_water: dict[str, int | None] = { + "hot_water_switch": None, + "hot_water_boost_switch": None, + } self.__alarms = None self.__historical_data_registers_map = None @@ -95,9 +101,12 @@ def get_register_indexes(self): def set_register_index_operation_mode(self, register_index: int): self.__register_indexes["operation_mode"] = register_index - def set_register_index_hot_water_switch(self, register_index: int): + def set_register_index_hot_water_switch(self, register_index: int | None): self.__register_indexes["hot_water_switch"] = register_index + def set_register_index_hot_water_boost_switch(self, register_index: int | None): + self.__register_indexes["hot_water_boost_switch"] = register_index + def set_temperature(self, temperature: int): if self.__status is None: self._LOGGER.error("Status not available, cannot set temperature") @@ -124,14 +133,29 @@ def set_operation_mode(self, mode: str): def set_hot_water_switch_state(self, state: int): self._LOGGER.info("Setting hot water switch to " + str(state)) - if self.__group_hot_water is None: + if self.__group_hot_water["hot_water_switch"] is None: self._LOGGER.error("Hot water switch not available") return - self.__group_hot_water = state # update local state before refetching data + self.__group_hot_water[ + "hot_water_switch" + ] = state # update local state before refetching data self.__api_interface.set_hot_water_switch_state(self, state) self.update_data() + def set_hot_water_boost_switch_state(self, state: int): + self._LOGGER.info("Setting hot water boost switch to " + str(state)) + + if self.__group_hot_water["hot_water_boost_switch"] is None: + self._LOGGER.error("Hot water switch not available") + return + + self.__group_hot_water[ + "hot_water_boost_switch" + ] = state # update local state before refetching data + self.__api_interface.set_hot_water_boost_switch_state(self, state) + self.update_data() + def get_all_available_register_groups(self): installation_profile_id = get_dict_value_safe( self.__info, "installationProfileId" @@ -314,9 +338,7 @@ def __get_value_by_key_and_register_name_from_operational_status( return None def __get_all_operational_statuses_from_operational_status(self) -> ChainMap | None: - data = self.__get_register_from_operational_status( - "REG_OPERATIONAL_STATUS_PRIO1" - ) + data = self.__get_register_from_operational_status(REG_OPERATIONAL_STATUS_PRIO1) if not data: return None @@ -480,9 +502,7 @@ def cooling_supply_line_temperature(self): @property def operational_status(self): - data = self.__get_register_from_operational_status( - "REG_OPERATIONAL_STATUS_PRIO1" - ) + data = self.__get_register_from_operational_status(REG_OPERATIONAL_STATUS_PRIO1) if not data: return None @@ -584,7 +604,7 @@ def operational_status_heating_status(self): @property def operational_status_integral(self): - data = self.__get_register_from_operational_status("REG_INTEGRAL_LSD") + data = self.__get_register_from_operational_status(REG_INTEGRAL_LSD) return get_dict_value_safe(data, "registerValue") ########################################################################### @@ -651,16 +671,21 @@ def is_operation_mode_read_only(self): return get_dict_value_safe(self.__group_operational_operation, "isReadOnly") ########################################################################### - # Hot water switch data + # Hot water data ########################################################################### + # TODO: DEPRECATED, remove in next major release @property def is_hot_water_switch_available(self): return self.__group_hot_water is not None @property - def hot_water_switch_state(self): - return self.__group_hot_water + def hot_water_switch_state(self) -> int | None: + return self.__group_hot_water["hot_water_switch"] + + @property + def hot_water_boost_switch_state(self) -> int | None: + return self.__group_hot_water["hot_water_boost_switch"] ########################################################################### # Alarm data diff --git a/example.py b/example.py index dff10b9..39d106f 100644 --- a/example.py +++ b/example.py @@ -2,7 +2,9 @@ from ThermiaOnlineAPI import Thermia from credentials import USERNAME, PASSWORD -CHANGE_HEAT_PUMP_DATA_DURING_TEST = False # Set to True if you want to change heat pump data during test +CHANGE_HEAT_PUMP_DATA_DURING_TEST = ( + False # Set to True if you want to change heat pump data during test +) if not USERNAME or not PASSWORD: USERNAME = input("Enter username: ") @@ -110,9 +112,8 @@ print("\n") print("Hot Water data") -print("Is Hot Water Switch Available: " + str(heat_pump.is_hot_water_switch_available)) -if heat_pump.is_hot_water_switch_available: - print("Hot Water Switch State: " + str(heat_pump.hot_water_switch_state)) +print("Hot Water Switch State: " + str(heat_pump.hot_water_switch_state)) +print("Hot Water Boost Switch State: " + str(heat_pump.hot_water_boost_switch_state)) print("\n") @@ -147,15 +148,22 @@ if CHANGE_HEAT_PUMP_DATA_DURING_TEST: heat_pump.set_temperature(19) + heat_pump.set_register_data_by_register_group_and_name( "REG_GROUP_HEATING_CURVE", "REG_HEATING_HEAT_CURVE", 30 ) + heat_pump.set_operation_mode("COMPRESSOR") - if heat_pump.is_hot_water_switch_available: + + if heat_pump.hot_water_switch_state: heat_pump.set_hot_water_switch_state(1) + if heat_pump.hot_water_boost_switch_state: + heat_pump.set_hot_water_boost_switch_state(1) + print("Heat Temperature: " + str(heat_pump.heat_temperature)) print("Operation Mode: " + str(heat_pump.operation_mode)) print("Available Operation Modes: " + str(heat_pump.available_operation_modes)) -if heat_pump.is_hot_water_switch_available: - print("Hot Water Switch State: " + str(heat_pump.hot_water_switch_state)) + +print("Hot Water Switch State: " + str(heat_pump.hot_water_switch_state)) +print("Hot Water Boost Switch State: " + str(heat_pump.hot_water_boost_switch_state))