debugging a recommendation for hhrsh where the property currently has underfloor heating

This commit is contained in:
Khalim Conn-Kowlessar 2025-06-22 16:42:41 +01:00
parent b81e2a4eba
commit 53e0a651c9
8 changed files with 137 additions and 3 deletions

2
.idea/Model.iml generated
View file

@ -7,7 +7,7 @@
<sourceFolder url="file://$MODULE_DIR$/open_uprn" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/recommendations" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="AssetList" jdkType="Python SDK" />
<orderEntry type="jdk" jdkName="Fastapi-backend" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

2
.idea/misc.xml generated
View file

@ -3,7 +3,7 @@
<component name="Black">
<option name="sdkName" value="Python 3.10 (backend)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="AssetList" project-jdk-type="Python SDK" />
<component name="ProjectRootManager" version="2" project-jdk-name="Fastapi-backend" project-jdk-type="Python SDK" />
<component name="PyCharmProfessionalAdvertiser">
<option name="shown" value="true" />
</component>

View file

@ -96,3 +96,7 @@ class PlanTriggerRequest(BaseModel):
# When performing a remote assessment, if this has been set, it will allow the engine to
# pull data from the find my epc website, to utilise as part of a remote assessment
event_type: Optional[Literal["remote_assessment"]] = None
# If true, before optimising the engine will select a slightly larger package, to account for the SAP 10 causing
# scores to drop by a few points
simulate_sap_10: Optional[bool] = False

View file

@ -30,7 +30,6 @@ import backend.app.assumptions as assumptions
from backend.ml_models.api import ModelApi
from backend.Property import Property
from backend.Funding import Funding
from backend.apis.GoogleSolarApi import GoogleSolarApi
from recommendations.optimiser.CostOptimiser import CostOptimiser

View file

@ -57,6 +57,10 @@ class HeatingRecommender:
},
# These are the heating types we need to produce a dual heating recommendation
"dual": None
},
'Electric underfloor heating, electric storage heaters': {
# For this, we would recommend a heat pump
"dual": None
}
}
@ -109,6 +113,10 @@ class HeatingRecommender:
hhr_suitable = no_mains or self.has_electric_heating_description or self.has_room_heaters
hhr_suitable = hhr_suitable and (
"underfloor heating" not in self.property.main_heating["clean_description"]
)
return (
hhr_suitable and (not ashp_only_heating_recommendation) and not self.has_ashp and
("high_heat_retention_storage_heater" in measures)

View file

@ -0,0 +1,47 @@
"""
This is a script for preparing a sample for testing the end to end process, so that when Spring send us
data, we know it will work.
"""
import pandas as pd
birmingham_epcs = pd.read_csv(
"/Users/khalimconn-kowlessar/Documents/hestia/sfr/Spring JV/domestic-E08000025-Birmingham/certificates.csv"
)
# We get the newest EPC, by UPRN and LODGEMENT_DATE
birmingham_epcs['LODGEMENT_DATE'] = pd.to_datetime(birmingham_epcs['LODGEMENT_DATE'])
birmingham_epcs = birmingham_epcs.sort_values(
by=['UPRN', 'LODGEMENT_DATE'],
ascending=[True, False]
).drop_duplicates(subset='UPRN')
# Take a sample of properties, EPC F or G, EPC lodged in 2025. We focus on houses/bingalows
sample = birmingham_epcs[
(birmingham_epcs['CURRENT_ENERGY_RATING'].isin(['F', 'G'])) &
(birmingham_epcs['LODGEMENT_DATE'] >= '2025-01-01') &
(birmingham_epcs['PROPERTY_TYPE'].isin(['House', 'Bungalow']))
]
# Prepare the sample, with just the columns we would expect to receive from Spring
# 1) UPRN
# 2) Address
# 3) Postcode
# 4) Property type
# 5) Built form
# 6) Number of bedrooms (we'll simulate this)
# 7) Number of bathrooms (we'll simulate this)
# 8) Valuation (We'll simulate this, around 200,000)
sample = sample[['UPRN', 'ADDRESS', 'POSTCODE', 'PROPERTY_TYPE', 'BUILT_FORM']].copy()
sample['BEDROOMS'] = 3 # Simulating number of bedrooms
sample['BATHROOMS'] = 1 # Simulating number of bathrooms
sample['VALUATION'] = 200000 # Simulating valuation
sample.columns = [x.lower() for x in sample.columns]
# Store this as a excel
sample.to_excel(
"/Users/khalimconn-kowlessar/Documents/hestia/sfr/Spring JV/birmingham_sample.xlsx",
index=False
)

View file

@ -0,0 +1,76 @@
"""
This script prepares the data for the principal pitch modelling
"""
import os
import pandas as pd
from dotenv import load_dotenv
from utils.s3 import save_csv_to_s3
from etl.find_my_epc.AssetListEpcData import AssetListEpcData
load_dotenv(dotenv_path="backend/.env")
EPC_AUTH_TOKEN = os.getenv("EPC_AUTH_TOKEN")
PORTFOLIO_ID = 206
USER_ID = 8
EPC_TARGET = "C"
# Read the input file
properties = pd.read_excel(
"/Users/khalimconn-kowlessar/Documents/hestia/sfr/Spring JV/birmingham_sample.xlsx"
)
# Pull the non-invasive recommendations
asset_list_epc_client = AssetListEpcData(
asset_list=properties,
epc_auth_token=EPC_AUTH_TOKEN
)
asset_list_epc_client.get_data()
asset_list_epc_client.get_non_invasive_recommendations()
asset_list_epc_client.get_patch()
# TODO; Find some new, on-market opportunities that aren't on the EPC API, so we definitely have a patch
# Store the asset list in s3
filename = f"{USER_ID}/{PORTFOLIO_ID}/asset_list.csv"
save_csv_to_s3(
dataframe=properties,
bucket_name="retrofit-plan-inputs-dev",
file_name=filename
)
# Store non-invasive recommendations in S3
non_invasive_recommendations_filename = f"{USER_ID}/{PORTFOLIO_ID}/non_invasive_recommendations.csv"
save_csv_to_s3(
dataframe=pd.DataFrame(asset_list_epc_client.non_invasive_recommendations),
bucket_name="retrofit-plan-inputs-dev",
file_name=non_invasive_recommendations_filename
)
# Store patches in S3
patches_filename = ""
if asset_list_epc_client.patches:
patches_filename = f"{USER_ID}/{PORTFOLIO_ID}/patches.csv"
save_csv_to_s3(
dataframe=pd.DataFrame(asset_list_epc_client.patches),
bucket_name="retrofit-plan-inputs-dev",
file_name=patches_filename
)
body = {
"portfolio_id": str(PORTFOLIO_ID),
"housing_type": "Private",
"goal": "Increasing EPC",
"goal_value": "C",
"trigger_file_path": filename,
"already_installed_file_path": "",
"patches_file_path": patches_filename,
"non_invasive_recommendations_file_path": non_invasive_recommendations_filename,
"valuation_file_path": "",
"scenario_name": "EPC C",
"multi_plan": True,
"budget": None,
"ashp_cop": 3.5,
# This is new - when optimising, we drop scores by a few points to account for SAP 10
"simulate_sap_10": True,
"exclusions": ["external_wall_insulation"]
}
print(body)

View file