mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
from pydantic import BaseModel, conlist, validator
|
|
from typing import Optional
|
|
|
|
TYPICAL_MEASURE_TYPES = [
|
|
"wall_insulation",
|
|
"roof_insulation",
|
|
"ventilation",
|
|
"floor_insulation",
|
|
"windows",
|
|
"fireplace",
|
|
"heating",
|
|
"hot_water",
|
|
"low_energy_lighting",
|
|
"secondary_heating",
|
|
"solar_pv"
|
|
]
|
|
|
|
SPECIFIC_MEASURES = [
|
|
# Specific measures
|
|
# Walls
|
|
"internal_wall_insulation",
|
|
"external_wall_insulation",
|
|
"cavity_wall_insulation",
|
|
# Roof
|
|
"loft_insulation",
|
|
"flat_roof_insulation",
|
|
"room_roof_insulation",
|
|
# Floor
|
|
"suspended_floor_insulation",
|
|
"solid_floor_insulation",
|
|
# Heating
|
|
"boiler_upgrade",
|
|
"high_heat_retention_storage_heater",
|
|
"air_source_heat_pump",
|
|
"secondary_heating",
|
|
# Solar
|
|
"solar_pv",
|
|
# Windows Glazing
|
|
"double_glazing",
|
|
"secondary_glazing",
|
|
# Mechanical ventilation
|
|
"ventilation",
|
|
# Other
|
|
"low_energy_lighting",
|
|
"fireplace",
|
|
"hot_water",
|
|
]
|
|
|
|
NON_INVASIVE_SPECIFIC_MEASURES = [
|
|
# Specific measures that will typically come from an energy assessment
|
|
"trickle_vents",
|
|
"draught_proofing",
|
|
"mixed_glazing", # This covers partial double glazing and secondary glazing
|
|
"cavity_extract_and_refill",
|
|
]
|
|
|
|
# This allows us to extend high level categories for measures such as "wall_insulation" to the specific measures
|
|
# such as "external_wall_insulation", "internal_wall_insulation", "cavity_wall_insulation"
|
|
MEASURE_MAP = {
|
|
"wall_insulation": [
|
|
"internal_wall_insulation", "external_wall_insulation", "cavity_wall_insulation",
|
|
],
|
|
"roof_insulation": ["loft_insulation", "flat_roof_insulation", "room_roof_insulation"],
|
|
"floor_insulation": ["suspended_floor_insulation", "solid_floor_insulation"],
|
|
"heating": ["boiler_upgrade", "high_heat_retention_storage_heater", "air_source_heat_pump"],
|
|
"windows": ["double_glazing", "secondary_glazing"],
|
|
"heating_controls": ["roomstat_programmer_trvs", "time_temperature_zone_control"]
|
|
}
|
|
|
|
|
|
class PlanTriggerRequest(BaseModel):
|
|
budget: Optional[float] = None
|
|
goal: str
|
|
housing_type: str
|
|
goal_value: str
|
|
portfolio_id: int
|
|
trigger_file_path: str
|
|
already_installed_file_path: Optional[str] = None
|
|
patches_file_path: Optional[str] = None
|
|
non_invasive_recommendations_file_path: Optional[str] = None
|
|
exclusions: Optional[conlist(str, min_items=1)] = None
|
|
inclusions: Optional[conlist(str, min_items=1)] = None
|
|
|
|
scenario_name: Optional[str] = ""
|
|
# If true, will allow us to create multiple plans for the same portfolio, whereas if this is false, if this property
|
|
# exists in the portfolio, it will be ignored
|
|
multi_plan: Optional[bool] = False
|
|
|
|
# if False, allows optimisation to be switched off
|
|
optimise: Optional[bool] = True
|
|
|
|
# If True, uses default u-values for models
|
|
default_u_values: Optional[bool] = True
|
|
|
|
_allowed_goals = {"Increasing EPC"}
|
|
|
|
_allowed_housing_types = {"Social", "Private"}
|
|
|
|
# Validator to ensure exclusions are within the pre-defined possibilities
|
|
@validator('exclusions', each_item=True)
|
|
def check_exclusions(cls, v):
|
|
if v not in TYPICAL_MEASURE_TYPES + SPECIFIC_MEASURES + NON_INVASIVE_SPECIFIC_MEASURES:
|
|
raise ValueError(f"{v} is not an allowed exclusion")
|
|
return v
|
|
|
|
@validator('inclusions', each_item=True)
|
|
def check_inclusions(cls, v):
|
|
if v not in TYPICAL_MEASURE_TYPES + SPECIFIC_MEASURES + NON_INVASIVE_SPECIFIC_MEASURES:
|
|
raise ValueError(f"{v} is not an allowed inclusion")
|
|
return v
|
|
|
|
# Validator to ensure that the goal is within the pre-defined possibilities
|
|
@validator('goal')
|
|
def check_goal(cls, v):
|
|
if v not in cls._allowed_goals:
|
|
raise ValueError(f"{v} is not a valid goal")
|
|
return v
|
|
|
|
# Validator to ensure that the housing type is within the pre-defined possibilities
|
|
@validator('housing_type')
|
|
def check_housing_type(cls, v):
|
|
if v not in cls._allowed_housing_types:
|
|
raise ValueError(f"{v} is not a valid housing type")
|
|
return v
|
|
|
|
|
|
class MdsRequest(PlanTriggerRequest):
|
|
# When creating the mds report, we allow an optional list of measures to select from. If this is passed, it will
|
|
# cause the service to select the optimal package from the list of measures
|
|
measures: Optional[conlist(str, min_items=1)] = None
|