diff --git a/.idea/Model.iml b/.idea/Model.iml
index 09f2e496..c6561970 100644
--- a/.idea/Model.iml
+++ b/.idea/Model.iml
@@ -7,7 +7,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index fb10c6b0..50cad4ca 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,7 +3,7 @@
-
+
diff --git a/asset_list/AssetList.py b/asset_list/AssetList.py
index 66cdf575..21376708 100644
--- a/asset_list/AssetList.py
+++ b/asset_list/AssetList.py
@@ -450,6 +450,8 @@ class AssetList:
self.non_intrusives_present = "CIGA Check Required" in self.raw_asset_list.columns
# We detect if we have the old format of non-intruvies
self.old_format_non_intrusives_present = "WFT Findings" in self.raw_asset_list.columns
+ if self.old_format_non_intrusives_present:
+ self.non_intrusives_present = False
self.non_intrusives_eligibility = "Eligibility (Red/Yellow/Green)" in self.raw_asset_list.columns
@@ -1320,7 +1322,7 @@ class AssetList:
# Before we being, we identify if a property has solar already as we use this
# for identifying cavity jobs
- if self.non_intrusives_present:
+ if self.non_intrusives_present and not self.old_format_non_intrusives_present:
if self.new_format_non_insturives_present_v2:
existing_solar_non_intrusives_check = (
@@ -3011,7 +3013,7 @@ class AssetList:
outcomes["row_id"] = outcomes.index
if outcomes_houseno[idx] is None:
- outcomes_houseno = "houseno"
+ outcomes_houseno[idx] = "houseno"
outcomes["houseno"] = outcomes[outcomes_address[idx]].apply(
lambda x: SearchEpc.get_house_number(x, outcomes[outcomes_postcode])
)
@@ -3286,9 +3288,14 @@ class AssetList:
else:
raise ValueError("No install or cancellation date")
- submission_col = (
- "SUBMISSION DATE" if "SUBMISSION DATE" in master_data.columns else "SUBMISSION DATE TO INSTALLERS"
- )
+ if "SUBMISSION DATE" in master_data.columns:
+ submission_col = "SUBMISSION DATE"
+ elif "SUBMISSION DATE TO INSTALLERS" in master_data.columns:
+ submission_col = "SUBMISSION DATE TO INSTALLERS"
+ elif "Submission Date" in master_data.columns:
+ submission_col = "Submission Date"
+ else:
+ raise ValueError("No submission date column found in master data")
master_data["row_id"] = master_data.index
@@ -3331,11 +3338,21 @@ class AssetList:
installer_notes_col = "INSTALLERS NOTES ; REASONS FOR CANCELLATIONS"
elif "INSTALLERS NOTES" in master_data.columns:
installer_notes_col = "INSTALLERS NOTES"
+ elif 'Installers Notes' in master_data.columns:
+ installer_notes_col = 'Installers Notes'
+ elif 'NOTES ; REASONS FOR CANCELLATIONS OR WHERE INSTALL DATE WAS OBTAINED FROM' in master_data.columns:
+ installer_notes_col = 'NOTES ; REASONS FOR CANCELLATIONS OR WHERE INSTALL DATE WAS OBTAINED FROM'
else:
raise ValueError("No installer notes column found in master data")
+ if "INSTALLER" in master_data.columns:
+ installer_col = "INSTALLER"
+ elif "Installer" in master_data.columns:
+ installer_col = "Installer"
+ else:
+ raise ValueError("No installer column found in master data")
+
measure_mix_col = "MEASURE COMBO"
- installer_col = "INSTALLER"
town_colname = "TOWN" if "TOWN" in master_data.columns else 'Town/Area'
logger.info("Matching master data to asset list")
diff --git a/asset_list/app.py b/asset_list/app.py
index 93739b8b..e431f723 100644
--- a/asset_list/app.py
+++ b/asset_list/app.py
@@ -59,42 +59,227 @@ def app():
Property UPRN
"""
- # Pickering and Ferens
- data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Pickering & Ferens"
- data_filename = "SAP 9 vs SAP 10 Sava Intelligent Energy - Property List (190625).xlsx"
- sheet_name = "Sava Intelligent Energy - Prope"
+ # CDS
+ data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/CDS"
+ data_filename = "Founder Estates - Asset List.xlsx"
+ sheet_name = "Combined"
postcode_column = 'Postcode'
- fulladdress_column = 'Address'
+ fulladdress_column = "Address"
address1_column = None
address1_method = "house_number_extraction"
address_cols_to_concat = []
missing_postcodes_method = None
landlord_year_built = None
landlord_os_uprn = None
- landlord_property_type = "Property Type" # Using the inspections property type
- landlord_built_form = "Archetype 2"
+ landlord_property_type = None
+ landlord_built_form = None
landlord_wall_construction = None
- landlord_roof_construction = None
- landlord_heating_system = None
+ landlord_heating_system = "Heating Type"
landlord_existing_pv = None
- landlord_property_id = "UPRN"
- landlord_sap = "SAP Rating (RdSAP 10)"
+ landlord_property_id = "Row ID"
outcomes_filename = []
outcomes_sheetname = []
outcomes_postcode = []
outcomes_houseno = []
- outcomes_id = []
outcomes_address = []
- master_filepaths = [
- os.path.join(data_folder, "PICKERING & FERENS ROLLING MASTER SHEET HEDGEFUND - 26.7.24 - K.csv"),
- os.path.join(data_folder, "PICKERING & FERENS NEW MASTER GBIS UPDATED 21.8.24 - M - For Analysis.csv"),
- ]
+ outcomes_id = []
+ master_filepaths = []
master_to_asset_list_filepath = None
- phase = False
- ecosurv_landlords = "pickering"
asset_list_header = 0
landlord_block_reference = None
+ master_id_colnames = []
+ landlord_roof_construction = None
+ phase = False
+ landlord_sap = None
+ ecosurv_landlords = None
+
+ # Plus Dane
+ data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Plus Dane/New Programme July 2025/"
+ data_filename = "20250711 Plus Dane Asset List.xlsx"
+ sheet_name = "Sheet1"
+ postcode_column = 'Postcode'
+ fulladdress_column = "Address"
+ address1_column = None
+ address1_method = "house_number_extraction"
+ address_cols_to_concat = []
+ missing_postcodes_method = None
+ landlord_year_built = "Property Age"
+ landlord_os_uprn = None
+ landlord_property_type = "Property Type"
+ landlord_built_form = "Built Form"
+ landlord_wall_construction = "Wall Construction"
+ landlord_heating_system = "Full Heating System"
+ landlord_existing_pv = None
+ landlord_property_id = "UPRN"
+ outcomes_filename = [
+ os.path.join(data_folder, "Outcomes - Plus Dane_CWI_2024.xlsx"),
+ os.path.join(data_folder, "Outcomes - Plus Dane_CWI_2025.xlsx"),
+ os.path.join(data_folder, "Outcomes - Plus Dane_PV_2025.xlsx"),
+ ]
+ outcomes_sheetname = [
+ "CWI & LI - 2024", "2025 - CWI", "PV - 2025",
+ ]
+ outcomes_postcode = ["Postcode", "Postcode", "Postcode"]
+ outcomes_houseno = ["No.", "No", "No"]
+ outcomes_address = ["Address", "Address", "Address"]
+ outcomes_id = ["Asset Reference", "LL UPRN", "LL UPRN"]
+ master_filepaths = [
+ os.path.join(data_folder, "submissions/JJC-Table 1.csv"),
+ os.path.join(data_folder, "submissions/SCIS-Table 1.csv")
+ ]
+ master_to_asset_list_filepath = None
+ asset_list_header = 1
+ landlord_block_reference = None
master_id_colnames = [None, None]
+ landlord_roof_construction = None
+ phase = False
+ landlord_sap = "SAP Rating"
+ ecosurv_landlords = "plus dane"
+
+ # data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Brentwood/July 2025 New Programme"
+ # data_filename = "20250710 Asset List Brentwood.xlsx"
+ # sheet_name = "Sheet1"
+ # postcode_column = 'Postcode'
+ # fulladdress_column = None
+ # address1_column = "House Number"
+ # address1_method = None
+ # address_cols_to_concat = ["House Number", "Address Line 1", "Address Line 2", "Address Line 3"]
+ # missing_postcodes_method = None
+ # landlord_year_built = "Year Built"
+ # landlord_os_uprn = None
+ # landlord_property_type = "Dwelling"
+ # landlord_built_form = None
+ # landlord_wall_construction = None
+ # landlord_heating_system = "Heating"
+ # landlord_existing_pv = None
+ # landlord_property_id = "UPRN"
+ # outcomes_filename = [os.path.join(data_folder, "Brentwood - outcomes for analysis.xlsx")]
+ # outcomes_sheetname = ["OUTCOMES"]
+ # outcomes_postcode = ["POSTCODE"]
+ # outcomes_houseno = [None]
+ # outcomes_address = ["ADDRESS"]
+ # outcomes_id = [None]
+ # master_filepaths = [os.path.join(data_folder, "Submissions.csv")]
+ # master_to_asset_list_filepath = None
+ # asset_list_header = 1
+ # landlord_block_reference = None
+ # master_id_colnames = [None]
+ # landlord_roof_construction = None
+ # phase = False
+ # landlord_sap = None
+ # ecosurv_landlords = "brentwood"
+
+ # Brentwood
+ # data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Brentwood/July 2025 New Programme"
+ # data_filename = "20250710 Asset List Brentwood.xlsx"
+ # sheet_name = "Sheet1"
+ # postcode_column = 'Postcode'
+ # fulladdress_column = None
+ # address1_column = "House Number"
+ # address1_method = None
+ # address_cols_to_concat = ["House Number", "Address Line 1", "Address Line 2", "Address Line 3"]
+ # missing_postcodes_method = None
+ # landlord_year_built = "Year Built"
+ # landlord_os_uprn = None
+ # landlord_property_type = "Dwelling"
+ # landlord_built_form = None
+ # landlord_wall_construction = None
+ # landlord_heating_system = "Heating"
+ # landlord_existing_pv = None
+ # landlord_property_id = "UPRN"
+ # outcomes_filename = [os.path.join(data_folder, "Brentwood - outcomes for analysis.xlsx")]
+ # outcomes_sheetname = ["OUTCOMES"]
+ # outcomes_postcode = ["POSTCODE"]
+ # outcomes_houseno = [None]
+ # outcomes_address = ["ADDRESS"]
+ # outcomes_id = [None]
+ # master_filepaths = [os.path.join(data_folder, "Submissions.csv")]
+ # master_to_asset_list_filepath = None
+ # asset_list_header = 1
+ # landlord_block_reference = None
+ # master_id_colnames = [None]
+ # landlord_roof_construction = None
+ # phase = False
+ # landlord_sap = None
+ # ecosurv_landlords = "brentwood"
+ #
+ # # Eastlight
+ # data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Eastlight/New Programme"
+ # data_filename = "INSPECTIONS MASTER Non Tech.xlsx"
+ # sheet_name = "EASTLIGHT CW"
+ # postcode_column = 'Postcode'
+ # fulladdress_column = None
+ # address1_column = "HouseName"
+ # address1_method = None
+ # address_cols_to_concat = ["HouseName", "Block", "Address1", "Address2", "Address3"]
+ # missing_postcodes_method = None
+ # landlord_year_built = "Built In Year"
+ # landlord_os_uprn = None
+ # landlord_property_type = "AssetType"
+ # landlord_built_form = "Archetype" # Using inspections archetype
+ # landlord_wall_construction = None
+ # landlord_roof_construction = None
+ # landlord_heating_system = "Main Heating Source"
+ # landlord_existing_pv = None
+ # landlord_property_id = "UPRN"
+ # landlord_sap = "SAP Score"
+ # outcomes_filename = [
+ # os.path.join(data_folder, "Eastlight_CWI_JJC_2025.xlsx"),
+ # os.path.join(data_folder, "Eastlight_CWI_SCIS_2025.xlsx"),
+ # ]
+ # outcomes_sheetname = ["Outcomes", "Feedback"]
+ # outcomes_postcode = ["Postcode", "Postcode"]
+ # outcomes_houseno = ["No", "No."]
+ # outcomes_id = [None, None]
+ # outcomes_address = ["Address", "Address"]
+ # master_filepaths = [
+ # os.path.join(data_folder, "ECO 3-Table 1.csv"),
+ # os.path.join(data_folder, "ECO 4-Table 1.csv"),
+ # ]
+ # master_to_asset_list_filepath = None
+ # phase = False
+ # ecosurv_landlords = "eastlight"
+ # asset_list_header = 0
+ # landlord_block_reference = None
+ # master_id_colnames = [None, None]
+ # landlord_sap = None
+
+ # Pickering and Ferens
+ # data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Pickering & Ferens"
+ # data_filename = "SAP 9 vs SAP 10 Sava Intelligent Energy - Property List (190625).xlsx"
+ # sheet_name = "Sava Intelligent Energy - Prope"
+ # postcode_column = 'Postcode'
+ # fulladdress_column = 'Address'
+ # address1_column = None
+ # address1_method = "house_number_extraction"
+ # address_cols_to_concat = []
+ # missing_postcodes_method = None
+ # landlord_year_built = None
+ # landlord_os_uprn = None
+ # landlord_property_type = "Property Type" # Using the inspections property type
+ # landlord_built_form = "Archetype 2"
+ # landlord_wall_construction = None
+ # landlord_roof_construction = None
+ # landlord_heating_system = None
+ # landlord_existing_pv = None
+ # landlord_property_id = "UPRN"
+ # landlord_sap = "SAP Rating (RdSAP 10)"
+ # outcomes_filename = []
+ # outcomes_sheetname = []
+ # outcomes_postcode = []
+ # outcomes_houseno = []
+ # outcomes_id = []
+ # outcomes_address = []
+ # master_filepaths = [
+ # os.path.join(data_folder, "PICKERING & FERENS ROLLING MASTER SHEET HEDGEFUND - 26.7.24 - K.csv"),
+ # os.path.join(data_folder, "PICKERING & FERENS NEW MASTER GBIS UPDATED 21.8.24 - M - For Analysis.csv"),
+ # ]
+ # master_to_asset_list_filepath = None
+ # phase = False
+ # ecosurv_landlords = "pickering"
+ # asset_list_header = 0
+ # landlord_block_reference = None
+ # master_id_colnames = [None, None]
# Colchester
# data_folder = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Colchester"
diff --git a/asset_list/mappings/built_form.py b/asset_list/mappings/built_form.py
index 0245b71d..c17e0ed4 100644
--- a/asset_list/mappings/built_form.py
+++ b/asset_list/mappings/built_form.py
@@ -365,6 +365,12 @@ BUILT_FORM_MAPPINGS = {
'DETACHED': 'detached',
'MID TERRACE': 'mid-terrace',
'END TERRACE': 'end-terrace',
- 'ENCLOSED MID': 'enclosed mid-terrace'
+ 'ENCLOSED MID': 'enclosed mid-terrace',
+ 'BUILDING': 'unknown',
+ 'FLAT COMMUNAL FACILITIES': 'unknown',
+ 'MAISONETTE': 'unknown',
+ 'HOUSE': 'unknown',
+ 'FLAT': 'unknown',
+ 'BLOCK': 'unknown'
}
diff --git a/asset_list/mappings/heating_systems.py b/asset_list/mappings/heating_systems.py
index dced36a7..010d49a5 100644
--- a/asset_list/mappings/heating_systems.py
+++ b/asset_list/mappings/heating_systems.py
@@ -341,5 +341,28 @@ HEATING_MAPPINGS = {
'Boiler: D rated Combi': 'gas condensing combi',
'Heat Pump: (from database)': 'air source heat pump',
'Community Heating Systems: Community CHP and boilers (RdSAP)': 'communal heating',
- '': 'unknown'
+ '': 'unknown',
+
+ 'Solid Fuel Boiler': 'solid fuel',
+ 'Heating (Other)': 'other',
+ 'Solid Fuel Fire Only': 'solid fuel',
+ 'No Main Heat Source': 'no heating',
+ 'Electric Programmable': 'electric storage heaters',
+ 'Linked to Communal Boiler': 'communal heating',
+ 'Bio Mass Boiler': 'solid fuel',
+ 'Electric Non Programmable': 'electric storage heaters',
+
+ 'Room heaters, Mains gas': 'room heaters',
+ 'Boiler, Solid fuel': 'solid fuel',
+ 'Room heaters, Electricity': 'room heaters',
+ 'Room heaters, Solid fuel': 'room heaters',
+ 'Boiler, Oil': 'oil boiler',
+ 'Boiler, Biomass': 'boiler - other fuel',
+ 'Community heating, Community (non-gas)': 'communal heating',
+ 'Heat pump (wet), Electricity': 'air source heat pump',
+ 'Community heating, Community (mains gas)': 'communal gas boiler',
+ 'Boiler, Electricity': 'electric boiler',
+ 'Boiler, LPG': 'gas boiler, radiators',
+ 'Boiler, Mains gas': 'gas boiler, radiators',
+ 'Storage heating, Electricity': 'electric storage heaters'
}
diff --git a/asset_list/mappings/property_type.py b/asset_list/mappings/property_type.py
index 19c23f0e..caca0cf0 100644
--- a/asset_list/mappings/property_type.py
+++ b/asset_list/mappings/property_type.py
@@ -266,5 +266,10 @@ PROPERTY_MAPPING = {
'Office Block': 'other',
'BLOCK (Non-Communal)': 'block of flats',
'Refuge': 'other',
- None: 'unknown'
+ None: 'unknown',
+ 'HFOP FLAT': 'flat',
+ 'HFOP BEDSIT': 'bedsit',
+ 'LINKED FLAT': 'flat',
+ 'LINKED BUNGALOW': 'bungalow'
+
}
diff --git a/backend/Property.py b/backend/Property.py
index c1d6324a..22eb2fc3 100644
--- a/backend/Property.py
+++ b/backend/Property.py
@@ -1200,7 +1200,7 @@ class Property:
self.heating_energy_source = self.heating_energy_source[0]
if self.heating_energy_source == "Varied (Community Scheme)":
- if self.main_fuel["fuel_type"] == "mains gas":
+ if self.main_fuel["fuel_type"] in ["mains gas", None]: # We assume when None as it's unknown
self.heating_energy_source = "Natural Gas (Community Scheme)"
else:
raise Exception("Implement me")
diff --git a/backend/app/assumptions.py b/backend/app/assumptions.py
index 08bd6b6b..d36266d3 100644
--- a/backend/app/assumptions.py
+++ b/backend/app/assumptions.py
@@ -64,6 +64,13 @@ DESCRIPTIONS_TO_FUEL_TYPES = {
'Boiler and radiators, mains gas, Boiler and radiators, mains gas': {"fuel": "Natural Gas", "cop": 0.85},
'Room heaters, electric, Electric storage heaters': {"fuel": "Electricity", "cop": 1},
"Boiler and radiators, mains gas, Electric storage heaters": {"fuel": "Natural Gas", "cop": 0.85},
+ "Boiler and radiators, anthracite": {"fuel": "Anthracite", "cop": 0.85},
+ 'Electric immersion, off-peak, plus solar': {"fuel": "Electricity + Solar Thermal", "cop": 1},
+ 'Ground source heat pump, radiators, electric': {
+ "fuel": "Electricity", "cop": AVERAGE_ASHP_EFFICIENCY / 100
+ },
+ 'Electric instantaneous at point of use, plus solar': {"fuel": "Electricity + Solar Thermal", "cop": 1},
+ "Electric storage heaters, Room heaters, electric": {"fuel": "Electricity", "cop": 1},
}
# These are the measure types where if there is a ventilation recommendation, we force the inclusion of it
diff --git a/backend/engine/engine.py b/backend/engine/engine.py
index 11701bdb..d631e349 100644
--- a/backend/engine/engine.py
+++ b/backend/engine/engine.py
@@ -506,7 +506,7 @@ async def model_engine(body: PlanTriggerRequest):
)
# if we have a remote assment data type, we pull the additional data and include it
- if (body.event_type == "remote_assessment") and not (epc_searcher.newest_epc["estimated"]):
+ if (body.event_type == "remote_assessment") and not (epc_searcher.newest_epc.get("estimated")):
logger.info("Retrieving find my epc data")
try:
property_non_invasive_recommendations, patch = RetrieveFindMyEpc.get_from_epc(
diff --git a/backend/ml_models/AnnualBillSavings.py b/backend/ml_models/AnnualBillSavings.py
index b22837d8..4291b1d1 100644
--- a/backend/ml_models/AnnualBillSavings.py
+++ b/backend/ml_models/AnnualBillSavings.py
@@ -28,8 +28,8 @@ class AnnualBillSavings:
# Latest price cap figures from Ofgem are for April 2024
# https://www.ofgem.gov.uk/energy-price-cap
- ELECTRICITY_PRICE_CAP = 0.2486
- GAS_PRICE_CAP = 0.0634
+ ELECTRICITY_PRICE_CAP = 0.2573
+ GAS_PRICE_CAP = 0.0633
# This is the most recent export payment figure, at 9.28p/kWh
# Smart export guarantee rates can be found here:
# https://www.sunsave.energy/solar-panels-advice/exporting-to-the-grid/best-seg-rates
@@ -39,8 +39,8 @@ class AnnualBillSavings:
PRICE_FACTOR = 0.09549999999999999
# Daily standard charge, based on average across England, Scotland and Wales, and includes VAT
- DAILY_STANDARD_CHARGE_GAS = 0.3165
- DAILY_STANDARD_CHARGE_ELECTRICITY = 0.6097
+ DAILY_STANDARD_CHARGE_GAS = 0.2982
+ DAILY_STANDARD_CHARGE_ELECTRICITY = 0.5137
# Based on https://www.nottenergy.com/advice-and-tools/project-energy-cost-comparison
# For July 2024. These quotes are based on the east midlands region, so we
diff --git a/etl/customers/Brentwood/compile_new_asset_list.py b/etl/customers/Brentwood/compile_new_asset_list.py
new file mode 100644
index 00000000..e3ced5ab
--- /dev/null
+++ b/etl/customers/Brentwood/compile_new_asset_list.py
@@ -0,0 +1,38 @@
+"""
+Brentwood sent us a new asset list in July 2025. This script will combine the data in the new asset list with the
+old, so we have a single picture
+"""
+
+import pandas as pd
+
+new_asset_list = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Brentwood/July 2025 New Programme/All Assets "
+ "29.05.2025.xlsx",
+ sheet_name="Sheet1",
+ header=1
+)
+
+old_asset_list = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Brentwood/July 2025 New Programme/BRENTWOOD Asset "
+ "list.xlsx",
+ sheet_name="Asset List"
+)
+
+# We combine based on the data we want
+compiled = new_asset_list.merge(
+ old_asset_list[["UPRN", "Asset Type", "Year Built", "Dwelling", "Bedrooms", "Ownership", 'Asbestos Full Survey',
+ 'Stock Condition Survey', 'Cat', 'Heating',
+ 'WFT Findings', 'ECO Eligibility', 'CIGA Requested', 'CIGA Guarantee',
+ 'ECO Survey completed']],
+ how="left",
+ on="UPRN"
+)
+
+compiled["WFT Findings"] = compiled["WFT Findings"].fillna("Not Inspected")
+
+# Store this data
+compiled.to_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Brentwood/July 2025 New Programme/20250710 Asset List "
+ "Brentwood.xlsx",
+ index=False
+)
diff --git a/etl/customers/blakeridge_mill/data.py b/etl/customers/blakeridge_mill/data.py
new file mode 100644
index 00000000..c9d7f9e6
--- /dev/null
+++ b/etl/customers/blakeridge_mill/data.py
@@ -0,0 +1,49 @@
+# Get units for postcodes WF17 8RA, WF17 8RB
+import os
+
+import pandas as pd
+from epc_api.client import EpcClient
+from dotenv import load_dotenv
+
+load_dotenv(dotenv_path="backend/.env")
+EPC_AUTH_TOKEN = os.getenv("EPC_AUTH_TOKEN")
+
+postcodes = [
+ "WF17 8RA",
+ "WF17 8RB",
+]
+
+client = EpcClient(auth_token=EPC_AUTH_TOKEN)
+
+data = []
+for postcode in postcodes:
+ resp = client.domestic.search(
+ params={"postcode": postcode, "address": None, "local-authority": None, "property-type": None,
+ "floor-area": None,
+ "energy-band": None, "from-month": None, "from-year": None, "to-month": None, "to-year": None,
+ 'constituency': None},
+ size=1000
+ )
+ data.extend(resp["rows"])
+
+df = pd.DataFrame(data)
+# Get newest field by UPRN, inspection-date
+df["inspection-date"] = pd.to_datetime(df["inspection-date"])
+df = df.sort_values(by=["uprn", "inspection-date"], ascending=[True, False])
+df = df.drop_duplicates(subset=["uprn"], keep="first")
+
+df.to_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Blakeridge Mill/blakeridge_mill_epc_data.xlsx", index=False
+)
+
+df = df[df["address"] != "The Tower Blakeridge Mill, Upper Blakeridge Lane"]
+df["walls-description"].value_counts()
+df["roof-description"].value_counts()
+
+df["total-floor-area"].astype(float).mean()
+df["current-energy-efficiency"] = pd.to_numeric(df["current-energy-efficiency"], errors='coerce')
+
+df.groupby("transaction-type")["current-energy-efficiency"].mean()
+df["transaction-type"].value_counts()
+
+df[df["transaction-type"] == "rental"]["built-form"].value_counts()
diff --git a/etl/customers/ealing/fixing houses asset list.py b/etl/customers/ealing/fixing houses asset list.py
new file mode 100644
index 00000000..4a39428a
--- /dev/null
+++ b/etl/customers/ealing/fixing houses asset list.py
@@ -0,0 +1,45 @@
+import pandas as pd
+
+houses_list = pd.read_csv(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Ealing/Ealing BC - HOUSES(UNCHECKED).csv"
+)
+
+features = pd.read_csv(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Ealing/Ealing BC - HOUSES(IGNORE - FULL MAIN).csv"
+)
+features = features.drop(
+ columns=[
+ 'Archetype', 'Construction', 'Insulated', 'Material',
+ 'CIGA Check Required', 'PV, ACCESS ISSUE, SEE NOTES',
+ 'OFF GAS - ROOF ORIENTATION', 'Any further surveyor notes', 'Surveyors Name',
+ 'Unnamed: 30', 'Unnamed: 31'
+ ]
+)
+
+demolitions = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Ealing/Ealing - Demolished or due to be.xlsx",
+ sheet_name="Demolished or due to be"
+)
+
+inspections_data = houses_list[
+ [
+ "Property ref", "Postcode", 'Archetype', 'Construction', 'Insulated', 'Material',
+ 'CIGA Check Required', 'PV, ACCESS ISSUE, SEE NOTES',
+ 'OFF GAS - ROOF ORIENTATION', 'Any further surveyor notes', 'YET TO BE SURVEYED'
+ ]
+].rename(columns={"YET TO BE SURVEYED": "Surveyors Name"})
+
+asset_list = features.drop(
+ columns=[
+ 'Archetype', 'Construction', 'Insulated', 'Material', 'CIGA Check Required',
+ 'PV, ACCESS ISSUE, SEE NOTES', 'OFF GAS - ROOF ORIENTATION',
+ 'Any further surveyor notes', 'Surveyors Name', "Postcode"
+ ]
+).merge(
+ inspections_data,
+ how="inner",
+ on="Property ref",
+)
+
+asset_list.to_csv("/Users/khalimconn-kowlessar/Documents/hestia/Customers/Ealing/Ealing_rechecked_cleaned_05042025.csv",
+ index=False)
diff --git a/etl/customers/ncha/portfolio.py b/etl/customers/ncha/portfolio.py
new file mode 100644
index 00000000..f47c87c8
--- /dev/null
+++ b/etl/customers/ncha/portfolio.py
@@ -0,0 +1,14 @@
+import pandas as pd
+
+cavity = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Downloads/Energy Information MASTER June 2025 - Standardised.xlsx",
+ sheet_name="Cavity Properties (for review)",
+)
+solar = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Downloads/Energy Information MASTER June 2025 - Standardised.xlsx",
+ sheet_name="Solar Properties",
+)
+
+cavity_al = cavity[["domna_address_1", "domna_postcode", "epc_os_uprn"]].rename(
+ columns={"domna_address_1": "address", "domna_postcode": "postcode", "epc_os_uprn": "uprn"}
+)
diff --git a/etl/customers/plus dane/prepare_asset_list.py b/etl/customers/plus dane/prepare_asset_list.py
new file mode 100644
index 00000000..430c7b5a
--- /dev/null
+++ b/etl/customers/plus dane/prepare_asset_list.py
@@ -0,0 +1,48 @@
+"""
+July 2025, this script prepares the asset list for Plus Dane
+"""
+import pandas as pd
+
+oldest_asset_list = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Plus Dane/New Programme July 2025/PLUS DANE Asset List.xlsx"
+)
+solar_asset_list = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Plus Dane/New Programme July 2025/Plus Dane - potential "
+ "PV List 04.03.2025.xlsx"
+)
+newest_asset_list = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Plus Dane/New Programme July 2025/Sava Intelligent Energy "
+ "- Property List - March 2025.xlsx"
+)
+
+old_missed = oldest_asset_list[~oldest_asset_list["UPRN"].isin(newest_asset_list["UPRN"])]
+solar_missed = solar_asset_list[~solar_asset_list["UPRN"].isin(newest_asset_list["UPRN"])] # Empty
+
+# Build new asset list
+# NEWEST
+# 'UPRN', 'Address', 'Postcode', 'Town', 'EPC SAP Band', 'SAP Rating',
+# 'CO₂ Emissions', 'EPC EI Band', 'Data Quality Indicator',
+# 'Results Calculated', 'Property Age', 'Property Type', 'Built Form',
+# 'Wall Construction', 'Wall Insulation', 'Roof Construction',
+# 'Joist Insulation', 'Space Heating System', 'Space Heating Fuel'
+#
+# SOlAR
+
+df = newest_asset_list.merge(
+ solar_asset_list, how="left", on="UPRN", suffixes=("", "_solar"),
+).merge(
+ oldest_asset_list, how="left", on="UPRN", suffixes=("", "_old")
+)
+df["asset_list_versiion"] = "July 2025"
+old_missed["asset_list_versiion"] = "Historic"
+
+# Append on the old missed?
+df = pd.concat(
+ [df, old_missed], ignore_index=True, sort=False
+)
+# Store excel
+df.to_excel(
+ "/Users/khalimconn-kowlessar/Documents/hestia/Customers/Plus Dane/New Programme July 2025/Plus Dane Asset List "
+ "July 2025.xlsx",
+ index=False,
+)
diff --git a/etl/customers/remote_assessments/app.py b/etl/customers/remote_assessments/app.py
index a8805a71..df4a16fe 100644
--- a/etl/customers/remote_assessments/app.py
+++ b/etl/customers/remote_assessments/app.py
@@ -4,7 +4,7 @@ from dotenv import load_dotenv
from utils.s3 import save_csv_to_s3
from etl.find_my_epc.AssetListEpcData import AssetListEpcData
-PORTFOLIO_ID = 141
+PORTFOLIO_ID = 212
USER_ID = 8
load_dotenv(dotenv_path="backend/.env")
@@ -17,25 +17,15 @@ def app():
:return:
"""
- asset_list = [
- {
- "address": "196 Merrow Street",
- "postcode": "SE17 2NP",
- "uprn": 200003423454,
- "patch": True
- },
- {
- "address": "65 Liverpool Grove",
- "postcode": "SE17 2HP",
- "uprn": 200003423194
- },
- {
- "address": "2 Brettell Street",
- "postcode": "SE17 2NZ",
- "uprn": 200003423607
- },
- ]
- asset_list = pd.DataFrame(asset_list)
+ asset_list = pd.read_excel(
+ "/Users/khalimconn-kowlessar/Downloads/Energy Information MASTER June 2025 - Standardised.xlsx",
+ sheet_name="Solar Properties",
+ )
+ asset_list = asset_list[~asset_list["estimated"]]
+ asset_list["domna_address_1"] = asset_list["domna_address_1"].astype(str)
+ asset_list = asset_list[["domna_address_1", "domna_postcode", "epc_os_uprn"]].rename(
+ columns={"domna_address_1": "address", "domna_postcode": "postcode", "epc_os_uprn": "uprn"}
+ )
# Store the asset list in s3
filename = f"{USER_ID}/{PORTFOLIO_ID}/asset_list.csv"
@@ -98,14 +88,15 @@ def app():
"portfolio_id": str(PORTFOLIO_ID),
"housing_type": "Private",
"goal": "Increasing EPC",
- "goal_value": "C",
+ "goal_value": "A",
"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": valuation_filename,
+ "valuation_file_path": "",
"scenario_name": "Full package remote assessment",
"multi_plan": True,
"budget": None,
+ "inclusions": ["cavity_wall_insulation", "ventilation"]
}
print(body)
diff --git a/etl/find_my_epc/RetrieveFindMyEpc.py b/etl/find_my_epc/RetrieveFindMyEpc.py
index 7439200f..50955377 100644
--- a/etl/find_my_epc/RetrieveFindMyEpc.py
+++ b/etl/find_my_epc/RetrieveFindMyEpc.py
@@ -676,6 +676,9 @@ class RetrieveFindMyEpc:
"roomstat_programmer_trvs", "time_temperature_zone_control"
],
"Internal wall insulation": ["internal_wall_insulation"],
+ "High heat retention storage heaters and dual immersion cylinder and dual rate meter": [
+ "high_heat_retention_storage_heater"
+ ]
}
survey = True
@@ -709,8 +712,13 @@ class RetrieveFindMyEpc:
find_epc_data = searcher.retrieve_newest_find_my_epc_data()
except Exception as e:
logger.error(f"Error retrieving find my epc data: {e}")
+ if epc["address1"] == epc["address"]:
+ # There's no benefit of using the same address, so we split on comma
+ address1 = epc["address"].split(",")[0]
+ else:
+ address1 = epc["address1"]
# We attempt with the backup add
- searcher = cls(address=epc["address1"], postcode=epc["postcode"])
+ searcher = cls(address=address1, postcode=epc["postcode"])
find_epc_data = searcher.retrieve_newest_find_my_epc_data()
non_invasive_recommendations = {
diff --git a/recommendations/Recommendations.py b/recommendations/Recommendations.py
index 0e73cffe..462d43aa 100644
--- a/recommendations/Recommendations.py
+++ b/recommendations/Recommendations.py
@@ -679,7 +679,7 @@ class Recommendations:
# Handle the case of community schemes
if (heating_description == "Community scheme") or (hotwater_description == "Community scheme"):
- if main_fuel_description == "mains gas (community)":
+ if main_fuel_description in ["mains gas (community)", "UNKNOWN"]:
return {
"heating_fuel_type": "Natural Gas (Community Scheme)",
"hotwater_fuel_type": "Natural Gas (Community Scheme)",