first draft dataclasses with loading tests

This commit is contained in:
Daniel Roth 2026-04-10 11:33:17 +00:00
parent 36f8a50e7e
commit d95be6ce65
20 changed files with 4023 additions and 1 deletions

View file

@ -0,0 +1,17 @@
from .rdsap_schema_17_0 import RdSapSchema17_0
from .rdsap_schema_17_1 import RdSapSchema17_1
from .rdsap_schema_18_0 import RdSapSchema18_0
from .rdsap_schema_19_0 import RdSapSchema19_0
from .rdsap_schema_20_0_0 import RdSapSchema20_0_0
from .rdsap_schema_21_0_0 import RdSapSchema21_0_0
from .rdsap_schema_21_0_1 import RdSapSchema21_0_1
__all__ = [
"RdSapSchema17_0",
"RdSapSchema17_1",
"RdSapSchema18_0",
"RdSapSchema19_0",
"RdSapSchema20_0_0",
"RdSapSchema21_0_0",
"RdSapSchema21_0_1",
]

View file

@ -0,0 +1,22 @@
from dataclasses import dataclass
@dataclass
class Measurement:
"""A numeric value with a physical unit, e.g. {"value": 2.4, "quantity": "metres"}."""
value: float
quantity: str
@dataclass
class DescriptionV1:
"""Localised description object used in schemas 17.x, 18.x, 19.x, and 21.0.1."""
value: str
language: str
@dataclass
class CostAmount:
"""Monetary amount used in schemas 17.x, 18.x, and 19.x."""
value: int
currency: str

View file

@ -0,0 +1,222 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import CostAmount, DescriptionV1, Measurement
@dataclass
class EnergyElement:
description: DescriptionV1
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class InstantaneousWwhrs:
rooms_with_bath_and_or_shower: int
rooms_with_mixer_shower_no_bath: int
rooms_with_bath_and_mixer_shower: int
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
cylinder_insulation_type: int
has_fixed_air_conditioning: str
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
pv_connection: int
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbines_terrain_type: int
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
party_wall_length: Measurement
heat_loss_perimeter: Measurement
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
wall_thickness: int
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
roof_insulation_thickness: str
wall_insulation_thickness: Optional[str] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
@dataclass
class ImprovementDetails:
improvement_number: int
@dataclass
class SuggestedImprovement:
sequence: int
typical_saving: CostAmount
indicative_cost: str
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class AlternativeImprovement:
sequence: int
typical_saving: CostAmount
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema17_0:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
glazed_area: int
glazing_gap: str
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
dwelling_type: DescriptionV1
language_code: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
pvc_window_frames: str
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
lzc_energy_sources: List[int]
sap_building_parts: List[SapBuildingPart]
low_energy_lighting: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: CostAmount
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: CostAmount
main_heating_controls: List[EnergyElement]
multiple_glazing_type: int
open_fireplaces_count: int
has_hot_water_cylinder: str
heating_cost_potential: CostAmount
hot_water_cost_current: CostAmount
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: CostAmount
schema_version_original: str
hot_water_cost_potential: CostAmount
renewable_heat_incentive: RenewableHeatIncentive
energy_consumption_current: int
has_fixed_air_conditioning: str
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
fixed_lighting_outlets_count: int
current_energy_efficiency_band: str
environmental_impact_potential: int
has_heated_separate_conservatory: str
potential_energy_efficiency_band: str
co2_emissions_current_per_floor_area: int
low_energy_fixed_lighting_outlets_count: int
sap_flat_details: Optional[SapFlatDetails] = None
address_line_2: Optional[str] = None
alternative_improvements: Optional[List[AlternativeImprovement]] = None

View file

@ -0,0 +1,234 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import CostAmount, DescriptionV1, Measurement
@dataclass
class EnergyElement:
description: DescriptionV1
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class InstantaneousWwhrs:
rooms_with_bath_and_or_shower: int
rooms_with_mixer_shower_no_bath: int
rooms_with_bath_and_mixer_shower: int
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
boiler_flue_type: Optional[int] = None
fan_flue_present: Optional[str] = None
mcs_installed_heat_pump: Optional[str] = None
main_heating_index_number: Optional[int] = None
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
cylinder_insulation_type: int
has_fixed_air_conditioning: str
cylinder_thermostat: Optional[str] = None
secondary_fuel_type: Optional[int] = None
secondary_heating_type: Optional[int] = None
cylinder_insulation_thickness: Optional[int] = None
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
pv_connection: int
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbines_terrain_type: int
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
# Can be a Measurement object or 0 (int) for party walls of zero length
party_wall_length: Union[Measurement, int]
heat_loss_perimeter: Measurement
floor_insulation: Optional[int] = None
floor_construction: Optional[int] = None
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
wall_thickness: int
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
# Can be a thickness string (e.g. "100mm") or 0 for uninsulated flat roofs
roof_insulation_thickness: Union[str, int]
wall_insulation_thickness: Optional[str] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
@dataclass
class ImprovementDetails:
improvement_number: int
@dataclass
class SuggestedImprovement:
sequence: int
typical_saving: CostAmount
indicative_cost: str
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class AlternativeImprovement:
sequence: int
typical_saving: CostAmount
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema17_1:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
glazed_area: int
glazing_gap: str
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
dwelling_type: DescriptionV1
language_code: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
pvc_window_frames: str
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
lzc_energy_sources: List[int]
sap_building_parts: List[SapBuildingPart]
low_energy_lighting: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: CostAmount
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: CostAmount
main_heating_controls: List[EnergyElement]
multiple_glazing_type: int
open_fireplaces_count: int
has_hot_water_cylinder: str
heating_cost_potential: CostAmount
hot_water_cost_current: CostAmount
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: CostAmount
schema_version_original: str
hot_water_cost_potential: CostAmount
renewable_heat_incentive: RenewableHeatIncentive
energy_consumption_current: int
has_fixed_air_conditioning: str
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
fixed_lighting_outlets_count: int
current_energy_efficiency_band: str
environmental_impact_potential: int
has_heated_separate_conservatory: str
potential_energy_efficiency_band: str
co2_emissions_current_per_floor_area: int
low_energy_fixed_lighting_outlets_count: int
sap_flat_details: Optional[SapFlatDetails] = None
address_line_2: Optional[str] = None
alternative_improvements: Optional[List[AlternativeImprovement]] = None

View file

@ -0,0 +1,245 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import CostAmount, DescriptionV1, Measurement
@dataclass
class EnergyElement:
description: DescriptionV1
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class InstantaneousWwhrs:
rooms_with_bath_and_or_shower: int
rooms_with_mixer_shower_no_bath: int
rooms_with_bath_and_mixer_shower: int
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
boiler_flue_type: Optional[int] = None
fan_flue_present: Optional[str] = None
central_heating_pump_age: Optional[int] = None
main_heating_index_number: Optional[int] = None
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
has_fixed_air_conditioning: str
cylinder_insulation_type: Optional[int] = None
cylinder_thermostat: Optional[str] = None
secondary_fuel_type: Optional[int] = None
secondary_heating_type: Optional[int] = None
cylinder_insulation_thickness: Optional[int] = None
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
pv_connection: int
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbines_terrain_type: int
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
party_wall_length: Union[Measurement, int]
heat_loss_perimeter: Measurement
floor_insulation: Optional[int] = None
floor_construction: Optional[int] = None
@dataclass
class SapRoomInRoof:
"""Room-in-roof details. floor_area is a Measurement object in schema 18.0."""
floor_area: Measurement
insulation: str
roof_room_connected: str
construction_age_band: str
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
wall_thickness: int
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
roof_insulation_thickness: Union[str, int]
sap_room_in_roof: Optional[SapRoomInRoof] = None
wall_insulation_thickness: Optional[str] = None
floor_insulation_thickness: Optional[str] = None
flat_roof_insulation_thickness: Optional[Union[str, int]] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
@dataclass
class ImprovementDetails:
improvement_number: int
@dataclass
class SuggestedImprovement:
sequence: int
typical_saving: CostAmount
indicative_cost: str
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class AlternativeImprovement:
sequence: int
typical_saving: CostAmount
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema18_0:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
glazed_area: int
# glazing_gap is an integer in 18.0 (e.g. 12 mm), unlike 17.x where it was a string
glazing_gap: int
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
dwelling_type: DescriptionV1
language_code: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
pvc_window_frames: str
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
lzc_energy_sources: List[int]
sap_building_parts: List[SapBuildingPart]
low_energy_lighting: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: CostAmount
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: CostAmount
main_heating_controls: List[EnergyElement]
multiple_glazing_type: int
open_fireplaces_count: int
has_hot_water_cylinder: str
heating_cost_potential: CostAmount
hot_water_cost_current: CostAmount
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: CostAmount
schema_version_original: str
hot_water_cost_potential: CostAmount
renewable_heat_incentive: RenewableHeatIncentive
energy_consumption_current: int
has_fixed_air_conditioning: str
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
fixed_lighting_outlets_count: int
current_energy_efficiency_band: str
environmental_impact_potential: int
has_heated_separate_conservatory: str
potential_energy_efficiency_band: str
co2_emissions_current_per_floor_area: int
low_energy_fixed_lighting_outlets_count: int
sap_flat_details: Optional[SapFlatDetails] = None
address_line_2: Optional[str] = None
alternative_improvements: Optional[List[AlternativeImprovement]] = None

View file

@ -0,0 +1,251 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import CostAmount, DescriptionV1, Measurement
@dataclass
class EnergyElement:
description: DescriptionV1
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class InstantaneousWwhrs:
rooms_with_bath_and_or_shower: int
rooms_with_mixer_shower_no_bath: int
rooms_with_bath_and_mixer_shower: int
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
boiler_flue_type: Optional[int] = None
fan_flue_present: Optional[str] = None
central_heating_pump_age: Optional[int] = None
main_heating_index_number: Optional[int] = None
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
has_fixed_air_conditioning: str
cylinder_insulation_type: Optional[int] = None
cylinder_thermostat: Optional[str] = None
secondary_fuel_type: Optional[int] = None
secondary_heating_type: Optional[int] = None
cylinder_insulation_thickness: Optional[int] = None
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
pv_connection: int
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbines_terrain_type: int
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
party_wall_length: Union[Measurement, int]
heat_loss_perimeter: Measurement
floor_insulation: Optional[int] = None
floor_construction: Optional[int] = None
@dataclass
class SapRoomInRoof:
floor_area: Measurement
insulation: str
roof_room_connected: str
construction_age_band: str
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
wall_thickness: int
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
roof_insulation_thickness: Union[str, int]
sap_room_in_roof: Optional[SapRoomInRoof] = None
wall_insulation_thickness: Optional[str] = None
floor_insulation_thickness: Optional[str] = None
flat_roof_insulation_thickness: Optional[Union[str, int]] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
@dataclass
class WindowsTransmissionDetails:
u_value: float
data_source: int
solar_transmittance: float
@dataclass
class ImprovementDetails:
improvement_number: int
@dataclass
class SuggestedImprovement:
sequence: int
typical_saving: CostAmount
indicative_cost: str
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class AlternativeImprovement:
sequence: int
typical_saving: CostAmount
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema19_0:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
glazed_area: int
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
dwelling_type: DescriptionV1
language_code: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
pvc_window_frames: str
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
lzc_energy_sources: List[int]
sap_building_parts: List[SapBuildingPart]
low_energy_lighting: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: CostAmount
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: CostAmount
main_heating_controls: List[EnergyElement]
multiple_glazing_type: int
open_fireplaces_count: int
has_hot_water_cylinder: str
heating_cost_potential: CostAmount
hot_water_cost_current: CostAmount
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: CostAmount
schema_version_original: str
hot_water_cost_potential: CostAmount
renewable_heat_incentive: RenewableHeatIncentive
windows_transmission_details: WindowsTransmissionDetails
energy_consumption_current: int
has_fixed_air_conditioning: str
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
fixed_lighting_outlets_count: int
current_energy_efficiency_band: str
environmental_impact_potential: int
has_heated_separate_conservatory: str
potential_energy_efficiency_band: str
co2_emissions_current_per_floor_area: int
low_energy_fixed_lighting_outlets_count: int
sap_flat_details: Optional[SapFlatDetails] = None
address_line_2: Optional[str] = None
glazing_gap: Optional[Union[str, int]] = None
alternative_improvements: Optional[List[AlternativeImprovement]] = None

View file

@ -0,0 +1,282 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import Measurement
@dataclass
class EnergyElement:
# description is a plain string in schema 20.0.0 onwards (no longer a localised object)
description: str
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class Addendum:
addendum_numbers: List[int]
stone_walls: Optional[str] = None
system_build: Optional[str] = None
@dataclass
class InstantaneousWwhrs:
rooms_with_bath_and_or_shower: int
rooms_with_mixer_shower_no_bath: int
rooms_with_bath_and_mixer_shower: int
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
boiler_flue_type: Optional[int] = None
fan_flue_present: Optional[str] = None
central_heating_pump_age: Optional[int] = None
main_heating_index_number: Optional[int] = None
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
has_fixed_air_conditioning: str
cylinder_insulation_type: Optional[int] = None
cylinder_thermostat: Optional[str] = None
secondary_fuel_type: Optional[int] = None
secondary_heating_type: Optional[int] = None
cylinder_insulation_thickness: Optional[int] = None
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
pv_connection: int
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbines_terrain_type: int
@dataclass
class SapWindow:
orientation: int
window_area: float
window_type: int
glazing_type: int
window_location: int
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
party_wall_length: Union[Measurement, int]
heat_loss_perimeter: Measurement
floor_insulation: Optional[int] = None
floor_construction: Optional[int] = None
@dataclass
class SapRoomInRoof:
"""Room-in-roof details. floor_area is a plain number in schema 20.0.0 (not a Measurement object)."""
floor_area: Union[int, float]
insulation: str
roof_room_connected: str
construction_age_band: str
@dataclass
class SapAlternativeWall:
wall_area: float
wall_dry_lined: str
wall_construction: int
wall_insulation_type: int
wall_thickness_measured: str
wall_insulation_thickness: Optional[str] = None
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
roof_insulation_thickness: Union[str, int]
sap_room_in_roof: Optional[SapRoomInRoof] = None
wall_thickness: Optional[int] = None
wall_insulation_thickness: Optional[str] = None
floor_insulation_thickness: Optional[str] = None
flat_roof_insulation_thickness: Optional[Union[str, int]] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
storey_count: Optional[int] = None
unheated_corridor_length: Optional[int] = None
@dataclass
class WindowsTransmissionDetails:
u_value: float
data_source: int
solar_transmittance: float
@dataclass
class ImprovementTexts:
improvement_description: str
improvement_summary: Optional[str] = None
@dataclass
class ImprovementDetails:
improvement_number: Optional[int] = None
improvement_texts: Optional[ImprovementTexts] = None
@dataclass
class SuggestedImprovement:
sequence: int
# typical_saving is a plain number in schema 20.0.0 (not a CostAmount object)
typical_saving: float
# indicative_cost can be a formatted string (e.g. "£100 - £350") or a plain integer
indicative_cost: Union[str, int]
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_cavity_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema20_0_0:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
glazed_area: int
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
sap_windows: List[SapWindow]
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
# dwelling_type is a plain string in schema 20.0.0 onwards
dwelling_type: str
language_code: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
lzc_energy_sources: List[int]
sap_building_parts: List[SapBuildingPart]
low_energy_lighting: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: float
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: float
main_heating_controls: List[EnergyElement]
multiple_glazing_type: int
open_fireplaces_count: int
heating_cost_potential: float
hot_water_cost_current: float
insulated_door_u_value: float
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: float
schema_version_original: str
hot_water_cost_potential: float
renewable_heat_incentive: RenewableHeatIncentive
windows_transmission_details: WindowsTransmissionDetails
energy_consumption_current: int
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
fixed_lighting_outlets_count: int
multiple_glazed_proportion_nr: Optional[str]
current_energy_efficiency_band: str
environmental_impact_potential: int
potential_energy_efficiency_band: str
co2_emissions_current_per_floor_area: int
low_energy_fixed_lighting_outlets_count: int
sap_flat_details: Optional[SapFlatDetails] = None
addendum: Optional[Addendum] = None
address_line_2: Optional[str] = None
has_hot_water_cylinder: Optional[str] = None
has_fixed_air_conditioning: Optional[str] = None
has_heated_separate_conservatory: Optional[str] = None

View file

@ -0,0 +1,339 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import Measurement
@dataclass
class EnergyElement:
# description is a plain string in schema 21.0.0 (no longer a localised object)
description: str
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class Addendum:
addendum_numbers: List[int]
stone_walls: Optional[str] = None
system_build: Optional[str] = None
@dataclass
class ShowerOutlet:
shower_wwhrs: int
shower_outlet_type: int
@dataclass
class ShowerOutlets:
shower_outlet: ShowerOutlet
@dataclass
class InstantaneousWwhrs:
"""Changed in 21.0.0: references WWHRS product index numbers instead of room counts."""
wwhrs_index_number1: Optional[int] = None
wwhrs_index_number2: Optional[int] = None
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
boiler_flue_type: Optional[int] = None
fan_flue_present: Optional[str] = None
boiler_ignition_type: Optional[int] = None
central_heating_pump_age: Optional[int] = None
main_heating_index_number: Optional[int] = None
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
has_fixed_air_conditioning: str
shower_outlets: Optional[ShowerOutlets] = None
cylinder_insulation_type: Optional[int] = None
cylinder_thermostat: Optional[str] = None
secondary_fuel_type: Optional[int] = None
secondary_heating_type: Optional[int] = None
cylinder_insulation_thickness: Optional[int] = None
@dataclass
class PvBattery:
battery_capacity: float
@dataclass
class PvBatteries:
pv_battery: PvBattery
@dataclass
class WindTurbineDetails:
hub_height: float
rotor_diameter: float
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
pv_connection: int
pv_battery_count: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbine_details: WindTurbineDetails
gas_smart_meter_present: str
is_dwelling_export_capable: str
wind_turbines_terrain_type: int
electricity_smart_meter_present: str
pv_batteries: Optional[PvBatteries] = None
@dataclass
class WindowTransmissionDetails:
u_value: float
data_source: int
solar_transmittance: float
@dataclass
class SapWindow:
pvc_frame: str
glazing_gap: int
orientation: int
window_type: int
frame_factor: float
glazing_type: int
window_width: float
window_height: float
draught_proofed: str
window_location: int
window_wall_type: int
permanent_shutters_present: str
window_transmission_details: WindowTransmissionDetails
permanent_shutters_insulated: str
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
party_wall_length: Union[Measurement, int]
heat_loss_perimeter: Measurement
floor_insulation: Optional[int] = None
floor_construction: Optional[int] = None
@dataclass
class SapRoomInRoof:
"""Room-in-roof details. insulation and roof_room_connected removed in schema 21.0.0."""
floor_area: Union[int, float]
construction_age_band: str
@dataclass
class SapAlternativeWall:
wall_area: float
wall_dry_lined: str
wall_construction: int
wall_insulation_type: int
wall_thickness_measured: str
wall_insulation_thickness: Optional[str] = None
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
roof_insulation_thickness: Union[str, int]
sap_room_in_roof: Optional[SapRoomInRoof] = None
sap_alternative_wall_1: Optional[SapAlternativeWall] = None
sap_alternative_wall_2: Optional[SapAlternativeWall] = None
wall_thickness: Optional[int] = None
wall_insulation_thickness: Optional[str] = None
floor_insulation_thickness: Optional[str] = None
flat_roof_insulation_thickness: Optional[Union[str, int]] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
storey_count: Optional[int] = None
unheated_corridor_length: Optional[int] = None
@dataclass
class WindowsTransmissionDetails:
u_value: float
data_source: int
solar_transmittance: float
@dataclass
class ImprovementTexts:
improvement_description: str
improvement_summary: Optional[str] = None
@dataclass
class ImprovementDetails:
improvement_number: Optional[int] = None
improvement_texts: Optional[ImprovementTexts] = None
@dataclass
class SuggestedImprovement:
sequence: int
typical_saving: float
indicative_cost: Union[str, int]
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_cavity_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema21_0_0:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
sap_windows: List[SapWindow]
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
dwelling_type: str
language_code: int
pressure_test: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
wet_rooms_count: int
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
sap_building_parts: List[SapBuildingPart]
open_chimneys_count: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: float
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: float
main_heating_controls: List[EnergyElement]
has_hot_water_cylinder: str
heating_cost_potential: float
hot_water_cost_current: float
insulated_door_u_value: float
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: float
schema_version_original: str
hot_water_cost_potential: float
renewable_heat_incentive: RenewableHeatIncentive
draughtproofed_door_count: int
mechanical_vent_duct_type: int
windows_transmission_details: WindowsTransmissionDetails
cfl_fixed_lighting_bulbs_count: int
energy_consumption_current: int
has_fixed_air_conditioning: str
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
led_fixed_lighting_bulbs_count: int
mechanical_vent_duct_placement: int
mechanical_vent_duct_insulation: int
potential_energy_efficiency_band: str
pressure_test_certificate_number: int
mechanical_ventilation_index_number: int
co2_emissions_current_per_floor_area: int
current_energy_efficiency_band: str
environmental_impact_potential: int
low_energy_fixed_lighting_bulbs_count: int
mechanical_vent_duct_insulation_level: int
mechanical_vent_measured_installation: str
incandescent_fixed_lighting_bulbs_count: int
sap_flat_details: Optional[SapFlatDetails] = None
addendum: Optional[Addendum] = None
address_line_2: Optional[str] = None
has_heated_separate_conservatory: Optional[str] = None
fixed_lighting_outlets_count: Optional[int] = None
low_energy_fixed_lighting_outlets_count: Optional[int] = None

View file

@ -0,0 +1,340 @@
from dataclasses import dataclass
from typing import List, Optional, Union
from .common import DescriptionV1, Measurement
@dataclass
class EnergyElement:
# Descriptions revert to localised objects in schema 21.0.1 (were plain strings in 21.0.0)
description: DescriptionV1
energy_efficiency_rating: int
environmental_efficiency_rating: int
@dataclass
class Addendum:
addendum_numbers: List[int]
stone_walls: Optional[str] = None
system_build: Optional[str] = None
@dataclass
class ShowerOutlet:
shower_wwhrs: int
shower_outlet_type: int
@dataclass
class ShowerOutlets:
shower_outlet: ShowerOutlet
@dataclass
class InstantaneousWwhrs:
"""References WWHRS product index numbers (introduced in 21.0.0)."""
wwhrs_index_number1: Optional[int] = None
wwhrs_index_number2: Optional[int] = None
@dataclass
class MainHeatingDetail:
has_fghrs: str
main_fuel_type: int
heat_emitter_type: int
emitter_temperature: Union[int, str]
main_heating_number: int
main_heating_control: int
main_heating_category: int
main_heating_fraction: int
main_heating_data_source: int
boiler_flue_type: Optional[int] = None
fan_flue_present: Optional[str] = None
boiler_ignition_type: Optional[int] = None
central_heating_pump_age: Optional[int] = None
main_heating_index_number: Optional[int] = None
sap_main_heating_code: Optional[int] = None
@dataclass
class SapHeating:
cylinder_size: int
water_heating_code: int
water_heating_fuel: int
instantaneous_wwhrs: InstantaneousWwhrs
main_heating_details: List[MainHeatingDetail]
immersion_heating_type: Union[int, str]
has_fixed_air_conditioning: str
shower_outlets: Optional[ShowerOutlets] = None
cylinder_insulation_type: Optional[int] = None
cylinder_thermostat: Optional[str] = None
secondary_fuel_type: Optional[int] = None
secondary_heating_type: Optional[int] = None
cylinder_insulation_thickness: Optional[int] = None
@dataclass
class PvBattery:
battery_capacity: float
@dataclass
class PvBatteries:
pv_battery: PvBattery
@dataclass
class WindTurbineDetails:
hub_height: float
rotor_diameter: float
@dataclass
class PhotovoltaicSupplyNoneOrNoDetails:
percent_roof_area: int
@dataclass
class PhotovoltaicSupply:
none_or_no_details: PhotovoltaicSupplyNoneOrNoDetails
@dataclass
class SapEnergySource:
mains_gas: str
meter_type: int
pv_connection: int
pv_battery_count: int
photovoltaic_supply: PhotovoltaicSupply
wind_turbines_count: int
wind_turbine_details: WindTurbineDetails
gas_smart_meter_present: str
is_dwelling_export_capable: str
wind_turbines_terrain_type: int
electricity_smart_meter_present: str
pv_batteries: Optional[PvBatteries] = None
@dataclass
class WindowTransmissionDetails:
u_value: float
data_source: int
solar_transmittance: float
@dataclass
class SapWindow:
pvc_frame: str
glazing_gap: int
orientation: int
window_type: int
frame_factor: float
glazing_type: int
window_width: float
window_height: float
draught_proofed: str
window_location: int
window_wall_type: int
permanent_shutters_present: str
window_transmission_details: WindowTransmissionDetails
permanent_shutters_insulated: str
@dataclass
class SapFloorDimension:
floor: int
room_height: Measurement
total_floor_area: Measurement
party_wall_length: Union[Measurement, int]
heat_loss_perimeter: Measurement
floor_insulation: Optional[int] = None
floor_construction: Optional[int] = None
@dataclass
class SapRoomInRoof:
floor_area: Union[int, float]
construction_age_band: str
@dataclass
class SapAlternativeWall:
wall_area: float
wall_dry_lined: str
wall_construction: int
wall_insulation_type: int
wall_thickness_measured: str
wall_insulation_thickness: Optional[str] = None
@dataclass
class SapBuildingPart:
identifier: str
wall_dry_lined: str
floor_heat_loss: int
roof_construction: int
wall_construction: int
building_part_number: int
sap_floor_dimensions: List[SapFloorDimension]
wall_insulation_type: int
construction_age_band: str
party_wall_construction: Union[int, str]
wall_thickness_measured: str
roof_insulation_location: Union[int, str]
roof_insulation_thickness: Union[str, int]
sap_room_in_roof: Optional[SapRoomInRoof] = None
sap_alternative_wall_1: Optional[SapAlternativeWall] = None
sap_alternative_wall_2: Optional[SapAlternativeWall] = None
wall_thickness: Optional[int] = None
wall_insulation_thickness: Optional[str] = None
floor_insulation_thickness: Optional[str] = None
flat_roof_insulation_thickness: Optional[Union[str, int]] = None
@dataclass
class SapFlatDetails:
level: int
top_storey: str
flat_location: int
heat_loss_corridor: int
storey_count: Optional[int] = None
# Changed from plain int in 21.0.0 to a Measurement object in 21.0.1
unheated_corridor_length: Optional[Union[Measurement, int]] = None
@dataclass
class WindowsTransmissionDetails:
u_value: float
data_source: int
solar_transmittance: float
@dataclass
class ImprovementTexts:
improvement_description: str
improvement_summary: Optional[str] = None
@dataclass
class ImprovementDetails:
improvement_number: Optional[int] = None
improvement_texts: Optional[ImprovementTexts] = None
@dataclass
class SuggestedImprovement:
sequence: int
typical_saving: float
indicative_cost: Union[str, int]
improvement_type: str
improvement_details: ImprovementDetails
improvement_category: int
energy_performance_rating: int
environmental_impact_rating: int
@dataclass
class RenewableHeatIncentive:
water_heating: int
space_heating_existing_dwelling: int
impact_of_loft_insulation: Optional[int] = None
impact_of_cavity_insulation: Optional[int] = None
impact_of_solid_wall_insulation: Optional[int] = None
@dataclass
class RdSapSchema21_0_1:
uprn: int
roofs: List[EnergyElement]
walls: List[EnergyElement]
floors: List[EnergyElement]
status: str
tenure: int
window: EnergyElement
lighting: EnergyElement
postcode: str
hot_water: EnergyElement
post_town: str
built_form: int
door_count: int
region_code: int
report_type: int
sap_heating: SapHeating
sap_version: float
sap_windows: List[SapWindow]
schema_type: str
uprn_source: str
country_code: str
main_heating: List[EnergyElement]
# dwelling_type remains a plain string (not reverted to DescriptionV1) in 21.0.1
dwelling_type: str
language_code: int
pressure_test: int
property_type: int
address_line_1: str
assessment_type: str
completion_date: str
inspection_date: str
wet_rooms_count: int
extensions_count: int
measurement_type: int
total_floor_area: int
transaction_type: int
conservatory_type: int
heated_room_count: int
registration_date: str
sap_energy_source: SapEnergySource
secondary_heating: EnergyElement
sap_building_parts: List[SapBuildingPart]
open_chimneys_count: int
solar_water_heating: str
habitable_room_count: int
heating_cost_current: float
insulated_door_count: int
co2_emissions_current: float
energy_rating_average: int
energy_rating_current: int
lighting_cost_current: float
main_heating_controls: List[EnergyElement]
has_hot_water_cylinder: str
heating_cost_potential: float
hot_water_cost_current: float
insulated_door_u_value: float
mechanical_ventilation: int
percent_draughtproofed: int
suggested_improvements: List[SuggestedImprovement]
co2_emissions_potential: float
energy_rating_potential: int
lighting_cost_potential: float
schema_version_original: str
hot_water_cost_potential: float
renewable_heat_incentive: RenewableHeatIncentive
draughtproofed_door_count: int
mechanical_vent_duct_type: int
windows_transmission_details: WindowsTransmissionDetails
cfl_fixed_lighting_bulbs_count: int
energy_consumption_current: int
has_fixed_air_conditioning: str
multiple_glazed_proportion: int
calculation_software_version: str
energy_consumption_potential: int
environmental_impact_current: int
led_fixed_lighting_bulbs_count: int
mechanical_vent_duct_placement: int
mechanical_vent_duct_insulation: int
potential_energy_efficiency_band: str
pressure_test_certificate_number: int
mechanical_ventilation_index_number: int
co2_emissions_current_per_floor_area: int
current_energy_efficiency_band: str
environmental_impact_potential: int
low_energy_fixed_lighting_bulbs_count: int
mechanical_vent_duct_insulation_level: int
mechanical_vent_measured_installation: str
incandescent_fixed_lighting_bulbs_count: int
sap_flat_details: Optional[SapFlatDetails] = None
addendum: Optional[Addendum] = None
address_line_2: Optional[str] = None
has_heated_separate_conservatory: Optional[str] = None
fixed_lighting_outlets_count: Optional[int] = None
low_energy_fixed_lighting_outlets_count: Optional[int] = None

View file

View file

@ -0,0 +1,218 @@
{
"uprn": 12457,
"roofs": [
{
"description": {"value": "(another dwelling above)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"walls": [
{
"description": {"value": "System built, with internal insulation", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"floors": [
{
"description": {"value": "(another dwelling below)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"status": "entered",
"tenure": 2,
"window": {
"description": {"value": "Fully double glazed", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
"lighting": {
"description": {"value": "Low energy lighting in 57% of fixed outlets", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
},
"postcode": "PT5 4RZ",
"hot_water": {
"description": {"value": "Electric immersion, off-peak", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 2
},
"post_town": "POSTTOWN",
"built_form": 2,
"door_count": 2,
"glazed_area": 1,
"glazing_gap": "16+",
"region_code": 3,
"report_type": 2,
"sap_heating": {
"cylinder_size": 2,
"water_heating_code": 903,
"water_heating_fuel": 29,
"instantaneous_wwhrs": {
"rooms_with_bath_and_or_shower": 1,
"rooms_with_mixer_shower_no_bath": 0,
"rooms_with_bath_and_mixer_shower": 0
},
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 29,
"heat_emitter_type": 0,
"emitter_temperature": "NA",
"main_heating_number": 1,
"main_heating_control": 2401,
"main_heating_category": 7,
"main_heating_fraction": 1,
"sap_main_heating_code": 402,
"main_heating_data_source": 2
}
],
"immersion_heating_type": 1,
"cylinder_insulation_type": 0,
"has_fixed_air_conditioning": "false"
},
"sap_version": 9.92,
"schema_type": "RdSAP-Schema-17.0",
"uprn_source": "Energy Assessor",
"country_code": "EAW",
"main_heating": [
{
"description": {"value": "Electric storage heaters", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 1
}
],
"dwelling_type": {"value": "Mid-floor flat", "language": "1"},
"language_code": 1,
"property_type": 2,
"address_line_1": "42, Moria Mines Lane",
"assessment_type": "RdSAP",
"completion_date": "2016-01-12",
"inspection_date": "2016-01-12",
"extensions_count": 0,
"measurement_type": 1,
"sap_flat_details": {
"level": 2,
"top_storey": "N",
"flat_location": 1,
"heat_loss_corridor": 0
},
"total_floor_area": 55,
"transaction_type": 8,
"conservatory_type": 1,
"heated_room_count": 1,
"pvc_window_frames": "true",
"registration_date": "2016-01-12",
"sap_energy_source": {
"mains_gas": "N",
"meter_type": 1,
"photovoltaic_supply": {
"none_or_no_details": {"pv_connection": 0, "percent_roof_area": 0}
},
"wind_turbines_count": 0,
"wind_turbines_terrain_type": 2
},
"secondary_heating": {
"description": {"value": "Portable electric heaters (assumed)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"lzc_energy_sources": [11],
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"wall_thickness": 240,
"floor_heat_loss": 6,
"roof_construction": 3,
"wall_construction": 8,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.4, "quantity": "metres"},
"total_floor_area": {"value": 54.6, "quantity": "square metres"},
"party_wall_length": {"value": 7.3, "quantity": "metres"},
"heat_loss_perimeter": {"value": 23.3, "quantity": "metres"}
}
],
"wall_insulation_type": 3,
"construction_age_band": "D",
"party_wall_construction": 0,
"wall_thickness_measured": "Y",
"roof_insulation_location": "ND",
"roof_insulation_thickness": "ND",
"wall_insulation_thickness": "50mm"
}
],
"low_energy_lighting": 57,
"solar_water_heating": "N",
"habitable_room_count": 3,
"heating_cost_current": {"value": 214, "currency": "GBP"},
"insulated_door_count": 0,
"co2_emissions_current": 3.9,
"energy_rating_average": 60,
"energy_rating_current": 66,
"lighting_cost_current": {"value": 61, "currency": "GBP"},
"main_heating_controls": [
{
"description": {"value": "Manual charge control", "language": "1"},
"energy_efficiency_rating": 2,
"environmental_efficiency_rating": 2
}
],
"multiple_glazing_type": 3,
"open_fireplaces_count": 0,
"has_hot_water_cylinder": "true",
"heating_cost_potential": {"value": 216, "currency": "GBP"},
"hot_water_cost_current": {"value": 396, "currency": "GBP"},
"mechanical_ventilation": 0,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": {"value": 158, "currency": "GBP"},
"indicative_cost": "£15 - £30",
"improvement_type": "C",
"improvement_details": {"improvement_number": 1},
"improvement_category": 5,
"energy_performance_rating": 74,
"environmental_impact_rating": 60
}
],
"co2_emissions_potential": 2.5,
"energy_rating_potential": 79,
"lighting_cost_potential": {"value": 42, "currency": "GBP"},
"schema_version_original": "LIG-17.0",
"alternative_improvements": [
{
"sequence": 1,
"typical_saving": {"value": 141, "currency": "GBP"},
"improvement_type": "J2",
"improvement_details": {"improvement_number": 54},
"improvement_category": 6,
"energy_performance_rating": 81,
"environmental_impact_rating": 96
}
],
"hot_water_cost_potential": {"value": 154, "currency": "GBP"},
"renewable_heat_incentive": {
"water_heating": 4818,
"space_heating_existing_dwelling": 2415
},
"energy_consumption_current": 427,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "9.0.0",
"energy_consumption_potential": 267,
"environmental_impact_current": 48,
"fixed_lighting_outlets_count": 7,
"current_energy_efficiency_band": "D",
"environmental_impact_potential": 66,
"has_heated_separate_conservatory": "false",
"potential_energy_efficiency_band": "C",
"co2_emissions_current_per_floor_area": 72,
"low_energy_fixed_lighting_outlets_count": 4
}

View file

@ -0,0 +1,243 @@
{
"uprn": 12457,
"roofs": [
{
"description": {"value": "Pitched, 100 mm loft insulation", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
{
"description": {"value": "Pitched, insulated (assumed)", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"walls": [
{
"description": {"value": "Cavity wall, filled cavity", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"floors": [
{
"description": {"value": "Solid, no insulation (assumed)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"status": "entered",
"tenure": 1,
"window": {
"description": {"value": "Fully double glazed", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
"lighting": {
"description": {"value": "Low energy lighting in 23% of fixed outlets", "language": "1"},
"energy_efficiency_rating": 2,
"environmental_efficiency_rating": 2
},
"postcode": "PT42 5HL",
"hot_water": {
"description": {"value": "From main system", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
"post_town": "POSTTOWN",
"built_form": 1,
"door_count": 4,
"glazed_area": 1,
"glazing_gap": "16+",
"region_code": 17,
"report_type": 2,
"sap_heating": {
"cylinder_size": 2,
"water_heating_code": 901,
"water_heating_fuel": 28,
"cylinder_thermostat": "Y",
"instantaneous_wwhrs": {
"rooms_with_bath_and_or_shower": 1,
"rooms_with_mixer_shower_no_bath": 0,
"rooms_with_bath_and_mixer_shower": 1
},
"secondary_fuel_type": 29,
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 28,
"boiler_flue_type": 1,
"fan_flue_present": "N",
"heat_emitter_type": 1,
"emitter_temperature": "NA",
"main_heating_number": 1,
"main_heating_control": 2104,
"main_heating_category": 2,
"main_heating_fraction": 1,
"mcs_installed_heat_pump": "false",
"main_heating_data_source": 1,
"main_heating_index_number": 9049
}
],
"immersion_heating_type": "NA",
"secondary_heating_type": 691,
"cylinder_insulation_type": 1,
"has_fixed_air_conditioning": "false",
"cylinder_insulation_thickness": 12
},
"sap_version": 9.92,
"schema_type": "RdSAP-Schema-17.1",
"uprn_source": "Energy Assessor",
"country_code": "EAW",
"main_heating": [
{
"description": {"value": "Boiler and radiators, oil", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
}
],
"dwelling_type": {"value": "Detached house", "language": "1"},
"language_code": 1,
"property_type": 0,
"address_line_1": "15, Hedge Lane",
"address_line_2": "Lower Moria",
"assessment_type": "RdSAP",
"completion_date": "2018-05-29",
"inspection_date": "2018-05-29",
"extensions_count": 1,
"measurement_type": 2,
"total_floor_area": 101,
"transaction_type": 1,
"conservatory_type": 1,
"heated_room_count": 7,
"pvc_window_frames": "true",
"registration_date": "2018-05-27",
"sap_energy_source": {
"mains_gas": "N",
"meter_type": 2,
"photovoltaic_supply": {
"none_or_no_details": {"pv_connection": 0, "percent_roof_area": 0}
},
"wind_turbines_count": 0,
"wind_turbines_terrain_type": 2
},
"secondary_heating": {
"description": {"value": "Room heaters, electric", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"lzc_energy_sources": [11],
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"wall_thickness": 270,
"floor_heat_loss": 7,
"roof_construction": 4,
"wall_construction": 4,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.4, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 48.45, "quantity": "square metres"},
"party_wall_length": {"value": 0, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 22.3, "quantity": "metres"}
}
],
"wall_insulation_type": 2,
"construction_age_band": "G",
"party_wall_construction": "NA",
"wall_thickness_measured": "Y",
"roof_insulation_location": 2,
"roof_insulation_thickness": "100mm"
},
{
"identifier": "Extension 1",
"wall_dry_lined": "N",
"wall_thickness": 260,
"floor_heat_loss": 7,
"roof_construction": 5,
"wall_construction": 4,
"building_part_number": 2,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.4, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 21.84, "quantity": "square metres"},
"party_wall_length": 0,
"floor_construction": 1,
"heat_loss_perimeter": {"value": 16.6, "quantity": "metres"}
}
],
"wall_insulation_type": 4,
"construction_age_band": "H",
"party_wall_construction": "NA",
"wall_thickness_measured": "Y",
"roof_insulation_location": 4,
"roof_insulation_thickness": 0,
"wall_insulation_thickness": "NI"
}
],
"low_energy_lighting": 23,
"solar_water_heating": "N",
"habitable_room_count": 7,
"heating_cost_current": {"value": 659, "currency": "GBP"},
"insulated_door_count": 0,
"co2_emissions_current": 5.8,
"energy_rating_average": 60,
"energy_rating_current": 53,
"lighting_cost_current": {"value": 115, "currency": "GBP"},
"main_heating_controls": [
{
"description": {"value": "Programmer and room thermostat", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
}
],
"multiple_glazing_type": 3,
"open_fireplaces_count": 0,
"has_hot_water_cylinder": "true",
"heating_cost_potential": {"value": 470, "currency": "GBP"},
"hot_water_cost_current": {"value": 161, "currency": "GBP"},
"mechanical_ventilation": 0,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": {"value": 25, "currency": "GBP"},
"indicative_cost": "£100 - £350",
"improvement_type": "A",
"improvement_details": {"improvement_number": 5},
"improvement_category": 5,
"energy_performance_rating": 54,
"environmental_impact_rating": 47
}
],
"co2_emissions_potential": 2.7,
"energy_rating_potential": 78,
"lighting_cost_potential": {"value": 65, "currency": "GBP"},
"schema_version_original": "LIG-17.1",
"hot_water_cost_potential": {"value": 77, "currency": "GBP"},
"renewable_heat_incentive": {
"water_heating": 3301,
"impact_of_loft_insulation": -565,
"space_heating_existing_dwelling": 11351
},
"energy_consumption_current": 234,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "v92.0.1.1",
"energy_consumption_potential": 95,
"environmental_impact_current": 46,
"fixed_lighting_outlets_count": 13,
"current_energy_efficiency_band": "E",
"environmental_impact_potential": 72,
"has_heated_separate_conservatory": "false",
"potential_energy_efficiency_band": "C",
"co2_emissions_current_per_floor_area": 57,
"low_energy_fixed_lighting_outlets_count": 3
}

View file

@ -0,0 +1,251 @@
{
"uprn": 12457,
"roofs": [
{
"description": {"value": "Pitched, 100 mm loft insulation", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
{
"description": {"value": "Flat, insulated", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
{
"description": {"value": "Roof room(s), insulated (assumed)", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"walls": [
{
"description": {"value": "Solid brick, as built, no insulation (assumed)", "language": "1"},
"energy_efficiency_rating": 1,
"environmental_efficiency_rating": 1
}
],
"floors": [
{
"description": {"value": "Solid, no insulation (assumed)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"status": "entered",
"tenure": 1,
"window": {
"description": {"value": "Fully double glazed", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
"lighting": {
"description": {"value": "Low energy lighting in 67% of fixed outlets", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
},
"postcode": "PT11 4RF",
"hot_water": {
"description": {"value": "From main system", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
},
"post_town": "POSTTOWN",
"built_form": 4,
"door_count": 2,
"glazed_area": 1,
"glazing_gap": 12,
"region_code": 1,
"report_type": 2,
"sap_heating": {
"cylinder_size": 1,
"water_heating_code": 901,
"water_heating_fuel": 26,
"instantaneous_wwhrs": {
"rooms_with_bath_and_or_shower": 1,
"rooms_with_mixer_shower_no_bath": 0,
"rooms_with_bath_and_mixer_shower": 0
},
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 26,
"boiler_flue_type": 2,
"heat_emitter_type": 1,
"emitter_temperature": 0,
"main_heating_number": 1,
"main_heating_control": 2106,
"main_heating_category": 2,
"main_heating_fraction": 1,
"central_heating_pump_age": 0,
"main_heating_data_source": 1,
"main_heating_index_number": 16137
}
],
"immersion_heating_type": "NA",
"has_fixed_air_conditioning": "false"
},
"sap_version": 9.92,
"schema_type": "RdSAP-Schema-18.0",
"uprn_source": "Energy Assessor",
"country_code": "EAW",
"main_heating": [
{
"description": {"value": "Boiler and radiators, mains gas", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"dwelling_type": {"value": "Mid-terrace house", "language": "1"},
"language_code": 1,
"property_type": 0,
"address_line_1": "1, Bagshot Lane",
"address_line_2": "Village",
"assessment_type": "RdSAP",
"completion_date": "2017-03-19",
"inspection_date": "2017-03-19",
"extensions_count": 1,
"measurement_type": 1,
"total_floor_area": 93,
"transaction_type": 5,
"conservatory_type": 1,
"heated_room_count": 5,
"pvc_window_frames": "true",
"registration_date": "2017-03-19",
"sap_energy_source": {
"mains_gas": "Y",
"meter_type": 1,
"photovoltaic_supply": {
"none_or_no_details": {"pv_connection": 0, "percent_roof_area": 0}
},
"wind_turbines_count": 0,
"wind_turbines_terrain_type": 2
},
"secondary_heating": {
"description": {"value": "None", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"lzc_energy_sources": [11],
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"wall_thickness": 330,
"floor_heat_loss": 7,
"sap_room_in_roof": {
"floor_area": {"value": 9, "quantity": "square metres"},
"insulation": "AB",
"roof_room_connected": "N",
"construction_age_band": "G"
},
"roof_construction": 4,
"wall_construction": 3,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.4, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 29.12, "quantity": "square metres"},
"party_wall_length": {"value": 11.2, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 5.2, "quantity": "metres"}
}
],
"wall_insulation_type": 4,
"construction_age_band": "C",
"party_wall_construction": 0,
"wall_thickness_measured": "Y",
"roof_insulation_location": 2,
"roof_insulation_thickness": "100mm",
"wall_insulation_thickness": "NI"
},
{
"identifier": "Extension",
"wall_dry_lined": "N",
"wall_thickness": 290,
"floor_heat_loss": 7,
"roof_construction": 1,
"wall_construction": 4,
"building_part_number": 2,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.4, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 15.6, "quantity": "square metres"},
"party_wall_length": {"value": 6, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 5.2, "quantity": "metres"}
}
],
"wall_insulation_type": 4,
"construction_age_band": "G",
"party_wall_construction": 0,
"wall_thickness_measured": "Y",
"roof_insulation_location": 6,
"roof_insulation_thickness": "NI",
"wall_insulation_thickness": "NI",
"flat_roof_insulation_thickness": "NI"
}
],
"low_energy_lighting": 67,
"solar_water_heating": "N",
"habitable_room_count": 5,
"heating_cost_current": {"value": 619, "currency": "GBP"},
"insulated_door_count": 0,
"co2_emissions_current": 3.4,
"energy_rating_average": 60,
"energy_rating_current": 69,
"lighting_cost_current": {"value": 81, "currency": "GBP"},
"main_heating_controls": [
{
"description": {"value": "Programmer, room thermostat and TRVs", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"multiple_glazing_type": 3,
"open_fireplaces_count": 0,
"has_hot_water_cylinder": "false",
"heating_cost_potential": {"value": 534, "currency": "GBP"},
"hot_water_cost_current": {"value": 100, "currency": "GBP"},
"mechanical_ventilation": 0,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": {"value": 88, "currency": "GBP"},
"indicative_cost": "£4,000 - £14,000",
"improvement_type": "Q",
"improvement_details": {"improvement_number": 7},
"improvement_category": 5,
"energy_performance_rating": 72,
"environmental_impact_rating": 71
}
],
"co2_emissions_potential": 1.7,
"energy_rating_potential": 85,
"lighting_cost_potential": {"value": 61, "currency": "GBP"},
"schema_version_original": "LIG-17.0",
"hot_water_cost_potential": {"value": 68, "currency": "GBP"},
"renewable_heat_incentive": {
"water_heating": 2087,
"impact_of_loft_insulation": -214,
"impact_of_solid_wall_insulation": -1864,
"space_heating_existing_dwelling": 10483
},
"energy_consumption_current": 230,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "2.0.0.0",
"energy_consumption_potential": 115,
"environmental_impact_current": 66,
"fixed_lighting_outlets_count": 9,
"current_energy_efficiency_band": "C",
"environmental_impact_potential": 83,
"has_heated_separate_conservatory": "false",
"potential_energy_efficiency_band": "B",
"co2_emissions_current_per_floor_area": 41,
"low_energy_fixed_lighting_outlets_count": 6
}

View file

@ -0,0 +1,213 @@
{
"uprn": 12457,
"roofs": [
{
"description": {"value": "Pitched, 150 mm loft insulation", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"walls": [
{
"description": {"value": "Cavity wall, filled cavity", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
}
],
"floors": [
{
"description": {"value": "Solid, no insulation (assumed)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
}
],
"status": "entered",
"tenure": 3,
"window": {
"description": {"value": "Fully double glazed", "language": "1"},
"energy_efficiency_rating": 3,
"environmental_efficiency_rating": 3
},
"lighting": {
"description": {"value": "Low energy lighting in 87% of fixed outlets", "language": "1"},
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
},
"postcode": "A1 1AA",
"hot_water": {
"description": {"value": "From main system", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
},
"post_town": "Town",
"built_form": 2,
"door_count": 1,
"glazed_area": 1,
"region_code": 19,
"report_type": 2,
"sap_heating": {
"cylinder_size": 1,
"water_heating_code": 901,
"water_heating_fuel": 26,
"instantaneous_wwhrs": {
"rooms_with_bath_and_or_shower": 1,
"rooms_with_mixer_shower_no_bath": 0,
"rooms_with_bath_and_mixer_shower": 0
},
"secondary_fuel_type": 9,
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 26,
"boiler_flue_type": 2,
"heat_emitter_type": 1,
"emitter_temperature": 0,
"main_heating_number": 1,
"main_heating_control": 2106,
"main_heating_category": 2,
"main_heating_fraction": 1,
"central_heating_pump_age": 0,
"main_heating_data_source": 1,
"main_heating_index_number": 15274
}
],
"immersion_heating_type": "NA",
"secondary_heating_type": 631,
"has_fixed_air_conditioning": "false"
},
"sap_version": 9.94,
"schema_type": "RdSAP-Schema-19.0",
"uprn_source": "Energy Assessor",
"country_code": "EAW",
"main_heating": [
{
"description": {"value": "Boiler and radiators, mains gas", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"dwelling_type": {"value": "Semi-detached house", "language": "1"},
"language_code": 1,
"property_type": 0,
"address_line_1": "15, Address Lane",
"address_line_2": "New Town",
"assessment_type": "RdSAP",
"completion_date": "2020-06-04",
"inspection_date": "2020-06-03",
"extensions_count": 1,
"measurement_type": 1,
"total_floor_area": 94,
"transaction_type": 8,
"conservatory_type": 2,
"heated_room_count": 5,
"pvc_window_frames": "false",
"registration_date": "2020-06-04",
"sap_energy_source": {
"mains_gas": "Y",
"meter_type": 3,
"photovoltaic_supply": {
"none_or_no_details": {"pv_connection": 0, "percent_roof_area": 0}
},
"wind_turbines_count": 0,
"wind_turbines_terrain_type": 2
},
"secondary_heating": {
"description": {"value": "Room heaters, dual fuel (mineral and wood)", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"lzc_energy_sources": [11, 9],
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"wall_thickness": 300,
"floor_heat_loss": 7,
"roof_construction": 4,
"wall_construction": 4,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.47, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 39.91, "quantity": "square metres"},
"party_wall_length": {"value": 8.81, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 13.65, "quantity": "metres"}
}
],
"wall_insulation_type": 2,
"construction_age_band": "D",
"party_wall_construction": 1,
"wall_thickness_measured": "Y",
"roof_insulation_location": 2,
"roof_insulation_thickness": "150mm",
"wall_insulation_thickness": "NI",
"floor_insulation_thickness": "NI"
}
],
"low_energy_lighting": 87,
"solar_water_heating": "N",
"habitable_room_count": 5,
"heating_cost_current": {"value": 666, "currency": "GBP"},
"insulated_door_count": 0,
"co2_emissions_current": 3.8,
"energy_rating_average": 60,
"energy_rating_current": 66,
"lighting_cost_current": {"value": 81, "currency": "GBP"},
"main_heating_controls": [
{
"description": {"value": "Programmer, room thermostat and TRVs", "language": "1"},
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"multiple_glazing_type": 3,
"open_fireplaces_count": 0,
"has_hot_water_cylinder": "false",
"heating_cost_potential": {"value": 615, "currency": "GBP"},
"hot_water_cost_current": {"value": 107, "currency": "GBP"},
"mechanical_ventilation": 0,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": {"value": 51, "currency": "GBP"},
"indicative_cost": "£4,000 - £6,000",
"improvement_type": "W2",
"improvement_details": {"improvement_number": 58},
"improvement_category": 5,
"energy_performance_rating": 68,
"environmental_impact_rating": 65
}
],
"co2_emissions_potential": 2.4,
"energy_rating_potential": 79,
"lighting_cost_potential": {"value": 81, "currency": "GBP"},
"schema_version_original": "LIG-19.0",
"hot_water_cost_potential": {"value": 74, "currency": "GBP"},
"renewable_heat_incentive": {
"water_heating": 2207,
"impact_of_loft_insulation": -394,
"space_heating_existing_dwelling": 9825
},
"energy_consumption_current": 222,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "2.1.1.0",
"energy_consumption_potential": 137,
"environmental_impact_current": 62,
"fixed_lighting_outlets_count": 15,
"windows_transmission_details": {
"u_value": 3.1,
"data_source": 2,
"solar_transmittance": 0.76
},
"current_energy_efficiency_band": "D",
"environmental_impact_potential": 75,
"has_heated_separate_conservatory": "false",
"potential_energy_efficiency_band": "C",
"co2_emissions_current_per_floor_area": 41,
"low_energy_fixed_lighting_outlets_count": 13
}

View file

@ -0,0 +1,225 @@
{
"uprn": 12457,
"roofs": [
{"description": "Pitched, 25 mm loft insulation", "energy_efficiency_rating": 2, "environmental_efficiency_rating": 2},
{"description": "Pitched, 250 mm loft insulation", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"walls": [
{"description": "Solid brick, as built, no insulation (assumed)", "energy_efficiency_rating": 1, "environmental_efficiency_rating": 1},
{"description": "Cavity wall, as built, insulated (assumed)", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"floors": [
{"description": "Suspended, no insulation (assumed)", "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0},
{"description": "Solid, insulated (assumed)", "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0}
],
"status": "entered",
"tenure": 1,
"window": {"description": "Fully double glazed", "energy_efficiency_rating": 3, "environmental_efficiency_rating": 3},
"addendum": {
"stone_walls": "true",
"system_build": "true",
"addendum_numbers": [1, 8]
},
"lighting": {"description": "Low energy lighting in 50% of fixed outlets", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
"postcode": "A0 0AA",
"hot_water": {"description": "From main system", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
"post_town": "Whitbury",
"built_form": 2,
"door_count": 2,
"glazed_area": 1,
"region_code": 1,
"report_type": 2,
"sap_heating": {
"cylinder_size": 1,
"water_heating_code": 901,
"water_heating_fuel": 26,
"instantaneous_wwhrs": {
"rooms_with_bath_and_or_shower": 1,
"rooms_with_mixer_shower_no_bath": 0,
"rooms_with_bath_and_mixer_shower": 0
},
"secondary_fuel_type": 25,
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 26,
"boiler_flue_type": 2,
"fan_flue_present": "N",
"heat_emitter_type": 1,
"emitter_temperature": 0,
"main_heating_number": 1,
"main_heating_control": 2106,
"main_heating_category": 2,
"main_heating_fraction": 1,
"sap_main_heating_code": 101,
"central_heating_pump_age": 0,
"main_heating_data_source": 1,
"main_heating_index_number": 17507
}
],
"immersion_heating_type": "NA",
"has_fixed_air_conditioning": "false"
},
"sap_version": 9.8,
"sap_windows": [
{"orientation": 1, "window_area": 200.1, "window_type": 2, "glazing_type": 1, "window_location": 0},
{"orientation": 2, "window_area": 180.2, "window_type": 1, "glazing_type": 2, "window_location": 1}
],
"schema_type": "RdSAP-Schema-20.0.0",
"uprn_source": "Energy Assessor",
"country_code": "EAW",
"main_heating": [
{"description": "Boiler and radiators, anthracite", "energy_efficiency_rating": 3, "environmental_efficiency_rating": 1},
{"description": "Boiler and radiators, mains gas", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"dwelling_type": "Mid-terrace house",
"language_code": 1,
"property_type": 0,
"address_line_1": "1 Some Street",
"assessment_type": "RdSAP",
"completion_date": "2020-05-04",
"inspection_date": "2020-05-04",
"extensions_count": 0,
"measurement_type": 1,
"sap_flat_details": {
"level": 1,
"top_storey": "N",
"storey_count": 3,
"flat_location": 1,
"heat_loss_corridor": 2,
"unheated_corridor_length": 10
},
"total_floor_area": 55,
"transaction_type": 1,
"conservatory_type": 1,
"heated_room_count": 5,
"registration_date": "2020-05-04",
"sap_energy_source": {
"mains_gas": "Y",
"meter_type": 2,
"photovoltaic_supply": {
"none_or_no_details": {"pv_connection": 0, "percent_roof_area": 50}
},
"wind_turbines_count": 0,
"wind_turbines_terrain_type": 2
},
"secondary_heating": {"description": "Room heaters, electric", "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0},
"lzc_energy_sources": [11],
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"floor_heat_loss": 7,
"sap_room_in_roof": {
"floor_area": 100,
"insulation": "AB",
"roof_room_connected": "N",
"construction_age_band": "B"
},
"roof_construction": 4,
"wall_construction": 4,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.45, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 45.82, "quantity": "square metres"},
"party_wall_length": {"value": 7.9, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 19.5, "quantity": "metres"}
}
],
"wall_insulation_type": 2,
"construction_age_band": "K",
"party_wall_construction": 0,
"wall_thickness_measured": "N",
"roof_insulation_location": 2,
"roof_insulation_thickness": "200mm",
"wall_insulation_thickness": "NI",
"floor_insulation_thickness": "NI"
}
],
"low_energy_lighting": 100,
"solar_water_heating": "N",
"habitable_room_count": 5,
"heating_cost_current": 365.98,
"insulated_door_count": 2,
"co2_emissions_current": 2.4,
"energy_rating_average": 60,
"energy_rating_current": 50,
"lighting_cost_current": 123.45,
"main_heating_controls": [
{"description": "Programmer, room thermostat and TRVs", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
{"description": "Time and temperature zone control", "energy_efficiency_rating": 5, "environmental_efficiency_rating": 5}
],
"multiple_glazing_type": 2,
"open_fireplaces_count": 0,
"heating_cost_potential": 250.34,
"hot_water_cost_current": 200.4,
"insulated_door_u_value": 3,
"mechanical_ventilation": 0,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": 360,
"indicative_cost": "£100 - £350",
"improvement_type": "Z3",
"improvement_details": {"improvement_number": 5},
"improvement_category": 6,
"energy_performance_rating": 50,
"environmental_impact_rating": 50
},
{
"sequence": 2,
"typical_saving": 99,
"indicative_cost": 2000,
"improvement_type": "Z2",
"improvement_details": {"improvement_number": 1},
"improvement_category": 2,
"energy_performance_rating": 60,
"environmental_impact_rating": 64
},
{
"sequence": 3,
"typical_saving": 99,
"indicative_cost": 1000,
"improvement_type": "Z2",
"improvement_details": {
"improvement_texts": {
"improvement_summary": "An improvement summary",
"improvement_description": "An improvement desc"
}
},
"improvement_category": 2,
"energy_performance_rating": 60,
"environmental_impact_rating": 64
}
],
"co2_emissions_potential": 1.4,
"energy_rating_potential": 72,
"lighting_cost_potential": 84.23,
"schema_version_original": "SAP-19.0",
"hot_water_cost_potential": 180.43,
"renewable_heat_incentive": {
"water_heating": 2285,
"impact_of_loft_insulation": -2114,
"impact_of_cavity_insulation": -122,
"impact_of_solid_wall_insulation": -3560,
"space_heating_existing_dwelling": 13120
},
"energy_consumption_current": 230,
"multiple_glazed_proportion": 100,
"calculation_software_version": "13.05r16",
"energy_consumption_potential": 88,
"environmental_impact_current": 52,
"fixed_lighting_outlets_count": 16,
"windows_transmission_details": {"u_value": 2, "data_source": 2, "solar_transmittance": 0.72},
"multiple_glazed_proportion_nr": "NR",
"current_energy_efficiency_band": "E",
"environmental_impact_potential": 74,
"potential_energy_efficiency_band": "C",
"co2_emissions_current_per_floor_area": 20,
"low_energy_fixed_lighting_outlets_count": 16
}

View file

@ -0,0 +1,245 @@
{
"uprn": 12457,
"roofs": [
{"description": "Pitched, 25 mm loft insulation", "energy_efficiency_rating": 2, "environmental_efficiency_rating": 2},
{"description": "Pitched, 250 mm loft insulation", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"walls": [
{"description": "Solid brick, as built, no insulation (assumed)", "energy_efficiency_rating": 1, "environmental_efficiency_rating": 1},
{"description": "Cavity wall, as built, insulated (assumed)", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"floors": [
{"description": "Suspended, no insulation (assumed)", "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0},
{"description": "Solid, insulated (assumed)", "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0}
],
"status": "entered",
"tenure": 1,
"window": {"description": "Fully double glazed", "energy_efficiency_rating": 3, "environmental_efficiency_rating": 3},
"addendum": {"stone_walls": "true", "system_build": "true", "addendum_numbers": [1, 8]},
"lighting": {"description": "Low energy lighting in 50% of fixed outlets", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
"postcode": "A0 0AA",
"hot_water": {"description": "From main system", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
"post_town": "Whitbury",
"built_form": 2,
"door_count": 3,
"region_code": 1,
"report_type": 2,
"sap_heating": {
"cylinder_size": 1,
"shower_outlets": {
"shower_outlet": {"shower_wwhrs": 1, "shower_outlet_type": 1}
},
"water_heating_code": 901,
"water_heating_fuel": 26,
"instantaneous_wwhrs": {"wwhrs_index_number1": 1, "wwhrs_index_number2": 2},
"secondary_fuel_type": 25,
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 26,
"boiler_flue_type": 2,
"fan_flue_present": "N",
"heat_emitter_type": 1,
"emitter_temperature": 0,
"main_heating_number": 1,
"boiler_ignition_type": 1,
"main_heating_control": 2106,
"main_heating_category": 2,
"main_heating_fraction": 1,
"sap_main_heating_code": 101,
"central_heating_pump_age": 0,
"main_heating_data_source": 1,
"main_heating_index_number": 17507
}
],
"immersion_heating_type": "NA",
"has_fixed_air_conditioning": "false"
},
"sap_version": 10.2,
"sap_windows": [
{
"pvc_frame": "false",
"glazing_gap": 6,
"orientation": 1,
"window_type": 2,
"frame_factor": 1.0,
"glazing_type": 14,
"window_width": 1.2,
"window_height": 2.0,
"draught_proofed": "true",
"window_location": 0,
"window_wall_type": 6,
"permanent_shutters_present": "N",
"window_transmission_details": {"u_value": 1.0, "data_source": 2, "solar_transmittance": 1.0},
"permanent_shutters_insulated": "N"
}
],
"schema_type": "RdSAP-Schema-21.0.0",
"uprn_source": "Energy Assessor",
"country_code": "ENG",
"main_heating": [
{"description": "Boiler and radiators, anthracite", "energy_efficiency_rating": 3, "environmental_efficiency_rating": 1},
{"description": "Boiler and radiators, mains gas", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"dwelling_type": "Mid-terrace house",
"language_code": 1,
"pressure_test": 6,
"property_type": 0,
"address_line_1": "1 Some Street",
"assessment_type": "RdSAP",
"completion_date": "2023-12-01",
"inspection_date": "2023-12-01",
"wet_rooms_count": 0,
"extensions_count": 0,
"measurement_type": 1,
"sap_flat_details": {
"level": 1,
"top_storey": "N",
"storey_count": 3,
"flat_location": 1,
"heat_loss_corridor": 2,
"unheated_corridor_length": 10
},
"total_floor_area": 55,
"transaction_type": 16,
"conservatory_type": 1,
"heated_room_count": 5,
"registration_date": "2023-12-01",
"sap_energy_source": {
"mains_gas": "Y",
"meter_type": 2,
"pv_batteries": {"pv_battery": {"battery_capacity": 5}},
"pv_connection": 0,
"pv_battery_count": 1,
"photovoltaic_supply": {"none_or_no_details": {"percent_roof_area": 0}},
"wind_turbines_count": 0,
"wind_turbine_details": {"hub_height": 0, "rotor_diameter": 0},
"gas_smart_meter_present": "false",
"is_dwelling_export_capable": "false",
"wind_turbines_terrain_type": 4,
"electricity_smart_meter_present": "true"
},
"secondary_heating": {"description": "Room heaters, electric", "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0},
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"floor_heat_loss": 7,
"sap_room_in_roof": {"floor_area": 100, "construction_age_band": "B"},
"roof_construction": 4,
"wall_construction": 4,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.45, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 45.82, "quantity": "square metres"},
"party_wall_length": {"value": 7.9, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 19.5, "quantity": "metres"}
}
],
"wall_insulation_type": 2,
"construction_age_band": "M",
"sap_alternative_wall_1": {
"wall_area": 10.4,
"wall_dry_lined": "N",
"wall_construction": 4,
"wall_insulation_type": 2,
"wall_thickness_measured": "N"
},
"sap_alternative_wall_2": {
"wall_area": 10.8,
"wall_dry_lined": "N",
"wall_construction": 4,
"wall_insulation_type": 2,
"wall_thickness_measured": "N"
},
"party_wall_construction": 0,
"wall_thickness_measured": "N",
"roof_insulation_location": 2,
"roof_insulation_thickness": "200mm",
"wall_insulation_thickness": "NI",
"floor_insulation_thickness": "NI"
}
],
"open_chimneys_count": 1,
"solar_water_heating": "N",
"habitable_room_count": 5,
"heating_cost_current": 365.98,
"insulated_door_count": 2,
"co2_emissions_current": 2.4,
"energy_rating_average": 60,
"energy_rating_current": 50,
"lighting_cost_current": 123.45,
"main_heating_controls": [
{"description": "Programmer, room thermostat and TRVs", "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
{"description": "Time and temperature zone control", "energy_efficiency_rating": 5, "environmental_efficiency_rating": 5}
],
"has_hot_water_cylinder": "true",
"heating_cost_potential": 250.34,
"hot_water_cost_current": 200.4,
"insulated_door_u_value": 3,
"mechanical_ventilation": 6,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": 360,
"indicative_cost": "£100 - £350",
"improvement_type": "Z3",
"improvement_details": {"improvement_number": 5},
"improvement_category": 6,
"energy_performance_rating": 50,
"environmental_impact_rating": 50
},
{
"sequence": 3,
"typical_saving": 99,
"indicative_cost": 1000,
"improvement_type": "Z2",
"improvement_details": {
"improvement_texts": {"improvement_description": "Improvement desc"}
},
"improvement_category": 2,
"energy_performance_rating": 60,
"environmental_impact_rating": 64
}
],
"co2_emissions_potential": 1.4,
"energy_rating_potential": 72,
"lighting_cost_potential": 84.23,
"schema_version_original": "SAP-19.0",
"hot_water_cost_potential": 180.43,
"renewable_heat_incentive": {
"water_heating": 2285,
"impact_of_loft_insulation": -2114,
"impact_of_cavity_insulation": -122,
"impact_of_solid_wall_insulation": -3560,
"space_heating_existing_dwelling": 13120
},
"draughtproofed_door_count": 1,
"mechanical_vent_duct_type": 3,
"energy_consumption_current": 230,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "13.05r16",
"energy_consumption_potential": 88,
"environmental_impact_current": 52,
"windows_transmission_details": {"u_value": 2, "data_source": 2, "solar_transmittance": 0.72},
"cfl_fixed_lighting_bulbs_count": 5,
"current_energy_efficiency_band": "E",
"environmental_impact_potential": 74,
"led_fixed_lighting_bulbs_count": 10,
"mechanical_vent_duct_placement": 2,
"mechanical_vent_duct_insulation": 2,
"potential_energy_efficiency_band": "C",
"pressure_test_certificate_number": 0,
"mechanical_ventilation_index_number": 12,
"co2_emissions_current_per_floor_area": 20,
"low_energy_fixed_lighting_bulbs_count": 16,
"mechanical_vent_duct_insulation_level": 2,
"mechanical_vent_measured_installation": "false",
"incandescent_fixed_lighting_bulbs_count": 5
}

View file

@ -0,0 +1,222 @@
{
"uprn": 12457,
"roofs": [
{"description": {"value": "Pitched, 25 mm loft insulation", "language": "1"}, "energy_efficiency_rating": 2, "environmental_efficiency_rating": 2},
{"description": {"value": "Pitched, 250 mm loft insulation", "language": "1"}, "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"walls": [
{"description": {"value": "Solid brick, as built, no insulation (assumed)", "language": "1"}, "energy_efficiency_rating": 1, "environmental_efficiency_rating": 1},
{"description": {"value": "Cavity wall, as built, insulated (assumed)", "language": "1"}, "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"floors": [
{"description": {"value": "Suspended, no insulation (assumed)", "language": "1"}, "energy_efficiency_rating": 0, "environmental_efficiency_rating": 0}
],
"status": "entered",
"tenure": 1,
"window": {"description": {"value": "Fully double glazed", "language": "1"}, "energy_efficiency_rating": 3, "environmental_efficiency_rating": 3},
"addendum": {"stone_walls": "true", "system_build": "true", "addendum_numbers": [1, 13]},
"lighting": {"description": {"value": "Low energy lighting in 50% of fixed outlets", "language": "1"}, "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
"postcode": "A0 0AA",
"hot_water": {"description": {"value": "From main system", "language": "1"}, "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
"post_town": "Whitbury",
"built_form": 2,
"door_count": 3,
"region_code": 1,
"report_type": 2,
"sap_heating": {
"cylinder_size": 1,
"shower_outlets": {"shower_outlet": {"shower_wwhrs": 1, "shower_outlet_type": 1}},
"water_heating_code": 901,
"water_heating_fuel": 26,
"instantaneous_wwhrs": {"wwhrs_index_number1": 1, "wwhrs_index_number2": 2},
"secondary_fuel_type": 25,
"main_heating_details": [
{
"has_fghrs": "N",
"main_fuel_type": 26,
"boiler_flue_type": 2,
"fan_flue_present": "N",
"heat_emitter_type": 1,
"emitter_temperature": 0,
"main_heating_number": 1,
"boiler_ignition_type": 1,
"main_heating_control": 2106,
"main_heating_category": 2,
"main_heating_fraction": 1,
"sap_main_heating_code": 101,
"central_heating_pump_age": 0,
"main_heating_data_source": 1,
"main_heating_index_number": 17507
}
],
"immersion_heating_type": "NA",
"has_fixed_air_conditioning": "false"
},
"sap_version": 10.2,
"sap_windows": [
{
"pvc_frame": "false",
"glazing_gap": 6,
"orientation": 1,
"window_type": 2,
"frame_factor": 1.0,
"glazing_type": 14,
"window_width": 1.2,
"window_height": 2.0,
"draught_proofed": "true",
"window_location": 0,
"window_wall_type": 6,
"permanent_shutters_present": "N",
"window_transmission_details": {"u_value": 1.0, "data_source": 2, "solar_transmittance": 1.0},
"permanent_shutters_insulated": "N"
}
],
"schema_type": "RdSAP-Schema-21.0.1",
"uprn_source": "Energy Assessor",
"country_code": "ENG",
"main_heating": [
{"description": {"value": "Boiler and radiators, anthracite", "language": "1"}, "energy_efficiency_rating": 3, "environmental_efficiency_rating": 1},
{"description": {"value": "Boiler and radiators, mains gas", "language": "1"}, "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4}
],
"dwelling_type": "Mid-terrace house",
"language_code": 1,
"pressure_test": 6,
"property_type": 0,
"address_line_1": "1 Some Street",
"assessment_type": "RdSAP",
"completion_date": "2025-04-04",
"inspection_date": "2025-04-04",
"wet_rooms_count": 0,
"extensions_count": 0,
"measurement_type": 1,
"sap_flat_details": {
"level": 1,
"top_storey": "N",
"storey_count": 3,
"flat_location": 1,
"heat_loss_corridor": 2,
"unheated_corridor_length": {"value": 10, "quantity": "metres"}
},
"total_floor_area": 55,
"transaction_type": 16,
"conservatory_type": 1,
"heated_room_count": 5,
"registration_date": "2025-04-04",
"sap_energy_source": {
"mains_gas": "Y",
"meter_type": 2,
"pv_batteries": {"pv_battery": {"battery_capacity": 5}},
"pv_connection": 0,
"pv_battery_count": 1,
"photovoltaic_supply": {"none_or_no_details": {"percent_roof_area": 0}},
"wind_turbines_count": 0,
"wind_turbine_details": {"hub_height": 0, "rotor_diameter": 0},
"gas_smart_meter_present": "false",
"is_dwelling_export_capable": "false",
"wind_turbines_terrain_type": 4,
"electricity_smart_meter_present": "true"
},
"secondary_heating": {
"description": {"value": "Room heaters, electric", "language": "1"},
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"sap_building_parts": [
{
"identifier": "Main Dwelling",
"wall_dry_lined": "N",
"floor_heat_loss": 7,
"sap_room_in_roof": {"floor_area": 100, "construction_age_band": "B"},
"roof_construction": 4,
"wall_construction": 4,
"building_part_number": 1,
"sap_floor_dimensions": [
{
"floor": 0,
"room_height": {"value": 2.45, "quantity": "metres"},
"floor_insulation": 1,
"total_floor_area": {"value": 45.82, "quantity": "square metres"},
"party_wall_length": {"value": 7.9, "quantity": "metres"},
"floor_construction": 1,
"heat_loss_perimeter": {"value": 19.5, "quantity": "metres"}
}
],
"wall_insulation_type": 2,
"construction_age_band": "M",
"sap_alternative_wall_1": {"wall_area": 10.4, "wall_dry_lined": "N", "wall_construction": 4, "wall_insulation_type": 2, "wall_thickness_measured": "N"},
"sap_alternative_wall_2": {"wall_area": 10.8, "wall_dry_lined": "N", "wall_construction": 4, "wall_insulation_type": 2, "wall_thickness_measured": "N"},
"party_wall_construction": 0,
"wall_thickness_measured": "N",
"roof_insulation_location": 2,
"roof_insulation_thickness": "200mm",
"wall_insulation_thickness": "NI",
"floor_insulation_thickness": "NI"
}
],
"open_chimneys_count": 1,
"solar_water_heating": "N",
"habitable_room_count": 5,
"heating_cost_current": 365.98,
"insulated_door_count": 2,
"co2_emissions_current": 2.4,
"energy_rating_average": 60,
"energy_rating_current": 50,
"lighting_cost_current": 123.45,
"main_heating_controls": [
{"description": {"value": "Programmer, room thermostat and TRVs", "language": "1"}, "energy_efficiency_rating": 4, "environmental_efficiency_rating": 4},
{"description": {"value": "Time and temperature zone control", "language": "1"}, "energy_efficiency_rating": 5, "environmental_efficiency_rating": 5}
],
"has_hot_water_cylinder": "true",
"heating_cost_potential": 250.34,
"hot_water_cost_current": 200.4,
"insulated_door_u_value": 3,
"mechanical_ventilation": 6,
"percent_draughtproofed": 100,
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": 139,
"indicative_cost": "£220 - £250",
"improvement_type": "G",
"improvement_details": {"improvement_number": 66},
"improvement_category": 5,
"energy_performance_rating": 70,
"environmental_impact_rating": 70
}
],
"co2_emissions_potential": 1.4,
"energy_rating_potential": 72,
"lighting_cost_potential": 84.23,
"schema_version_original": "SAP-19.0",
"hot_water_cost_potential": 180.43,
"renewable_heat_incentive": {
"water_heating": 2285,
"impact_of_loft_insulation": -2114,
"impact_of_cavity_insulation": -122,
"impact_of_solid_wall_insulation": -3560,
"space_heating_existing_dwelling": 13120
},
"draughtproofed_door_count": 1,
"mechanical_vent_duct_type": 3,
"energy_consumption_current": 230,
"has_fixed_air_conditioning": "false",
"multiple_glazed_proportion": 100,
"calculation_software_version": "13.05r16",
"energy_consumption_potential": 88,
"environmental_impact_current": 52,
"windows_transmission_details": {"u_value": 2, "data_source": 2, "solar_transmittance": 0.72},
"cfl_fixed_lighting_bulbs_count": 5,
"current_energy_efficiency_band": "E",
"environmental_impact_potential": 74,
"led_fixed_lighting_bulbs_count": 10,
"mechanical_vent_duct_placement": 2,
"mechanical_vent_duct_insulation": 2,
"potential_energy_efficiency_band": "C",
"pressure_test_certificate_number": 0,
"mechanical_ventilation_index_number": 12,
"co2_emissions_current_per_floor_area": 20,
"low_energy_fixed_lighting_bulbs_count": 16,
"mechanical_vent_duct_insulation_level": 2,
"mechanical_vent_measured_installation": "false",
"incandescent_fixed_lighting_bulbs_count": 0
}

View file

@ -0,0 +1,73 @@
import dataclasses
import typing
from typing import Any, Dict, Type, TypeVar
T = TypeVar("T")
def from_dict(cls: Type[T], data: Dict[str, Any]) -> T:
"""
Recursively convert a plain dict (e.g. from json.loads) into the given
dataclass type, using the field type hints to convert nested structures.
Handles:
- Nested dataclasses
- List[SomeDataclass]
- Optional[X] / Union[X, None]
- Union[DataclassType, primitive] (e.g. Union[Measurement, int])
- Primitive pass-through for Union[str, int] etc.
"""
return _from_dict_impl(cls, data) # type: ignore[return-value]
def _from_dict_impl(cls: Any, data: Any) -> Any:
hints = typing.get_type_hints(cls)
kwargs: Dict[str, Any] = {}
for field in dataclasses.fields(cls): # type: ignore[arg-type]
has_default = (
field.default is not dataclasses.MISSING
or field.default_factory is not dataclasses.MISSING # type: ignore[misc]
)
if field.name not in data:
if has_default:
continue
raise ValueError(f"{cls.__name__}: missing required field '{field.name}'")
kwargs[field.name] = _coerce(data[field.name], hints[field.name])
return cls(**kwargs)
def _coerce(value: Any, hint: Any) -> Any:
if value is None:
return None
origin = typing.get_origin(hint)
args = typing.get_args(hint)
# Union (includes Optional[X] which is Union[X, None])
if origin is typing.Union:
if value is None:
return None
non_none_args = [a for a in args if a is not type(None)]
if len(non_none_args) == 1:
# Optional[X] — recurse so List[X] and nested dataclasses are handled
return _coerce(value, non_none_args[0])
# Multi-type Union (e.g. Union[Measurement, int]): try dataclasses first
for arg in non_none_args:
if dataclasses.is_dataclass(arg) and isinstance(value, dict):
return _from_dict_impl(arg, value)
# All remaining args are primitives — return value as-is
return value
# List[X]
if origin is list:
item_hint = args[0]
return [_coerce(item, item_hint) for item in value]
# Plain dataclass
if dataclasses.is_dataclass(hint) and isinstance(value, dict):
return _from_dict_impl(hint, value)
return value

View file

@ -0,0 +1,380 @@
import json
import os
from typing import Any, Dict
import pytest
from datatypes.epc.schema import (
RdSapSchema17_0,
RdSapSchema17_1,
RdSapSchema18_0,
RdSapSchema19_0,
RdSapSchema20_0_0,
RdSapSchema21_0_0,
RdSapSchema21_0_1,
)
from datatypes.epc.schema.common import CostAmount, DescriptionV1, Measurement
from datatypes.epc.schema.tests.helpers import from_dict
FIXTURES = os.path.join(os.path.dirname(__file__), "fixtures")
def load(filename: str) -> Dict[str, Any]:
with open(os.path.join(FIXTURES, filename)) as f:
return json.load(f) # type: ignore[no-any-return]
class TestRdSapSchema17_0:
@pytest.fixture
def epc(self) -> RdSapSchema17_0:
return from_dict(RdSapSchema17_0, load("17_0.json"))
def test_schema_type(self, epc: RdSapSchema17_0) -> None:
assert epc.schema_type == "RdSAP-Schema-17.0"
def test_uprn(self, epc: RdSapSchema17_0) -> None:
assert epc.uprn == 12457
def test_description_is_localised_object(self, epc: RdSapSchema17_0) -> None:
assert isinstance(epc.roofs[0].description, DescriptionV1)
assert epc.roofs[0].description.value == "(another dwelling above)"
assert epc.roofs[0].description.language == "1"
def test_dwelling_type_is_localised_object(self, epc: RdSapSchema17_0) -> None:
assert isinstance(epc.dwelling_type, DescriptionV1)
assert epc.dwelling_type.value == "Mid-floor flat"
def test_costs_are_cost_amount_objects(self, epc: RdSapSchema17_0) -> None:
assert isinstance(epc.heating_cost_current, CostAmount)
assert epc.heating_cost_current.value == 214
assert epc.heating_cost_current.currency == "GBP"
def test_suggested_improvement_saving_is_cost_amount(self, epc: RdSapSchema17_0) -> None:
assert isinstance(epc.suggested_improvements[0].typical_saving, CostAmount)
assert epc.suggested_improvements[0].typical_saving.value == 158
def test_flat_details_populated(self, epc: RdSapSchema17_0) -> None:
assert epc.sap_flat_details is not None
assert epc.sap_flat_details.level == 2
def test_floor_dimensions_use_measurement(self, epc: RdSapSchema17_0) -> None:
dim = epc.sap_building_parts[0].sap_floor_dimensions[0]
assert isinstance(dim.room_height, Measurement)
assert dim.room_height.value == 2.4
assert dim.room_height.quantity == "metres"
def test_alternative_improvements_present(self, epc: RdSapSchema17_0) -> None:
assert epc.alternative_improvements is not None
assert len(epc.alternative_improvements) == 1
assert epc.alternative_improvements[0].improvement_type == "J2"
def test_renewable_heat_incentive(self, epc: RdSapSchema17_0) -> None:
assert epc.renewable_heat_incentive.water_heating == 4818
assert epc.renewable_heat_incentive.space_heating_existing_dwelling == 2415
assert epc.renewable_heat_incentive.impact_of_loft_insulation is None
def test_glazing_gap_is_string(self, epc: RdSapSchema17_0) -> None:
assert epc.glazing_gap == "16+"
def test_lzc_energy_sources(self, epc: RdSapSchema17_0) -> None:
assert epc.lzc_energy_sources == [11]
class TestRdSapSchema17_1:
@pytest.fixture
def epc(self) -> RdSapSchema17_1:
return from_dict(RdSapSchema17_1, load("17_1.json"))
def test_schema_type(self, epc: RdSapSchema17_1) -> None:
assert epc.schema_type == "RdSAP-Schema-17.1"
def test_description_is_localised_object(self, epc: RdSapSchema17_1) -> None:
assert isinstance(epc.roofs[0].description, DescriptionV1)
assert epc.roofs[0].description.value == "Pitched, 100 mm loft insulation"
def test_address_line_2(self, epc: RdSapSchema17_1) -> None:
assert epc.address_line_2 == "Lower Moria"
def test_cylinder_thermostat(self, epc: RdSapSchema17_1) -> None:
assert epc.sap_heating.cylinder_thermostat == "Y"
def test_cylinder_insulation_thickness(self, epc: RdSapSchema17_1) -> None:
assert epc.sap_heating.cylinder_insulation_thickness == 12
def test_boiler_flue_type_in_heating_detail(self, epc: RdSapSchema17_1) -> None:
detail = epc.sap_heating.main_heating_details[0]
assert detail.boiler_flue_type == 1
assert detail.main_heating_index_number == 9049
def test_extension_party_wall_length_is_int(self, epc: RdSapSchema17_1) -> None:
# Extension floor dimension has party_wall_length as a plain int (0)
extension = epc.sap_building_parts[1]
assert extension.identifier == "Extension 1"
dim = extension.sap_floor_dimensions[0]
assert dim.party_wall_length == 0
def test_extension_roof_insulation_thickness_is_int(self, epc: RdSapSchema17_1) -> None:
extension = epc.sap_building_parts[1]
assert extension.roof_insulation_thickness == 0
def test_renewable_heat_incentive_has_loft_impact(self, epc: RdSapSchema17_1) -> None:
assert epc.renewable_heat_incentive.impact_of_loft_insulation == -565
def test_multiple_roofs(self, epc: RdSapSchema17_1) -> None:
assert len(epc.roofs) == 2
class TestRdSapSchema18_0:
@pytest.fixture
def epc(self) -> RdSapSchema18_0:
return from_dict(RdSapSchema18_0, load("18_0.json"))
def test_schema_type(self, epc: RdSapSchema18_0) -> None:
assert epc.schema_type == "RdSAP-Schema-18.0"
def test_glazing_gap_is_integer(self, epc: RdSapSchema18_0) -> None:
assert epc.glazing_gap == 12
assert isinstance(epc.glazing_gap, int)
def test_room_in_roof_present(self, epc: RdSapSchema18_0) -> None:
main = epc.sap_building_parts[0]
assert main.sap_room_in_roof is not None
assert main.sap_room_in_roof.insulation == "AB"
assert main.sap_room_in_roof.construction_age_band == "G"
def test_room_in_roof_floor_area_is_measurement(self, epc: RdSapSchema18_0) -> None:
room_in_roof = epc.sap_building_parts[0].sap_room_in_roof
assert room_in_roof is not None
assert isinstance(room_in_roof.floor_area, Measurement)
assert room_in_roof.floor_area.value == 9.0
assert room_in_roof.floor_area.quantity == "square metres"
def test_flat_roof_insulation_on_extension(self, epc: RdSapSchema18_0) -> None:
extension = epc.sap_building_parts[1]
assert extension.flat_roof_insulation_thickness == "NI"
def test_description_is_localised_object(self, epc: RdSapSchema18_0) -> None:
assert isinstance(epc.walls[0].description, DescriptionV1)
def test_three_roofs(self, epc: RdSapSchema18_0) -> None:
assert len(epc.roofs) == 3
def test_renewable_heat_incentive_has_solid_wall_impact(self, epc: RdSapSchema18_0) -> None:
assert epc.renewable_heat_incentive.impact_of_solid_wall_insulation == -1864
class TestRdSapSchema19_0:
@pytest.fixture
def epc(self) -> RdSapSchema19_0:
return from_dict(RdSapSchema19_0, load("19_0.json"))
def test_schema_type(self, epc: RdSapSchema19_0) -> None:
assert epc.schema_type == "RdSAP-Schema-19.0"
def test_windows_transmission_details(self, epc: RdSapSchema19_0) -> None:
wtd = epc.windows_transmission_details
assert wtd.u_value == 3.1
assert wtd.data_source == 2
assert wtd.solar_transmittance == 0.76
def test_description_is_localised_object(self, epc: RdSapSchema19_0) -> None:
assert isinstance(epc.roofs[0].description, DescriptionV1)
assert epc.roofs[0].description.value == "Pitched, 150 mm loft insulation"
def test_glazing_gap_absent(self, epc: RdSapSchema19_0) -> None:
assert epc.glazing_gap is None
def test_secondary_heating_type(self, epc: RdSapSchema19_0) -> None:
assert epc.sap_heating.secondary_heating_type == 631
def test_multiple_lzc_sources(self, epc: RdSapSchema19_0) -> None:
assert epc.lzc_energy_sources == [11, 9]
def test_floor_insulation_thickness_on_building_part(self, epc: RdSapSchema19_0) -> None:
assert epc.sap_building_parts[0].floor_insulation_thickness == "NI"
class TestRdSapSchema20_0_0:
@pytest.fixture
def epc(self) -> RdSapSchema20_0_0:
return from_dict(RdSapSchema20_0_0, load("20_0_0.json"))
def test_schema_type(self, epc: RdSapSchema20_0_0) -> None:
assert epc.schema_type == "RdSAP-Schema-20.0.0"
def test_description_is_plain_string(self, epc: RdSapSchema20_0_0) -> None:
assert isinstance(epc.roofs[0].description, str)
assert epc.roofs[0].description == "Pitched, 25 mm loft insulation"
def test_dwelling_type_is_plain_string(self, epc: RdSapSchema20_0_0) -> None:
assert isinstance(epc.dwelling_type, str)
assert epc.dwelling_type == "Mid-terrace house"
def test_costs_are_floats(self, epc: RdSapSchema20_0_0) -> None:
assert isinstance(epc.heating_cost_current, float)
assert epc.heating_cost_current == pytest.approx(365.98)
def test_suggested_improvement_saving_is_numeric(self, epc: RdSapSchema20_0_0) -> None:
assert epc.suggested_improvements[0].typical_saving == 360
def test_indicative_cost_can_be_int(self, epc: RdSapSchema20_0_0) -> None:
# Second improvement has indicative_cost as a plain integer
assert epc.suggested_improvements[1].indicative_cost == 2000
def test_improvement_details_with_texts(self, epc: RdSapSchema20_0_0) -> None:
# Third improvement uses improvement_texts instead of improvement_number
third = epc.suggested_improvements[2]
assert third.improvement_details.improvement_number is None
assert third.improvement_details.improvement_texts is not None
assert third.improvement_details.improvement_texts.improvement_summary == "An improvement summary"
def test_sap_windows_present(self, epc: RdSapSchema20_0_0) -> None:
assert len(epc.sap_windows) == 2
assert epc.sap_windows[0].window_area == pytest.approx(200.1)
assert epc.sap_windows[0].glazing_type == 1
def test_addendum(self, epc: RdSapSchema20_0_0) -> None:
assert epc.addendum is not None
assert epc.addendum.stone_walls == "true"
assert epc.addendum.addendum_numbers == [1, 8]
def test_flat_details_has_storey_count(self, epc: RdSapSchema20_0_0) -> None:
assert epc.sap_flat_details is not None
assert epc.sap_flat_details.storey_count == 3
assert epc.sap_flat_details.unheated_corridor_length == 10
def test_room_in_roof_floor_area_is_plain_number(self, epc: RdSapSchema20_0_0) -> None:
room_in_roof = epc.sap_building_parts[0].sap_room_in_roof
assert room_in_roof is not None
assert room_in_roof.floor_area == 100
assert not isinstance(room_in_roof.floor_area, Measurement)
def test_renewable_heat_incentive_has_cavity_impact(self, epc: RdSapSchema20_0_0) -> None:
assert epc.renewable_heat_incentive.impact_of_cavity_insulation == -122
def test_multiple_glazed_proportion_nr(self, epc: RdSapSchema20_0_0) -> None:
assert epc.multiple_glazed_proportion_nr == "NR"
class TestRdSapSchema21_0_0:
@pytest.fixture
def epc(self) -> RdSapSchema21_0_0:
return from_dict(RdSapSchema21_0_0, load("21_0_0.json"))
def test_schema_type(self, epc: RdSapSchema21_0_0) -> None:
assert epc.schema_type == "RdSAP-Schema-21.0.0"
def test_description_is_plain_string(self, epc: RdSapSchema21_0_0) -> None:
assert isinstance(epc.roofs[0].description, str)
def test_pressure_test(self, epc: RdSapSchema21_0_0) -> None:
assert epc.pressure_test == 6
def test_wet_rooms_count(self, epc: RdSapSchema21_0_0) -> None:
assert epc.wet_rooms_count == 0
def test_instantaneous_wwhrs_uses_index_numbers(self, epc: RdSapSchema21_0_0) -> None:
wwhrs = epc.sap_heating.instantaneous_wwhrs
assert wwhrs.wwhrs_index_number1 == 1
assert wwhrs.wwhrs_index_number2 == 2
def test_shower_outlets(self, epc: RdSapSchema21_0_0) -> None:
outlets = epc.sap_heating.shower_outlets
assert outlets is not None
assert outlets.shower_outlet.shower_wwhrs == 1
assert outlets.shower_outlet.shower_outlet_type == 1
def test_boiler_ignition_type(self, epc: RdSapSchema21_0_0) -> None:
assert epc.sap_heating.main_heating_details[0].boiler_ignition_type == 1
def test_smart_meters(self, epc: RdSapSchema21_0_0) -> None:
src = epc.sap_energy_source
assert src.electricity_smart_meter_present == "true"
assert src.gas_smart_meter_present == "false"
def test_pv_batteries(self, epc: RdSapSchema21_0_0) -> None:
assert epc.sap_energy_source.pv_batteries is not None
assert epc.sap_energy_source.pv_batteries.pv_battery.battery_capacity == 5
def test_alternative_walls(self, epc: RdSapSchema21_0_0) -> None:
part = epc.sap_building_parts[0]
assert part.sap_alternative_wall_1 is not None
assert part.sap_alternative_wall_1.wall_area == pytest.approx(10.4)
assert part.sap_alternative_wall_2 is not None
assert part.sap_alternative_wall_2.wall_area == pytest.approx(10.8)
def test_detailed_sap_windows(self, epc: RdSapSchema21_0_0) -> None:
win = epc.sap_windows[0]
assert win.glazing_gap == 6
assert win.window_width == pytest.approx(1.2)
assert win.window_transmission_details.u_value == pytest.approx(1.0)
def test_mechanical_vent_fields(self, epc: RdSapSchema21_0_0) -> None:
assert epc.mechanical_vent_duct_type == 3
assert epc.mechanical_ventilation_index_number == 12
def test_lighting_bulb_counts(self, epc: RdSapSchema21_0_0) -> None:
assert epc.led_fixed_lighting_bulbs_count == 10
assert epc.cfl_fixed_lighting_bulbs_count == 5
assert epc.incandescent_fixed_lighting_bulbs_count == 5
def test_open_chimneys_count(self, epc: RdSapSchema21_0_0) -> None:
assert epc.open_chimneys_count == 1
def test_room_in_roof_has_no_insulation_field(self, epc: RdSapSchema21_0_0) -> None:
room_in_roof = epc.sap_building_parts[0].sap_room_in_roof
assert room_in_roof is not None
assert room_in_roof.construction_age_band == "B"
assert not hasattr(room_in_roof, "insulation")
class TestRdSapSchema21_0_1:
@pytest.fixture
def epc(self) -> RdSapSchema21_0_1:
return from_dict(RdSapSchema21_0_1, load("21_0_1.json"))
def test_schema_type(self, epc: RdSapSchema21_0_1) -> None:
assert epc.schema_type == "RdSAP-Schema-21.0.1"
def test_description_reverts_to_localised_object(self, epc: RdSapSchema21_0_1) -> None:
# Descriptions on energy elements revert to DescriptionV1 in 21.0.1
assert isinstance(epc.roofs[0].description, DescriptionV1)
assert epc.roofs[0].description.value == "Pitched, 25 mm loft insulation"
def test_main_heating_description_is_localised_object(self, epc: RdSapSchema21_0_1) -> None:
assert isinstance(epc.main_heating[0].description, DescriptionV1)
assert epc.main_heating[0].description.value == "Boiler and radiators, anthracite"
def test_dwelling_type_remains_plain_string(self, epc: RdSapSchema21_0_1) -> None:
# dwelling_type does NOT revert — stays as plain str in 21.0.1
assert isinstance(epc.dwelling_type, str)
assert epc.dwelling_type == "Mid-terrace house"
def test_unheated_corridor_length_is_measurement(self, epc: RdSapSchema21_0_1) -> None:
# Changed from plain int (21.0.0) to Measurement object in 21.0.1
assert epc.sap_flat_details is not None
corridor_length = epc.sap_flat_details.unheated_corridor_length
assert isinstance(corridor_length, Measurement)
assert corridor_length.value == 10
assert corridor_length.quantity == "metres"
def test_completion_date(self, epc: RdSapSchema21_0_1) -> None:
assert epc.completion_date == "2025-04-04"
def test_addendum_numbers(self, epc: RdSapSchema21_0_1) -> None:
assert epc.addendum is not None
assert epc.addendum.addendum_numbers == [1, 13]
def test_pv_battery_capacity(self, epc: RdSapSchema21_0_1) -> None:
assert epc.sap_energy_source.pv_batteries is not None
assert epc.sap_energy_source.pv_batteries.pv_battery.battery_capacity == 5
def test_incandescent_bulb_count(self, epc: RdSapSchema21_0_1) -> None:
assert epc.incandescent_fixed_lighting_bulbs_count == 0

View file

@ -3,6 +3,6 @@ pythonpath = .
log_cli = true
log_cli_level = INFO
addopts = --cov-report term-missing --cov=etl/epc --cov=recommendations --cov=backend --cov=etl/epc_clean --cov=etl/spatial
testpaths = recommendations/tests backend/tests etl/epc/tests etl/epc_clean/tests etl/spatial/tests backend/condition/tests backend/address2UPRN/tests backend/onboarders/tests backend/categorisation/tests backend/export/tests etl/hubspot/tests backend/hubspot_trigger_orchestrator/tests
testpaths = recommendations/tests backend/tests etl/epc/tests etl/epc_clean/tests etl/spatial/tests backend/condition/tests backend/address2UPRN/tests backend/onboarders/tests backend/categorisation/tests backend/export/tests etl/hubspot/tests backend/hubspot_trigger_orchestrator/tests datatypes/epc/schema/tests
markers =
integration: mark a test as an integration test