adding retrieve find my epc to engine

This commit is contained in:
Khalim Conn-Kowlessar 2025-04-03 09:06:58 +01:00
parent 2d69c671d3
commit 9e2914156f
9 changed files with 112 additions and 9 deletions

View file

@ -1351,7 +1351,8 @@ class AssetList:
# Check 1: Does the property have a valid heating system?
self.standardised_asset_list["solar_landlord_data_indicates_correct_heating_system"] = (
self.standardised_asset_list[self.STANDARD_HEATING_SYSTEM].isin(
["air source heat pump", "ground source heat pump", "high heat retention storage heaters"]
["air source heat pump", "ground source heat pump", "high heat retention storage heaters",
"electric boiler"]
)
)
self.standardised_asset_list["solar_landlord_data_indicates_needs_heating_upgrade"] = (
@ -1363,7 +1364,7 @@ class AssetList:
self.standardised_asset_list["solar_epc_data_indicates_correct_heating_system"] = (
(
self.standardised_asset_list[self.EPC_API_DATA_NAMES["mainheat-description"]]
.str.lower().str.contains("air source heat pump|ground source heat pump")
.str.lower().str.contains("air source heat pump|ground source heat pump|boiler and radiators, electric")
) | (
self.standardised_asset_list[
self.EPC_API_DATA_NAMES["mainheat-description"]].str.lower().str.contains(

View file

@ -111,6 +111,7 @@ def app():
outcomes_postcode = None
outcomes_houseno = None
outcomes_id = None
outcomes_address = None
master_filepaths = []
master_to_asset_list_filepath = None

View file

@ -63,6 +63,22 @@ BUILT_FORM_MAPPINGS = {
np.nan: 'unknown',
'Third Floor Flat': 'mid-floor',
'2 Ext. Wall Flat': 'mid-terrace',
'Hostel': 'unknown'
'Hostel': 'unknown',
'Flat: Mid Terrace: Mid Floor': 'mid-terrace',
'Bungalow: SemiDetached': 'semi-detached',
'Flat: End Terrace: Top Floor': 'end-terrace',
'Flat: Enclosed End Terrace: Top Floor': 'end-terrace',
'Maisonette: End Terrace: Ground Floor': 'end-terrace',
'Flat: End Terrace: Ground Floor': 'end-terrace',
'Flat: Mid Terrace: Top Floor': 'mid-terrace',
'House: Detached': 'detached',
'Flat: End Terrace: Mid Floor': 'end-terrace',
'House: SemiDetached': 'semi-detached',
'Flat: Semi Detached: Ground Floor': 'semi-detached',
'Flat: Semi Detached: Top Floor': 'semi-detached',
'Flat: Mid Terrace: Ground Floor': 'mid-terrace',
'House: MidTerrace': 'mid-terrace',
'House: EndTerrace': 'end-terrace',
'Bungalow: EndTerrace': 'end-terrace',
'Bungalow: MidTerrace': 'mid-terrace'
}

View file

@ -122,12 +122,26 @@ HEATING_MAPPINGS = {
'SOLID FUEL': 'solid fuel',
'GAS': 'gas combi boiler',
'DO NOT SURVEY': 'unknown',
'Gas Boiler': 'gas combi boiler',
'Communal Gas ': 'communal gas boiler',
'Communal': 'communal gas boiler',
'Communal Gas': 'communal gas boiler',
'Wood Burning Boiler': "boiler - other fuel",
'Oil Fired Boiler': 'oil boiler'
'Oil Fired Boiler': 'oil boiler',
'Electric (direct acting) room heaters: Panel, convector or radiant heaters Electricity: Electricity': 'room '
'heaters',
'Electric Storage Systems: Integrated storage+direct-acting heater Electricity: Electricity': 'electric storage '
'heaters',
'Community Heating Systems: Community CHP and boilers (RdSAP) Gas: Mains Gas (Community)': 'communal gas boiler',
'Boiler: D rated Regular Boiler Gas: Mains Gas': 'gas boiler',
'Boiler: C rated Combi Gas: Mains Gas': 'gas combi boiler',
'Electric Storage Systems: Fan storage heaters Electricity: Electricity': 'electric storage heaters',
' ': 'unknown',
'Boiler: G rated Regular Boiler Gas: Mains Gas': 'gas boiler',
'Electric Storage Systems: Modern (slimline) storage heaters Electricity: Electricity': 'electric storage heaters',
'Boiler: E rated Regular Boiler Gas: Mains Gas': 'gas boiler',
'Boiler: A rated Regular Boiler Electricity: Electricity': 'electric boiler',
'Community Heating Systems: Community boilers only (RdSAP) Gas: Mains Gas (Community)': 'communal gas boiler',
'Boiler: A rated Combi Gas: Mains Gas': 'gas condensing combi',
'Boiler: A rated CPSU Electricity: Electricity': 'electric boiler'
}

View file

@ -119,6 +119,22 @@ PROPERTY_MAPPING = {
'Studio (2nd floor)': 'flat',
'Third Floor Flat': 'flat',
'2 Ext. Wall Flat': 'flat',
'Hostel': 'other'
'Hostel': 'other',
'House: MidTerrace': 'house',
'House: EndTerrace': 'house',
'Flat: Mid Terrace: Mid Floor': 'flat',
'Bungalow: SemiDetached': 'bungalow',
'Bungalow: EndTerrace': 'bungalow',
'Flat: End Terrace: Top Floor': 'flat',
'Maisonette: End Terrace: Ground Floor': 'maisonette',
'Flat: End Terrace: Ground Floor': 'flat',
'Flat: Mid Terrace: Top Floor': 'flat',
'House: Detached': 'house',
'Flat: End Terrace: Mid Floor': 'flat',
'House: SemiDetached': 'house',
'Flat: Semi Detached: Ground Floor': 'flat',
'Flat: Semi Detached: Top Floor': 'flat',
'Flat: Mid Terrace: Ground Floor': 'flat',
'Bungalow: MidTerrace': 'bungalow',
'Flat: Enclosed End Terrace: Top Floor': 'flat'
}

View file

@ -137,4 +137,15 @@ WALL_CONSTRUCTION_MAPPINGS = {
'Cavity CWI Completed by Dyson': 'filled cavity',
None: "unknown",
"Cavity": "cavity unknown insulation",
'SolidBrick: Unknown': 'solid brick unknown insulation',
'Cavity: Unknown': 'cavity unknown insulation',
'Cavity: AsBuilt (Post 1995)': 'filled cavity',
'Cavity: AsBuilt (1976-1982)': 'cavity unknown insulation',
'SystemBuilt: AsBuilt': 'system built',
'TimberFrame: AsBuilt': "timber frame unknown insulation",
'Cavity: AsBuilt (1983-1995)': 'cavity unknown insulation',
'Cavity: AsBuilt (1983-1995), Cavity: FilledCavity': 'filled cavity',
'SolidBrick: AsBuilt': 'solid brick unknown insulation',
'Cavity: FilledCavity': 'filled cavity',
'SolidBrick: Internal': 'insulated solid brick'
}

View file

@ -44,6 +44,7 @@ from backend.ml_models.Valuation import PropertyValuation
from etl.bill_savings.KwhData import KwhData
from etl.spatial.OpenUprnClient import OpenUprnClient
from etl.find_my_epc.RetrieveFindMyEpc import RetrieveFindMyEpc
logger = setup_logger()
@ -514,6 +515,13 @@ async def trigger_plan(body: PlanTriggerRequest):
)
)
# if we have a remote assment data type, we pull the additional data and include it
if body.event_type == "remote_assessment":
logger.info("Retrieving find my epc data")
property_non_invasive_recommendations = RetrieveFindMyEpc.get_from_epc(
epc_searcher.newest_epc
)
epc_records = patch_epc(patch, epc_records)
prepared_epc = EPCRecord(

View file

@ -37,6 +37,7 @@ MEASURE_MAP = {
VALID_GOALS = ["Increasing EPC"]
VALID_HOUSING_TYPES = ["Social", "Private"]
VALID_EVENT_TYPES = ["remote_assessment"]
# Define the validation function for inclusions/exclusions
@ -56,10 +57,16 @@ def check_housing_type(value: str) -> str:
return value
def check_event_type(value: str) -> str:
assert value in VALID_EVENT_TYPES, f"{value} is not a valid event type"
return value
# Use Annotated with BeforeValidator for each list item validation
InclusionOrExclusionItem = Annotated[str, BeforeValidator(check_inclusion_or_exclusion)]
Goal = Annotated[str, BeforeValidator(check_goals)]
HousingType = Annotated[str, BeforeValidator(check_housing_type)]
EventType = Annotated[str, BeforeValidator(check_event_type)]
class PlanTriggerRequest(BaseModel):
@ -84,3 +91,7 @@ class PlanTriggerRequest(BaseModel):
default_u_values: Optional[bool] = True
ashp_cop: Optional[float] = 2.8
# 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[float] = "remote_assessment",

View file

@ -3,6 +3,10 @@ import requests
from bs4 import BeautifulSoup
from datetime import datetime
from utils.logger import setup_logger
logger = setup_logger()
class RetrieveFindMyEpc:
SEARCH_POSTCODE_URL = (
@ -366,3 +370,24 @@ class RetrieveFindMyEpc:
formatted_recommendations.append(to_append)
return formatted_recommendations
@classmethod
def get_from_epc(cls, epc):
# Attempt both methods:
try:
searcher = cls(address=epc["address"], postcode=epc["postcode"])
find_epc_data = searcher.retrieve_newest_find_my_epc_data()
except Exception as e:
logger.error(f"Error retrieving find my epc data: {e}")
# We attempt with the backup add
searcher = cls(address=epc["address1"], postcode=epc["postcode"])
find_epc_data = searcher.retrieve_newest_find_my_epc_data()
non_invasive_recommendations = {
"uprn": epc["uprn"],
"address": epc["address"],
"postcode": epc["postcode"],
"recommendations": find_epc_data["recommendations"],
}
return non_invasive_recommendations