mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
255 lines
11 KiB
Python
255 lines
11 KiB
Python
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
|
|
|
|
if heating_description in ["Boiler and radiators, electric"]:
|
|
self.recommend_roomstat_programmer_trvs()
|
|
return
|
|
|
|
if heating_description in ["Air source heat pump, radiators, electric"]:
|
|
self.recommend_time_temperature_zone_controls()
|
|
|
|
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
|
|
}
|
|
)
|