Resolve PasHub main-heating control label to its SAP Table 4e code 🟩

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Daniel Roth 2026-07-14 16:01:04 +00:00
parent fc53594c99
commit 59215c822e

View file

@ -6031,7 +6031,7 @@ def _map_sap_heating(
heat_emitter_type=main.emitter,
emitter_temperature=main.emitter_temperature,
fan_flue_present=main.fan_assist,
main_heating_control=main.controls,
main_heating_control=_pashub_main_heating_control_code(main.controls),
condensing=main.condensing,
weather_compensator=main.weather_compensator,
central_heating_pump_age_str=main.central_heating_pump_age,
@ -7081,6 +7081,33 @@ def _pashub_main_fuel_code(fuel_label: str) -> Union[int, str]:
return code
# PasHub Site-Notes surveyed main-heating "Controls" labels mapped to their
# SAP 10.2 Table 4e (PDF p.171) code, which the calculator's `_control_type`
# keys off. Copying the raw label onto `main_heating_control` strict-raises
# `UnmappedSapCode` deep in the calculator; resolving it here at the boundary
# (ADR-0015) hands the cascade the int it expects. Seeded with the boiler
# (Group 1) control labels confirmed in the live cohort — all standard
# time-and-temperature single-zone controls that resolve to control type 2.
_PASHUB_MAIN_HEATING_CONTROL_TO_SAP10: Dict[str, int] = {
"Programmer, room thermostat and TRVs": 2106,
}
def _pashub_main_heating_control_code(control_label: str) -> Union[int, str]:
"""Resolve a PasHub surveyed main-heating Controls label to its SAP 10.2
Table 4e code at the mapper boundary (ADR-0015). A genuinely blank label is
the "no controls lodged" shape and passes through unchanged; a non-empty
label the lookup does not cover strict-raises `UnmappedPasHubLabel` so the
gap is fixed here, never strict-raised deep in the calculator as
`UnmappedSapCode`."""
if not control_label:
return control_label
code = _PASHUB_MAIN_HEATING_CONTROL_TO_SAP10.get(control_label)
if code is None:
raise UnmappedPasHubLabel("main heating control", control_label)
return code
def _resolve_elmhurst_underfloor_subtype(
main_floor: ElmhurstFloorDetails,
main_age_band: str,