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/backend/app/plan/router.py b/backend/app/plan/router.py index 855fd9d6..1b72e10e 100644 --- a/backend/app/plan/router.py +++ b/backend/app/plan/router.py @@ -772,6 +772,32 @@ async def trigger_plan(body: PlanTriggerRequest): ] recommendations[p.id] = final_recommendations + # when we have buildings, we tweak our solar PV recommendations as if one unit needs it, we apply it to all + # of them + # TODO: We can probably do better and optimise at the building level - this is temp + logger.info("Adjusting solar PV recommendations for buildings") + building_ids = set([p.building_id for p in input_properties if p.building_id is not None]) + + for bid in building_ids: + # We check if any of them have solar PV + building = [p for p in input_properties if p.building_id == bid] + has_solar = False + for unit in building: + # Get default recommendations + has_solar = len([r for r in recommendations[unit.id] if r["default"] and r["type"] == "solar_pv"]) > 0 + if has_solar: + break + + if has_solar: + # We adjust the units within the building + for unit in building: + for rec in recommendations[unit.id]: + if rec["type"] == "solar_pv": + # This is straightforward, we just set the default to True, since when we're at a building + # level, we only allow 1 solar PV option for each unit. If we change this, this logic will + # need to be updated + rec["default"] = True + # ~~~~~~~~~~~~~~~~ # Funding # ~~~~~~~~~~~~~~~~ diff --git a/etl/find_my_epc/RetrieveFindMyEpc.py b/etl/find_my_epc/RetrieveFindMyEpc.py index a172f27d..f93a5a73 100644 --- a/etl/find_my_epc/RetrieveFindMyEpc.py +++ b/etl/find_my_epc/RetrieveFindMyEpc.py @@ -263,7 +263,7 @@ class RetrieveFindMyEpc: "roomstat_programmer_trvs", "time_temperature_zone_control" ], "Change heating to gas condensing boiler": ["boiler_upgrade"], - "Fan assisted storage heaters and dual immersion cylinder": ["high_heat_retention_storage_heaters"], + "Fan assisted storage heaters and dual immersion cylinder": ["high_heat_retention_storage_heater"], "Flat roof or sloping ceiling insulation": ["flat_roof_insulation"], "Heating controls (room thermostat)": [ "roomstat_programmer_trvs", "time_temperature_zone_control" @@ -291,7 +291,7 @@ class RetrieveFindMyEpc: "PV Cells recommendation": [], "Replacement glazing units": ["double_glazing"], "Heating controls (time and temperature zone control)": ["time_temperature_zone_control"], - "High heat retention storage heaters": ["high_heat_retention_storage_heaters"], + "High heat retention storage heaters": ["high_heat_retention_storage_heater"], "Gas condensing boiler": ["boiler_upgrade"], "Change room heaters to condensing boiler": ["boiler_upgrade"], "Cylinder thermostat": ["cylinder_thermostat"], diff --git a/recommendations/HeatingRecommender.py b/recommendations/HeatingRecommender.py index 1eab7d42..c5c07f89 100644 --- a/recommendations/HeatingRecommender.py +++ b/recommendations/HeatingRecommender.py @@ -1,6 +1,5 @@ import re import backend.app.assumptions as assumptions -from etl.customers.immo.pilot.asset_list import non_invasive_recommendations from recommendations.Costs import Costs, BOILER_UPGRADE_SCHEME_ASHP_VALUE from recommendations.recommendation_utils import ( check_simulation_difference, override_costs, combine_recommendation_configs @@ -632,7 +631,8 @@ class HeatingRecommender: heating_controls_only, system_change, system_type, - measure_type + measure_type, + non_intrusive_recommendation=None ): """ Given a recommendation for heating controls, and a recommendation for the heating system, we combine the two @@ -650,8 +650,13 @@ class HeatingRecommender: :param system_type: The type of heating system we are recommending :param measure_type: The type of measure we are recommending - more granular than the "type" field, allowing us to distinguish between different types of heating recommendations + :param non_intrusive_recommendation: A non-intrusive recommendation, which may specify the number of SAP points + or a cost for this recommendation """ + if non_intrusive_recommendation is None: + non_intrusive_recommendation = {} + # We produce recommendations with & without heating controls # We will also produce a recommendation for heating controls only heating_controls_switch = [True, False] if controls_recommendations else [False] @@ -699,13 +704,14 @@ class HeatingRecommender: "description": recommendation_description, "starting_u_value": None, "new_u_value": None, - "sap_points": None, + "sap_points": non_intrusive_recommendation.get("sap_points"), "already_installed": already_installed, **total_costs, "simulation_config": recommendation_simulation_config, "description_simulation": recommendation_description_simulation, # We insert the heating system type here - "system_type": system_type + "system_type": system_type, + "survey": non_intrusive_recommendation.get("survey", False) } output.append(recommendation) @@ -808,6 +814,13 @@ class HeatingRecommender: # No recommendation needed return + # We check if there is a high heat retention non-intrusive recommendation + non_intrusive_recommendation = next( + (r for r in self.property.non_invasive_recommendations if + r["type"] == "high_heat_retention_storage_heater"), + {} + ) + # We check if the property has dual heating in place with a boiler and storage heaters if self.dual_heating: new_heating_description = self.DUAL_HEATING_DESCRIPTIONS[ @@ -896,7 +909,8 @@ class HeatingRecommender: heating_controls_only=heating_controls_only, system_change=system_change, system_type="high_heat_retention_storage_heater", - measure_type="high_heat_retention_storage_heater" + measure_type="high_heat_retention_storage_heater", + non_intrusive_recommendation=non_intrusive_recommendation ) if _return: return recommendations