from backend.Property import Property from recommendations.Costs import Costs from recommendations.recommendation_utils import override_costs, check_simulation_difference, check_use_survey from etl.epc_clean.epc_attributes.HotWaterAttributes import HotWaterAttributes class HotwaterRecommendations: def __init__(self, property_instance: Property): self.property = property_instance self.costs = Costs(self.property) self.recommendations = [] def recommend(self, phase): """ There are maybe a number of recommendations that are simultaneously applicable to the property. If this is true then the phase may need to be incrememnted from within this recommendation :param phase: :return: """ # Reset the recommendations recommendations_phase = phase self.recommendations = [] non_invasive_recommendations = self.property.non_invasive_recommendations if non_invasive_recommendations: measures = [ r["type"] for r in non_invasive_recommendations if r["type"] in ["hot_water_tank_insulation", "cylinder_thermostat"] ] for m in measures: non_invasive_rec = [ r for r in non_invasive_recommendations if r["type"] == m ][0] if m == "hot_water_tank_insulation": # We need to be able to stack these recommendations self.recommend_tank_insulation( phase=recommendations_phase, sap_points=non_invasive_rec["sap_points"], survey=check_use_survey(non_invasive_rec, self.property.epc_record.has_been_remodelled), ) recommendations_phase += 1 elif m == "cylinder_thermostat": self.recommend_cylinder_thermostat( phase=recommendations_phase, sap_points=non_invasive_rec["sap_points"], survey=check_use_survey(non_invasive_rec, self.property.epc_record.has_been_remodelled), ) recommendations_phase += 1 # This first iteration of the recommender will provide very basic recommendation # We recommend heating controls based on the main heating system if self.property.hotwater["clean_description"] == "Gas boiler/circulator, no cylinder thermostat": # Handle this case specifically: self.recommend_cylinder_thermostat_gas_boiler_circulator(phase=recommendations_phase) return # If there is no system present, but access to the mains, we has_tank_recommendation = [r for r in self.recommendations if r["type"] == "hot_water_tank_insulation"] if ( (self.property.hotwater["heater_type"] in ["electric immersion"]) & (self.property.epc_record.hot_water_energy_eff == "Very Poor") & (self.property.hotwater["no_system_present"] is None) & (len(has_tank_recommendation) == 0) ): self.recommend_tank_insulation(phase=recommendations_phase) return has_cylinder_recommendation = [r for r in self.recommendations if r["type"] == "cylinder_thermostat"] if ((self.property.hotwater["clean_description"] == "From main system, no cylinder thermostat") & (len(has_cylinder_recommendation) == 0)): self.recommend_cylinder_thermostat(phase=recommendations_phase) return def recommend_tank_insulation(self, phase, sap_points=None, survey=False, _return=False): """ If the home has a very poor hot water system, this is often indicative of a lack of insulation on the hot water tank. This is a very simple and cost effective improvement that can be made to the home. It will likely take the efficiency from very poor to poor. """ recommendation_cost = self.costs.hot_water_tank_insulation() already_installed = "hot_water_tank_insulation" in self.property.already_installed if already_installed: recommendation_cost = override_costs(recommendation_cost) description = "Insulation tank has already been insulated, no further action required" else: description = "Insulate hot water tank" to_append = { "phase": phase, "parts": [], "type": "hot_water_tank_insulation", "measure_type": "hot_water_tank_insulation", "description": description, "starting_u_value": None, "new_u_value": None, "sap_points": sap_points, "already_installed": already_installed, **recommendation_cost, "simulation_config": {"hot_water_energy_eff_ending": "Poor"}, "description_simulation": { "hot-water-energy-eff": "Poor" }, "survey": survey, "innovation_rate": 0 } if _return: return to_append self.recommendations.append(to_append) return def recommend_cylinder_thermostat(self, phase, sap_points=None, survey=False, _return=False): """ If the home has a very poor hot water system, this is often indicative of a lack of insulation on the hot water tank. This is a very simple and cost effective improvement that can be made to the home. """ recommendation_cost = self.costs.cylinder_thermostat() already_installed = "cylinder_thermostat" in self.property.already_installed if already_installed: recommendation_cost = override_costs(recommendation_cost) description = "Cylinder thermostat has already been installed, no further action required" else: description = "Install a smart cylinder thermostat on the hot water tank" new_epc_description = "From main system" hotwater_ending_config = HotWaterAttributes(new_epc_description).process() hotwater_simulation_config = check_simulation_difference( new_config=hotwater_ending_config, old_config=self.property.hotwater ) simulation_config = { "hot_water_energy_eff_ending": self.property.epc_record.hot_water_energy_eff, **hotwater_simulation_config } to_append = { "phase": phase, "parts": [], "type": "cylinder_thermostat", "measure_type": "cylinder_thermostat", "description": description, "starting_u_value": None, "new_u_value": None, "sap_points": sap_points, "already_installed": already_installed, **recommendation_cost, "simulation_config": simulation_config, "description_simulation": { "hot-water-energy-eff": self.property.epc_record.hot_water_energy_eff, "hotwater-description": new_epc_description, }, "survey": survey, "innovation_rate": 0 } if _return: return to_append self.recommendations.append(to_append) return def recommend_cylinder_thermostat_gas_boiler_circulator(self, phase): """ If the home has a very poor hot water system, this is often indicative of a lack of insulation on the hot water tank. This is a very simple and cost effective improvement that can be made to the home. """ thermostat_recommendation_cost = self.costs.cylinder_thermostat() cylinder_recommendation_cost = self.costs.hot_water_tank_insulation() # Add them total_cost = { k: thermostat_recommendation_cost[k] + cylinder_recommendation_cost[k] for k in thermostat_recommendation_cost.keys() } already_installed = "cylinder_thermostat" in self.property.already_installed if already_installed: total_cost = override_costs(total_cost) description = "Cylinder thermostat & insulation has already been installed, no further action required" else: description = "Install a smart cylinder thermostat and insulate the hot water tank with 80mm insulation" new_epc_description = "From main system" hotwater_ending_config = HotWaterAttributes(new_epc_description).process() hotwater_simulation_config = check_simulation_difference( new_config=hotwater_ending_config, old_config=self.property.hotwater ) if self.property.epc_record.hot_water_energy_eff in ["Very Poor", "Poor", "Average"]: new_efficiency = "Good" else: new_efficiency = self.property.epc_record.hot_water_energy_eff simulation_config = { "hot_water_energy_eff_ending": new_efficiency, **hotwater_simulation_config } to_append = { "phase": phase, "parts": [], "type": "cylinder_thermostat", "measure_type": "cylinder_thermostat", "description": description, "starting_u_value": None, "new_u_value": None, "sap_points": None, "already_installed": already_installed, **total_cost, "simulation_config": simulation_config, "description_simulation": { "hot-water-energy-eff": simulation_config["hot_water_energy_eff_ending"], "hotwater-description": new_epc_description, }, "survey": False, "innovation_rate": 0 } self.recommendations.append(to_append) return