From 2331228ff6365b010205e256c8d54230c461b086 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Tue, 3 Feb 2026 15:04:29 +0000 Subject: [PATCH] working through mapping heating --- backend/onboarders/epc/placeholder.py | 6 +++ backend/onboarders/parity.py | 72 +++++++++++++++++++++------ 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/backend/onboarders/epc/placeholder.py b/backend/onboarders/epc/placeholder.py index ba18a303..2d52d4ad 100644 --- a/backend/onboarders/epc/placeholder.py +++ b/backend/onboarders/epc/placeholder.py @@ -3,11 +3,17 @@ from enum import Enum class EpcFuel(Enum): electricity_not_community = "electricity (not community)" + lpg_not_community = "LPG (not community)" + mains_gas_not_community = "mains gas (not community)" class EpcHeatingControls(Enum): programmer_room_thermostat_trvs = "Programmer, room thermostat and TRVs" + programmers_trvs_bypass = "Programmer, TRVs and bypass" + time_and_temperature_zone_control = "Time and temperature zone control" class EpcHeatingSystems(Enum): boiler_and_radiators_electric = "Boiler and radiators, electric" + boiler_and_radiators_lpg = "Boiler and radiators, LPG" + boiler_radiators_mains_gas = "Boiler and radiators, mains gas" diff --git a/backend/onboarders/parity.py b/backend/onboarders/parity.py index b1d3e88a..3ca54cab 100644 --- a/backend/onboarders/parity.py +++ b/backend/onboarders/parity.py @@ -469,22 +469,65 @@ agg = data.groupby(['Heating', 'Boiler Efficiency', 'Main Fuel', 'Controls Adequ # 2) Heating efficiency # 3) Fuel type # 4) Heating controls +# 5) Heating controls efficiency + +# TODO - when mapping heating controls, we should check the existing heating controls and the efficiency rating +# For sub optimal heating controls, we're going to make an assumption as to what the heating controls are +# and the energy efficiency rating we prescribe here may not be accurate. We therefore use this as an upper limit +# as opposed to a guaranteed efficiency rating. To stress, this is only relevant for sub optimal heating +# controls. + +# Boiler ratings based on efficiency +# 90%+ = A +# 86-89.9% = B -> Mapped to good efficiency +# 78 - 85% = C +# 70 - 77.9% = D +# 65 - 69.9% = E +# 60 - 64.9% = F +# <60% = G heating_map = { ('Boilers', 'A', 'ElectricityNotCommunity', 'Optimal'): ( EpcHeatingSystems.boiler_and_radiators_electric, EpcEfficiency.VERY_POOR, EpcFuel.electricity_not_community, - EpcHeatingControls.programmer_room_thermostat_trvs + EpcHeatingControls.programmer_room_thermostat_trvs, EpcEfficiency.GOOD + ), + ('Boilers', 'A', 'ElectricityNotCommunity', 'Sub Optimal'): ( + EpcHeatingSystems.boiler_and_radiators_electric, EpcEfficiency.VERY_POOR, EpcFuel.electricity_not_community, + EpcHeatingControls.programmers_trvs_bypass, EpcEfficiency.AVERAGE + ), + ('Boilers', 'A', 'ElectricityNotCommunity', 'Top Spec'): ( + EpcHeatingSystems.boiler_and_radiators_electric, EpcEfficiency.VERY_POOR, EpcFuel.electricity_not_community, + EpcHeatingControls.time_and_temperature_zone_control, EpcEfficiency.VERY_GOOD + ), + ('Boilers', 'A', 'LPGNotCommunity', 'Optimal'): ( + EpcHeatingSystems.boiler_and_radiators_lpg, EpcEfficiency.POOR, EpcFuel.lpg_not_community, + EpcHeatingControls.programmer_room_thermostat_trvs, EpcEfficiency.GOOD + ), + ('Boilers', 'A', 'MainsGasNotCommunity', 'Optimal'): ( + EpcHeatingSystems.boiler_radiators_mains_gas, EpcEfficiency.GOOD, EpcFuel.mains_gas_not_community, + EpcHeatingControls.programmer_room_thermostat_trvs, EpcEfficiency.GOOD + ), + ('Boilers', 'A', 'MainsGasNotCommunity', 'Sub Optimal'): ( + EpcHeatingSystems.boiler_radiators_mains_gas, EpcEfficiency.GOOD, EpcFuel.mains_gas_not_community, + EpcHeatingControls.programmers_trvs_bypass, EpcEfficiency.AVERAGE + ), + ('Boilers', 'A', 'MainsGasNotCommunity', 'Top Spec'): ( + EpcHeatingSystems.boiler_radiators_mains_gas, EpcEfficiency.GOOD, EpcFuel.mains_gas_not_community, + EpcHeatingControls.time_and_temperature_zone_control, EpcEfficiency.VERY_GOOD + ), + ('Boilers', 'B', 'MainsGasNotCommunity', 'Optimal'): ( + EpcHeatingSystems.boiler_radiators_mains_gas, EpcEfficiency.GOOD, EpcFuel.mains_gas_not_community, + EpcHeatingControls.programmer_room_thermostat_trvs, EpcEfficiency.GOOD + ), + ('Boilers', 'B', 'MainsGasNotCommunity', 'Sub Optimal'): ( + EpcHeatingSystems.boiler_radiators_mains_gas, EpcEfficiency.GOOD, EpcFuel.mains_gas_not_community, + EpcHeatingControls.programmers_trvs_bypass, EpcEfficiency.AVERAGE + ), + ('Boilers', 'B', 'MainsGasNotCommunity', 'Top Spec'): ( + EpcHeatingSystems.boiler_radiators_mains_gas, EpcEfficiency.GOOD, EpcFuel.mains_gas_not_community, + EpcHeatingControls.time_and_temperature_zone_control, EpcEfficiency.VERY_GOOD ), - ('Boilers', 'A', 'ElectricityNotCommunity', 'Sub Optimal'): None, - ('Boilers', 'A', 'ElectricityNotCommunity', 'Top Spec'): None, - ('Boilers', 'A', 'LPGNotCommunity', 'Optimal'): None, - ('Boilers', 'A', 'MainsGasNotCommunity', 'Optimal'): None, - ('Boilers', 'A', 'MainsGasNotCommunity', 'Sub Optimal'): None, - ('Boilers', 'A', 'MainsGasNotCommunity', 'Top Spec'): None, - ('Boilers', 'B', 'MainsGasNotCommunity', 'Optimal'): None, - ('Boilers', 'B', 'MainsGasNotCommunity', 'Sub Optimal'): None, - ('Boilers', 'B', 'MainsGasNotCommunity', 'Top Spec'): None, ('Boilers', 'C', 'ElectricityNotCommunity', 'Optimal'): None, ('Boilers', 'C', 'ElectricityNotCommunity', 'Sub Optimal'): None, ('Boilers', 'C', 'ElectricityNotCommunity', 'Top Spec'): None, @@ -532,14 +575,14 @@ heating_map = { ('Warm Air (not heat pump)', 'G', 'MainsGasNotCommunity', 'Sub Optimal'): None } -example = list(heating_map.keys())[0] +example = list(heating_map.keys())[5] example_data = data[ (data["Heating"] == example[0]) & (data["Boiler Efficiency"] == example[1]) & (data["Main Fuel"] == example[2]) & ( data["Controls Adequacy"] == example[3]) ] -example_data["UPRN"] +example_data["UPRN"].values.tolist() agg_tuples = { (row['Heating'], row['Boiler Efficiency'], row['Main Fuel']): None for _, row in agg.iterrows() @@ -550,8 +593,9 @@ epcs[epcs["LODGEMENT_DATE"] > "2025-07-01"]["WINDOWS_DESCRIPTION"].value_counts( epcs[epcs["LODGEMENT_DATE"] > "2025-07-01"]["GLAZED_AREA"].value_counts() epcs[ - (epcs["WINDOWS_DESCRIPTION"] == "Full secondary glazing") & (epcs["LODGEMENT_DATE"] > "2025-07-01") - ]["WINDOWS_ENERGY_EFF"].value_counts() + (epcs["MAINHEAT_DESCRIPTION"] == EpcHeatingSystems.boiler_radiators_mains_gas.value) & ( + epcs["LODGEMENT_DATE"] > "2025-07-01") + ]["MAINHEAT_ENERGY_EFF"].value_counts() # ------------ Fuel ------------