mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
1820 lines
88 KiB
Python
1820 lines
88 KiB
Python
from datetime import date
|
|
from typing import List, Optional, Sequence, Union
|
|
|
|
from domain.epc.epc_property_data import (
|
|
EnergyElement,
|
|
EpcPropertyData,
|
|
InstantaneousWwhrs,
|
|
MainHeatingDetail,
|
|
PhotovoltaicSupply,
|
|
PhotovoltaicSupplyNoneOrNoDetails,
|
|
PvBatteries,
|
|
PvBattery,
|
|
SapAlternativeWall,
|
|
SapBuildingPart,
|
|
SapEnergySource,
|
|
SapFloorDimension,
|
|
SapHeating,
|
|
SapRoomInRoof,
|
|
SapVentilation,
|
|
SapWindow,
|
|
ShowerOutlet,
|
|
ShowerOutlets,
|
|
WindTurbineDetails,
|
|
WindowTransmissionDetails,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_17_0 import (
|
|
RdSapSchema17_0,
|
|
EnergyElement as EnergyElement_17_0,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_17_1 import (
|
|
RdSapSchema17_1,
|
|
EnergyElement as EnergyElement_17_1,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_18_0 import (
|
|
RdSapSchema18_0,
|
|
EnergyElement as EnergyElement_18_0,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_19_0 import (
|
|
RdSapSchema19_0,
|
|
EnergyElement as EnergyElement_19_0,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_20_0_0 import (
|
|
RdSapSchema20_0_0,
|
|
EnergyElement as EnergyElement_20_0,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_21_0_0 import (
|
|
RdSapSchema21_0_0,
|
|
EnergyElement as EnergyElement_21_0,
|
|
)
|
|
from datatypes.epc.schema.rdsap_schema_21_0_1 import (
|
|
RdSapSchema21_0_1,
|
|
EnergyElement as EnergyElement_21_0_1,
|
|
)
|
|
from datatypes.epc.surveys.elmhurst_site_notes import (
|
|
ElmhurstSiteNotes,
|
|
VentilationAndCooling as ElmhurstVentilation,
|
|
Window as ElmhurstWindow,
|
|
)
|
|
from datatypes.epc.surveys.pashub_rdsap_site_notes import (
|
|
BuildingConstruction,
|
|
BuildingMeasurements,
|
|
ExtensionConstruction,
|
|
ExtensionMeasurements,
|
|
ExtensionRoofSpace,
|
|
FloorMeasurement,
|
|
HeatingAndHotWater,
|
|
PasHubRdSapSiteNotes,
|
|
RoofSpaceDetail,
|
|
Ventilation,
|
|
WaterUse,
|
|
Window,
|
|
)
|
|
|
|
AnyRdSapSchema = Union[
|
|
RdSapSchema17_0,
|
|
RdSapSchema17_1,
|
|
RdSapSchema18_0,
|
|
RdSapSchema19_0,
|
|
RdSapSchema20_0_0,
|
|
RdSapSchema21_0_0,
|
|
RdSapSchema21_0_1,
|
|
]
|
|
|
|
|
|
class EpcPropertyDataMapper:
|
|
|
|
@staticmethod
|
|
def from_site_notes(survey: PasHubRdSapSiteNotes) -> EpcPropertyData:
|
|
general = survey.general
|
|
metadata = survey.inspection_metadata
|
|
address_parts = [p.strip() for p in metadata.property_address.split(", ")]
|
|
postcode = address_parts[-1] if address_parts else ""
|
|
post_town = (
|
|
address_parts[-3]
|
|
if len(address_parts) >= 4
|
|
else (address_parts[-2] if len(address_parts) >= 3 else "")
|
|
)
|
|
address_line_1 = (
|
|
", ".join(address_parts[:-3])
|
|
if len(address_parts) >= 4
|
|
else (
|
|
", ".join(address_parts[:-2])
|
|
if len(address_parts) >= 3
|
|
else address_parts[0] if address_parts else ""
|
|
)
|
|
)
|
|
|
|
construction = survey.building_construction
|
|
measurements = survey.building_measurements
|
|
heating = survey.heating_and_hot_water
|
|
ventilation = survey.ventilation
|
|
renewables = survey.renewables
|
|
room_counts = survey.room_count_elements
|
|
|
|
roof_space = survey.roof_space
|
|
sap_building_parts = [
|
|
_map_main_building_part(
|
|
construction, measurements, roof_space.main_building
|
|
)
|
|
]
|
|
if construction.extensions and measurements.extensions:
|
|
for ext_c in construction.extensions:
|
|
matching_m = [m for m in measurements.extensions if m.id == ext_c.id]
|
|
matching_r = [
|
|
r for r in (roof_space.extensions or []) if r.id == ext_c.id
|
|
]
|
|
if matching_m:
|
|
sap_building_parts.append(
|
|
_map_extension_building_part(
|
|
ext_c, matching_m[0], matching_r[0] if matching_r else None
|
|
)
|
|
)
|
|
|
|
total_floor_area = round(
|
|
sum(
|
|
floor.total_floor_area_m2
|
|
for part in sap_building_parts
|
|
for floor in part.sap_floor_dimensions
|
|
),
|
|
2,
|
|
) # TODO: verify that is the correct approach
|
|
|
|
return EpcPropertyData(
|
|
dwelling_type=f"{general.detachment_type} {general.property_type.lower()}",
|
|
inspection_date=general.inspection_date,
|
|
tenure=general.tenure,
|
|
transaction_type=general.transaction_type,
|
|
roofs=[],
|
|
walls=[],
|
|
floors=[],
|
|
main_heating=[],
|
|
door_count=room_counts.number_of_external_doors,
|
|
sap_heating=_map_sap_heating(heating, ventilation, survey.water_use),
|
|
sap_windows=[_map_sap_window(w) for w in survey.windows],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=general.mains_gas_available,
|
|
meter_type=general.electric_meter_type,
|
|
pv_battery_count=renewables.number_of_pv_batteries,
|
|
wind_turbines_count=0 if not renewables.wind_turbines else 1,
|
|
gas_smart_meter_present=general.gas_smart_meter,
|
|
is_dwelling_export_capable=general.dwelling_export_capable,
|
|
wind_turbines_terrain_type=general.terrain_type,
|
|
electricity_smart_meter_present=general.electricity_smart_meter,
|
|
pv_connection=renewables.pv_connection,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=renewables.percent_roof_covered_pv,
|
|
)
|
|
)
|
|
if renewables.percent_roof_covered_pv is not None
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=sap_building_parts,
|
|
solar_water_heating=renewables.solar_hot_water,
|
|
has_hot_water_cylinder=heating.water_heating.cylinder_size != "No Cylinder",
|
|
has_fixed_air_conditioning=ventilation.has_fixed_air_conditioning,
|
|
wet_rooms_count=0, # no equivalent in site notes
|
|
extensions_count=general.number_of_extensions,
|
|
heated_rooms_count=room_counts.number_of_heated_rooms
|
|
or 0, # absent in site notes → 0
|
|
open_chimneys_count=room_counts.number_of_open_chimneys,
|
|
habitable_rooms_count=room_counts.number_of_habitable_rooms,
|
|
insulated_door_count=room_counts.number_of_insulated_external_doors,
|
|
cfl_fixed_lighting_bulbs_count=room_counts.number_of_fixed_cfl_bulbs,
|
|
led_fixed_lighting_bulbs_count=room_counts.number_of_fixed_led_bulbs,
|
|
incandescent_fixed_lighting_bulbs_count=room_counts.number_of_fixed_incandescent_bulbs,
|
|
total_floor_area_m2=total_floor_area,
|
|
built_form=general.detachment_type,
|
|
property_type=general.property_type,
|
|
has_conservatory=survey.conservatories.has_conservatory,
|
|
blocked_chimneys_count=room_counts.number_of_blocked_chimneys,
|
|
draughtproofed_door_count=room_counts.number_of_draughtproofed_external_doors,
|
|
address_line_1=address_line_1,
|
|
post_town=post_town,
|
|
postcode=postcode,
|
|
report_reference=metadata.report_reference,
|
|
number_of_storeys=general.number_of_storeys,
|
|
any_unheated_rooms=room_counts.any_unheated_rooms,
|
|
waste_water_heat_recovery=room_counts.waste_water_heat_recovery,
|
|
hydro=renewables.hydro,
|
|
photovoltaic_array=renewables.photovoltaic_array,
|
|
sap_ventilation=_map_sap_ventilation(ventilation),
|
|
)
|
|
|
|
@staticmethod
|
|
def from_elmhurst_site_notes(survey: ElmhurstSiteNotes) -> EpcPropertyData:
|
|
pd = survey.property_details
|
|
built_form = _strip_code(survey.attachment)
|
|
property_type = _strip_code(survey.property_type)
|
|
|
|
prefix = pd.house_number or pd.house_name or ""
|
|
address_line_1 = f"{prefix}, {pd.street}" if prefix else pd.street
|
|
|
|
return EpcPropertyData(
|
|
dwelling_type=f"{built_form} {property_type.lower()}",
|
|
inspection_date=pd.inspection_date,
|
|
tenure=pd.tenure,
|
|
transaction_type=pd.transaction_type,
|
|
address_line_1=address_line_1,
|
|
post_town=pd.town,
|
|
postcode=pd.postcode,
|
|
report_reference=pd.reference_number,
|
|
roofs=[],
|
|
walls=[],
|
|
floors=[],
|
|
main_heating=[],
|
|
door_count=survey.door_count,
|
|
sap_heating=_map_elmhurst_sap_heating(survey),
|
|
sap_windows=[_map_elmhurst_window(w) for w in survey.windows],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=survey.meters.main_gas,
|
|
meter_type=survey.meters.electricity_meter_type,
|
|
pv_battery_count=0,
|
|
wind_turbines_count=1 if survey.renewables.wind_turbine_present else 0,
|
|
gas_smart_meter_present=survey.meters.gas_smart_meter,
|
|
is_dwelling_export_capable=survey.renewables.export_capable_meter,
|
|
wind_turbines_terrain_type=survey.renewables.wind_turbines_terrain_type,
|
|
electricity_smart_meter_present=survey.meters.electricity_smart_meter,
|
|
),
|
|
sap_building_parts=[_map_elmhurst_building_part(survey)],
|
|
solar_water_heating=survey.renewables.solar_water_heating,
|
|
has_hot_water_cylinder=survey.water_heating.hot_water_cylinder_present,
|
|
has_fixed_air_conditioning=survey.ventilation.fixed_space_cooling,
|
|
wet_rooms_count=0,
|
|
extensions_count=0,
|
|
heated_rooms_count=survey.heated_habitable_rooms,
|
|
open_chimneys_count=survey.ventilation.open_chimneys_count,
|
|
habitable_rooms_count=survey.habitable_rooms,
|
|
insulated_door_count=survey.insulated_door_count,
|
|
cfl_fixed_lighting_bulbs_count=survey.lighting.cfl_count,
|
|
led_fixed_lighting_bulbs_count=survey.lighting.led_count,
|
|
incandescent_fixed_lighting_bulbs_count=survey.lighting.incandescent_count,
|
|
total_floor_area_m2=round(
|
|
sum(f.area_m2 for f in survey.dimensions.floors), 2
|
|
),
|
|
built_form=built_form,
|
|
property_type=property_type,
|
|
has_conservatory=survey.has_conservatory,
|
|
blocked_chimneys_count=survey.ventilation.blocked_chimneys_count,
|
|
number_of_storeys=survey.number_of_storeys,
|
|
hydro=survey.renewables.hydro_electricity_generated_kwh > 0,
|
|
photovoltaic_array=survey.renewables.photovoltaic_panel != "None",
|
|
sap_ventilation=_map_elmhurst_ventilation(survey.ventilation),
|
|
percent_draughtproofed=survey.draught_proofing_percent,
|
|
waste_water_heat_recovery=(
|
|
"None" if not survey.renewables.wwhrs_present else "Present"
|
|
),
|
|
any_unheated_rooms=survey.heated_habitable_rooms < survey.habitable_rooms,
|
|
low_energy_fixed_lighting_bulbs_count=(
|
|
survey.lighting.low_energy_count if not survey.lighting.led_cfl_count_known else None
|
|
),
|
|
energy_rating_current=survey.current_sap_rating,
|
|
energy_rating_potential=survey.potential_sap_rating,
|
|
environmental_impact_current=survey.current_ei_rating,
|
|
environmental_impact_potential=survey.potential_ei_rating,
|
|
co2_emissions_current=survey.co2_emissions_current_t,
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_17_0(schema: RdSapSchema17_0) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type.value,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=0,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=0,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=None,
|
|
led_fixed_lighting_bulbs_count=0,
|
|
cfl_fixed_lighting_bulbs_count=0,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=None,
|
|
fan_flue_present=None,
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=None,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=None,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=None,
|
|
secondary_fuel_type=None,
|
|
secondary_heating_type=None,
|
|
cylinder_insulation_thickness_mm=None,
|
|
),
|
|
sap_windows=[],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=0,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=False,
|
|
is_dwelling_export_capable=False,
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=False,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=None,
|
|
floor_construction=None,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=None,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=None,
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_17_1(schema: RdSapSchema17_1) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type.value,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=0,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=0,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=None,
|
|
led_fixed_lighting_bulbs_count=0,
|
|
cfl_fixed_lighting_bulbs_count=0,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=d.boiler_flue_type,
|
|
fan_flue_present=d.fan_flue_present == "Y",
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=None,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=d.main_heating_index_number,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
|
secondary_fuel_type=schema.sap_heating.secondary_fuel_type,
|
|
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
|
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
|
),
|
|
sap_windows=[],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=0,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=False,
|
|
is_dwelling_export_capable=False,
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=False,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=fd.floor_insulation,
|
|
floor_construction=fd.floor_construction,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=None,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=None,
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_18_0(schema: RdSapSchema18_0) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type.value,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=0,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=0,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=None,
|
|
led_fixed_lighting_bulbs_count=0,
|
|
cfl_fixed_lighting_bulbs_count=0,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=d.boiler_flue_type,
|
|
fan_flue_present=d.fan_flue_present == "Y",
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=d.central_heating_pump_age,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=d.main_heating_index_number,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
|
secondary_fuel_type=schema.sap_heating.secondary_fuel_type,
|
|
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
|
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
|
),
|
|
sap_windows=[],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=0,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=False,
|
|
is_dwelling_export_capable=False,
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=False,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=fd.floor_insulation,
|
|
floor_construction=fd.floor_construction,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=bp.floor_insulation_thickness,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=(
|
|
SapRoomInRoof(
|
|
floor_area=bp.sap_room_in_roof.floor_area.value,
|
|
construction_age_band=bp.sap_room_in_roof.construction_age_band,
|
|
)
|
|
if bp.sap_room_in_roof
|
|
else None
|
|
),
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_19_0(schema: RdSapSchema19_0) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type.value,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=0,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=0,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=None,
|
|
led_fixed_lighting_bulbs_count=0,
|
|
cfl_fixed_lighting_bulbs_count=0,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=d.boiler_flue_type,
|
|
fan_flue_present=d.fan_flue_present == "Y",
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=d.central_heating_pump_age,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=d.main_heating_index_number,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
|
secondary_fuel_type=schema.sap_heating.secondary_fuel_type,
|
|
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
|
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
|
),
|
|
# 19.0 has no per-window list; individual window fields are at schema root
|
|
sap_windows=[],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=0,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=False,
|
|
is_dwelling_export_capable=False,
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=False,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=fd.floor_insulation,
|
|
floor_construction=fd.floor_construction,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=bp.floor_insulation_thickness,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=(
|
|
SapRoomInRoof(
|
|
# floor_area is a Measurement in 19.0
|
|
floor_area=bp.sap_room_in_roof.floor_area.value,
|
|
construction_age_band=bp.sap_room_in_roof.construction_age_band,
|
|
)
|
|
if bp.sap_room_in_roof
|
|
else None
|
|
),
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_20_0_0(schema: RdSapSchema20_0_0) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=0,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=0,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=None,
|
|
led_fixed_lighting_bulbs_count=0,
|
|
cfl_fixed_lighting_bulbs_count=0,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
sap_heating=SapHeating(
|
|
# 20.0.0 uses room counts not product index numbers; domain fields default to None
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=d.boiler_flue_type,
|
|
fan_flue_present=d.fan_flue_present == "Y",
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=d.central_heating_pump_age,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=d.main_heating_index_number,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
|
secondary_fuel_type=schema.sap_heating.secondary_fuel_type,
|
|
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
|
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
|
),
|
|
# 20.0.0 SapWindow lacks frame/gap/draught fields present in later schemas
|
|
sap_windows=[
|
|
SapWindow(
|
|
frame_material=None,
|
|
glazing_gap=0,
|
|
orientation=w.orientation,
|
|
window_type=w.window_type,
|
|
glazing_type=w.glazing_type,
|
|
window_width=0.0,
|
|
window_height=0.0,
|
|
draught_proofed=False,
|
|
window_location=w.window_location,
|
|
window_wall_type=0,
|
|
permanent_shutters_present=False,
|
|
)
|
|
for w in schema.sap_windows
|
|
],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=0,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=False,
|
|
is_dwelling_export_capable=False,
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=False,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=fd.floor_insulation,
|
|
floor_construction=fd.floor_construction,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=bp.floor_insulation_thickness,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=(
|
|
SapRoomInRoof(
|
|
floor_area=bp.sap_room_in_roof.floor_area,
|
|
construction_age_band=bp.sap_room_in_roof.construction_age_band,
|
|
)
|
|
if bp.sap_room_in_roof
|
|
else None
|
|
),
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_21_0_0(schema: RdSapSchema21_0_0) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=schema.wet_rooms_count,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=schema.open_chimneys_count,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=schema.draughtproofed_door_count,
|
|
led_fixed_lighting_bulbs_count=schema.led_fixed_lighting_bulbs_count,
|
|
cfl_fixed_lighting_bulbs_count=schema.cfl_fixed_lighting_bulbs_count,
|
|
incandescent_fixed_lighting_bulbs_count=schema.incandescent_fixed_lighting_bulbs_count,
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(
|
|
wwhrs_index_number1=schema.sap_heating.instantaneous_wwhrs.wwhrs_index_number1,
|
|
wwhrs_index_number2=schema.sap_heating.instantaneous_wwhrs.wwhrs_index_number2,
|
|
),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=d.boiler_flue_type,
|
|
fan_flue_present=d.fan_flue_present == "Y",
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
boiler_ignition_type=d.boiler_ignition_type,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=d.central_heating_pump_age,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=d.main_heating_index_number,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
shower_outlets=(
|
|
ShowerOutlets(
|
|
ShowerOutlet(
|
|
shower_wwhrs=schema.sap_heating.shower_outlets.shower_outlet.shower_wwhrs,
|
|
shower_outlet_type=schema.sap_heating.shower_outlets.shower_outlet.shower_outlet_type,
|
|
)
|
|
)
|
|
if schema.sap_heating.shower_outlets
|
|
else None
|
|
),
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
|
secondary_fuel_type=schema.sap_heating.secondary_fuel_type,
|
|
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
|
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
|
),
|
|
sap_windows=[
|
|
SapWindow(
|
|
frame_material="PVC" if w.pvc_frame == "true" else None,
|
|
glazing_gap=w.glazing_gap,
|
|
orientation=w.orientation,
|
|
window_type=w.window_type,
|
|
frame_factor=w.frame_factor,
|
|
glazing_type=w.glazing_type,
|
|
window_width=w.window_width,
|
|
window_height=w.window_height,
|
|
draught_proofed=w.draught_proofed == "true",
|
|
window_location=w.window_location,
|
|
window_wall_type=w.window_wall_type,
|
|
permanent_shutters_present=w.permanent_shutters_present == "Y",
|
|
window_transmission_details=WindowTransmissionDetails(
|
|
u_value=w.window_transmission_details.u_value,
|
|
data_source=w.window_transmission_details.data_source,
|
|
solar_transmittance=w.window_transmission_details.solar_transmittance,
|
|
),
|
|
permanent_shutters_insulated=w.permanent_shutters_insulated,
|
|
)
|
|
for w in schema.sap_windows
|
|
],
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=es.pv_battery_count,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=es.gas_smart_meter_present == "true",
|
|
is_dwelling_export_capable=es.is_dwelling_export_capable == "true",
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=es.electricity_smart_meter_present
|
|
== "true",
|
|
pv_connection=es.pv_connection,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
wind_turbine_details=(
|
|
WindTurbineDetails(
|
|
hub_height=es.wind_turbine_details.hub_height,
|
|
rotor_diameter=es.wind_turbine_details.rotor_diameter,
|
|
)
|
|
if es.wind_turbine_details
|
|
else None
|
|
),
|
|
pv_batteries=(
|
|
PvBatteries(
|
|
pv_battery=PvBattery(
|
|
battery_capacity=es.pv_batteries.pv_battery.battery_capacity
|
|
)
|
|
)
|
|
if es.pv_batteries
|
|
else None
|
|
),
|
|
),
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=fd.floor_insulation,
|
|
floor_construction=fd.floor_construction,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=bp.floor_insulation_thickness,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=(
|
|
SapRoomInRoof(
|
|
floor_area=bp.sap_room_in_roof.floor_area,
|
|
construction_age_band=bp.sap_room_in_roof.construction_age_band,
|
|
)
|
|
if bp.sap_room_in_roof
|
|
else None
|
|
),
|
|
sap_alternative_wall_1=(
|
|
SapAlternativeWall(
|
|
wall_area=bp.sap_alternative_wall_1.wall_area,
|
|
wall_dry_lined=bp.sap_alternative_wall_1.wall_dry_lined,
|
|
wall_construction=bp.sap_alternative_wall_1.wall_construction,
|
|
wall_insulation_type=bp.sap_alternative_wall_1.wall_insulation_type,
|
|
wall_thickness_measured=bp.sap_alternative_wall_1.wall_thickness_measured,
|
|
wall_insulation_thickness=bp.sap_alternative_wall_1.wall_insulation_thickness,
|
|
)
|
|
if bp.sap_alternative_wall_1
|
|
else None
|
|
),
|
|
sap_alternative_wall_2=(
|
|
SapAlternativeWall(
|
|
wall_area=bp.sap_alternative_wall_2.wall_area,
|
|
wall_dry_lined=bp.sap_alternative_wall_2.wall_dry_lined,
|
|
wall_construction=bp.sap_alternative_wall_2.wall_construction,
|
|
wall_insulation_type=bp.sap_alternative_wall_2.wall_insulation_type,
|
|
wall_thickness_measured=bp.sap_alternative_wall_2.wall_thickness_measured,
|
|
wall_insulation_thickness=bp.sap_alternative_wall_2.wall_insulation_thickness,
|
|
)
|
|
if bp.sap_alternative_wall_2
|
|
else None
|
|
),
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def from_rdsap_schema_21_0_1(schema: RdSapSchema21_0_1) -> EpcPropertyData:
|
|
es = schema.sap_energy_source
|
|
return EpcPropertyData(
|
|
# General
|
|
uprn=schema.uprn,
|
|
assessment_type=schema.assessment_type,
|
|
sap_version=schema.sap_version,
|
|
dwelling_type=schema.dwelling_type,
|
|
property_type=str(schema.property_type),
|
|
built_form=str(schema.built_form),
|
|
address_line_1=schema.address_line_1,
|
|
address_line_2=schema.address_line_2,
|
|
postcode=schema.postcode,
|
|
post_town=schema.post_town,
|
|
status=schema.status,
|
|
tenure=str(schema.tenure),
|
|
transaction_type=str(schema.transaction_type),
|
|
inspection_date=date.fromisoformat(schema.inspection_date),
|
|
completion_date=date.fromisoformat(schema.completion_date),
|
|
registration_date=date.fromisoformat(schema.registration_date),
|
|
total_floor_area_m2=float(schema.total_floor_area),
|
|
# Property flags
|
|
solar_water_heating=schema.solar_water_heating == "Y",
|
|
has_hot_water_cylinder=schema.has_hot_water_cylinder == "true",
|
|
has_fixed_air_conditioning=schema.has_fixed_air_conditioning == "true",
|
|
conservatory_type=schema.conservatory_type,
|
|
has_conservatory=schema.conservatory_type != 1,
|
|
# Counts
|
|
door_count=schema.door_count,
|
|
habitable_rooms_count=schema.habitable_room_count,
|
|
heated_rooms_count=schema.heated_room_count,
|
|
wet_rooms_count=schema.wet_rooms_count,
|
|
extensions_count=schema.extensions_count,
|
|
open_chimneys_count=schema.open_chimneys_count,
|
|
insulated_door_count=schema.insulated_door_count,
|
|
draughtproofed_door_count=schema.draughtproofed_door_count,
|
|
# Lighting
|
|
led_fixed_lighting_bulbs_count=schema.led_fixed_lighting_bulbs_count,
|
|
cfl_fixed_lighting_bulbs_count=schema.cfl_fixed_lighting_bulbs_count,
|
|
incandescent_fixed_lighting_bulbs_count=schema.incandescent_fixed_lighting_bulbs_count,
|
|
# Energy elements
|
|
roofs=EpcPropertyDataMapper._map_energy_elements(schema.roofs),
|
|
walls=EpcPropertyDataMapper._map_energy_elements(schema.walls),
|
|
floors=EpcPropertyDataMapper._map_energy_elements(schema.floors),
|
|
main_heating=EpcPropertyDataMapper._map_energy_elements(
|
|
schema.main_heating
|
|
),
|
|
window=EpcPropertyDataMapper._map_energy_element(schema.window),
|
|
lighting=EpcPropertyDataMapper._map_energy_element(schema.lighting),
|
|
hot_water=EpcPropertyDataMapper._map_energy_element(schema.hot_water),
|
|
secondary_heating=EpcPropertyDataMapper._map_energy_element(
|
|
schema.secondary_heating
|
|
),
|
|
# SAP heating
|
|
sap_heating=SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(
|
|
wwhrs_index_number1=schema.sap_heating.instantaneous_wwhrs.wwhrs_index_number1,
|
|
wwhrs_index_number2=schema.sap_heating.instantaneous_wwhrs.wwhrs_index_number2,
|
|
),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=d.has_fghrs == "Y",
|
|
main_fuel_type=d.main_fuel_type,
|
|
boiler_flue_type=d.boiler_flue_type,
|
|
fan_flue_present=d.fan_flue_present == "Y",
|
|
heat_emitter_type=d.heat_emitter_type,
|
|
emitter_temperature=d.emitter_temperature,
|
|
main_heating_number=d.main_heating_number,
|
|
boiler_ignition_type=d.boiler_ignition_type,
|
|
main_heating_control=d.main_heating_control,
|
|
main_heating_category=d.main_heating_category,
|
|
main_heating_fraction=d.main_heating_fraction,
|
|
sap_main_heating_code=d.sap_main_heating_code,
|
|
central_heating_pump_age=d.central_heating_pump_age,
|
|
main_heating_data_source=d.main_heating_data_source,
|
|
main_heating_index_number=d.main_heating_index_number,
|
|
)
|
|
for d in schema.sap_heating.main_heating_details
|
|
],
|
|
has_fixed_air_conditioning=schema.sap_heating.has_fixed_air_conditioning
|
|
== "true",
|
|
cylinder_size=schema.sap_heating.cylinder_size,
|
|
water_heating_code=schema.sap_heating.water_heating_code,
|
|
water_heating_fuel=schema.sap_heating.water_heating_fuel,
|
|
immersion_heating_type=schema.sap_heating.immersion_heating_type,
|
|
shower_outlets=(
|
|
ShowerOutlets(
|
|
ShowerOutlet(
|
|
shower_wwhrs=schema.sap_heating.shower_outlets.shower_outlet.shower_wwhrs,
|
|
shower_outlet_type=schema.sap_heating.shower_outlets.shower_outlet.shower_outlet_type,
|
|
)
|
|
)
|
|
if schema.sap_heating.shower_outlets
|
|
else None
|
|
),
|
|
cylinder_insulation_type=schema.sap_heating.cylinder_insulation_type,
|
|
cylinder_thermostat=schema.sap_heating.cylinder_thermostat,
|
|
secondary_fuel_type=schema.sap_heating.secondary_fuel_type,
|
|
secondary_heating_type=schema.sap_heating.secondary_heating_type,
|
|
cylinder_insulation_thickness_mm=schema.sap_heating.cylinder_insulation_thickness,
|
|
),
|
|
# SAP windows
|
|
sap_windows=[
|
|
SapWindow(
|
|
frame_material="PVC" if w.pvc_frame == "true" else None,
|
|
glazing_gap=w.glazing_gap,
|
|
orientation=w.orientation,
|
|
window_type=w.window_type,
|
|
frame_factor=w.frame_factor,
|
|
glazing_type=w.glazing_type,
|
|
window_width=w.window_width,
|
|
window_height=w.window_height,
|
|
draught_proofed=w.draught_proofed == "true",
|
|
window_location=w.window_location,
|
|
window_wall_type=w.window_wall_type,
|
|
permanent_shutters_present=w.permanent_shutters_present == "Y",
|
|
window_transmission_details=WindowTransmissionDetails(
|
|
u_value=w.window_transmission_details.u_value,
|
|
data_source=w.window_transmission_details.data_source,
|
|
solar_transmittance=w.window_transmission_details.solar_transmittance,
|
|
),
|
|
permanent_shutters_insulated=w.permanent_shutters_insulated,
|
|
)
|
|
for w in schema.sap_windows
|
|
],
|
|
# SAP energy source
|
|
sap_energy_source=SapEnergySource(
|
|
mains_gas=es.mains_gas == "Y",
|
|
meter_type=str(es.meter_type),
|
|
pv_battery_count=es.pv_battery_count,
|
|
wind_turbines_count=es.wind_turbines_count,
|
|
gas_smart_meter_present=es.gas_smart_meter_present == "true",
|
|
is_dwelling_export_capable=es.is_dwelling_export_capable == "true",
|
|
wind_turbines_terrain_type=str(es.wind_turbines_terrain_type),
|
|
electricity_smart_meter_present=es.electricity_smart_meter_present
|
|
== "true",
|
|
pv_connection=es.pv_connection,
|
|
photovoltaic_supply=(
|
|
PhotovoltaicSupply(
|
|
none_or_no_details=PhotovoltaicSupplyNoneOrNoDetails(
|
|
percent_roof_area=es.photovoltaic_supply.none_or_no_details.percent_roof_area,
|
|
)
|
|
)
|
|
if es.photovoltaic_supply
|
|
else None
|
|
),
|
|
wind_turbine_details=(
|
|
WindTurbineDetails(
|
|
hub_height=es.wind_turbine_details.hub_height,
|
|
rotor_diameter=es.wind_turbine_details.rotor_diameter,
|
|
)
|
|
if es.wind_turbine_details
|
|
else None
|
|
),
|
|
pv_batteries=(
|
|
PvBatteries(
|
|
pv_battery=PvBattery(
|
|
battery_capacity=es.pv_batteries.pv_battery.battery_capacity
|
|
)
|
|
)
|
|
if es.pv_batteries
|
|
else None
|
|
),
|
|
),
|
|
# SAP building parts
|
|
sap_building_parts=[
|
|
SapBuildingPart(
|
|
identifier=bp.identifier,
|
|
construction_age_band=bp.construction_age_band,
|
|
wall_construction=bp.wall_construction,
|
|
wall_insulation_type=bp.wall_insulation_type,
|
|
wall_thickness_measured=bp.wall_thickness_measured == "Y",
|
|
party_wall_construction=bp.party_wall_construction,
|
|
sap_floor_dimensions=[
|
|
SapFloorDimension(
|
|
room_height_m=fd.room_height.value,
|
|
total_floor_area_m2=fd.total_floor_area.value,
|
|
party_wall_length_m=(
|
|
float(fd.party_wall_length)
|
|
if isinstance(fd.party_wall_length, int)
|
|
else fd.party_wall_length.value
|
|
),
|
|
heat_loss_perimeter_m=fd.heat_loss_perimeter.value,
|
|
floor=fd.floor,
|
|
floor_insulation=fd.floor_insulation,
|
|
floor_construction=fd.floor_construction,
|
|
)
|
|
for fd in bp.sap_floor_dimensions
|
|
],
|
|
building_part_number=bp.building_part_number,
|
|
wall_dry_lined=bp.wall_dry_lined == "Y",
|
|
wall_thickness_mm=bp.wall_thickness,
|
|
wall_insulation_thickness=bp.wall_insulation_thickness,
|
|
floor_heat_loss=bp.floor_heat_loss,
|
|
floor_insulation_thickness=bp.floor_insulation_thickness,
|
|
roof_construction=bp.roof_construction,
|
|
roof_insulation_location=bp.roof_insulation_location,
|
|
roof_insulation_thickness=bp.roof_insulation_thickness,
|
|
sap_room_in_roof=(
|
|
SapRoomInRoof(
|
|
floor_area=bp.sap_room_in_roof.floor_area,
|
|
construction_age_band=bp.sap_room_in_roof.construction_age_band,
|
|
)
|
|
if bp.sap_room_in_roof
|
|
else None
|
|
),
|
|
sap_alternative_wall_1=(
|
|
SapAlternativeWall(
|
|
wall_area=bp.sap_alternative_wall_1.wall_area,
|
|
wall_dry_lined=bp.sap_alternative_wall_1.wall_dry_lined,
|
|
wall_construction=bp.sap_alternative_wall_1.wall_construction,
|
|
wall_insulation_type=bp.sap_alternative_wall_1.wall_insulation_type,
|
|
wall_thickness_measured=bp.sap_alternative_wall_1.wall_thickness_measured,
|
|
wall_insulation_thickness=bp.sap_alternative_wall_1.wall_insulation_thickness,
|
|
)
|
|
if bp.sap_alternative_wall_1
|
|
else None
|
|
),
|
|
sap_alternative_wall_2=(
|
|
SapAlternativeWall(
|
|
wall_area=bp.sap_alternative_wall_2.wall_area,
|
|
wall_dry_lined=bp.sap_alternative_wall_2.wall_dry_lined,
|
|
wall_construction=bp.sap_alternative_wall_2.wall_construction,
|
|
wall_insulation_type=bp.sap_alternative_wall_2.wall_insulation_type,
|
|
wall_thickness_measured=bp.sap_alternative_wall_2.wall_thickness_measured,
|
|
wall_insulation_thickness=bp.sap_alternative_wall_2.wall_insulation_thickness,
|
|
)
|
|
if bp.sap_alternative_wall_2
|
|
else None
|
|
),
|
|
)
|
|
for bp in schema.sap_building_parts
|
|
],
|
|
)
|
|
|
|
@staticmethod
|
|
def _map_energy_element(
|
|
element: Union[
|
|
EnergyElement_17_0,
|
|
EnergyElement_17_1,
|
|
EnergyElement_18_0,
|
|
EnergyElement_19_0,
|
|
EnergyElement_20_0,
|
|
EnergyElement_21_0,
|
|
EnergyElement_21_0_1,
|
|
],
|
|
) -> EnergyElement:
|
|
description = (
|
|
element.description
|
|
if isinstance(element.description, str)
|
|
else element.description.value
|
|
)
|
|
return EnergyElement(
|
|
description=description,
|
|
energy_efficiency_rating=element.energy_efficiency_rating,
|
|
environmental_efficiency_rating=element.environmental_efficiency_rating,
|
|
)
|
|
|
|
@staticmethod
|
|
def _map_energy_elements(
|
|
elements: Sequence[
|
|
Union[
|
|
EnergyElement_17_0,
|
|
EnergyElement_17_1,
|
|
EnergyElement_18_0,
|
|
EnergyElement_19_0,
|
|
EnergyElement_20_0,
|
|
EnergyElement_21_0,
|
|
EnergyElement_21_0_1,
|
|
]
|
|
],
|
|
) -> List[EnergyElement]:
|
|
return [EpcPropertyDataMapper._map_energy_element(e) for e in elements]
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Private helpers
|
|
# ---------------------------------------------------------------------------
|
|
|
|
|
|
def _strip_code(value: str) -> str:
|
|
"""Strip leading uppercase code from Elmhurst coded strings, e.g. 'CA Cavity' → 'Cavity'."""
|
|
parts = value.split(" ", 1)
|
|
return parts[1] if len(parts) > 1 else value
|
|
|
|
|
|
def _extract_age_band(age_range: str) -> str:
|
|
"""Return the letter code from a site-notes age range, e.g. 'I: 1996 - 2002' → 'I'."""
|
|
return age_range.split(":")[0].strip()
|
|
|
|
|
|
def _map_floor_dimensions(floors: List[FloorMeasurement]) -> List[SapFloorDimension]:
|
|
return [
|
|
SapFloorDimension(
|
|
room_height_m=floor.height_m,
|
|
total_floor_area_m2=floor.area_m2,
|
|
party_wall_length_m=floor.pwl_m,
|
|
heat_loss_perimeter_m=floor.heat_loss_perimeter_m,
|
|
floor=int(floor.name.split()[-1]),
|
|
)
|
|
for floor in floors
|
|
]
|
|
|
|
|
|
def _map_roof(
|
|
roof: Optional[Union[RoofSpaceDetail, ExtensionRoofSpace]],
|
|
) -> tuple[Optional[str], Optional[Union[str, int]]]:
|
|
if roof is None:
|
|
return None, None
|
|
thickness: Optional[Union[str, int]] = (
|
|
roof.insulation_thickness_mm
|
|
if roof.insulation_thickness_mm is not None
|
|
else roof.insulation_thickness
|
|
)
|
|
return roof.insulation_at or None, thickness
|
|
|
|
|
|
def _map_main_building_part(
|
|
construction: BuildingConstruction,
|
|
measurements: BuildingMeasurements,
|
|
roof: RoofSpaceDetail,
|
|
) -> SapBuildingPart:
|
|
main = construction.main_building
|
|
floor = construction.floor
|
|
roof_location, roof_thickness = _map_roof(roof)
|
|
return SapBuildingPart(
|
|
identifier="main",
|
|
construction_age_band=_extract_age_band(main.age_range),
|
|
wall_construction=main.walls_construction_type,
|
|
wall_insulation_type=main.walls_insulation_type,
|
|
wall_thickness_measured=main.wall_thickness_mm is not None,
|
|
party_wall_construction=main.party_wall_construction_type,
|
|
sap_floor_dimensions=_map_floor_dimensions(measurements.main_building.floors),
|
|
wall_thickness_mm=main.wall_thickness_mm,
|
|
roof_insulation_location=roof_location,
|
|
roof_insulation_thickness=roof_thickness,
|
|
floor_type=floor.floor_type,
|
|
floor_construction_type=floor.floor_construction,
|
|
floor_insulation_type_str=floor.floor_insulation_type,
|
|
floor_u_value_known=floor.floor_u_value_known,
|
|
)
|
|
|
|
|
|
def _map_extension_building_part(
|
|
ext_c: ExtensionConstruction,
|
|
ext_m: ExtensionMeasurements,
|
|
roof: Optional[ExtensionRoofSpace],
|
|
) -> SapBuildingPart:
|
|
roof_location, roof_thickness = _map_roof(roof)
|
|
return SapBuildingPart(
|
|
identifier=f"extension_{ext_c.id}",
|
|
construction_age_band=_extract_age_band(ext_c.age_range),
|
|
wall_construction=ext_c.walls_construction_type,
|
|
wall_insulation_type=ext_c.walls_insulation_type,
|
|
wall_thickness_measured=ext_c.wall_thickness_mm is not None,
|
|
party_wall_construction=ext_c.party_wall_construction_type,
|
|
sap_floor_dimensions=_map_floor_dimensions(ext_m.floors),
|
|
wall_thickness_mm=ext_c.wall_thickness_mm,
|
|
roof_insulation_location=roof_location,
|
|
roof_insulation_thickness=roof_thickness,
|
|
)
|
|
|
|
|
|
def _map_sap_window(window: Window) -> SapWindow:
|
|
return SapWindow(
|
|
frame_material=window.frame_type,
|
|
glazing_gap=window.glazing_gap,
|
|
orientation=window.orientation,
|
|
window_type=window.window_type,
|
|
glazing_type=window.glazing_type,
|
|
window_width=window.width_m,
|
|
window_height=window.height_m,
|
|
draught_proofed=window.draught_proofed,
|
|
window_location=window.location,
|
|
window_wall_type=window.wall_type,
|
|
permanent_shutters_present=window.permanent_shutters,
|
|
)
|
|
|
|
|
|
def _map_sap_heating(
|
|
heating: HeatingAndHotWater, ventilation: Ventilation, water_use: WaterUse
|
|
) -> SapHeating:
|
|
main = heating.main_heating
|
|
secondary = heating.secondary_heating
|
|
|
|
# secondary_fuel_type is an int code in the domain model; we can't map a
|
|
# site-notes string directly, so leave it None unless there is secondary heating.
|
|
# The string fuel type is preserved via sap_heating when needed.
|
|
secondary_fuel_type = (
|
|
None if secondary.secondary_fuel == "No Secondary Heating" else None
|
|
)
|
|
|
|
shower_outlets = (
|
|
ShowerOutlets(
|
|
shower_outlet=ShowerOutlet(
|
|
shower_outlet_type=water_use.showers[0].outlet_type,
|
|
)
|
|
)
|
|
if water_use.showers
|
|
else None
|
|
)
|
|
|
|
_ELECTRIC_SYSTEM_TYPES = {"electric storage heaters", "electric underfloor heating"}
|
|
_raw_fuel = main.fuel.split(", ")[0] if main.fuel else ""
|
|
fuel_type = (
|
|
_raw_fuel
|
|
if _raw_fuel
|
|
else (
|
|
"Electricity"
|
|
if main.system_type.lower() in _ELECTRIC_SYSTEM_TYPES
|
|
else _raw_fuel
|
|
)
|
|
)
|
|
|
|
return SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=main.flue_gas_heat_recovery_system,
|
|
main_fuel_type=fuel_type,
|
|
heat_emitter_type=main.emitter,
|
|
emitter_temperature=main.emitter_temperature,
|
|
fan_flue_present=main.fan_assist,
|
|
main_heating_control=main.controls,
|
|
condensing=main.condensing,
|
|
weather_compensator=main.weather_compensator,
|
|
central_heating_pump_age_str=main.central_heating_pump_age,
|
|
)
|
|
],
|
|
has_fixed_air_conditioning=ventilation.has_fixed_air_conditioning,
|
|
secondary_fuel_type=secondary_fuel_type,
|
|
secondary_heating_type=heating.secondary_heating.secondary_system,
|
|
shower_outlets=shower_outlets,
|
|
cylinder_size=(
|
|
heating.water_heating.cylinder_size
|
|
if heating.water_heating.cylinder_size != "No Cylinder"
|
|
else None
|
|
),
|
|
cylinder_insulation_type=heating.water_heating.insulation_type,
|
|
cylinder_insulation_thickness_mm=heating.water_heating.insulation_thickness_mm,
|
|
immersion_heating_type=heating.water_heating.immersion_type,
|
|
)
|
|
|
|
|
|
def _map_sap_ventilation(ventilation: Ventilation) -> SapVentilation:
|
|
return SapVentilation(
|
|
ventilation_type=ventilation.ventilation_type,
|
|
draught_lobby=ventilation.draught_lobby,
|
|
pressure_test=ventilation.pressure_test,
|
|
open_flues_count=ventilation.number_of_open_flues,
|
|
closed_flues_count=ventilation.number_of_closed_flues,
|
|
boiler_flues_count=ventilation.number_of_boiler_flues,
|
|
other_flues_count=ventilation.number_of_other_flues,
|
|
extract_fans_count=ventilation.number_of_extract_fans,
|
|
passive_vents_count=ventilation.number_of_passive_vents,
|
|
flueless_gas_fires_count=ventilation.number_of_flueless_gas_fires,
|
|
ventilation_in_pcdf_database=ventilation.ventilation_in_pcdf_database,
|
|
)
|
|
|
|
|
|
def _map_elmhurst_building_part(survey: ElmhurstSiteNotes) -> SapBuildingPart:
|
|
dims = survey.dimensions
|
|
floor_dims = [
|
|
SapFloorDimension(
|
|
room_height_m=f.room_height_m,
|
|
total_floor_area_m2=f.area_m2,
|
|
party_wall_length_m=f.party_wall_length_m,
|
|
heat_loss_perimeter_m=f.heat_loss_perimeter_m,
|
|
floor=i,
|
|
)
|
|
for i, f in enumerate(dims.floors)
|
|
]
|
|
return SapBuildingPart(
|
|
identifier="main",
|
|
construction_age_band=_strip_code(survey.construction_age_band),
|
|
wall_construction=_strip_code(survey.walls.wall_type),
|
|
wall_insulation_type=_strip_code(survey.walls.insulation),
|
|
wall_thickness_measured=not survey.walls.thickness_unknown,
|
|
party_wall_construction=_strip_code(survey.walls.party_wall_type),
|
|
sap_floor_dimensions=floor_dims,
|
|
wall_thickness_mm=survey.walls.thickness_mm,
|
|
roof_insulation_location=_strip_code(survey.roof.insulation),
|
|
roof_insulation_thickness=survey.roof.insulation_thickness_mm,
|
|
floor_type=_strip_code(survey.floor.location),
|
|
floor_construction_type=_strip_code(survey.floor.floor_type),
|
|
floor_insulation_type_str=_strip_code(survey.floor.insulation),
|
|
floor_u_value_known=survey.floor.u_value_known,
|
|
)
|
|
|
|
|
|
def _map_elmhurst_window(w: ElmhurstWindow) -> SapWindow:
|
|
return SapWindow(
|
|
frame_material=w.frame_type or None,
|
|
glazing_gap=w.glazing_gap or "",
|
|
orientation=w.orientation,
|
|
window_type="Window",
|
|
glazing_type=w.glazing_type,
|
|
window_width=w.width_m,
|
|
window_height=w.height_m,
|
|
draught_proofed=w.draught_proofed,
|
|
window_location=w.building_part,
|
|
window_wall_type=w.location,
|
|
permanent_shutters_present=w.permanent_shutters,
|
|
frame_factor=w.frame_factor,
|
|
window_transmission_details=WindowTransmissionDetails(
|
|
u_value=w.u_value,
|
|
solar_transmittance=w.g_value,
|
|
data_source=w.data_source,
|
|
),
|
|
)
|
|
|
|
|
|
def _map_elmhurst_sap_heating(survey: ElmhurstSiteNotes) -> SapHeating:
|
|
mh = survey.main_heating
|
|
sap_control = mh.heating_controls_sap
|
|
control = (
|
|
sap_control.split(", ", 1)[1]
|
|
if sap_control.startswith("SAP code") and ", " in sap_control
|
|
else sap_control
|
|
)
|
|
shower_outlets = (
|
|
ShowerOutlets(
|
|
shower_outlet=ShowerOutlet(
|
|
shower_outlet_type=survey.baths_and_showers.showers[0].outlet_type
|
|
)
|
|
)
|
|
if survey.baths_and_showers.showers
|
|
else None
|
|
)
|
|
return SapHeating(
|
|
instantaneous_wwhrs=InstantaneousWwhrs(),
|
|
main_heating_details=[
|
|
MainHeatingDetail(
|
|
has_fghrs=survey.renewables.flue_gas_heat_recovery_present,
|
|
main_fuel_type=mh.fuel_type,
|
|
heat_emitter_type=mh.heat_emitter,
|
|
emitter_temperature=mh.design_flow_temperature,
|
|
fan_flue_present=mh.fan_assisted_flue,
|
|
main_heating_control=control,
|
|
central_heating_pump_age_str=mh.heat_pump_age,
|
|
)
|
|
],
|
|
has_fixed_air_conditioning=survey.ventilation.fixed_space_cooling,
|
|
shower_outlets=shower_outlets,
|
|
cylinder_size=(
|
|
None
|
|
if not survey.water_heating.hot_water_cylinder_present
|
|
else survey.water_heating.water_heating_code
|
|
),
|
|
water_heating_code=survey.water_heating.water_heating_sap_code,
|
|
)
|
|
|
|
|
|
def _map_elmhurst_ventilation(v: ElmhurstVentilation) -> SapVentilation:
|
|
return SapVentilation(
|
|
ventilation_type=None,
|
|
draught_lobby=v.draught_lobby != "Not present",
|
|
pressure_test=v.pressure_test_method,
|
|
open_flues_count=v.open_flues_count,
|
|
closed_flues_count=v.open_chimneys_closed_fire_count,
|
|
boiler_flues_count=v.solid_fuel_boiler_flues_count,
|
|
other_flues_count=v.other_heater_flues_count,
|
|
extract_fans_count=v.extract_fans_count,
|
|
passive_vents_count=v.passive_vents_count,
|
|
flueless_gas_fires_count=v.flueless_gas_fires_count,
|
|
ventilation_in_pcdf_database=None,
|
|
)
|