from recommendations.Costs import Costs from recommendations.recommendation_utils import check_simulation_difference, override_costs from backend.Property import Property from etl.epc_clean.epc_attributes.MainheatControlAttributes import MainheatControlAttributes class HeatingControlRecommender: def __init__(self, property_instance: Property): self.property = property_instance self.costs = Costs(self.property) self.recommendation = [] def recommend(self, heating_description): # Reset the recommendations self.recommendation = [] # This first iteration of the recommender will provide very basic recommendation # We recommend heating controls based on the main heating system if heating_description in ["Room heaters, electric"]: self.recommend_room_heaters_electric_controls() return if heating_description in ["Electric storage heaters", "Electric storage heaters, radiators"]: self.recommend_high_heat_retention_controls() return if heating_description in ["Boiler and radiators, mains gas"]: # We can recommend roomstat programmer trvs self.recommend_roomstat_programmer_trvs() # We can also recommend time and temperature zone controls self.recommend_time_temperature_zone_controls() return def recommend_room_heaters_electric_controls(self): """ If the home has Room heaters, electric, we start by identifying potential heating controls that could be upgraded, that would provide a practical impact. This will be the least invasive improvement. We can then consider the heating system itself :return: """ if (self.property.data["mainheatc-energy-eff"] in ["Poor", "Very Poor", "Average"]) or ( self.property.main_heating_controls["clean_description"] in ["Programmer and room thermostat"] ): # We recommend Programmer and appliance thermostats as the heating control. This has an average energy # efficiency rating, and is likely to be more efficient than the current heating controls. if the # rating is poor or very poor, the home may have a Programmer and room thermostat, which is less efficient # than a Programmer and appliance thermostats, because it allows for much more granular control at not # just a room level but individual heater/appliance level # Note: A room thermostat is commonly placed in a hallway, and it measures the temperature of the air # surrounding it. It then sends a signal to the heating system to turn on or off, depending on the # temperature. An appliance thermostat, on the other hand, is placed on the heater/appliance itself, and # measures the temperature of the heater/appliance. This allows for much more granular control, and # prevents overheating. # In order to cost, we check if the property already has a programmer, and therefor we will just need to # add the cost of the appliance thermostats has_programmer = self.property.main_heating_controls["switch_system"] == "programmer" ending_config = MainheatControlAttributes("Programmer and appliance thermostats").process() # We look at what has changed in the ending config, and compare it to the current config # We use this to determine how we should be updating the config simulation_config = check_simulation_difference( new_config=ending_config, old_config=self.property.main_heating_controls ) # This upgrade will only take the heating system to average energy efficiency simulation_config["mainheatc_energy_eff_ending"] = "Good" self.recommendation.append( { "description": "upgrade heating controls to Programmer and Appliance or Smart Thermostats", **self.costs.programmer_and_appliance_thermostat(has_programmer=has_programmer), "simulation_config": simulation_config } ) # We don't implement any other recommendations right now return def recommend_high_heat_retention_controls(self): """ When applicable, we recommend upgrading the heating controls to high heat retention controls. This is a specific type of control system that is designed to work with electric storage heaters. It is a more efficient control system than the standard controls that come with electric storage heaters. We can then consider the heating system itself :return: """ # We recommend upgrading to Celect type controls ending_config = MainheatControlAttributes("Controls for high heat retention storage heaters").process() # We look at what has changed in the ending config, and compare it to the current config simulation_config = check_simulation_difference( new_config=ending_config, old_config=self.property.main_heating_controls ) # This upgrade will only take the heating system to average energy efficiency simulation_config["mainheatc_energy_eff_ending"] = "Good" self.recommendation.append( { "description": "upgrade heating controls to High Heat Retention Storage Heater Controls", **self.costs.celect_type_controls(), "simulation_config": simulation_config } ) # We don't implement any other recommendations right now return def recommend_roomstat_programmer_trvs(self): """ If the home has a boiler and radiators, mains gas, we start by identifying potential heating controls that could be upgraded, that would provide a practical impact. The criteria for recommending an upgrade to heating controls are (one of these must be true) 1) There are no controls 2) No programmer 3) No room thermostat 4) No TRVs :return: """ # We check if we have the conditions to recommend this upgrade needs_programmer = self.property.main_heating_controls["switch_system"] is None needs_room_thermostat = self.property.main_heating_controls["thermostatic_control"] is None needs_trvs = self.property.main_heating_controls["trvs"] is None can_recommend = ( (self.property.main_heating_controls["no_control"] is not None) or needs_programmer or needs_room_thermostat or needs_trvs ) if not can_recommend: return ending_config = MainheatControlAttributes("Programmer, room thermostat and TRVS").process() # We use this to determine how we should be updating the config simulation_config = check_simulation_difference( new_config=ending_config, old_config=self.property.main_heating_controls ) # This upgrade will only take the heating system to average energy efficiency # If the current system is below good, we make it good if self.property.data["mainheatc-energy-eff"] in ["Poor", "Very Poor", "Average"]: simulation_config["mainheatc_energy_eff_ending"] = "Good" has_programmer = not needs_programmer has_room_thermostat = not needs_room_thermostat has_trvs = not needs_trvs cost_result = self.costs.roomstat_programmer_trvs( number_heated_rooms=int(self.property.data["number-heated-rooms"]), has_programmer=has_programmer, has_room_thermostat=has_room_thermostat, has_trvs=has_trvs ) description = "upgrade heating controls to Room thermostat, programmer and TRVs" already_installed = "heating_control" in self.property.already_installed if already_installed: cost_result = override_costs(cost_result) description = "Heating controls have already been upgraded, no further action needed." self.recommendation.append( { "type": "heating_control", "parts": [], "description": description, **cost_result, "starting_u_value": None, "new_u_value": None, "sap_points": None, "already_installed": already_installed, "simulation_config": simulation_config } ) return def recommend_time_temperature_zone_controls(self): """ If the home has a boiler, we can recommend time and temperature zone controls. This is a more advanced and more efficient control system than the standard controls that come with a boiler. However, it may come with a higher cost and more involved usage :return: """ # We check if the efficiency of the current heating controls is good or below, and # Conditions for installation are as follows: # 1) The current heating controls are not time and temperature zone controls # 2) The current heating controls are not already at 'Very Good' or above if ( (self.property.main_heating_controls["thermostatic_control"] == "time and temperature zone control") or (self.property.data["mainheatc-energy-eff"] in ["Very Good"]) ): # No recommendation needed return ending_config = MainheatControlAttributes("Time and temperature zone control").process() # We use this to determine how we should be updating the config simulation_config = check_simulation_difference( new_config=ending_config, old_config=self.property.main_heating_controls ) # If the current system is below very good, we make it very good if self.property.data["mainheatc-energy-eff"] in ["Poor", "Very Poor", "Average", "Good"]: simulation_config["mainheatc_energy_eff_ending"] = "Very Good" cost_result = self.costs.time_and_temperature_zone_control( number_heated_rooms=int(self.property.data["number-heated-rooms"]) ) description = ("Upgrade heating controls to Smart Thermostats, room sensors and smart radiator valves (time & " "temperature zone control)") already_installed = "heating_control" in self.property.already_installed if already_installed: cost_result = override_costs(cost_result) description = "Heating controls have already been upgraded, no further action needed." self.recommendation.append( { "type": "heating_control", "parts": [], "description": description, **cost_result, "starting_u_value": None, "new_u_value": None, "sap_points": None, "already_installed": already_installed, "simulation_config": simulation_config } )