Added dual heating combined recommendation

This commit is contained in:
Khalim Conn-Kowlessar 2024-09-17 09:15:31 +01:00
parent 76154c5172
commit 68fc8b8cbb
5 changed files with 360 additions and 42 deletions

View file

@ -12,8 +12,11 @@ class HeatingControlRecommender:
self.recommendation = []
def recommend(self, heating_description):
def recommend(self, heating_description, description_prefix="", description_suffix=""):
# TODO: Many of these functions are quite similar. We can possibly create a single wrapper function that
# takes in the heating description and the description prefix/suffix, and then creates the appropriate
# output
# Reset the recommendations
self.recommendation = []
@ -24,14 +27,14 @@ class HeatingControlRecommender:
return
if heating_description in ["Electric storage heaters", "Electric storage heaters, radiators"]:
self.recommend_high_heat_retention_controls()
self.recommend_high_heat_retention_controls(description_prefix=description_prefix)
return
if heating_description in ["Boiler and radiators, mains gas"]:
# We can recommend roomstat programmer trvs
self.recommend_roomstat_programmer_trvs()
self.recommend_roomstat_programmer_trvs(description_suffix=description_suffix)
# We can also recommend time and temperature zone controls
self.recommend_time_temperature_zone_controls()
self.recommend_time_temperature_zone_controls(description_suffix=description_suffix)
return
@ -94,16 +97,22 @@ class HeatingControlRecommender:
# We don't implement any other recommendations right now
return
def recommend_high_heat_retention_controls(self):
def recommend_high_heat_retention_controls(self, description_prefix=""):
"""
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
If there is a description prefix, this means there is a dual heating system and so we need to add this to the
description
:return:
"""
new_description = "Controls for high heat retention storage heaters"
if description_prefix:
new_description = f"{description_prefix}, {new_description}"
# We recommend upgrading to Celect type controls
ending_config = MainheatControlAttributes(new_description).process()
@ -112,7 +121,10 @@ class HeatingControlRecommender:
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"
if self.property.data["mainheatc-energy-eff"] in ["Poor", "Very Poor", "Average"]:
simulation_config["mainheatc_energy_eff_ending"] = "Good"
else:
simulation_config["mainheatc_energy_eff_ending"] = self.property.data["mainheatc-energy-eff"]
description_simulation = {
"mainheatcont-description": new_description,
@ -131,7 +143,7 @@ class HeatingControlRecommender:
# We don't implement any other recommendations right now
return
def recommend_roomstat_programmer_trvs(self):
def recommend_roomstat_programmer_trvs(self, description_suffix=""):
"""
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.
@ -163,6 +175,8 @@ class HeatingControlRecommender:
return
new_controls_description = "Programmer, room thermostat and TRVS"
if description_suffix:
new_controls_description = f"{new_controls_description}, {description_suffix}"
ending_config = MainheatControlAttributes(new_controls_description).process()
# We use this to determine how we should be updating the config
@ -216,7 +230,7 @@ class HeatingControlRecommender:
return
def recommend_time_temperature_zone_controls(self):
def recommend_time_temperature_zone_controls(self, description_suffix=""):
"""
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
@ -238,6 +252,8 @@ class HeatingControlRecommender:
return
new_controls_description = "Time and temperature zone control"
if description_suffix:
new_controls_description = f"{new_controls_description}, {description_suffix}"
ending_config = MainheatControlAttributes(new_controls_description).process()
@ -260,8 +276,10 @@ class HeatingControlRecommender:
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)")
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:

View file

@ -1,5 +1,7 @@
from recommendations.Costs import Costs, BOILER_UPGRADE_SCHEME_ASHP_VALUE
from recommendations.recommendation_utils import check_simulation_difference, override_costs
from recommendations.recommendation_utils import (
check_simulation_difference, override_costs, combine_recommendation_configs
)
from backend.Property import Property
from backend.app.plan.schemas import MEASURE_MAP
from etl.epc_clean.epc_attributes.MainheatAttributes import MainHeatAttributes
@ -11,6 +13,37 @@ from recommendations.HeatingControlRecommender import HeatingControlRecommender
class HeatingRecommender:
high_heat_retention_contols_desc = "Controls for high heat retention storage heaters"
DUAL_HEATING_DESCRIPTIONS = {
"Boiler and radiators, mains gas, electric storage heaters": {
"hhr": {
"mainheating_description": "Boiler and radiators, mains gas, Electric storage heaters",
"recommendation_description": "Install high heat retention electric storage heaters alongside the "
"boiler. The current electric heaters may be retrofit with high heat "
"retention storage controls"
" however this is dependent on the existing system and may not be "
"possible.",
"controls_prefix": "current_controls"
},
"boiler": {
"mainheating_description": "Boiler and radiators, mains gas, electric storage heaters",
"recommendation_description": "Upgrade the existing boiler to a new, more efficient condensing "
"boiler. ",
"controls_suffix": "Manual charge controls"
},
# These are the heating types we need to produce a dual heating recommendation
"dual": {
"recommendation_description": "Upgrade both the existing boiler to a new condensing boiler and"
"upgrade storage heaters to high heat retention storage heaters.",
"types": [
# type 1
"boiler_upgrade",
# type 2
"high_heat_retention_storage_heater",
]
}
}
}
def __init__(self, property_instance: Property):
self.property = property_instance
self.costs = Costs(self.property)
@ -20,10 +53,34 @@ class HeatingRecommender:
self.has_electric_heating_description = self.property.main_heating["has_electric"]
self.has_ashp = self.property.main_heating["has_air_source_heat_pump"]
self.has_room_heaters = (
self.property.main_heating["has_room_heaters"] or
self.property.main_heating["has_portable_electric_heaters"]
)
self.has_boiler = self.property.main_heating["has_boiler"]
self.dual_heating = self.identify_dual_heating()
def identify_dual_heating(self):
# All heat systems are in here so we identify whether two of these are true
# MainHeatAttributes.HEAT_SYSTEMS
n_trues = 0
for heat_system in MainHeatAttributes.HEAT_SYSTEMS:
if self.property.main_heating[f"has_{heat_system.replace(' ', '_')}"]:
n_trues += 1
if n_trues > 2 or n_trues == 0:
raise Exception("Implement me")
if n_trues == 1:
return False
return True
def is_high_heat_retention_valid(self, ashp_only_heating_recommendation, measures):
"""
Check conditions if high heat retention storage is valid
If there's already an ASHP in place, we don't recommend HHR
:return:
"""
@ -32,8 +89,6 @@ class HeatingRecommender:
hhr_suitable = no_mains or self.has_electric_heating_description
# If there's already an ASHP in place, we don't recommend HHR
return (
hhr_suitable and (not ashp_only_heating_recommendation) and not self.has_ashp and
("high_heat_retention_storage_heater" in measures)
@ -47,7 +102,7 @@ class HeatingRecommender:
# 1) if the property has mains heating with boiler and radiators, we recommend optimal heating controls
# If it's NOT a gas boiler, we'll potentially recommend a boiler
has_gas_boiler = self.property.main_heating["has_boiler"] and self.property.main_heating["has_mains_gas"]
has_gas_boiler = self.has_boiler and self.property.main_heating["has_mains_gas"]
# 2) If the property doesn't have a heating system, but it has access to the mains gas
no_heating_has_mains = self.property.main_heating["clean_description"] in [
@ -55,21 +110,13 @@ class HeatingRecommender:
] and self.property.data["mains-gas-flag"]
# The property is using portable heaters and has access to gas mains
has_room_heaters = (
(
self.property.main_heating["has_room_heaters"] or
self.property.main_heating["has_portable_electric_heaters"]
) and
self.property.data["mains-gas-flag"]
)
has_room_heaters = self.has_room_heaters and self.property.data["mains-gas-flag"]
# We also check if the property has electric heating, but it has access to the mains gas
electic_heating_has_mains = self.has_electric_heating_description and self.property.data["mains-gas-flag"]
portable_heaters_has_mains = (
self.property.main_heating["clean_description"] in ["Portable electric heaters assumed for most rooms"]
and
self.property.data["mains-gas-flag"]
self.property.main_heating["has_portable_electric_heaters"] and self.property.data["mains-gas-flag"]
)
# The next condition is if the home has a non-gas boiler, such as an oil boiler, with a mains gas connection
@ -95,6 +142,55 @@ class HeatingRecommender:
return is_valid, has_gas_boiler
def recommend_dual_heating(self):
if self.property.main_heating["clean_description"] not in self.DUAL_HEATING_DESCRIPTIONS:
return
dual_heating_description = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["dual"]["types"]
recommendation_system_types = list(set([x["system_type"] for x in self.heating_recommendations]))
# We check if we have the required type
if not any([x in recommendation_system_types for x in dual_heating_description]):
return
type_1_recommendations = [
x for x in self.heating_recommendations if x["system_type"] == dual_heating_description[0]
]
type_2_recommendations = [
x for x in self.heating_recommendations if x["system_type"] == dual_heating_description[1]
]
# we combine the two recommendations
combined_recommendations = []
for rec in type_1_recommendations:
for rec2 in type_2_recommendations:
combined_rec = rec.copy()
# Update the description
combined_rec["description"] = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["dual"]["recommendation_description"]
# Combine simulation_config
# Make sure we end up with the best efficiecy values
combined_rec["simulation_config"] = combine_recommendation_configs(
rec["simulation_config"], rec2["simulation_config"]
)
# Combine description_simulation
combined_rec["description_simulation"] = combine_recommendation_configs(
rec["description_simulation"], rec2["description_simulation"]
)
# Combine costs
for k in ["total", "subtotal", "vat", "labour_hours", "labour_days"]:
combined_rec[k] = rec[k] + rec2[k]
combined_recommendations.append(combined_rec)
self.heating_recommendations.extend(combined_recommendations)
def recommend(self, has_cavity_or_loft_recommendations, phase=0, measures=None):
"""
Produces heating recommendations
@ -144,14 +240,16 @@ class HeatingRecommender:
# This indicates that the home previously did not have a boiler in place and so would require
# an overhaul to the system - right now, this is all reasons, apart from if there is an existing boiler
system_change = not has_gas_boiler
exising_room_heaters = self.property.main_heating["clean_description"] in [
"Room heaters, electric", "Room heaters, mains gas"
]
exising_room_heaters = self.property.main_heating["has_room_heaters"]
self.recommend_boiler_upgrades(
phase=phase, system_change=system_change, exising_room_heaters=exising_room_heaters
)
# If we have dual heating and we allow for a combined recommendation, to upgrade both systems
if self.dual_heating:
self.recommend_dual_heating(phase=phase, measures=measures)
# We recommend air source heat pumps
# Heat pumps are suitable for all property types:
# https://energysavingtrust.org.uk/from-flats-to-terraced-houses-heat-pumps-are-suitable-for-all-property-types/
@ -424,7 +522,8 @@ class HeatingRecommender:
description,
phase,
heating_controls_only,
system_change
system_change,
system_type
):
"""
Given a recommendation for heating controls, and a recommendation for the heating system, we combine the two
@ -439,6 +538,7 @@ class HeatingRecommender:
:param system_change: Indicates if we are recommending a different type of heating system, compared to the
current system. If we have a system change and we have a heat control recommendation, we only recommend
both heating and controls together
:param system_type: The type of heating system we are recommending
:return:
"""
@ -494,7 +594,9 @@ class HeatingRecommender:
"already_installed": already_installed,
**total_costs,
"simulation_config": recommendation_simulation_config,
"description_simulation": recommendation_description_simulation
"description_simulation": recommendation_description_simulation,
# We insert the heating system type here
"system_type": system_type
}
output.append(recommendation)
@ -572,7 +674,19 @@ class HeatingRecommender:
# We only recommend Celect-type controls if the current heating system is not Celect-type controls
if self.property.main_heating_controls["clean_description"] != self.high_heat_retention_contols_desc:
controls_recommender.recommend(heating_description="Electric storage heaters, radiators")
if self.dual_heating:
if self.DUAL_HEATING_DESCRIPTIONS[self.property.main_heating["clean_description"]]["hhr"][
"controls_prefix"
] == "current_controls":
description_prefix = self.property.main_heating_controls["clean_description"]
else:
raise NotImplementedError("Implement me")
else:
description_prefix = ""
controls_recommender.recommend(
heating_description="Electric storage heaters, radiators", description_prefix=description_prefix
)
has_hhr = self.is_hhr_already_installed()
# Conditions for not recommending electric storage heaters
@ -580,7 +694,13 @@ class HeatingRecommender:
# No recommendation needed
return
new_heating_description = "Electric storage heaters, radiators"
# We check if the property has dual heating in place with a boiler and storage heaters
if self.dual_heating:
new_heating_description = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["hhr"]["mainheating_description"]
else:
new_heating_description = "Electric storage heaters, radiators"
# Set up artefacts, suitable for the simulation and regardless of controls
heating_ending_config = MainHeatAttributes(new_heating_description).process()
@ -588,7 +708,10 @@ class HeatingRecommender:
new_config=heating_ending_config, old_config=self.property.main_heating
)
# This upgrade will only take the heating system to average energy efficiency
heating_simulation_config["mainheat_energy_eff_ending"] = "Average"
if self.property.data["mainheat-energy-eff"] in ["Very Poor", "Poor"]:
heating_simulation_config["mainheat_energy_eff_ending"] = "Average"
else:
heating_simulation_config["mainheat_energy_eff_ending"] = self.property.data["mainheat-energy-eff"]
# If the property is off-gas and has no heating system in place, the number of heated rooms will actually
# be 0, so we use the number of rooms as the figure
@ -603,7 +726,13 @@ class HeatingRecommender:
costs = self.costs.high_heat_electric_storage_heaters(
number_heated_rooms=number_heated_rooms
)
description = "Install high heat retention electric storage heaters."
if self.dual_heating:
description = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["hhr"]["recommendation_description"]
else:
description = "Install high heat retention electric storage heaters."
# We check the existing heating system and controls
if (
@ -627,7 +756,8 @@ class HeatingRecommender:
description=description,
phase=phase,
heating_controls_only=heating_controls_only,
system_change=system_change
system_change=system_change,
system_type="high_heat_retention_storage_heater"
)
if _return:
return recommendations
@ -721,11 +851,26 @@ class HeatingRecommender:
num_heated_rooms=self.property.data["number-heated-rooms"],
)
description = "Upgrade to a new condensing boiler"
if self.dual_heating:
description = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["boiler"]["recommendation_description"]
else:
description = "Upgrade to a new condensing boiler"
new_heating_eff = (
"Good" if self.property.data["mainheat-energy-eff"] in ["Very Poor", "Poor", "Average"]
else self.property.data["mainheat-energy-eff"]
)
new_hotwater_eff = (
"Good" if self.property.data["hot-water-energy-eff"] in ["Very Poor", "Poor", "Average"]
else self.property.data["hot-water-energy-eff"]
)
simulation_config = {
"mainheat_energy_eff_ending": "Good",
"hot_water_energy_eff_ending": "Good"
"mainheat_energy_eff_ending": new_heating_eff,
"hot_water_energy_eff_ending": new_hotwater_eff
}
description_simulation = {
@ -736,7 +881,13 @@ class HeatingRecommender:
if system_change:
# Installation of a boiler improves the hot water system so we need to reflect this in
# the outcome of the recommendation
new_heating_description = "Boiler and radiators, mains gas"
if self.dual_heating:
new_heating_description = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["boiler"]["mainheating_description"]
else:
new_heating_description = "Boiler and radiators, mains gas"
new_hotwater_description = "From main system"
new_fuel_description = "mains gas (not community)"
@ -794,13 +945,23 @@ class HeatingRecommender:
"already_installed": already_installed,
"simulation_config": simulation_config,
"description_simulation": description_simulation,
**boiler_costs
**boiler_costs,
"system_type": "boiler_upgrade",
}
# We recommend the heating controls
# If the property did not previously have a boiler, we combine
controls_recommender = HeatingControlRecommender(self.property)
controls_recommender.recommend(heating_description="Boiler and radiators, mains gas")
if self.dual_heating:
description_suffix = self.DUAL_HEATING_DESCRIPTIONS[
self.property.main_heating["clean_description"]
]["boiler"]["controls_suffix"]
else:
description_suffix = ""
controls_recommender.recommend(
heating_description="Boiler and radiators, mains gas",
description_suffix=description_suffix
)
# We may have 2 recommendations from the heating controls
if not controls_recommender.recommendation and not boiler_recommendation:
@ -822,7 +983,8 @@ class HeatingRecommender:
description=boiler_recommendation["description"],
phase=recommendation_phase,
heating_controls_only=False,
system_change=True
system_change=True,
system_type="boiler_upgrade"
)
combined_recommendations.extend(combined_recommendation)

View file

@ -800,3 +800,44 @@ def override_costs(costs):
costs[k] = 0
return costs
def combine_recommendation_configs(recommendation_config1, recommendation_config2):
"""
Given two simulation configs, this function will combine them into one
:param recommendation_config1:
:param recommendation_config2:
:return:
"""
# Efficiency values - keys which contain _energy_eff_ending
eff_1 = {
k: v for k, v in recommendation_config1.items() if ("_energy_eff_ending" in k) or ("-energy-eff" in k)
}
eff_2 = {
k: v for k, v in recommendation_config2.items() if ("_energy_eff_ending" in k) or ("-energy-eff" in k)
}
# We combine the simulation configs
combined = {
**recommendation_config1,
**recommendation_config2
}
# Find overlapping keys
overlapping_keys = set(eff_1.keys()).intersection(set(eff_2.keys()))
if overlapping_keys:
# We make sure we take the best value - map efficiency values to numbers
numerical_embedding = {
"Very poor": 1,
"Poor": 2,
"Average": 3,
"Good": 4,
"Very good": 5,
}
for key in overlapping_keys:
if numerical_embedding[eff_1[key]] >= numerical_embedding[eff_2[key]]:
combined[key] = eff_1[key]
else:
combined[key] = eff_2[key]
return combined

View file

@ -1066,6 +1066,99 @@ testing_examples = [
"heating_recommendation_descriptions": [],
"heating_controls_recommendation_descriptions": [],
"notes": "This property already has an ashp. We don't recommend any heating upgrades"
},
{
"epc": {
'lmk-key': '1dd9aa80d6e5bae3e0e4892d9ed1a83b53f3af848568f4a928c9f7a63d8825ea',
'address1': '49 Ridgeway Road', 'address2': 'Wordsley', 'address3': None, 'postcode': 'DY8 5UD',
'building-reference-number': 10003464876, 'current-energy-rating': 'F', 'potential-energy-rating': 'D',
'current-energy-efficiency': 35, 'potential-energy-efficiency': 64, 'property-type': 'House',
'built-form': 'Semi-Detached', 'inspection-date': '2021-11-17', 'local-authority': 'E08000027',
'constituency': 'E14000672', 'county': None, 'lodgement-date': '2022-10-10', 'transaction-type': 'rental',
'environment-impact-current': 41, 'environment-impact-potential': 67, 'energy-consumption-current': 401,
'energy-consumption-potential': 207, 'co2-emissions-current': 6.1, 'co2-emiss-curr-per-floor-area': 69,
'co2-emissions-potential': 3.2, 'lighting-cost-current': 61, 'lighting-cost-potential': 61,
'heating-cost-current': 1488, 'heating-cost-potential': 1015, 'hot-water-cost-current': 114,
'hot-water-cost-potential': 77, 'total-floor-area': 89.0, 'energy-tariff': 'Single', 'mains-gas-flag': 'Y',
'floor-level': None, 'flat-top-storey': None, 'flat-storey-count': None, 'main-heating-controls': None,
'multi-glaze-proportion': 100.0, 'glazed-type': 'double glazing installed during or after 2002',
'glazed-area': 'Normal', 'extension-count': 2, 'number-habitable-rooms': 5, 'number-heated-rooms': 5,
'low-energy-lighting': 91, 'number-open-fireplaces': 0, 'hotwater-description': 'From main system',
'hot-water-energy-eff': 'Good', 'hot-water-env-eff': 'Good',
'floor-description': 'Solid, no insulation (assumed)', 'floor-energy-eff': None,
'windows-description': 'Fully double glazed', 'windows-energy-eff': 'Good', 'windows-env-eff': 'Good',
'walls-description': 'Cavity wall, as built, no insulation (assumed)', 'walls-energy-eff': 'Poor',
'walls-env-eff': 'Poor', 'secondheat-description': 'Room heaters, electric',
'roof-description': 'Pitched, 200 mm loft insulation', 'roof-energy-eff': 'Good', 'roof-env-eff': 'Good',
'mainheat-description': 'Boiler and radiators, mains gas, Electric storage heaters',
'mainheat-energy-eff': 'Good', 'mainheat-env-eff': 'Good',
'mainheatcont-description': 'Programmer, room thermostat and TRVs', 'mainheatc-energy-eff': 'Good',
'mainheatc-env-eff': 'Good', 'lighting-description': 'Low energy lighting in 91% of fixed outlets',
'lighting-energy-eff': 'Very Good', 'lighting-env-eff': 'Very Good',
'main-fuel': 'mains gas (not community)', 'wind-turbine-count': 0, 'heat-loss-corridor': None,
'unheated-corridor-length': None, 'floor-height': 2.53, 'photo-supply': 0.0,
'solar-water-heating-flag': 'N',
'mechanical-ventilation': 'natural', 'address': '49 Ridgeway Road, Wordsley',
'local-authority-label': 'Dudley', 'constituency-label': 'Dudley South', 'posttown': 'Stourbridge',
'construction-age-band': 'England and Wales: 1950-1966', 'lodgement-datetime': '2022-10-10 16:41:36',
'tenure': 'Rented (social)', 'fixed-lighting-outlets-count': 11.0, 'low-energy-fixed-light-count': None,
'uprn': 90041166, 'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
},
"heating_recommendation_descriptions": [
'Install an air source heat pump, and upgrade heating controls to Smart Thermostats, room sensors and '
'smart radiator valves (time & temperature zone control). The cost includes the £7500 boiler upgrade '
'scheme grant',
'Install high heat retention electric storage heaters alongside the boiler. The current electric heaters '
'may be retrofit with high heat retention storage controls however this is dependent on the existing '
'system and may not be possible. Upgrade heating controls to High Heat Retention Storage Heater Controls'
],
"heating_controls_recommendation_descriptions": [],
"notes": "This property has dual heating. A boiler and electric storage heaters. The heating is efficient so"
"we recommend ASHP and HHR"
},
{
"epc": {
'lmk-key': '1dd9aa80d6e5bae3e0e4892d9ed1a83b53f3af848568f4a928c9f7a63d8825ea',
'address1': '49 Ridgeway Road', 'address2': 'Wordsley', 'address3': None, 'postcode': 'DY8 5UD',
'building-reference-number': 10003464876, 'current-energy-rating': 'F', 'potential-energy-rating': 'D',
'current-energy-efficiency': 35, 'potential-energy-efficiency': 64, 'property-type': 'House',
'built-form': 'Semi-Detached', 'inspection-date': '2021-11-17', 'local-authority': 'E08000027',
'constituency': 'E14000672', 'county': None, 'lodgement-date': '2022-10-10', 'transaction-type': 'rental',
'environment-impact-current': 41, 'environment-impact-potential': 67, 'energy-consumption-current': 401,
'energy-consumption-potential': 207, 'co2-emissions-current': 6.1, 'co2-emiss-curr-per-floor-area': 69,
'co2-emissions-potential': 3.2, 'lighting-cost-current': 61, 'lighting-cost-potential': 61,
'heating-cost-current': 1488, 'heating-cost-potential': 1015, 'hot-water-cost-current': 114,
'hot-water-cost-potential': 77, 'total-floor-area': 89.0, 'energy-tariff': 'Single', 'mains-gas-flag': 'Y',
'floor-level': None, 'flat-top-storey': None, 'flat-storey-count': None, 'main-heating-controls': None,
'multi-glaze-proportion': 100.0, 'glazed-type': 'double glazing installed during or after 2002',
'glazed-area': 'Normal', 'extension-count': 2, 'number-habitable-rooms': 5, 'number-heated-rooms': 5,
'low-energy-lighting': 91, 'number-open-fireplaces': 0, 'hotwater-description': 'From main system',
'hot-water-energy-eff': 'Good', 'hot-water-env-eff': 'Good',
'floor-description': 'Solid, no insulation (assumed)', 'floor-energy-eff': None,
'windows-description': 'Fully double glazed', 'windows-energy-eff': 'Good', 'windows-env-eff': 'Good',
'walls-description': 'Cavity wall, as built, no insulation (assumed)', 'walls-energy-eff': 'Poor',
'walls-env-eff': 'Poor', 'secondheat-description': 'Room heaters, electric',
'roof-description': 'Pitched, 200 mm loft insulation', 'roof-energy-eff': 'Good', 'roof-env-eff': 'Good',
'mainheat-description': 'Boiler and radiators, mains gas, Electric storage heaters',
'mainheat-energy-eff': 'Average', 'mainheat-env-eff': 'Good',
'mainheatcont-description': 'Programmer, room thermostat and TRVs', 'mainheatc-energy-eff': 'Good',
'mainheatc-env-eff': 'Good', 'lighting-description': 'Low energy lighting in 91% of fixed outlets',
'lighting-energy-eff': 'Very Good', 'lighting-env-eff': 'Very Good',
'main-fuel': 'mains gas (not community)', 'wind-turbine-count': 0, 'heat-loss-corridor': None,
'unheated-corridor-length': None, 'floor-height': 2.53, 'photo-supply': 0.0,
'solar-water-heating-flag': 'N',
'mechanical-ventilation': 'natural', 'address': '49 Ridgeway Road, Wordsley',
'local-authority-label': 'Dudley', 'constituency-label': 'Dudley South', 'posttown': 'Stourbridge',
'construction-age-band': 'England and Wales: 1950-1966', 'lodgement-datetime': '2022-10-10 16:41:36',
'tenure': 'Rented (social)', 'fixed-lighting-outlets-count': 11.0, 'low-energy-fixed-light-count': None,
'uprn': 90041166, 'uprn-source': 'Energy Assessor', 'sheating-energy-eff': None, 'sheating-env-eff': None
},
"heating_recommendation_descriptions": [
],
"heating_controls_recommendation_descriptions": [],
"notes": "This property is a modified version of the previous dual heating property, where we lower the"
"starting heating efficiency so that we a combined heating upgrade to both the boiler and the electric"
"storage heaters"
}
]
@ -1125,6 +1218,8 @@ completed_descriptions = [
"Boiler and radiators, smokeless fuel",
"Boiler and radiators, wood pellets",
"Room heaters, dual fuel (mineral and wood)",
"Air source heat pump, radiators, electric",
"Portable electric heaters assumed for most rooms, Room heaters, electric",
]
portfolio = pd.read_excel(
@ -1139,7 +1234,7 @@ portfolio["lodgement-datetime"] = portfolio["lodgement-datetime"].astype(str)
print(portfolio["mainheat-description"].value_counts())
eg = portfolio[
(portfolio["mainheat-description"] == "Air source heat pump, radiators, electric")
(portfolio["mainheat-description"] == "Boiler and radiators, mains gas, Electric storage heaters")
].sample(1)
eg = eg.squeeze().to_dict()
print(eg)

View file

@ -53,6 +53,8 @@ class TestHeatingRecommendations:
we retrieve alongside them
:return:
"""
if test_case["epc"]["uprn"] == 90041166:
raise Exception("Finish the second test case with this uprn")
epc_records = {"original_epc": test_case["epc"].copy(), "full_sap_epc": {}, "old_data": []}