mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Implemeted solar api wip
This commit is contained in:
parent
b20e00a736
commit
1d28a7e335
10 changed files with 62 additions and 17 deletions
|
|
@ -351,6 +351,7 @@ class Property:
|
||||||
if r["phase"] <= phase
|
if r["phase"] <= phase
|
||||||
]
|
]
|
||||||
epc_transformations = [x["description_simulation"] for x in represenative_recs_to_this_phase]
|
epc_transformations = [x["description_simulation"] for x in represenative_recs_to_this_phase]
|
||||||
|
|
||||||
# It is possible that we could have two simulations applied to the same descriptions
|
# It is possible that we could have two simulations applied to the same descriptions
|
||||||
# We extract these out
|
# We extract these out
|
||||||
phase_epc_transformation = {}
|
phase_epc_transformation = {}
|
||||||
|
|
|
||||||
|
|
@ -448,12 +448,13 @@ async def trigger_plan(body: PlanTriggerRequest):
|
||||||
p.set_solar_panel_configuration(unit_solar_panel_configuration)
|
p.set_solar_panel_configuration(unit_solar_panel_configuration)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Model the solar potential at the property level
|
# # Model the solar potential at the property level
|
||||||
for p in input_properties:
|
# for p in input_properties:
|
||||||
# TODO: Complete me! - we probably won't do this for individual flats
|
# # TODO: Complete me! - we probably won't do this for individual flats
|
||||||
solar_performance = solar_api_client.get(
|
# solar_performance = solar_api_client.get(
|
||||||
longitude=p.spatial["longitude"], latitude=p.spatial["latitude"]
|
# longitude=p.spatial["longitude"], latitude=p.spatial["latitude"]
|
||||||
)
|
# )
|
||||||
|
print("Implement me")
|
||||||
|
|
||||||
logger.info("Getting components and epc recommendations")
|
logger.info("Getting components and epc recommendations")
|
||||||
recommendations = {}
|
recommendations = {}
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ class PlanTriggerRequest(BaseModel):
|
||||||
|
|
||||||
# Pre-defined list of possibilities for exclusions
|
# Pre-defined list of possibilities for exclusions
|
||||||
_allowed_exclusions = {
|
_allowed_exclusions = {
|
||||||
|
# Measure classes
|
||||||
"wall_insulation",
|
"wall_insulation",
|
||||||
"ventilation",
|
"ventilation",
|
||||||
"roof_insulation",
|
"roof_insulation",
|
||||||
|
|
@ -25,7 +26,9 @@ class PlanTriggerRequest(BaseModel):
|
||||||
"heating",
|
"heating",
|
||||||
"hot_water",
|
"hot_water",
|
||||||
"lighting",
|
"lighting",
|
||||||
"solar_pv"
|
"solar_pv",
|
||||||
|
# Specific measures
|
||||||
|
"air_source_heat_pump",
|
||||||
}
|
}
|
||||||
|
|
||||||
_allowed_goals = {"Increase EPC"}
|
_allowed_goals = {"Increase EPC"}
|
||||||
|
|
|
||||||
|
|
@ -119,11 +119,12 @@ def app():
|
||||||
"portfolio_id": str(PORTFOLIO_ID),
|
"portfolio_id": str(PORTFOLIO_ID),
|
||||||
"housing_type": "Private",
|
"housing_type": "Private",
|
||||||
"goal": "Increase EPC",
|
"goal": "Increase EPC",
|
||||||
"goal_value": "A",
|
"goal_value": "C",
|
||||||
"trigger_file_path": filename,
|
"trigger_file_path": filename,
|
||||||
"already_installed_file_path": already_installed_filename,
|
"already_installed_file_path": already_installed_filename,
|
||||||
"patches_file_path": "",
|
"patches_file_path": "",
|
||||||
"non_invasive_recommendations_file_path": "",
|
"non_invasive_recommendations_file_path": "",
|
||||||
|
"exclusions": ["wall_insulation", "air_source_heat_pump"],
|
||||||
"budget": None,
|
"budget": None,
|
||||||
}
|
}
|
||||||
print(body)
|
print(body)
|
||||||
|
|
|
||||||
|
|
@ -190,7 +190,11 @@ class HeatingControlRecommender:
|
||||||
"new_u_value": None,
|
"new_u_value": None,
|
||||||
"sap_points": None,
|
"sap_points": None,
|
||||||
"already_installed": already_installed,
|
"already_installed": already_installed,
|
||||||
"simulation_config": simulation_config
|
"simulation_config": simulation_config,
|
||||||
|
"description_simulation": {
|
||||||
|
"mainheatcont-description": "Programmer, room thermostat and TRVS",
|
||||||
|
"mainheatc-energy-eff": "Good"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -250,6 +254,10 @@ class HeatingControlRecommender:
|
||||||
"new_u_value": None,
|
"new_u_value": None,
|
||||||
"sap_points": None,
|
"sap_points": None,
|
||||||
"already_installed": already_installed,
|
"already_installed": already_installed,
|
||||||
"simulation_config": simulation_config
|
"simulation_config": simulation_config,
|
||||||
|
"description_simulation": {
|
||||||
|
"mainheatcont-description": "Time and temperature zone control",
|
||||||
|
"mainheatc-energy-eff": "Very Good"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -42,18 +42,21 @@ class HeatingRecommender:
|
||||||
|
|
||||||
return self.has_electric_heating_description or electric_heating_assumed
|
return self.has_electric_heating_description or electric_heating_assumed
|
||||||
|
|
||||||
def recommend(self, has_cavity_or_loft_recommendations, phase=0):
|
def recommend(self, has_cavity_or_loft_recommendations, phase=0, exclusions=None):
|
||||||
"""
|
"""
|
||||||
Produces heating recommendations
|
Produces heating recommendations
|
||||||
:param has_cavity_or_loft_recommendations: boolean indicating if we have produced a cavity or loft insulation
|
:param has_cavity_or_loft_recommendations: boolean indicating if we have produced a cavity or loft insulation
|
||||||
recommendation. If there are cavity or loft recommendations, the property would need to complete those measures
|
recommendation. If there are cavity or loft recommendations, the property would need to complete those measures
|
||||||
before being able to get the boiler upgrade scheme benefits. The messaging in the front end would be to
|
before being able to get the boiler upgrade scheme benefits. The messaging in the front end would be to
|
||||||
:param phase: indicates the phase of the retrofit programme
|
:param phase: indicates the phase of the retrofit programme
|
||||||
|
:param exclusions: A list of exclusions for the recommendations
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: We could have a system flush recommendation for an existing boiler, where there is no need to replace
|
# TODO: We could have a system flush recommendation for an existing boiler, where there is no need to replace
|
||||||
# the boiler, but instead flushing the system will make it run more efficiently. There is a cost for this
|
# the boiler, but instead flushing the system will make it run more efficiently. There is a cost for this
|
||||||
# in the Costs class, stored as SYSTEM_FLUSH_COST
|
# in the Costs class, stored as SYSTEM_FLUSH_COST
|
||||||
|
|
||||||
|
exclusions = [] if exclusions is None else exclusions
|
||||||
|
|
||||||
self.heating_recommendations = []
|
self.heating_recommendations = []
|
||||||
self.heating_control_recommendations = []
|
self.heating_control_recommendations = []
|
||||||
|
|
@ -112,7 +115,7 @@ class HeatingRecommender:
|
||||||
# In the future, we'll allow overrides, so that non-intrusive surveys can contradict these conditions
|
# In the future, we'll allow overrides, so that non-intrusive surveys can contradict these conditions
|
||||||
# and either allow or prevent the recommendation of an air source heat pump
|
# and either allow or prevent the recommendation of an air source heat pump
|
||||||
|
|
||||||
if self.is_ashp_valid():
|
if self.is_ashp_valid(exclusions=exclusions):
|
||||||
self.recommend_air_source_heat_pump(
|
self.recommend_air_source_heat_pump(
|
||||||
phase=phase, has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations
|
phase=phase, has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations
|
||||||
)
|
)
|
||||||
|
|
@ -182,11 +185,14 @@ class HeatingRecommender:
|
||||||
description = ("Replace the existing boiler and cylinder without a thermostat with a new electric combi "
|
description = ("Replace the existing boiler and cylinder without a thermostat with a new electric combi "
|
||||||
"boiler")
|
"boiler")
|
||||||
|
|
||||||
def is_ashp_valid(self):
|
def is_ashp_valid(self, exclusions):
|
||||||
|
|
||||||
if "air_source_heat_pump" in self.property.non_invasive_recommendations:
|
if "air_source_heat_pump" in self.property.non_invasive_recommendations:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
if "air_source_heat_pump" in exclusions:
|
||||||
|
return False
|
||||||
|
|
||||||
suitable_property_type = self.property.data["property-type"] in ["House", "Bungalow"]
|
suitable_property_type = self.property.data["property-type"] in ["House", "Bungalow"]
|
||||||
has_air_source_heat_pump = self.property.main_heating["has_air_source_heat_pump"]
|
has_air_source_heat_pump = self.property.main_heating["has_air_source_heat_pump"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -109,8 +109,12 @@ class LightingRecommendations:
|
||||||
# For SAP points, we use the fact that lighting is usually worth 2 points and we scale this to
|
# For SAP points, we use the fact that lighting is usually worth 2 points and we scale this to
|
||||||
# the proportion of lights that will be set to low energy
|
# the proportion of lights that will be set to low energy
|
||||||
"sap_points": round(2 * (number_non_lel_outlets / number_lighting_outlets), 2),
|
"sap_points": round(2 * (number_non_lel_outlets / number_lighting_outlets), 2),
|
||||||
"heat_demand": heat_demand_change,
|
"kwh_savings": heat_demand_change,
|
||||||
"co2_equivalent_savings": carbon_change,
|
"co2_equivalent_savings": carbon_change,
|
||||||
|
"description_simulation": {
|
||||||
|
"lighting-energy-eff": "Very Good",
|
||||||
|
"lighting-description": "Low energy lighting in all fixed outlets",
|
||||||
|
},
|
||||||
**cost_result
|
**cost_result
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,9 @@ class Recommendations:
|
||||||
has_cavity_or_loft_recommendations = len(cavity_or_loft_recommendations) > 0
|
has_cavity_or_loft_recommendations = len(cavity_or_loft_recommendations) > 0
|
||||||
|
|
||||||
self.heating_recommender.recommend(
|
self.heating_recommender.recommend(
|
||||||
phase=phase, has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations
|
phase=phase,
|
||||||
|
has_cavity_or_loft_recommendations=has_cavity_or_loft_recommendations,
|
||||||
|
exclusions=self.exclusions
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
self.heating_recommender.heating_recommendations or
|
self.heating_recommender.heating_recommendations or
|
||||||
|
|
@ -294,6 +296,13 @@ class Recommendations:
|
||||||
if rec["type"] != "solar_pv":
|
if rec["type"] != "solar_pv":
|
||||||
return 0, 0
|
return 0, 0
|
||||||
|
|
||||||
|
if property_instance.solar_panel_configuration is None:
|
||||||
|
print("PLACEHOLDER ESTIMATES")
|
||||||
|
# 50% reduction average
|
||||||
|
kwh_reduction = property_instance.energy_consumption_estimates["adjusted"]["appliances"] * 0.5
|
||||||
|
predicted_appliances_cost_reduction = kwh_reduction * AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
||||||
|
return predicted_appliances_cost_reduction, kwh_reduction
|
||||||
|
|
||||||
# Calulate the amount of energy the solar panel array will generate for this unit
|
# Calulate the amount of energy the solar panel array will generate for this unit
|
||||||
unit_energy_consumption = (
|
unit_energy_consumption = (
|
||||||
rec["initial_ac_kwh_per_year"] *
|
rec["initial_ac_kwh_per_year"] *
|
||||||
|
|
@ -721,10 +730,14 @@ class Recommendations:
|
||||||
heating_kwh_reduction = 0 if predicted_heating_cost_reduction == 0 else (
|
heating_kwh_reduction = 0 if predicted_heating_cost_reduction == 0 else (
|
||||||
phase_kwh_figures[previous_phase]["adjusted"]["heating"] - new_heating_kwh_adjusted
|
phase_kwh_figures[previous_phase]["adjusted"]["heating"] - new_heating_kwh_adjusted
|
||||||
)
|
)
|
||||||
|
if heating_kwh_reduction < 0:
|
||||||
|
heating_kwh_reduction = 0
|
||||||
|
|
||||||
hot_water_kwh_reduction = 0 if predicted_hot_water_cost_reduction == 0 else (
|
hot_water_kwh_reduction = 0 if predicted_hot_water_cost_reduction == 0 else (
|
||||||
phase_kwh_figures[previous_phase]["adjusted"]["hot_water"] - new_hot_water_kwh_adjusted
|
phase_kwh_figures[previous_phase]["adjusted"]["hot_water"] - new_hot_water_kwh_adjusted
|
||||||
)
|
)
|
||||||
|
if hot_water_kwh_reduction < 0:
|
||||||
|
hot_water_kwh_reduction = 0
|
||||||
|
|
||||||
lighting_kwh_reduction = predicted_lighting_cost_reduction / AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
lighting_kwh_reduction = predicted_lighting_cost_reduction / AnnualBillSavings.ELECTRICITY_PRICE_CAP
|
||||||
|
|
||||||
|
|
@ -773,7 +786,7 @@ class Recommendations:
|
||||||
# For the moment, we cap the number of SAP points that can be achieved by ventilation at 2
|
# For the moment, we cap the number of SAP points that can be achieved by ventilation at 2
|
||||||
rec["sap_points"] = min(predicted_sap_points, LightingRecommendations.SAP_LIMIT)
|
rec["sap_points"] = min(predicted_sap_points, LightingRecommendations.SAP_LIMIT)
|
||||||
rec["co2_equivalent_savings"] = min(predicted_co2_savings, rec["co2_equivalent_savings"])
|
rec["co2_equivalent_savings"] = min(predicted_co2_savings, rec["co2_equivalent_savings"])
|
||||||
rec["heat_demand"] = min(predicted_heat_demand, rec["heat_demand"])
|
rec["heat_demand"] = predicted_heat_demand
|
||||||
else:
|
else:
|
||||||
rec["sap_points"] = predicted_sap_points
|
rec["sap_points"] = predicted_sap_points
|
||||||
rec["co2_equivalent_savings"] = predicted_co2_savings
|
rec["co2_equivalent_savings"] = predicted_co2_savings
|
||||||
|
|
|
||||||
|
|
@ -244,6 +244,7 @@ class SolarPvRecommendations:
|
||||||
# This is required for simulating the SAP impact. solar_pv_percentage is between 0 & 1 so we scale
|
# This is required for simulating the SAP impact. solar_pv_percentage is between 0 & 1 so we scale
|
||||||
# back up here
|
# back up here
|
||||||
"photo_supply": 100 * roof_coverage,
|
"photo_supply": 100 * roof_coverage,
|
||||||
"has_battery": has_battery
|
"has_battery": has_battery,
|
||||||
|
"description_simulation": {"photo-supply": 100 * roof_coverage},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -115,5 +115,12 @@ class WindowsRecommendations:
|
||||||
"already_installed": already_installed,
|
"already_installed": already_installed,
|
||||||
**cost_result,
|
**cost_result,
|
||||||
"is_secondary_glazing": is_secondary_glazing,
|
"is_secondary_glazing": is_secondary_glazing,
|
||||||
|
# TODO: Make this condition on is_secondary_glazing
|
||||||
|
"description_simulation": {
|
||||||
|
"multi-glaze-proportion": 100,
|
||||||
|
"windows-energy-eff": "Average",
|
||||||
|
"windows-description": "Fully double glazed",
|
||||||
|
"glazed-type": "double glazing installed during or after 2002",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue