added condition data to router

This commit is contained in:
Khalim Conn-Kowlessar 2024-07-26 16:41:32 +01:00
parent 73b6fb2b70
commit 24508b2a84
7 changed files with 68 additions and 16 deletions

View file

@ -166,6 +166,7 @@ class Property:
)
self.floor_level = None
self.number_of_windows = None
self.windows_area = None
self.solar_pv_percentage = None
self.current_adjusted_energy = None
@ -707,17 +708,20 @@ class Property:
# Today's costs
todays_heating_cost = energy_consumption_client.convert_cost_to_today(
original_cost=float(self.data["heating-cost-current"]),
lodgement_date=pd.Timestamp(self.epc_record.prepared_epc["lodgement_date"])
lodgement_date=pd.Timestamp(self.epc_record.prepared_epc["lodgement_date"]).tz_localize(None)
)
todays_hot_water_cost = energy_consumption_client.convert_cost_to_today(
original_cost=float(self.data["hot-water-cost-current"]),
lodgement_date=pd.Timestamp(self.epc_record.prepared_epc["lodgement_date"])
lodgement_date=pd.Timestamp(self.epc_record.prepared_epc["lodgement_date"]).tz_localize(None)
)
todays_lighting_cost = energy_consumption_client.convert_cost_to_today(
original_cost=float(self.data["lighting-cost-current"]),
lodgement_date=pd.Timestamp(self.epc_record.prepared_epc["lodgement_date"])
lodgement_date=pd.Timestamp(self.epc_record.prepared_epc["lodgement_date"]).tz_localize(None)
)
# If we have the kwh figures, we don't need to predict them
condition_data = self.energy_assessment_condition_data.copy()
scoring_df = pd.DataFrame([self.epc_record.prepared_epc])
# Change columns from underscores to hyphens
scoring_df.columns = [
@ -727,13 +731,20 @@ class Property:
scoring_df[col] = None
energy_consumption_client.data = None
heating_prediction = energy_consumption_client.score_new_data(
new_data=scoring_df, target="heating_kwh"
)[0]
hot_water_prediction = energy_consumption_client.score_new_data(
new_data=scoring_df, target="hot_water_kwh"
)[0]
heating_prediction = (
float(condition_data["space_heating_kwh"]) if condition_data["space_heating_kwh"]
else energy_consumption_client.score_new_data(
new_data=scoring_df, target="heating_kwh"
)[0]
)
hot_water_prediction = (
float(condition_data["water_heating_kwh"]) if condition_data["water_heating_kwh"]
else energy_consumption_client.score_new_data(
new_data=scoring_df, target="hot_water_kwh"
)[0]
)
# We convert the lighting cost into kwh, just using the price cap
lighting_kwh = float(self.data["lighting-cost-current"]) / AnnualBillSavings.ELECTRICITY_PRICE_CAP
@ -1040,13 +1051,14 @@ class Property:
medians across the EPC data
:return:
"""
# TODO: These functions should work on an EPCRecord object, so that the format is more standardised.
# They could also be added as attributes to the EPC Record
# Many of these pieces of information are now contained in the condition data
condition_data = self.energy_assessment_condition_data.copy()
# We can update the number of floors if we have this information in the condition data
self.number_of_floors = int(self.energy_assessment_condition_data["number_of_floors"]) \
if condition_data["number_of_floors"] is not None \
else self.number_of_floors
self.perimeter = float(self.energy_assessment_condition_data["perimeter"]) \
if condition_data["perimeter"] is not None \
else estimate_perimeter(
@ -1054,14 +1066,18 @@ class Property:
num_rooms=self.number_of_rooms / self.number_of_floors
)
self.insulation_wall_area = estimate_external_wall_area(
self.insulation_wall_area = float(self.energy_assessment_condition_data["insulation_wall_area"]) \
if condition_data["insulation_wall_area"] is not None \
else estimate_external_wall_area(
num_floors=self.number_of_floors,
floor_height=self.floor_height,
perimeter=self.perimeter,
built_form=self.data["built-form"],
)
self.insulation_floor_area = self.floor_area / self.number_of_floors
self.insulation_floor_area = float(self.energy_assessment_condition_data["main_dwelling_ground_floor_area"]) \
if condition_data["main_dwelling_ground_floor_area"] is not None \
else self.floor_area / self.number_of_floors
self.pitched_roof_area = esimtate_pitched_roof_area(
floor_area=self.insulation_floor_area, floor_height=self.floor_height
@ -1163,7 +1179,11 @@ class Property:
:return:
"""
self.number_of_windows = estimate_windows(
condition_data = self.energy_assessment_condition_data.copy()
self.number_of_windows = int(condition_data["number_of_windows"]) \
if condition_data["number_of_windows"] is not None \
else estimate_windows(
property_type=self.data["property-type"],
built_form=self.data["built-form"],
construction_age_band=self.construction_age_band,
@ -1171,6 +1191,10 @@ class Property:
number_habitable_rooms=self.number_of_rooms,
)
self.windows_area = float(condition_data["windows_area"]) \
if condition_data["windows_area"] is not None \
else None
def set_solar_panel_area(self, photo_supply_lookup, floor_area_decile_thresholds):
"""
Sets the approximate area of the solar panels

View file

@ -119,6 +119,9 @@ class EnergyAssessment(Base):
cylinder_insulation_type = Column(Text)
cylinder_insulation_thickness = Column(Integer)
cylinder_thermostat = Column(Boolean)
main_dwelling_ground_floor_area = Column(Float)
number_of_windows = Column(Integer)
windows_area = Column(Float)
EPC_KEYS = [
'low_energy_fixed_light_count', 'address', 'uprn_source', 'floor_height', 'heating_cost_potential',

View file

@ -515,6 +515,8 @@ async def trigger_plan(body: PlanTriggerRequest):
# )
print("Implement me")
# TODO: We can set the pitched roof area based on the results of the solar api!
logger.info("Getting components and epc recommendations")
recommendations = {}
recommendations_scoring_data = []

View file

@ -102,6 +102,7 @@ class EnergyConsumptionModel:
# We also retrieve the newest retail price comparison data which comes from Ofgem:
# https://www.ofgem.gov.uk/energy-data-and-research/data-portal/retail-market-indicators
# We use the detail price comparison by company and tariff type data
print("Reading retail price comparison - make sure this is up-to-date")
self.read_retail_price_comparison()
def read_retail_price_comparison(self):

View file

@ -366,6 +366,16 @@ class XmlParser:
self.insulation_wall_area = self.get_insulation_wall_area()
# We pull this out which is used as the insulation floor area
main_dwelling_ground_floor_area = [
f for f in self.floor_dimensions if f["building_part_identifier"] == "Main Dwelling" and f["floor"] == "0"
][0]["total_floor_area"]
main_dwelling_windows = [w for w in self.windows if w["window_location"] == "0"]
number_of_windows = len(main_dwelling_windows)
windows_area = sum([float(w["window_area"]) for w in main_dwelling_windows])
boolean_lookup = {
"true": True,
"false": False,
@ -400,6 +410,9 @@ class XmlParser:
"cylinder_insulation_type": cylinder_insulation_type[self.get_node_value('Cylinder-Insulation-Type')],
"cylinder_insulation_thickness": int(self.get_node_value('Cylinder-Insulation-Thickness')),
"cylinder_thermostat": boolean_lookup[self.get_node_value('Cylinder-Thermostat')],
"main_dwelling_ground_floor_area": float(main_dwelling_ground_floor_area),
"number_of_windows": int(number_of_windows),
"windows_area": float(windows_area),
}
def get_node_value(self, tag_name):

View file

@ -58,6 +58,11 @@ def main():
# Idea: We can collect all of this information by building part and store it separately in the database
# against the uprn. We can have key data for the EPC, but then also additional data for each building
# part. We can then use this data to make recommendations that are specific to each building part
# We should probably re-think this data model, so we break up the data in a more considered fasion and produce
# the underlying EPC data as a summary of the building parts. Not only do we have data against the main
# dwelling and extensions, but we also have multiple windows with individiaul pieces of information that
# we can use to make recommendations. We should store this data in a way that we can easily access it and
# use it to make recommendations (e.g. we should have a Windows table)
# For each property, we download the xmls and extract the data
database_data = []

View file

@ -48,10 +48,14 @@ class WindowsRecommendations:
is_secondary_glazing = self.property.restricted_measures or (
self.property.windows["glazing_type"] == "secondary"
)
windows_area = self.property.windows_area
if not number_of_windows:
raise ValueError("Number of windows not specified")
if windows_area is not None:
raise Exception("We have windows area, we should use this data for our recommendations!!!")
if self.property.windows["has_glazing"] & (
self.property.windows["glazing_coverage"] == "full"
):