From 6cf0db87f7a3fc68db02d518f9e57bc28b3fe0c1 Mon Sep 17 00:00:00 2001 From: Khalim Conn-Kowlessar Date: Thu, 31 Oct 2024 14:35:14 +0000 Subject: [PATCH] completed packages for first 12 surveys --- .idea/Model.iml | 2 +- .idea/misc.xml | 2 +- etl/customers/aiha/xml_extraction.py | 139 ++++++++++++++++----------- 3 files changed, 85 insertions(+), 58 deletions(-) diff --git a/.idea/Model.iml b/.idea/Model.iml index 762580d9..df6c4faa 100644 --- a/.idea/Model.iml +++ b/.idea/Model.iml @@ -7,7 +7,7 @@ - + diff --git a/.idea/misc.xml b/.idea/misc.xml index c916a158..50cad4ca 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,7 @@ - + diff --git a/etl/customers/aiha/xml_extraction.py b/etl/customers/aiha/xml_extraction.py index 038e8593..65e0eb1e 100644 --- a/etl/customers/aiha/xml_extraction.py +++ b/etl/customers/aiha/xml_extraction.py @@ -9,6 +9,32 @@ SURVEY_FOLDER_PATH = "/Users/khalimconn-kowlessar/Documents/hestia/Customers/AIH CONTINGENCY_RATE = 0.26 +def sap_to_epc(sap_points: int | float): + """ + Simple utility function to convert SAP points to EPC rating. + :param sap_points: numerical value of SAP points, typically between 0 and 100 + :return: + """ + + if sap_points <= 0: + raise ValueError("SAP points should be above 0.") + + if sap_points >= 92: + return "A" + elif sap_points >= 81: + return "B" + elif sap_points >= 69: + return "C" + elif sap_points >= 55: + return "D" + elif sap_points >= 39: + return "E" + elif sap_points >= 21: + return "F" + else: + return "G" + + def main(): """ This script handles the extraction of data from the XML files in the survey folders. @@ -76,24 +102,14 @@ def main(): # TODO # - AIH001-03 has a loft that is inaccessible - ask Chenai about why this property didn't have access to the loft # [Can't remember, not clear - Chenai will check] - # - AIH001-03 instead of cylinder insulation, we could install an air source heat pump but it might not be the - # best option for this property due to it being extrememly large and the walls being uninsulated. It might not - # be performant enough in the winter, when COP will be more like 1.5. - # - AIH001-03 - can add additional 1.6kWp solar PV to flat roof to get close to EPC C. How many occupants are - # in the property? Does it make sense to have such a large solar PV system (5.6kWp)? # - AIH001-04 why couldn't the cylinder be accessed? - treating this could get to the EPC C # - Potential measure - search for the cylinder and insulate it # - AIH001-08 and AIH001-09, check if it's freehold - could solar work as both of these units are part of the same # buulding [Question for Lewis & Kevin] # - AIH001-09 - Is it not possible to install a loft hatch? [IT IS NOT, NO ACCESS - would need to accessed from # the other unit] - # - AIH001-09 - Why is there assumed secondary heating? [Question for Lewis & Kevin] # - AIH001-09 - Is there definitely an immersion water heater? Is this definitely the case for the other units? - # [Question for Lewis & Kevin] - # - AIH001-11 - The layout of this unit is confusing, is there roof access? [NO!!!! - It's a Sun room!!] - # - AIH001-12 - Why was there not access to the cylinder? [Sealed shut] - # - AIH001-12 - Is the need to draught proofing due to the windows? [This would be addressed by deailing with the - # windows] + # [Question for Lewis & Kevin] - [YES - ASHP!!!!] recommended_measures = [ { @@ -114,40 +130,32 @@ def main(): }, { "measure": "Solar PV", - "description": "5.6kWp Solar PV system", + "description": "4kWp Solar PV system", "config": [ { "size": "4kWp", "orientation": "East", "elavation": 30, - "overshading": "Modest", + "overshading": "None or little", }, - { - "size": "1.6kWp", - "orientation": "Horizontal", - "elavation": "Horizontal", - "overshading": "Modest", - } ], - "sap_points": 7, - "ending_sap": 53 + "sap_points": 10, + "ending_sap": 54 }, { - "measure": "Loft Insulation", - "description": "300mm loft insulation", - "floor_area": 80, # Based on area of 1st floor - "sap_points": 8, - "ending_sap": 61 + "measure": "Air Source Heat Pump", + "description": "Ecoforest ecoAIR EVI 4-20 20kW air source heat pump (+TTZC)", + "sap_points": 20, + "ending_sap": 74 }, { - "measure": "TTZC", - "description": "Smart Thermostat", - "sap_points": 3, - "ending_sap": 64 + "measure": "Tariff Review", + "description": "Switch to 24-hour tariff", + "sap_points": 15, + "ending_sap": 89 } ], - "notes": "There was no access to the loft for this property and so a loft hatch would need to be " - "installed..." + "notes": "Unclear if the loft is accessible" }, { "survey_key": "AIH001-04", @@ -174,14 +182,14 @@ def main(): "size": "4kWp", "orientation": "South", "elavation": 30, - "overshading": "Modest", + "overshading": "None or little", } ], - "sap_points": 12, - "ending_sap": 67 + "sap_points": 15, + "ending_sap": 70 } ], - "notes": "" + "notes": "Roof is flat, PV array should be installed south facing with elevation" }, { "survey_key": "AIH001-05", @@ -276,7 +284,7 @@ def main(): "measure": "Internal Wall Insulation", "description": "100mm internal wall insulation", "hlp": 24.13 * 2.63, - "sap_points": 5, + "sap_points": 7, "ending_sap": 69, }, { @@ -316,8 +324,32 @@ def main(): "description": "Smart Thermostat", "sap_points": 3, "ending_sap": 56, + }, + { + "measure": "Solar PV", + "description": "1.6kWp Solar PV system", + "config": [ + { + "size": "1.6W", + "orientation": "South-East", + "elavation": 30, + "overshading": "None or little", + } + ], + "sap_points": 6, + "ending_sap": 62 + }, + { + "measure": "Loft Insulation", + "description": "300mm loft insulation", + "floor_area": 63.59 + 12.31, # Based on area of main building and 1st extension + "sap_points": 8, + "ending_sap": 70, } - ] + ], + "notes": "This property is a house split into 2 flats. We can install a PV array for both units (one array" + "per unit). Area on south-east part of roof is ~22m2 with no overshadowing. Flat roof area is 8m2" + "with modest overshadowing. We suggest a 3.2kWp system, across two units" }, { "survey_key": "AIH001-11", @@ -353,14 +385,7 @@ def main(): "description": "Installation of double glazing", "n_windows": 20, # Counted the bay windows each as 3 "windows_area": 10.66, - "sap_points": 2, - "ending_sap": 48, - }, - { - "measure": "Draught Proofing", - "description": "Window draught proofing improvements", - "n_windows": 20, # Counted the bay windows each as 3 - "sap_points": 1, + "sap_points": 3, "ending_sap": 49, }, { @@ -379,7 +404,7 @@ def main(): }, { "measure": "Air Source Heat Pump", - "description": "Ecoforest ecoAIR EVI 4-20 20kW air source heat pump", + "description": "Ecoforest ecoAIR EVI 4-20 20kW air source heat pump (+TTZC)", "sap_points": 15, "ending_sap": 73 }, @@ -497,17 +522,19 @@ def main(): {'item': 'Window draught proofing improvements', 'unit_price': 63, 'unit': 'window'}, {'item': '100mm flat roof insulation', 'unit_price': 195, 'unit': 'floor_m2'}, {'item': 'Switch to 24-hour tariff', 'unit_price': 0, 'unit': None}, - {'item': '3.2kWp Solar PV system', 'unit_price': 3686, 'unit': 'unit_needs_scaffolding'}, - {'item': '5.6kWp Solar PV system', 'unit_price': 5015, 'unit': 'unit_needs_scaffolding'}, {'item': 'Installation of double glazing', 'unit_price': 1074, 'unit': 'window'}, - {'item': 'Ecoforest ecoAIR EVI 4-20 20kW air source heat pump', 'unit_price': 21189, 'unit': 'unit'}, - {'item': '2kWp Solar PV system', 'unit_price': 3201, 'unit': 'unit_needs_scaffolding'}, + {'item': 'Ecoforest ecoAIR EVI 4-20 20kW air source heat pump (+TTZC)', 'unit_price': 21189 + 1200, + 'unit': 'unit'}, {'item': '100mm+ RIR insulation on all surfaces (ceiling u=0.16, walls u=0.3)', 'unit_price': 244.80, 'unit': 'floor_m2'}, - {'item': '4kWp Solar PV system', 'unit_price': 4009, 'unit': 'unit_needs_scaffolding'}, {'item': '300mm loft insulation', 'unit_price': 16.07, 'unit': 'floor_m2'}, {'item': 'Smart Thermostat', 'unit_price': 1200, 'unit': 'unit'}, {'item': '2x DMEV fans', 'unit_price': 1070, 'unit': 'unit'}, + {'item': '1.6kWp Solar PV system', 'unit_price': 3040, 'unit': 'unit_needs_scaffolding'}, + {'item': '2kWp Solar PV system', 'unit_price': 3201, 'unit': 'unit_needs_scaffolding'}, + {'item': '3.2kWp Solar PV system', 'unit_price': 3686, 'unit': 'unit_needs_scaffolding'}, + {'item': '4kWp Solar PV system', 'unit_price': 4009, 'unit': 'unit_needs_scaffolding'}, + {'item': '5.6kWp Solar PV system', 'unit_price': 5015, 'unit': 'unit_needs_scaffolding'}, ] pricing_data = pd.DataFrame(pricing_data) @@ -587,13 +614,13 @@ def main(): result_df = pd.merge(pivoted_measures, starting_sap_df, on="survey_key", how="left") # Step 5: Calculate the ending SAP. - result_df["ending_sap"] = result_df["starting_sap"] + result_df["total_sap_points"] + result_df["Ending SAP"] = result_df["starting_sap"] + result_df["total_sap_points"] + result_df["Ending EPC Rating"] = result_df["Ending SAP"].apply(sap_to_epc) # Step 6: Merge the result with the measures_data to get the final DataFrame. final_measures = measures_data.merge( result_df, how="left", on="survey_key" ) - -if __name__ == "__main__": - main() +# if __name__ == "__main__": +# main()