Checkpoint: UPRN 10093116543 Elmhurst build + devcontainer VNC/Playwright + perms

- Add SAP-accuracy sample for uprn_10093116543 (epc.json, elmhurst_inputs.md,
  summary/worksheet PDFs)
- Persist hyde viewer stack (xvfb/fluxbox/x11vnc/novnc/websockify) and Playwright
  chromium in the backend devcontainer; forward noVNC 6080
- Broaden .claude/settings.local.json allowlist (display/python/grep/tail)
- In-progress campaign mapper/cert_to_inputs work carried from prior cert

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jun-te Kim 2026-06-16 15:21:28 +00:00
parent dad3044740
commit 2f0eb49eee
46 changed files with 10256 additions and 26 deletions

168
.claude/settings.json Normal file
View file

@ -0,0 +1,168 @@
{
"permissions": {
"allow": [
"Bash(python -c ' *)",
"Bash(python -m pytest tests/ -v --no-cov)",
"Bash(git -C /workspaces/model diff --stat)",
"Bash(python -c \"import moto; print\\('moto installed:', moto.__version__\\)\")",
"Bash(grep -E \"\\\\.\\(py|sql\\)$\")",
"Bash(xargs basename -a)",
"Bash(ls -la /workspaces/home 2>/dev/null | head -20)",
"Read(//workspaces/home/**)",
"Bash(command -v uv)",
"Bash(uv --version)",
"Bash(echo \"uv: $\\(uv --version\\)\")",
"Bash(python -m pyright --version)",
"Bash(npx --no-install pyright --version)",
"Bash(node /home/vscode/.npm/_npx/110e52990071af13/node_modules/pyright/dist/pyright.js --outputjson etl/hubspot/hubspotClient.py etl/hubspot/hubspotDataTodB.py etl/hubspot/project_data.py etl/hubspot/scripts/scraper/main.py backend/app/db/models/hubspot_project_data.py backend/app/db/models/hubspot_deal_data.py etl/hubspot/tests/test_scraper_handler.py etl/hubspot/tests/test_hubspot_data_to_db.py etl/hubspot/tests/test_hubspot_client_integration.py)",
"Bash(python -c \"import sys,json; d=json.load\\(sys.stdin\\); s=d['summary']; print\\('errors',s['errorCount'],'warnings',s['warningCount']\\); [print\\(f\\\\\"{x['severity']}: {x['file'].split\\('/'\\)[-1]}:{x['range']['start']['line']+1} {x['rule'] if 'rule' in x else ''} -- {x['message'].splitlines\\(\\)[0]}\\\\\"\\) for x in d['generalDiagnostics'] if x['severity']=='error']\")",
"Bash(node /home/vscode/.npm/_npx/110e52990071af13/node_modules/pyright/dist/pyright.js etl/hubspot/project_data.py backend/app/db/models/hubspot_project_data.py)",
"Bash(python -c \"import sqlmodel, sqlalchemy, hubspot; print\\('deps importable'\\)\")",
"Bash(python -m pytest --version)",
"Bash(python -m pytest etl/hubspot/tests/ -m \"not integration\" -p no:cacheprovider -o addopts=\"\" -q)",
"Bash(node /home/vscode/.npm/_npx/110e52990071af13/node_modules/pyright/dist/pyright.js --pythonpath /usr/local/bin/python etl/hubspot/project_data.py backend/app/db/models/hubspot_project_data.py)",
"Bash(node /home/vscode/.npm/_npx/110e52990071af13/node_modules/pyright/dist/pyright.js --pythonpath /usr/local/bin/python etl/hubspot/company_data.py)",
"Bash(python /tmp/inspect_project.py)",
"Read(//home/vscode/github/**)",
"Bash(find / -maxdepth 6 -type d -name assessment-model)",
"Bash(terraform fmt *)",
"Bash(terraform init *)",
"Bash(terraform validate *)",
"Bash(python -m pytest tests/orchestration/test_landlord_description_overrides_orchestrator.py -q)",
"Bash(python -m pytest tests/orchestration/test_landlord_description_overrides_orchestrator.py tests/repositories/landlord_overrides -q --no-cov)",
"Bash(python -m py_compile tests/infrastructure/chatgpt/test_chatgpt_column_classifier.py)",
"Bash(git add *)",
"Bash(git status *)",
"Bash(cp pyrightconfig.json /tmp/pyrightconfig.bak.json)",
"Bash(python3 -)",
"Bash(npx --yes pyright infrastructure/postgres/landlord_overrides_postgres_repository.py applications/landlord_description_overrides/handler.py tests/repositories/landlord_overrides/postgres/test_landlord_overrides_postgres_repository.py orchestration/classifiable_column.py)",
"Bash(git stash *)",
"Bash(npx --yes pyright applications/landlord_description_overrides/handler.py)",
"Bash(python3 -m pytest tests/repositories/landlord_overrides/postgres/test_landlord_overrides_postgres_repository.py -q)",
"Bash(python3 -m pytest tests/orchestration/test_landlord_description_overrides_orchestrator.py tests/repositories/landlord_overrides/ -q -p no:cov)",
"Bash(python3 -m pytest tests/orchestration/test_landlord_description_overrides_orchestrator.py tests/repositories/landlord_overrides/ -q)",
"Bash(cp pyrightconfig.json /tmp/pyrightconfig.bak2.json)",
"Bash(npx --yes pyright infrastructure/landlord_overrides/landlord_overrides_postgres_repository.py tests/repositories/landlord_overrides/postgres/test_landlord_overrides_postgres_repository.py)",
"Bash(GIT_EDITOR=true git rebase --continue)",
"Bash(git worktree *)",
"Bash(git branch *)",
"Bash(echo \"exit: $?\")",
"Bash(git reset *)",
"Bash(echo \"fetch-exit: $?\")",
"Bash(sed -n *)",
"Bash(set -e)",
"Bash(git rm *)",
"Bash(git ls-tree *)",
"Bash(command -v pyright)",
"Bash(git merge *)",
"Bash(git rev-list *)",
"Bash(git remote *)",
"Bash(git ls-remote *)",
"Bash(grep -v '\\\\.sample$')",
"Bash([ -f \".git/hooks/$h\" ])",
"Bash(python3 -m pytest tests/test_lambda_packaging.py -p no:cacheprovider --no-header -q)",
"Bash(python3 -m pytest tests/test_lambda_packaging.py -p no:cov --no-header -q)",
"Bash(python3 -m pytest tests/test_lambda_packaging.py --no-cov -p no:cacheprovider -q)",
"Bash(python3 -m pytest tests/test_lambda_packaging.py --no-cov -q)",
"Bash(python3 -m pyright tests/test_lambda_packaging.py)",
"Bash(python3 -m pytest tests/ --collect-only --no-cov -q)",
"Bash(python3 -c \"import yaml; [print\\(f, 'OK'\\) for f in ['.github/workflows/ddd_tests.yml','.github/workflows/unit_tests.yml'] if yaml.safe_load\\(open\\(f\\)\\)]\")",
"Bash(python3 -m pytest tests/ -q --no-cov)",
"Bash(python3 -c ' *)",
"Bash(python3 -m pyright --outputjson scripts/hyde/main.py)",
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); s=d['summary']; print\\('errors:',s['errorCount'],'warnings:',s['warningCount']\\); [print\\(f\\\\\" L{e['range']['start']['line']+1}: {e['message'].splitlines\\(\\)[0]}\\\\\"\\) for e in d['generalDiagnostics'] if e['severity']=='error']\")",
"Bash(python3 -c \"import json,sys; d=json.load\\(sys.stdin\\); s=d['summary']; print\\('pyright errors:',s['errorCount'],'warnings:',s['warningCount']\\); [print\\(f\\\\\" L{e['range']['start']['line']+1}: {e['message'].splitlines\\(\\)[0]}\\\\\"\\) for e in d['generalDiagnostics'] if e['severity']=='error']\")",
"Bash(python3 main.py)",
"Bash(netstat -ltnp)",
"Bash(fuser 8000/tcp)",
"Bash(kill 351610 685390 351625)",
"Read(//proc/531213/net/**)",
"Bash(ps -p 351610 -o pid=)",
"Bash(python -)",
"Bash(python -m pytest \"datatypes/epc/domain/tests/test_from_rdsap_schema.py::TestRdSap20_0_0ReducedFieldSynthesis::test_cert_omitting_sap_windows_maps_without_missing_required_field\")",
"Bash(python -m pytest datatypes/epc/domain/tests/test_from_rdsap_schema.py infrastructure/epc_client/tests/test_mapper_corpus.py)",
"Bash(git -C /workspaces/model stash push -u -- datatypes/epc/schema/rdsap_schema_20_0_0.py datatypes/epc/domain/mapper.py datatypes/epc/domain/tests/test_from_rdsap_schema.py)",
"Bash(python -m pytest \"datatypes/epc/domain/tests/test_from_rdsap_schema.py::TestFromRdSapSchema21_0_1::test_total_floor_area\")",
"Bash(git -C /workspaces/model stash pop)",
"Bash(python -m pytest \"datatypes/epc/domain/tests/test_from_rdsap_schema.py::TestRdSap20_0_0ReducedFieldSynthesis::test_band_more_than_typical_scales_glazing_by_1_25\")",
"Bash(python -m pytest \"datatypes/epc/domain/tests/test_from_rdsap_schema.py::TestRdSap20_0_0ReducedFieldSynthesis\")",
"Bash(python -m pytest \"datatypes/epc/domain/tests/test_from_rdsap_schema.py::TestRdSap20_0_0ReducedFieldSynthesis::test_synthesised_glazing_type_routed_through_cascade\")",
"Bash(python -m pytest infrastructure/epc_client/tests/test_mapper_corpus.py -k \"wip_schema_20\" -q -p no:cov --no-header -rN)",
"Bash(python -m pytest infrastructure/epc_client/tests/test_mapper_corpus.py -k \"wip_schema_20\" -q --no-header)",
"Bash(timeout 150 python scripts/eon/find_epc_data.py)",
"Bash(python -m scripts.run_modelling_e2e --scenario-id 1266 --portfolio-id 785 --measures high_heat_retention_storage_heaters,solar_pv 709634 709635 709636 709638 709639 709640 709641 709642 709644)",
"Read(//home/vscode/.claude/skills/grill-me/**)",
"Bash(awk '{print $9, $5}')",
"Bash(grep -E \"\\\\.py$\")",
"Bash(python3 scripts/eon/harvest_certs.py)",
"Bash(python scripts/eon/harvest_certs.py)",
"Bash(git commit -q -m ' *)",
"Bash(timeout 250 npx -y pyright@1.1.410 datatypes/epc/domain/mapper.py)",
"Bash(git check-ignore *)",
"Bash(timeout 250 npx -y pyright@1.1.410 datatypes/epc/schema/rdsap_schema_18_0.py datatypes/epc/domain/mapper.py)",
"Bash(timeout 250 npx -y pyright@1.1.410 datatypes/epc/schema/rdsap_schema_17_1.py datatypes/epc/domain/mapper.py)",
"Bash(python -m scripts.run_modelling_e2e --scenario-id 1266 --portfolio-id 785 --measures high_heat_retention_storage_heaters,solar_pv 709634 709635 709636 709638 709639 709640 709641 709642 709643 709644 709645 709637)",
"Read(//workspaces/**)",
"Bash(python -m scripts.run_modelling_e2e --scenario-id 1266 --portfolio-id 785 --measures high_heat_retention_storage_heaters,solar_pv 709634)",
"Bash(python 2_export_data.py)",
"Bash(git commit -q -m 'Map RdSAP-Schema-17.0 certs to EpcPropertyData 🟥 *)",
"Bash(python -m py_compile tests/utilities/floats.py backend/app/db/functions/tests/test_portfolio_functions.py backend/documents_parser/tests/test_summary_pdf_mapper_chain.py backend/documents_parser/tests/test_heating_systems_corpus.py)",
"Bash(PYTHONPATH=/workspaces/model python -)",
"Bash(npx --no-install pyright datatypes/epc/schema/sap_schema_17_1.py datatypes/epc/domain/mapper.py datatypes/epc/domain/tests/test_from_sap_schema.py)",
"Bash(git commit -q -m 'Map full-SAP cert identity and scalar fields to EpcPropertyData 🟩 *)",
"Bash(npx --no-install pyright --outputjson datatypes/epc/domain/mapper.py)",
"Bash(git commit -q -m 'Carry full-SAP measured fabric U-value descriptions into the domain model 🟩 *)",
"Bash(python scripts/hyde/elmhurst_session.py --help)",
"Bash(python scripts/hyde/elmhurst_session.py status)",
"Bash(DISPLAY=:99 import -window root /tmp/hyde-viewer/elm_now2.png)",
"Bash(DISPLAY=:99 timeout 90 python scripts/hyde/elmhurst_explore.py \"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx?Guid=B44A0DB4-4C08-4241-B818-86F060172105&Referrer=https%3a%2f%2fmembers.elmhurstenergy.co.uk%2fRdsapZone%2fHome.aspx\")",
"Bash(DISPLAY=:99 timeout 90 python scripts/hyde/elmhurst_explore.py \"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormPropertyDescription.aspx?Guid=B44A0DB4-4C08-4241-B818-86F060172105\")",
"Bash(DISPLAY=:99 timeout 90 python scripts/hyde/elmhurst_explore.py \"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx?Guid=B44A0DB4-4C08-4241-B818-86F060172105\")",
"Bash(DISPLAY=:99 timeout 150 python scripts/hyde/elmhurst_fill.py)",
"Bash(pkill -f \"rdsap10\\\\|for-testing\")",
"Bash(rm -f scripts/hyde/.elmhurst-session/Singleton*)",
"Bash(DISPLAY=:99 timeout 280 python -u scripts/hyde/elmhurst_fill.py --page property_description --commit)",
"Bash(npx --no-install pyright scripts/hyde/elmhurst_download.py)",
"Edit(/.claude/skills/expand-sap-accuracy-corpus/**)",
"Bash(PYTHONPATH=/workspaces/model python scripts/fetch_real_life_epc_sample.py 10093116528)",
"Bash(PYTHONPATH=/workspaces/model python -c ' *)",
"Bash(bash scripts/hyde/start_viewer.sh)",
"Bash(DISPLAY=:99 ELMHURST_URL=\"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx?Guid=B44A0DB4-4C08-4241-B818-86F060172105\" python scripts/hyde/elmhurst_session.py login)",
"Bash(break)",
"Bash(DISPLAY=:99 timeout 90 python /tmp/check_session.py)",
"Bash(pkill -9 -f \"elm_login_hold.py\")",
"Bash(pkill -9 -f \"elmhurst-session\")",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 150 python /tmp/elm_build_dims.py)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_dump_full.py Walls WebFormWalls.aspx)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_walls_disc.py)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_roof_disc.py)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_dump_full.py Openings WebFormOpenings.aspx)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_win_probe.py)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 220 python /tmp/elm_build_openings.py)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_tab_probe.py)",
"Bash(ELM_ACCESS=\"P960-0001\" ELM_PWD=\"y22bseGUzr\" DISPLAY=:99 timeout 120 python /tmp/elm_del_probe.py)",
"Bash(npx --no-install pyright datatypes/epc/domain/epc_property_data.py datatypes/epc/domain/mapper.py domain/sap10_calculator/rdsap/cert_to_inputs.py)",
"Bash(PYTHONPATH=/workspaces/model python -m pytest domain/sap10_calculator/tests/test_sap_accuracy_corpus.py -q --no-cov)",
"Bash(PYTHONPATH=/workspaces/model python -m pytest tests/domain/sap10_calculator/test_real_cert_sap_accuracy.py -q --no-cov)",
"Edit(/.claude/skills/epc-to-elmhurst-rdsap-inputs/**)",
"Bash(python3 -c \"import sys; sys.path.insert\\(0,'scripts/hyde'\\); import elmhurst_lib; print\\('elmhurst_lib imports OK:', [f for f in dir\\(elmhurst_lib\\) if not f.startswith\\('_'\\)][:12]\\)\")",
"Bash(PYTHONPATH=/workspaces/model python -m pytest tests/domain/sap10_calculator/test_real_cert_sap_accuracy.py tests/infrastructure/epc_client/test_sap_accuracy_corpus.py -q --no-cov)",
"Bash(PYTHONPATH=/workspaces/model python scripts/fetch_real_life_epc_sample.py 10093116543)",
"Bash(echo \"---EXIT $?---\")",
"Bash(sudo apt-get update -o Dir::Etc::sourceparts=-)",
"Bash(apt-cache policy *)",
"Bash(sudo apt-get update)",
"Bash(bash scripts/hyde/start_viewer.sh restart)",
"Bash(echo \"=== listen sockets \\(port 6080 / 5900\\) ===\"; ss -ltnp 2>/dev/null | grep -E ':6080|:5900' || netstat -ltnp 2>/dev/null | grep -E ':6080|:5900' || echo \"ss/netstat unavailable\" *)",
"Read(//proc/5476/**)",
"Bash(sudo python -m playwright install-deps chromium)",
"Bash(python -m playwright install chromium)",
"Bash(python -m playwright --version)",
"Bash(pip show *)"
],
"additionalDirectories": [
"/tmp",
"/workspaces/model/scripts/hyde/.elmhurst-session"
]
}
}

View file

@ -112,6 +112,21 @@ Per-window fields:
`door_count` when `percent_draughtproofed` 100. Engine default uninsulated door
U = 3.0 W/m²K, area 1.85 m² → `doors_w_per_k` ≈ count × 1.85 × 3.0.
## Air permeability (CRITICAL — q50 is AP50, not AP4)
A lodged "Air permeability X m³/h.m² (as tested)" is a **q50** result (Blower-Door,
at 50 Pa). SAP/RdSAP infiltration line `(18) = AP50/20 + (8)` — Elmhurst's worksheet
labels it **"Measured/design AP50"** and divides by 20 (worksheet lines 17/18).
⚠️ **Do not confuse with AP4** (air permeability at 4 Pa, from a *Pulse* test),
whose cascade is `(18) = 0.263 × AP4^0.924 + (8)` — a much larger number for the
same value. Mapping a q50 onto the AP4 path massively over-counts infiltration
(e.g. q50 4.5 → 1.0 ach vs the correct 4.5/20 = 0.225). The full-SAP mapper now
routes the lodged air permeability to `SapVentilation.air_permeability_ap50_m3_h_m2`
(the `/20` path); fixed in the uprn_10093116528 campaign (gov-API SAP 78→82, vs
Elmhurst worksheet 81). In Elmhurst enter it via Air Pressure Test → **Blower Door**
→ result (and a certificate number, which the validation requires).
## Ventilation & Lighting
- **Ventilation**: open chimneys = `open_fireplaces_count`; flues/passive

View file

@ -58,13 +58,60 @@ worksheet exposes calculator holes.
`[ ]` todo · `[x]` pinned (≤0.5) · `🔧` mapper extended · `⚠` xfail (engine bug) ·
`⛔` blocked. Annotate each done line: `— <schema> · eng <X> / elm <Y> · <note>`.
## Elmhurst build playbook (READ THIS before driving the browser)
Use **`scripts/hyde/elmhurst_lib.py`** — it encodes the auth + DOM gotchas below.
Pattern: `with E.session() as (ctx,page): E.goto(...); E.set_text/set_select(...); E.save_close(page)`.
- **Auth is a SESSION cookie** — Playwright's persistent context does NOT restore
it across process launches, so the old "log in once, reuse session" flow breaks.
Instead **log in fresh every run** (`E.session()` reads creds from `ELM_ACCESS`/
`ELM_PWD` or gitignored `scripts/hyde/.elmhurst-creds.json`). Assessment DATA
persists server-side via **Save & Close**, so you can build/verify ONE page per
run across separate processes. Start the viewer first: `bash scripts/hyde/start_viewer.sh`.
- **Build page-by-page, Save & Close each** — overwrite the reused assessment's
prior-UPRN state (incl. property type House↔Flat, which reveals/hides fields).
After each `set_*`, the page AutoPostBacks — re-locate the next control.
- **Sub-tabs hide fields** — Doors, Air Pressure Test, Lighting, FGHRS etc. are
Ajax tabs; their inputs exist in the DOM but are invisible until you
`E.click_tab(page, "TabContainer_TabPanel<X>Panel")`. Forgetting this → "element
not visible" timeouts AND missing-required-field validation errors.
- **Window grid is the hard part.** (a) delete is a Yes/No MODAL
(`E.delete_first_window`); (b) it WON'T delete the last row; (c) **each Add wipes
the previously-added row** → multi-row entry doesn't stick. So enter **ONE
combined window**: `E.add_combined_window(page, total_glazed_area, orientation)`
then delete the prior rows. Use a standard band glazing ("Double post or during
2022" ≈ U1.4/g0.72) — the "...known data" option demands per-row Frame-Factor/
Data-Source/Location/Building-Part and fails validation. Trust the grid only
after Save & Close + reload (the live grid mis-shows older rows as 0.00).
- **U-value-known overrides** (walls/roof/floor) don't toggle via automation →
accept the natural RdSAP age-band U-value; note the divergence for reconciliation.
- **Recommendations page = validation gate.** It must show ZERO errors before the
summary/worksheet PDFs download. Usual culprits: insulated-door U-value, and the
air-pressure-test **certificate number** (required when method=Blower Door).
- **Air permeability**: enter the lodged q50 via Air Pressure Test → Blower Door →
result. Elmhurst treats it as **AP50** and uses `(18)=AP50/20+(8)` (worksheet
lines 17/18). This drove the first campaign mapper fix — see Banked findings.
## Banked findings (fold new ones in here as the corpus grows)
- **Air-permeability AP50 fix** (uprn_10093116528, the first campaign cert): the
full-SAP mapper was routing the lodged q50 to the engine's AP4/Pulse formula
(`0.263×AP4^0.924`) instead of the AP50 `/20` path — a big infiltration
over-count. Fixed via `SapVentilation.air_permeability_ap50_m3_h_m2` +
`_sap_17_1_ventilation` + `cert_to_inputs`. Re-pinned uprn_10092973954 77→80.
See `epc-to-elmhurst-rdsap-inputs/reference/mapping.md` (Air permeability).
- **Full-SAP-through-RdSAP residual ≈ +12 SAP** is expected and usually NOT a
bug: the engine uses the cert's *measured* U-values (often better than RdSAP
age-band proxies) and Elmhurst RdSAP uses age-band defaults + a party-wall
default. Pin the engine's observed value; document the Elmhurst delta (don't tune).
- **FGHRS** (full-SAP `has_fghrs`/`fghrs_index_number`) is dropped by the mapper
and not yet modelled — omit it on BOTH sides so the comparison stays clean.
## Limitations / next improvements (make the campaign scale)
- **Per-assessment GUID**`elmhurst_fill.py` / `elmhurst_download.py` hard-code
`ASSESSMENT_GUID` (the Khalim-test cert). Each UPRN needs its own Elmhurst
assessment; create one and update the GUID, or parameterize it (`--guid`).
- **Cert-specific fill values**`PAGES` in `elmhurst_fill.py` hold one cert's
values. Make it **data-driven** (read field values from each cert's
`elmhurst_inputs.md` or a JSON sidecar) so one filler serves all UPRNs. Until
then, build each cert guided by its `elmhurst_inputs.md` (the filler is a template).
- **More dialogs** — boiler is automated (cascade); apply the same
open→select→OK pattern to the control code (2110) and the MV unit when wanted.
- **Per-assessment GUID**`elmhurst_lib.py` reuses one `ASSESSMENT_GUID`
(Khalim-test), overwritten per UPRN. For parallelism, create one assessment per
UPRN and parameterize the GUID.
- **Data-driven fill**`elmhurst_lib.py` gives the primitives; a per-cert driver
that reads field values straight from `elmhurst_inputs.md` (or a JSON sidecar)
would remove the remaining hand-keying. `elmhurst_fill.py` is the older template.
- **More dialogs** — boiler cascade is automatable; the control-code (2110) and
FGHRS/MV-unit search dialogs still need the open→search→select→OK pattern.

View file

@ -12,7 +12,7 @@ inputs 79 (calculator faithful within ~1). Use it to sanity-check the pipeline.
## The 100
- [ ] 10093116528
- [x] 🔧 10093116528 — SAP-17.1 (full-SAP semi) · eng 82 / elm 81 · 🔧 air-perm AP50 fix: q50 Blower-Door routed to (18)=AP50/20 not the AP4/Pulse formula (was eng 78). Residual +1 = lodged-U vs RdSAP age-band-U; FGHRS (60031) omitted both sides. Worked-ref 10092973954 re-pinned 77→80 by same fix.
- [ ] 10093116543
- [ ] 10093116529
- [ ] 100020933699

View file

@ -1,4 +1,7 @@
version: '3.8'
# Unique Compose project name (see backend/docker-compose.yml) so this repo's
# devcontainer doesn't collide with other model-* clones.
name: model-asset-list
services:
model-sal:

View file

@ -13,6 +13,15 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
ripgrep fd-find make unzip bash-completion \
&& rm -rf /var/lib/apt/lists/*
# 1b) Headed-browser viewer stack for the hyde Elmhurst automation.
# scripts/hyde/start_viewer.sh chains these: Xvfb (virtual :99 screen) ->
# fluxbox (window manager) -> x11vnc (VNC on 5900) -> novnc/websockify
# (browser-accessible desktop on 6080). Lets a human watch/click the headed
# Playwright browser while building certs in Elmhurst.
RUN apt-get update && apt-get install -y --no-install-recommends \
xvfb fluxbox x11vnc novnc websockify \
&& rm -rf /var/lib/apt/lists/*
# Neovim latest (LazyVim needs >=0.9)
RUN curl -fsSL https://github.com/neovim/neovim/releases/latest/download/nvim-linux-x86_64.tar.gz \
| tar -xz -C /opt \
@ -36,6 +45,13 @@ ADD etl/hubspot/requirements.txt requirements4.txt
RUN cat requirements1.txt requirements2.txt requirements3.txt requirements4.txt > requirements.txt
RUN pip install -r requirements.txt
# Playwright OS dependencies for the hyde Elmhurst automation (scripts/hyde/).
# The pip `playwright` package is in requirements above; this pulls the apt
# libraries chromium needs. The browser BINARY itself is downloaded as the
# vscode user further down (its cache lives in /home/vscode/.cache/ms-playwright,
# which is where the automation runs from).
RUN python -m playwright install-deps chromium
# 5) Workdir
WORKDIR /workspaces/model
@ -86,4 +102,11 @@ RUN git clone https://github.com/LazyVim/starter /home/${USER}/.config/nvim \
# Install Claude Code CLI (skills are installed via postCreate from Hestia-Homes/agentic-toolkit)
RUN curl -fsSL https://claude.ai/install.sh | bash
ENV PATH="/home/vscode/.local/bin:${PATH}"
# Playwright chromium browser for the hyde Elmhurst automation. Run as the
# vscode user so the download lands in /home/vscode/.cache/ms-playwright (the
# OS deps were installed as root above). Headed chromium is required — the
# automation launches with headless=False onto the noVNC desktop (:99).
RUN python -m playwright install chromium
USER root

View file

@ -42,11 +42,15 @@
"containerEnv": {
"PYTHONFLAGS": "-Xfrozen_modules=off"
},
"forwardPorts": ["model-backend:8000"],
"forwardPorts": ["model-backend:8000", "model-backend:6080"],
"portsAttributes": {
"model-backend:8000": {
"label": "FastAPI",
"onAutoForward": "notify"
},
"model-backend:6080": {
"label": "hyde noVNC desktop",
"onAutoForward": "silent"
}
}
}

View file

@ -1,4 +1,8 @@
version: '3.8'
# Unique Compose project name so this repo's devcontainer doesn't collide with
# other model-* clones (which all live in .devcontainer/backend/ and would
# otherwise default to the same project name "backend", clobbering each other).
name: model-backend
services:
model-backend:
@ -14,6 +18,10 @@ services:
# worktrees of this repo run at once without colliding. VS Code's
# forwardPorts (in devcontainer.json) forwards container :8000 to your machine.
- "8000"
# noVNC desktop for the hyde Elmhurst automation (scripts/hyde/start_viewer.sh).
# Dynamic host port like 8000; VS Code forwardPorts maps container :6080 to
# a stable localhost:6080 on your machine.
- "6080"
volumes:
- ../../:/workspaces/model
- ~/.gitconfig:/home/vscode/.gitconfig:ro

1
.gitignore vendored
View file

@ -311,3 +311,4 @@ scripts/eon/epc_cache.pkl
# Elmhurst Playwright session (auth cookies) + captured PDFs (scripts/hyde)
scripts/hyde/.elmhurst-session/
scripts/hyde/elmhurst_downloads/
scripts/hyde/.elmhurst-creds.json

View file

@ -0,0 +1,180 @@
# Elmhurst RdSAP inputs — UPRN 10093116528 (cert 8000-8495-2839-2607-9683, SAP-Schema-17.1)
**Lodged SAP:** 84 (band B) **Our engine:** 78 (continuous 78.04) ← compare Elmhurst against this
**Total fuel cost (engine):** £505.43/yr **Heat transfer coeff:** 177.05 W/K
**Known divergences (candidate mapper gaps — confirm against Elmhurst worksheet):**
- **Party wall U = 0.25 (engine) vs 0 (lodged).** Full-SAP Wall 2 (`wall_type` 4, area 79.1 m², `u_value` 0) is a party wall lodged at U=0. The mapper (`_sap_17_1_building_part`) derives party *length* but drops the lodged U and never sets `party_wall_construction`, so the engine applies the RdSAP house default **0.25**`party_walls_w_per_k` **19.775 W/K** (≈11 % of HTC). Likely the dominant under-prediction driver.
- **FGHRS dropped.** Raw cert: `has_fghrs:"true"`, `fghrs_index_number:60031`, HW description "flue gas heat recovery". `_sap_17_1_heating` hard-codes `has_fghrs=False` and carries no FGHRS index → engine ignores the flue-gas heat-recovery credit. Enter FGHRS 60031 in Elmhurst to expose the gap.
> Full-SAP cert forced through RdSAP. Windows keep **real geometry** (mapper preserved
> `sap_openings`, not a glazed-area band). 🔸 = assessor-only field the EPC can't supply.
> The **Fields to clear** table at the bottom is the explicit "absent" set.
> Reuse Elmhurst assessment GUID **B44A0DB4-4C08-4241-B818-86F060172105**; overwrite
> every prior-UPRN value (clears included). NEVER click Submit.
---
## Property Details (admin — does NOT affect SAP)
| Elmhurst field (`id`) | Enter | Notes |
|---|---|---|
| `DropDownListPurpose` | None of the above | not a retrofit/modelling job |
| `DropDownListTenure` | Owner-occupied | `tenure` ND; tenure doesn't affect SAP |
| `DropDownListTransactionType` | None of the above | `transaction_type` 6 = new dwelling |
| `TextBoxInspectionDate` | 2018-06-01 | admin only |
## Property Description
| Elmhurst field (`id`) | Enter | Notes |
|---|---|---|
| `DropDownListPropertyType1` | **H House** | `property_type` 0 |
| `DropDownListPropertyType2` | **S Semi-Detached** | `built_form` 2 |
| `TextBoxStoreys` | **2** | two storeys (`sap_floor_dimensions` storey 0 + 1) |
| `TextBoxHabitableRooms` | **5** 🔸 | not lodged; estimate for a 2-storey 90 m² semi — confirm/key by hand |
| `TextBoxHeatedHabitableRooms` | **5** 🔸 | all heated |
| `DropDownListDateBuiltMain` | **L 2012-2022** | `construction_year` 2017 — by YEAR (engine band differs; see gotcha) |
## Dimensions (Type = Internal)
Two floors, each `total_floor_area` 44.93 m², `storey_height` 2.6 m. TFA engine 89.86 (cert top-level 90).
| Floor | Field | Enter | Notes |
|---|---|---|---|
| Lowest (Ground) | `TextBoxFloorAreaLowestFloor` | **44.93** | `sap_floor_dimensions[storey 0]` |
| Lowest | `TextBoxRoomHeightLowestFloor` | **2.60** | storey height |
| Lowest | `TextBoxWallPerimeterLowestFloor` | **12.94** | exposed wall 67.29 m² ÷ Σheight 5.2 |
| Lowest | `TextBoxPartyWallLengthLowestFloor` | **15.21** | party wall 79.1 m² ÷ 5.2 (P1/P4 TB lengths confirm ≈15.2) |
| First | `TextBoxFloorAreaFirstFloor` | **44.93** | `sap_floor_dimensions[storey 1]` |
| First | `TextBoxRoomHeightFirstFloor` | **2.60** | storey height |
| First | `TextBoxWallPerimeterFirstFloor` | **12.94** | same perimeter |
| First | `TextBoxPartyWallLengthFirstFloor` | **15.21** | same party length |
## Conservatory
| Elmhurst field (`id`) | Enter | Notes |
|---|---|---|
| `CheckBoxIsConservatory` | unchecked | `conservatory_type` 1 = none |
## Walls (Main + Party)
| Elmhurst field (`id`, under `…WallMain_`) | Enter | Notes |
|---|---|---|
| `DropDownListType` | **TI Timber Frame** | 2017 new build, U 0.187; pick per construction |
| `DropDownListInsulation` | **A As Built** | factory-insulated |
| `CheckBoxUvalueKnown` + U-value | **0.19** | cert Wall 1 `u_value` 0.187 / "0.19 W/m²K"; engine walls 7.91 W/K |
| **Party wall** `DropDownListPartyWallType` | **Solid (U=0)** ⚠ | Wall 2 lodged `u_value` **0** → solid/sealed party wall. Engine wrongly uses 0.25 — this is the candidate gap. Do NOT leave "Unable to determine". |
## Roofs
| Elmhurst field (`id`, under `…RoofMain_`) | Enter | Notes |
|---|---|---|
| `DropDownListType` | **PB Pitched, insulation between/above joists** | `roof_type` 2, U 0.113 |
| `DropDownListInsulation` + thickness / U | **U-value 0.11** | cert "0.11 W/m²K"; engine roof 4.94 W/K |
## Floors
| Elmhurst field (`id`, under `…FloorsMain_`) | Enter | Notes |
|---|---|---|
| `DropDownListLocation` | **G Ground floor** | storey 0 |
| `DropDownListType` | **S Solid** | `floor_type` 2 |
| `DropDownListInsulation` | **A As built** | new-build |
| `CheckBoxUValueKnown` + U-value | **0.11** | cert "0.11 W/m²K"; engine floor 4.94 W/K |
## Openings — Windows (real geometry retained, 7 windows)
Mapper kept the lodged `sap_openings`: 7 windows totalling **23.82 m²**, whole-window
**U 1.4**, **g 0.72** (opening-type `name` 1, `glazing_type` 4 high-performance).
Engine windows = **31.59 W/K**.
| Elmhurst grid field (`id`, under `…WindowsPanel_`) | Enter | Notes |
|---|---|---|
| `DropDownListExtGlazing` | **Double, high performance** | `glazing_type` 4, 100% multiple-glazed |
| `DropDownListExtFrameType` | **PVC** | high-performance frame (frame factor 0.7) |
| `TextBoxExtUValue` | **1.4** | opening-type U |
| `TextBoxExtGValue` | **0.72** | opening-type g |
| 🔸 per-row geometry | enter rows totalling **23.82 m²** | real widths×2.5/2.45/2.2 (0.9,2.85,0.8,1.4,1.0,1.45,1.35) |
| `DropDownListExtOrientation` | as lodged | orientations 3 (×4 = S/E?) + 7 (×3); RdSAP treats per-window |
## Openings — Doors
| Elmhurst field (`id`, under `…DoorsPanel_`) | Enter | Notes |
|---|---|---|
| `TextBoxDoors` | **1** | `door_count` 1 (opening `name` 5, type 5) |
| `TextBoxDoorsInsulated` | **1** | `insulated_door_count` 1, door U 1.6; engine `doors_w_per_k` 2.96 |
## Ventilation & Lighting
| Elmhurst field (`id`) | Enter | Notes |
|---|---|---|
| `TabPanelMechVent_CheckBoxMechanicalVentilation` | **unchecked** | `ventilation_type` 1 = natural w/ intermittent extract |
| `TabPanelVentilationPanel_*` extract fans | **3** | `extract_fans_count` 3 (intermittent) |
| chimneys / open flues / flueless gas / PSV | **0** | none lodged |
| `TabPanelAirPressureTest_DropDownListTestMethod` | **Blower Door → 4.5** | `air_permeability` 4.5, `pressure_test` 1 (as tested) |
| Sheltered sides | **1** | `sheltered_sides_count` 1 (RdSAP defaults 2 — change) |
| `TabPanelLighting_*` low-energy | **100% LED** (10 of 10) | 10 fixed outlets, 10 low-energy |
## Space Heating — Main Heating 1
Cert: "Boiler and radiators, mains gas", `main_fuel_type` 1, **PCDB boiler index 17644**,
radiators, controls **2110** (time + temp zone, interlocked), fan-assisted balanced flue,
**FGHRS index 60031** (`has_fghrs` true on raw cert).
| Elmhurst field (`id`, under `…MainHeating1_`) | Enter | Notes |
|---|---|---|
| 🔸 `TextBoxPCDFBoilerReference` (via `SelectBoilerDialog`) | **17644** | PCDB index via boiler-search dialog |
| `RadioButtonListHeatEmitter` | **Radiators** | `heat_emitter_type` 1 |
| `RadioButtonListFlueType` | **Balanced** | room-sealed; `fan_flue_present` true |
| `RadioButtonListFanAssistedFlue` | **Yes** | `boiler_flue_type` 2 |
| `RadioButtonListHeatingPumpAge` | **2013 or later** | `central_heating_pump_age` 2, in heated space |
| 🔸 `TextBoxMainHeatingControls` (via `SelectHeatingControlsDialog`) | **2110** | time & temperature zone control; interlocked |
| 🔸 **FGHRS** (`SelectFGHRSDialog` / FGHRS index field) | **60031** | flue-gas heat recovery — engine drops it; enter to expose gap |
| `TextBoxPercentageOfHeat` | **100** | single main system (`main_heating_fraction` 1) |
## Space Heating — Meters
| Elmhurst field (`id`, under `TabPanelMeters_`) | Enter | Notes |
|---|---|---|
| `RadioButtonListElectricityType` | **Single** | `electricity_tariff` 1 — not Economy 7 |
| `CheckBoxMainGas` | **checked** | mains gas (`main_fuel_type` 1) |
## Water Heating
Cert: from main system (combi), `water_heating_code` 901, mains gas (`water_heating_fuel` 1),
no cylinder (`has_hot_water_cylinder` false), `thermal_store` 1, **FGHRS to HW (60031)**.
Engine HW = **2,684 kWh/yr**.
| Elmhurst field (`id`, under `TabPanelWaterHeating_`) | Enter | Notes |
|---|---|---|
| 🔸 `TextBoxWaterHeatingCode` | **from main system** (901) | combi; Boiler Circulator / from-main category |
| `CheckBoxHotWaterCylinder` | **unchecked** | combi instantaneous — no cylinder |
| `TabPanelFGHRS_*` | **FGHRS 60031** | flue-gas heat recovery present on HW |
| `TabPanelWWHRS_DropDownListWWHRSPresent` | **No** | none lodged (instantaneous_wwhrs empty) |
## New Technologies (all none)
| Elmhurst field (`id`) | Enter | Notes |
|---|---|---|
| `…PvPanelData` | None | no PV |
| `…CheckBoxWindTurbinePresent` | unchecked | `wind_turbines_count` 0 |
| `…TextBoxElectricityGenerated` (hydro) | 0 | none |
---
## Fields to clear in Elmhurst (do NOT map)
| Elmhurst page · field (`id`) | Set to | Why absent |
|---|---|---|
| Property Description · `DropDownListDateBuiltFirst``Forth` | (blank) | no extensions lodged |
| Property Description · `DropDownListRoomInRoofMain``Forth` | (blank) | no room-in-roof building part |
| Dimensions · `…TextBoxFloorAreaRoomInRoof` | (blank) | leave empty, not 0 |
| Dimensions · 1st4th Ext. sub-tabs (`TabPanel1stExt_…` etc.) | 0 / blank | single building part |
| Walls · `…DropDownListAlternativeWall1Type` + `TextBoxAddWallArea` | (blank / 0) | one external wall element |
| Walls · `…CheckBoxAditionalWallSheltered` | unchecked | no sheltered wall lodged |
| Openings · surplus window grid rows (`GridViewExtendedWidows_DeleteButton_*`) | delete to 7 rows | match the 7 lodged windows |
| Space Heating · `DropDownListSecondaryHeatingPresent` + `TextBoxSecondaryHeatingCode` | **No** / (blank) | `secondary_heating_category` 1 = None |
| Space Heating · `TabPanelMainHeating2_*` | (blank) | single main system |
| Water Heating · `CheckBoxHotWaterCylinder` + cylinder fields | unchecked / (blank) | combi instantaneous, no cylinder |
| Water Heating · Solar (`…CheckBoxSolaWaterHeating`), WWHRS | none | not lodged |
| Conservatory / PV / Wind / Hydro | none | not lodged |
## Engine reference figures (reconcile against Elmhurst's worksheet)
| Quantity | Engine value |
|---|---|
| **SAP score** | **78** (continuous 78.04) |
| Total fuel cost | £505.43/yr |
| Space-heating demand | 6,377.7 kWh/yr |
| Main heating fuel | 7,206.4 kWh/yr |
| Hot water | 2,684.3 kWh/yr |
| Pumps & fans | 86.0 kWh/yr |
| Lighting | 202.2 kWh/yr |
| CO₂ | 2,119.5 kg/yr |
| Heat transfer coefficient | 177.05 W/K |
**Heat-loss element breakdown (W/K):** walls 7.91 · floor 4.94 · roof 4.94 ·
**party wall 19.78 (U=0.25 — candidate gap, lodged U=0)** · windows 31.59 · doors 2.96 ·
thermal bridging 12.57 · infiltration 92.36 → total HTC 177.05.
> **🔸 Assessor-only fields:** habitable-room count, per-window geometry rows,
> boiler PCDB 17644 / control 2110 / FGHRS 60031 via their search dialogs,
> water-heating code 901.

View file

@ -0,0 +1,118 @@
# Elmhurst RdSAP inputs — UPRN 10093116543 (cert 8358-7436-5620-6889-0906, SAP-Schema-17.1)
**Lodged SAP:** 82 **Our engine:** 81 (continuous 81.30) ← compare Elmhurst against the engine
**Property:** 18 Woodfield Park Road, EMSWORTH PO10 8BG · semi-detached house · 2017 build · mains-gas combi
**Known divergences (flag, don't tune):**
- **Age band letter:** engine `construction_age_band = 'M'`, but construction year is **2017** → in Elmhurst pick the on-screen band **L (20122022)**, NOT M (M = 2023 onwards in the live RdSAP-10 tool). Year drives the default U-values.
- **Walls/roof/floor U-values:** cert lodges no measured U (`wall_u_value`/`roof_u_value`/`floor_u_value` all None) → accept Elmhurst's natural RdSAP age-band U for band L. Engine uses its own age-band proxies; small residual expected.
- **Windows:** synthesised from glazed-area band × TFA (not real geometry) → enter as ONE combined window. Per-window orientations are spread (mostly E, some S/W); a single combined orientation will move solar gains slightly — cosmetic.
## Property Description
| Elmhurst field | Value | Notes (SAP code / EES path) |
|---|---|---|
| Property Type | House | `dwelling_type` = "Semi-detached house" |
| Built form | Semi-detached | party wall present (1 party wall, 4.075 m/floor) |
| Age band (main) | **L (20122022)** | construction_year 2017; engine letter 'M' is wrong for the live tool — see divergence |
| Number of storeys | 2 | from floor dimensions (2 floors) |
| Habitable rooms | 3 | `habitable_rooms_count` |
| Extensions | 0 | `extensions_count` = 0 → clear all extension sub-tabs |
## Dimensions
| Elmhurst field | Value | Notes |
|---|---|---|
| Ground floor area | 46.68 m² | floor dim[0] `total_floor_area_m2` |
| First floor area | 36.70 m² | floor dim[1] `total_floor_area_m2` |
| Total floor area | 83.0 m² (engine TFA 83.38) | lodged `total_floor_area` 83; engine sums floor dims = 83.38 |
| Room height (each floor) | 2.6 m | `room_height_m` |
| Heat-loss perimeter (each floor) | 28.025 m | `heat_loss_perimeter_m` |
| Party wall length (each floor) | 4.075 m | `party_wall_length_m` |
## Walls
| Elmhurst field | Value | Notes (SAP code / EES path) |
|---|---|---|
| Construction | Cavity | main wall `wall_type` 2, area 145.73 m²; engine `wall_construction` 4 |
| Insulation | As built / age-band default (`wall_insulation_type` 0) | no measured U → accept band-L RdSAP U |
| Wall area | 145.73 m² (+ 21.19 m² second wall type) | `total_wall_area` |
| Dry-lined | (leave default) | `wall_dry_lined` None |
| **Party wall** | Present — band-L default (cavity) | `party_walls_w_per_k` = 5.2975 (≠0 → party wall exists); `party_wall_construction` None → accept default. **Do not set to "none".** |
## Roofs
| Elmhurst field | Value | Notes |
|---|---|---|
| Roof type | Pitched (`roof_type` 2) | three roof records, total ≈ 66 m² (5+33+28) |
| Insulation | Age-band default | `roof_u_value` None → accept band-L RdSAP U |
## Floors
| Elmhurst field | Value | Notes |
|---|---|---|
| Ground floor | `floor_type` 2, 46.68 m² | engine `floor_w_per_k` 5.1348 |
| First floor | `floor_type` 3, 36.70 m² (intermediate — not heat-loss) | `is_exposed_floor` False |
| Insulation / U | Age-band default | `floor_u_value` None |
## Openings — Windows
| Elmhurst field | Value | Notes |
|---|---|---|
| Entry mode | ONE combined window | synthesised, not real geometry — use the combined-window flow |
| Total glazed area | ~24.0 m² (engine `windows_w_per_k` 31.82) | sum of 10 synthesised window areas |
| Glazing | Double glazed, post-2002 band (U 1.4, g 0.72) | `glazing_type` 4, `multiple_glazed_percentage` 100; `WindowTransmissionDetails` U=1.4 / g=0.72 |
| Frame factor | 0.7 | `frame_factor` |
| Orientation | East (dominant) | per-window mostly orientation 3=E, some S/W — combined ⇒ solar-gain divergence is cosmetic |
## Openings — Doors
| Elmhurst field | Value | Notes |
|---|---|---|
| Door count | 1 insulated | `door_count` 1, `insulated_door_count` 1 |
| Door U-value | 1.6 | `insulated_door_u_value` 1.6 (engine `doors_w_per_k` 2.96 ⇒ ~1.85 m²) |
## Ventilation & Lighting
| Elmhurst field | Value | Notes |
|---|---|---|
| Ventilation type | Natural with intermittent extract fans | no MVHR/MEV (`mechanical_ventilation` None) |
| Extract fans | 3 | `extract_fans_count` 3 |
| Open flues | 0 | `open_flues_count` 0; `flueless_gas_fires_count` 0 |
| Sheltered sides | 2 | `sheltered_sides` 2 |
| **Air Pressure Test** | **Blower Door**, result **4.94** | `air_permeability_ap50` 4.94, `pressure_test` '1' (done). Elmhurst treats as AP50 ⇒ `(18)=AP50/20+(8)`. **Enter a certificate number** (Recommendations gate requires it). |
| Lighting | 100% low-energy | `low_energy_fixed_lighting_outlets_percentage` 100 (10/10 bulbs low-energy) |
## Space Heating — Main Heating 1
| Elmhurst field | Value | Notes |
|---|---|---|
| Fuel | Mains gas | `main_fuel_type` 1 |
| System | Boiler + radiators, condensing | `heat_emitter_type` 1 (radiators); engine efficiency 88.5% |
| Boiler (PCDF) | index **17644** | `main_heating_index_number` 17644, `main_heating_data_source` 1 → search PCDF by this index (🔸 dialog) |
| Flue | Fan-assisted / balanced | `boiler_flue_type` 2, `fan_flue_present` True |
| Controls | Programmer + room stat + TRVs | `main_heating_control` 2110 (control_type 3) |
| Central heating pump | In heated space, age band 2 | `central_heating_pump_age` 2, `is_central_heating_pump_in_heated_space` true |
| Secondary heating | **None** | no secondary system lodged (engine secondary fraction 0) |
## Water Heating
| Elmhurst field | Value | Notes |
|---|---|---|
| Water heating | From main system (combi) | `water_heating_code` 901 → Elmhurst "Boiler Circulator"; `water_heating_fuel` 1 = gas |
| Hot water cylinder | **None** | `has_hot_water_cylinder` False → combi, instantaneous DHW. Clear cylinder size/insulation. |
| Solar water heating | No | `solar_water_heating` False |
| WWHRS | No | `instantaneous_wwhrs` index1/2 None (ADR-0028: not a device) |
| FGHRS | No | `has_fghrs` False — omit on both sides |
## New Technologies
| Elmhurst field | Value | Notes |
|---|---|---|
| PV / Wind / Hydro | None | `photovoltaic_array`/`hydro` None |
| Special features | None | — |
## Fields to clear in Elmhurst (do NOT map)
| Elmhurst field | Set to | Why absent |
|---|---|---|
| Property Description · 1st4th Extension age band | (blank) | `extensions_count` = 0 |
| Property Description · Room-in-Roof age band | (blank) | no room-in-roof (`sap_room_in_roof` None) |
| Dimensions · Room(s) in Roof area | (blank) | ditto — leave empty, not 0 |
| Dimensions · 1st4th Ext. sub-tabs | 0 / blank | single building part |
| Conservatory | none | `has_conservatory` None / not lodged |
| Openings · surplus window rows | delete | one combined window only |
| Space Heating · Main Heating 2 | none | single main system, fraction 1 |
| Space Heating · Secondary heating | none | no secondary lodged |
| Water Heating · cylinder size / insulation | blank | combi, no cylinder |
| Water Heating · Solar / WWHRS / FGHRS | none | none lodged |
| New Tech · PV / Wind / Hydro / Special features | none | none lodged |
| Walls · Party wall | **keep present (cavity)** | `party_walls_w_per_k` ≠ 0 — this is NOT a clear; semi-detached |

View file

@ -0,0 +1,470 @@
{
"uprn": 10093116543,
"roofs": [
{
"description": "Average thermal transmittance 0.15 W/m\u00b2K",
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"walls": [
{
"description": "Average thermal transmittance 0.19 W/m\u00b2K",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
}
],
"floors": [
{
"description": "Average thermal transmittance 0.11 W/m\u00b2K",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
}
],
"status": "entered",
"tenure": "ND",
"windows": {
"description": "High performance glazing",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
},
"lighting": {
"description": "Low energy lighting in all fixed outlets",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
},
"postcode": "PO10 8BG",
"data_type": 2,
"hot_water": {
"description": "From main system, flue gas heat recovery",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
},
"post_town": "EMSWORTH",
"built_form": 2,
"created_at": "2018-06-04 10:56:49",
"living_area": 31.38,
"orientation": 0,
"region_code": 16,
"report_type": 3,
"sap_heating": {
"thermal_store": 1,
"water_fuel_type": 1,
"water_heating_code": 901,
"main_heating_details": [
{
"has_fghrs": "true",
"main_fuel_type": 1,
"heat_emitter_type": 1,
"fghrs_index_number": 60031,
"emitter_temperature": 1,
"is_flue_fan_present": "true",
"main_heating_number": 1,
"main_heating_control": 2110,
"is_interlocked_system": "true",
"main_heating_category": 2,
"main_heating_fraction": 1,
"main_heating_flue_type": 2,
"central_heating_pump_age": 2,
"main_heating_data_source": 1,
"main_heating_index_number": 17644,
"has_separate_delayed_start": "true",
"load_or_weather_compensation": 0,
"is_central_heating_pump_in_heated_space": "true"
}
],
"has_hot_water_cylinder": "false",
"has_fixed_air_conditioning": "false",
"secondary_heating_category": 1
},
"sap_version": 9.92,
"schema_type": "SAP-Schema-17.1",
"uprn_source": "Energy Assessor",
"country_code": "ENG",
"main_heating": [
{
"description": "Boiler and radiators, mains gas",
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
}
],
"air_tightness": {
"description": "Air permeability 4.9 m\u00b3/h.m\u00b2 (as tested)",
"energy_efficiency_rating": 4,
"environmental_efficiency_rating": 4
},
"dwelling_type": "Semi-detached house",
"language_code": 1,
"property_type": 0,
"address_line_1": "18, Woodfield Park Road",
"assessment_date": "2018-06-01",
"assessment_type": "SAP",
"completion_date": "2018-06-04",
"inspection_date": "2018-06-01",
"sap_ventilation": {
"psv_count": 0,
"pressure_test": 1,
"air_permeability": 4.94,
"open_flues_count": 0,
"ventilation_type": 1,
"extract_fans_count": 3,
"open_fireplaces_count": 0,
"sheltered_sides_count": 2,
"flueless_gas_fires_count": 0
},
"design_water_use": 1,
"sap_data_version": 9.92,
"total_floor_area": 83,
"transaction_type": 6,
"conservatory_type": 1,
"registration_date": "2018-06-04",
"sap_energy_source": {
"electricity_tariff": 1,
"wind_turbines_count": 0,
"wind_turbine_terrain_type": 2,
"fixed_lighting_outlets_count": 10,
"low_energy_fixed_lighting_outlets_count": 10,
"low_energy_fixed_lighting_outlets_percentage": 100
},
"sap_opening_types": [
{
"name": 1,
"type": 4,
"u_value": 1.4,
"data_source": 2,
"frame_factor": 0.7,
"glazing_type": 4,
"solar_transmittance": 0.72
},
{
"name": 5,
"type": 1,
"u_value": 1.6,
"data_source": 2,
"glazing_type": 1
}
],
"secondary_heating": {
"description": "None",
"energy_efficiency_rating": 0,
"environmental_efficiency_rating": 0
},
"sap_building_parts": [
{
"sap_roofs": [
{
"name": "Roof 3",
"u_value": 0.244,
"roof_type": 2,
"description": "Flat Dormer",
"total_roof_area": 5
},
{
"name": "Roof 2",
"u_value": 0.132,
"roof_type": 2,
"description": "Flat main",
"total_roof_area": 33
},
{
"name": "Roof 1",
"u_value": 0.156,
"roof_type": 2,
"description": "Roof 1",
"total_roof_area": 28
}
],
"sap_walls": [
{
"name": "Wall 1",
"u_value": 0.187,
"wall_type": 2,
"description": "External",
"total_wall_area": 145.73,
"is_curtain_walling": "false"
},
{
"name": "Wall 2",
"u_value": 0,
"wall_type": 4,
"description": "To other house",
"total_wall_area": 21.19
}
],
"identifier": "Main Dwelling",
"overshading": 2,
"sap_openings": [
{
"name": 1,
"type": 1,
"width": 1.8,
"height": 2.2,
"location": "Wall 1",
"orientation": 7
},
{
"name": 2,
"type": 1,
"width": 0.9,
"height": 1,
"location": "Wall 1",
"orientation": 7
},
{
"name": 3,
"type": 1,
"width": 0.9,
"height": 2.5,
"location": "Wall 1",
"orientation": 5
},
{
"name": 5,
"type": 5,
"width": 1,
"height": 2.5,
"location": "Wall 1",
"orientation": 0
},
{
"name": 6,
"type": 1,
"width": 0.9,
"height": 2.5,
"location": "Wall 1",
"orientation": 3
},
{
"name": 7,
"type": 1,
"width": 0.9,
"height": 2.5,
"location": "Wall 1",
"orientation": 3
},
{
"name": 8,
"type": 1,
"width": 0.9,
"height": 2.5,
"location": "Wall 1",
"orientation": 3
},
{
"name": 9,
"type": 1,
"width": 0.9,
"height": 1.5,
"location": "Wall 1",
"orientation": 3
},
{
"name": 10,
"type": 1,
"width": 2.3,
"height": 1.5,
"location": "Wall 1",
"orientation": 3
},
{
"name": 11,
"type": 1,
"width": 2.9,
"height": 1.5,
"location": "Wall 1",
"orientation": 3
},
{
"name": 12,
"type": 1,
"width": 0.9,
"height": 1.1,
"location": "Wall 1",
"orientation": 7
}
],
"construction_year": 2017,
"sap_thermal_bridges": {
"thermal_bridges": [
{
"length": 14.3,
"psi_value": 0.3,
"psi_value_source": 2,
"thermal_bridge_type": "E2"
},
{
"length": 13.3,
"psi_value": 0.04,
"psi_value_source": 2,
"thermal_bridge_type": "E3"
},
{
"length": 42.6,
"psi_value": 0.05,
"psi_value_source": 2,
"thermal_bridge_type": "E4"
},
{
"length": 28,
"psi_value": 0.16,
"psi_value_source": 2,
"thermal_bridge_type": "E5"
},
{
"length": 28.05,
"psi_value": 0.14,
"psi_value_source": 4,
"thermal_bridge_type": "E7"
},
{
"length": 28.05,
"psi_value": 0.08,
"psi_value_source": 4,
"thermal_bridge_type": "E14"
},
{
"length": 10.4,
"psi_value": 0.09,
"psi_value_source": 2,
"thermal_bridge_type": "E16"
},
{
"length": 10.4,
"psi_value": -0.09,
"psi_value_source": 2,
"thermal_bridge_type": "E17"
},
{
"length": 4.9,
"psi_value": 0.16,
"psi_value_source": 4,
"thermal_bridge_type": "P1"
},
{
"length": 4.9,
"psi_value": 0,
"psi_value_source": 4,
"thermal_bridge_type": "P3"
},
{
"length": 4.9,
"psi_value": 0.24,
"psi_value_source": 4,
"thermal_bridge_type": "P4"
}
],
"thermal_bridge_code": 5
},
"building_part_number": 1,
"sap_floor_dimensions": [
{
"storey": 0,
"u_value": 0.11,
"floor_type": 2,
"description": "Ground floor",
"storey_height": 2.6,
"heat_loss_area": 46.68,
"total_floor_area": 46.68
},
{
"storey": 1,
"u_value": 0,
"floor_type": 3,
"storey_height": 2.6,
"heat_loss_area": 0,
"total_floor_area": 36.7
}
],
"thermal_mass_parameter": 250
}
],
"heating_cost_current": {
"value": 240,
"currency": "GBP"
},
"co2_emissions_current": 1.4,
"energy_rating_average": 60,
"energy_rating_current": 82,
"lighting_cost_current": {
"value": 57,
"currency": "GBP"
},
"main_heating_controls": [
{
"description": "Time and temperature zone control",
"energy_efficiency_rating": 5,
"environmental_efficiency_rating": 5
}
],
"has_hot_water_cylinder": "false",
"heating_cost_potential": {
"value": 240,
"currency": "GBP"
},
"hot_water_cost_current": {
"value": 70,
"currency": "GBP"
},
"suggested_improvements": [
{
"sequence": 1,
"typical_saving": {
"value": 28,
"currency": "GBP"
},
"indicative_cost": "\u00a34,000 - \u00a36,000",
"improvement_type": "N",
"improvement_details": {
"improvement_number": 19
},
"improvement_category": 5,
"energy_performance_rating": 83,
"environmental_impact_rating": 85
},
{
"sequence": 2,
"typical_saving": {
"value": 327,
"currency": "GBP"
},
"indicative_cost": "\u00a35,000 - \u00a38,000",
"improvement_type": "U",
"improvement_details": {
"improvement_number": 34
},
"improvement_category": 5,
"energy_performance_rating": 94,
"environmental_impact_rating": 95
}
],
"co2_emissions_potential": 0.1,
"energy_rating_potential": 94,
"lighting_cost_potential": {
"value": 57,
"currency": "GBP"
},
"schema_version_original": "LIG-17.0",
"hot_water_cost_potential": {
"value": 41,
"currency": "GBP"
},
"is_in_smoke_control_area": "unknown",
"renewable_heat_incentive": {
"rhi_new_dwelling": {
"space_heating": 3152,
"water_heating": 1780
}
},
"seller_commission_report": "Y",
"energy_consumption_current": 93,
"has_fixed_air_conditioning": "false",
"multiple_glazed_percentage": 100,
"calculation_software_version": 6.2,
"energy_consumption_potential": 6,
"environmental_impact_current": 84,
"current_energy_efficiency_band": "B",
"environmental_impact_potential": 95,
"has_heated_separate_conservatory": "false",
"potential_energy_efficiency_band": "A",
"co2_emissions_current_per_floor_area": 16
}

View file

@ -192,6 +192,12 @@ class SapVentilation:
has_draught_lobby: Optional[bool] = (
None # (13) gate (overrides .draught_lobby for §2 cascade)
)
# SAP 10.2 §2 (17) — air permeability at 50 Pa from a Blower Door
# pressure test (the standard q50 result lodged on full-SAP certs),
# m³/h per m² of envelope area. When present the cascade routes (18)
# via `(18) = AP50 / 20 + (8)` (matches Elmhurst worksheet lines
# 17/18). Distinct from `air_permeability_ap4_m3_h_m2` below.
air_permeability_ap50_m3_h_m2: Optional[float] = None
# SAP 10.2 §2 (17a) — air permeability at 4 Pa from the low-pressure
# Pulse pressure test, m³/h per m² of envelope area. When present the
# cascade routes (18) via the AP4 formula `0.263 × AP4^0.924 + (8)`.

View file

@ -2546,9 +2546,10 @@ _SAP_LIVING_AREA_FRACTION_BY_ROOMS: Final[Dict[int, float]] = {
def _sap_17_1_ventilation(schema: SapSchema17_1) -> SapVentilation:
"""D5-vent: map full-SAP `sap_ventilation` onto the domain `SapVentilation`.
The measured `air_permeability` feeds the engine's AP4 path directly (vs the
RdSAP age-band default); `ventilation_type` MechanicalVentilationKind name
(unknown code fails loud)."""
The measured `air_permeability` is a q50 Blower-Door result, so it feeds the
engine's **AP50** path (`(18) = AP50/20 + (8)`, per Elmhurst worksheet lines
17/18) NOT the AP4/Pulse formula; `ventilation_type`
MechanicalVentilationKind name (unknown code fails loud)."""
sv = schema.sap_ventilation
mv_kind: Optional[str] = None
if sv.ventilation_type is not None:
@ -2556,7 +2557,7 @@ def _sap_17_1_ventilation(schema: SapSchema17_1) -> SapVentilation:
raise UnmappedApiCode("ventilation_type", sv.ventilation_type)
mv_kind = _SAP_VENTILATION_TYPE_TO_MV_KIND[sv.ventilation_type]
return SapVentilation(
air_permeability_ap4_m3_h_m2=sv.air_permeability,
air_permeability_ap50_m3_h_m2=sv.air_permeability,
mechanical_ventilation_kind=mv_kind,
sheltered_sides=sv.sheltered_sides_count,
pressure_test=str(sv.pressure_test) if sv.pressure_test is not None else None,

View file

@ -4966,9 +4966,11 @@ def ventilation_from_cert(
if sv is not None and sv.suspended_timber_floor_sealed is not None
else spec_sealed
)
# SAP 10.2 §2 (17a) — AP4 pressure-test reading routes to the
# cascade's `(18) = 0.263 × AP4^0.924 + (8)` formula; absent value
# falls through to the components-based (16) ach.
# SAP 10.2 §2 (17) — q50 Blower-Door reading routes to `(18) = AP50/20
# + (8)` (preferred over AP4); (17a) — AP4/Pulse reading routes to
# `(18) = 0.263 × AP4^0.924 + (8)`. Absent values fall through to the
# components-based (16) ach.
ap50 = sv.air_permeability_ap50_m3_h_m2 if sv is not None else None
ap4 = sv.air_permeability_ap4_m3_h_m2 if sv is not None else None
# SAP 10.2 §2 (23a)/(24a..d) — MV kind dispatch chooses the (25)m
# effective-ach formula. The Elmhurst mapper translates the lodged
@ -5006,6 +5008,7 @@ def ventilation_from_cert(
has_draught_lobby=_has_draught_lobby(epc, sv),
window_pct_draught_proofed=float(epc.percent_draughtproofed or 0),
sheltered_sides=int(sv.sheltered_sides) if sv is not None and sv.sheltered_sides is not None else 2,
air_permeability_ap50=ap50,
air_permeability_ap4=ap4,
mv_kind=mv_kind,
mv_system_ach=mv_system_ach,

View file

@ -0,0 +1,71 @@
# Elmhurst RdSAP entry-tool automation (POC)
Automates most of the one manual step in `validate-cert-sap-accuracy`: re-keying
`elmhurst_inputs.md` into Elmhurst's web RdSAP entry tool and exporting the
**Input Summary** + **SAP Worksheets** PDFs (which `compare_epc_paths.py` then
consumes). Built on Playwright (Python).
Proven end-to-end on UPRN 10092973954: filled most pages automatically,
downloaded both PDFs, and `compare_epc_paths.py` reconciled to **our engine 77
vs Elmhurst worksheet 78** (engine-on-Elmhurst-inputs 79 — the calculator
reproduces accredited Elmhurst within ~1 SAP on identical inputs).
## Scripts
| Script | Does |
|---|---|
| `start_viewer.sh` | Xvfb→x11vnc→noVNC desktop on **port 6080** so you can SEE/click the headed browser (`DISPLAY=:99`). `bash scripts/hyde/start_viewer.sh` |
| `elmhurst_session.py` | `login` / `open` / `status` — persistent login (MFA by hand once; session in `.elmhurst-session/`, gitignored) |
| `elmhurst_explore.py` | dump a page's DOM (field ids, options, autopostback) or `--all` sections — how specs are built |
| `elmhurst_fill.py` | `--page <name> [--commit] [--commit-mode saveclose\|next]` — fill/clear a page from its `PageSpec` |
| `elmhurst_download.py` | downloads Input Summary + SAP Worksheets → the cert's corpus dir. **Never clicks Submit** (code-enforced) |
Typical run (browser appears on the noVNC desktop at port 6080):
```bash
bash scripts/hyde/start_viewer.sh
DISPLAY=:99 python scripts/hyde/elmhurst_session.py login --url https://members.elmhurstenergy.co.uk/
DISPLAY=:99 python scripts/hyde/elmhurst_fill.py --page property_description --commit
DISPLAY=:99 python scripts/hyde/elmhurst_download.py
```
## Hard-won mechanics (ASP.NET WebForms)
- Enter via the Guid URL (`…online…/WebFormAddress.aspx?Guid=…`); section nav is
full-form `__doPostBack` to a Guid-less subdomain — use `expect_navigation`.
- **Almost every field AutoPostBacks** (whole-page reload): set one field, wait,
re-locate the next. A 600 ms settle after each interaction stops flake.
- **Never re-click the active tab** (double-postback misbehaves) — `goto_section`
is current-page-aware.
- **Navigating away saves**; **Save & Close commits to the DATABASE** (visible to
other sessions). Next > only saves the in-progress session.
- Fields **auto-disable** when an upstream choice removes them (Room-in-Roof once
no room-in-roof; cylinder once combi) — skip them, don't fight them.
- Button ids vary per page → match by id suffix (`[id$='_ButtonSaveClose']`).
- Setup (done in container): `python -m playwright install chromium` +
`sudo python -m playwright install-deps chromium`.
## What's automated vs manual
**Automated** (in `PAGES` + special actions): Property Description, Dimensions,
Flats (position/floor/corridor), Walls (main + clear alt-wall), Roofs, Floors,
Space Heating (**boiler** via the cascade dialog → BGW combi, flue, secondary),
Water Heating (code; cylinder auto-clears with the combi), New Tech/Conservatory
(none) — plus the consolidated **clears** from the markdown.
The **boiler cascade dialog** is driven by `select_boiler_combi()`: open the
Main-Heating-code modal, set the leaf dropdown to *BGW Post 98 Combi condens.*,
click OK. The generic combi (SAP 104) moves SAP by ~0 vs the cert's exact PCDB
model, so it's accurate enough.
**Manual (🔸):**
- **Exact PCDB boiler model** (e.g. 17929) — its search field is *disabled*
(`aspNetDisabled`) in this UI state; the cascade's generic combi is the
automatable substitute (negligible SAP impact).
- **Control code 2110** and the **MV unit** — same modal-dialog pattern; can be
automated the same way as the boiler when wanted (open dialog → select → OK).
All 🔸 fields are flagged in `elmhurst_inputs.md`.
## Adding a field/page
1. `elmhurst_explore.py <guid-url> <buttonAction<Section>_Link>` to dump ids/options.
2. Add a `Field(...)` (or new `PageSpec`) in `elmhurst_fill.py`.
3. `--page <name>` (dry-run, screenshots to `elmhurst_dom/fill_<name>.png`), verify, then `--commit`.

View file

@ -0,0 +1,583 @@
{
"url": "https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx?Guid=B44A0DB4-4C08-4241-B818-86F060172105",
"title": "Elmhurst - Energy Report Address",
"controls": [
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxRefNo",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxRefNo",
"label": "Reference",
"value": "001431",
"disabled": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxPRRN",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxPRRN",
"label": "PRRN",
"value": "17482451",
"disabled": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxMyReference",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxMyReference",
"label": "",
"value": "Khalim-test",
"disabled": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListRegsRegion",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListRegsRegion",
"label": "Regs Region",
"value": "England",
"disabled": true,
"options": [
{
"value": "Scotland",
"text": "Scotland",
"selected": false
},
{
"value": "Northern Ireland",
"text": "Northern Ireland",
"selected": false
},
{
"value": "England",
"text": "England",
"selected": true
},
{
"value": "Wales",
"text": "Wales",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListRegion",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListRegion",
"label": "SAP Region",
"value": "Thames Valley",
"disabled": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Thames Valley",
"text": "Thames Valley",
"selected": true
},
{
"value": "South East England",
"text": "South East England",
"selected": false
},
{
"value": "Southern England",
"text": "Southern England",
"selected": false
},
{
"value": "South West England",
"text": "South West England",
"selected": false
},
{
"value": "Severn Valley",
"text": "Severn Valley",
"selected": false
},
{
"value": "Midlands",
"text": "Midlands",
"selected": false
},
{
"value": "West Pennines",
"text": "West Pennines",
"selected": false
},
{
"value": "North West England",
"text": "North West England",
"selected": false
},
{
"value": "South West Scotland",
"text": "South West Scotland",
"selected": false
},
{
"value": "Borders",
"text": "Borders",
"selected": false
},
{
"value": "North East England",
"text": "North East England",
"selected": false
},
{
"value": "East Pennines",
"text": "East Pennines",
"selected": false
},
{
"value": "East Anglia",
"text": "East Anglia",
"selected": false
},
{
"value": "Wales",
"text": "Wales",
"selected": false
},
{
"value": "West Scotland",
"text": "West Scotland",
"selected": false
},
{
"value": "East Scotland",
"text": "East Scotland",
"selected": false
},
{
"value": "North East Scotland",
"text": "North East Scotland",
"selected": false
},
{
"value": "Highland",
"text": "Highland",
"selected": false
},
{
"value": "Western Isles",
"text": "Western Isles",
"selected": false
},
{
"value": "Orkney",
"text": "Orkney",
"selected": false
},
{
"value": "Shetland",
"text": "Shetland",
"selected": false
},
{
"value": "Northern Ireland",
"text": "Northern Ireland",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxHouseName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxHouseName",
"label": "House Name",
"value": "28 Distillery Wharf",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxHouseNo",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxHouseNo",
"label": "House No",
"value": "28",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxStreet",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxStreet",
"label": "Street",
"value": "Distillery Wharf",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxLocality",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxLocality",
"label": "Locality",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxTown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxTown",
"label": "Town",
"value": "London",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxCounty",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxCounty",
"label": "County",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxPostCode",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxPostCode",
"label": "Post code",
"value": "W6 9BF",
"disabled": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_ImageButtonAddressSearch",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$ImageButtonAddressSearch",
"label": "",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelPostcodeSearch_TextBoxPostcode",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelPostcodeSearch$TextBoxPostcode",
"label": "Postcode",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelPostcodeSearch_TextBoxHouseNameNumber",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelPostcodeSearch$TextBoxHouseNameNumber",
"label": "House Name & No",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelAdvancedSearch_TextBoxAdvancedAddressLine1",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelAdvancedSearch$TextBoxAdvancedAddressLine1",
"label": "Address Line 1",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelAdvancedSearch_TextBoxAdvancedAddressLine2",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelAdvancedSearch$TextBoxAdvancedAddressLine2",
"label": "Address Line 2",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelAdvancedSearch_TextBoxAdvancedAddressLine3",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelAdvancedSearch$TextBoxAdvancedAddressLine3",
"label": "Address Line 3",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelAdvancedSearch_TextBoxAdvancedTown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelAdvancedSearch$TextBoxAdvancedTown",
"label": "Town",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelAdvancedSearch_TextBoxAdvancedPostcode",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelAdvancedSearch$TextBoxAdvancedPostcode",
"label": "Postcode",
"value": "",
"disabled": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelRequestNewUPRN_TextBoxRequestNewAddressLine1",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelRequestNewUPRN$TextBoxRequestNewAddressLine1",
"label": "Address Line 1",
"value": "",
"disabled": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelRequestNewUPRN_TextBoxRequestNewAddressLine2",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelRequestNewUPRN$TextBoxRequestNewAddressLine2",
"label": "Address Line 2",
"value": "",
"disabled": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelRequestNewUPRN_TextBoxRequestNewAddressLine3",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelRequestNewUPRN$TextBoxRequestNewAddressLine3",
"label": "Address Line 3",
"value": "",
"disabled": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelRequestNewUPRN_TextBoxRequestNewTown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelRequestNewUPRN$TextBoxRequestNewTown",
"label": "Town",
"value": "",
"disabled": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelRequestNewUPRN_TextBoxRequestNewPostcode",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelRequestNewUPRN$TextBoxRequestNewPostcode",
"label": "Postcode",
"value": "",
"disabled": true
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_AddressSearchDialog_TabContainerMain_TabPanelResults_ListBoxResults",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$AddressSearchDialog$TabContainerMain$TabPanelResults$ListBoxResults",
"label": "",
"value": "",
"disabled": false,
"options": []
}
],
"nav": [
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_ContentPlaceHolderNavigationsTop_LinkButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$MobileCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_ContentPlaceHolderNavigationsTop_MobileCancel"
},
{
"text": "Clear Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$MobileClearAddress\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentTopControls_ContentPlaceHolderNavigationsTop_MobileClearAddress"
},
{
"text": "Copy Assessment",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$MobileButtonCopy\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_ContentPlaceHolderNavigationsTop_MobileButtonCopy"
},
{
"text": "Clear Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$LinkButtonClearAddress\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_LinkButtonClearAddress"
},
{
"text": "Copy Assessment",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$LinkButtonCopy\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ContentPlaceHolderNavigations_LinkButtonCopy"
},
{
"text": "< Previous",
"href": null,
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$LinkButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ContentPlaceHolderNavigations_LinkButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatories",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Rooms In Roof",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoomInRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoomInRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,187 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormConservatories.aspx",
"title": "Elmhurst - Conservatory",
"controls": [
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_CheckBoxIsConservatory",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$CheckBoxIsConservatory",
"label": "Is there a conservatory?",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,254 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormDimensions.aspx",
"title": "Elmhurst - Dimensions",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_RadioButtonDimensionsType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$RadioButtonDimensionsType",
"label": "Type",
"value": "Internal",
"disabled": true,
"autopostback": false,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Internal",
"text": "Internal",
"selected": true
},
{
"value": "External",
"text": "External",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlDimensionsMain_TextBoxFloorAreaLowestFloor",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlDimensionsMain$TextBoxFloorAreaLowestFloor",
"label": "",
"value": "59.50",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlDimensionsMain_TextBoxRoomHeightLowestFloor",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlDimensionsMain$TextBoxRoomHeightLowestFloor",
"label": "",
"value": "2.40",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlDimensionsMain_TextBoxWallPerimeterLowestFloor",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlDimensionsMain$TextBoxWallPerimeterLowestFloor",
"label": "",
"value": "13.86",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlDimensionsMain_TextBoxPartyWallLengthLowestFloor",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlDimensionsMain$TextBoxPartyWallLengthLowestFloor",
"label": "",
"value": "13.86",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlDimensionsMain_CheckBoxHeatedBasement",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlDimensionsMain$CheckBoxHeatedBasement",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,270 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormFlats.aspx",
"title": "Elmhurst - Flats",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_RadioButtonListFlatCoridor",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$RadioButtonListFlatCoridor",
"label": "",
"value": "Unheated corridor",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "None",
"text": "None",
"selected": false
},
{
"value": "Heated",
"text": "Heated",
"selected": false
},
{
"value": "Unheated corridor",
"text": "Unheated corridor",
"selected": true
},
{
"value": "Unheated stairwell",
"text": "Unheated stairwell",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxLengthOfShelteredWall",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxLengthOfShelteredWall",
"label": "",
"value": "5.00",
"disabled": false,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListPositionOfFlat",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListPositionOfFlat",
"label": "",
"value": "Top Floor",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Ground Floor",
"text": "Ground Floor",
"selected": false
},
{
"value": "Mid Floor",
"text": "Mid Floor",
"selected": false
},
{
"value": "Top Floor",
"text": "Top Floor",
"selected": true
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxFloor",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxFloor",
"label": "",
"value": "16",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxStoriesInBlock",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxStoriesInBlock",
"label": "",
"value": "16",
"disabled": false,
"autopostback": true
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,298 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormFloors.aspx",
"title": "Elmhurst - Floors",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlFloorsMain_DropDownListLocation",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlFloorsMain$DropDownListLocation",
"label": "Location",
"value": "G Ground floor",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "G Ground floor",
"text": "G Ground floor",
"selected": true
},
{
"value": "P Above partially heated space",
"text": "P Above partially heated space",
"selected": false
},
{
"value": "U Above unheated space",
"text": "U Above unheated space",
"selected": false
},
{
"value": "E To external air",
"text": "E To external air",
"selected": false
},
{
"value": "A Another dwelling below",
"text": "A Another dwelling below",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlFloorsMain_DropDownListType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlFloorsMain$DropDownListType",
"label": "Type",
"value": "S Solid",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "S Solid",
"text": "S Solid",
"selected": true
},
{
"value": "T Suspended timber",
"text": "T Suspended timber",
"selected": false
},
{
"value": "N Suspended, not timber",
"text": "N Suspended, not timber",
"selected": false
},
{
"value": "U Unknown",
"text": "U Unknown",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlFloorsMain_DropDownListInsulation",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlFloorsMain$DropDownListInsulation",
"label": "Insulation",
"value": "A As built",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "A As built",
"text": "A As built",
"selected": true
},
{
"value": "R Retro-fitted",
"text": "R Retro-fitted",
"selected": false
},
{
"value": "U Unknown",
"text": "U Unknown",
"selected": false
}
]
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlFloorsMain_CheckBoxUValueKnown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlFloorsMain$CheckBoxUValueKnown",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,284 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormNewTechnologies.aspx",
"title": "Elmhurst - New Technologies",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelPhotovoltaicPanel_DropDownListPvPanelData",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelPhotovoltaicPanel$DropDownListPvPanelData",
"label": "Photovoltaic panel",
"value": "None",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "None",
"text": "None",
"selected": true
},
{
"value": "Panel details",
"text": "Panel details",
"selected": false
},
{
"value": "% of roof area",
"text": "% of roof area",
"selected": false
}
]
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelPhotovoltaicPanel_CheckBoxPvExportCapableMeter",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelPhotovoltaicPanel$CheckBoxPvExportCapableMeter",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindTurbine_DropDownListTerrainType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindTurbine$DropDownListTerrainType",
"label": "Terrain Type",
"value": "Urban",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Urban",
"text": "Urban",
"selected": true
},
{
"value": "Suburban",
"text": "Suburban",
"selected": false
},
{
"value": "Rural",
"text": "Rural",
"selected": false
}
]
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindTurbine_CheckBoxWindTurbinePresent",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindTurbine$CheckBoxWindTurbinePresent",
"label": "Wind turbine present?",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelSmallScaleHydro_TextBoxElectricityGenerated",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelSmallScaleHydro$TextBoxElectricityGenerated",
"label": "",
"value": "0.00",
"disabled": false,
"autopostback": true
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Add new battery storage",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelPhotovoltaicPanel$ButtonAddBatteryData','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelPhotovoltaicPanel_ButtonAddBatteryData"
},
{
"text": "Add new",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelSpecialFeatures$ButtonAddPanelData_SF','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelSpecialFeatures_ButtonAddPanelData_SF"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,682 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormOpenings.aspx",
"title": "Elmhurst - Openings",
"controls": [
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_DeleteButton_0",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl02$DeleteButton",
"label": "1",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_CopyButton_0",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl02$CopyButton",
"label": "1",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_DeleteButton_1",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl03$DeleteButton",
"label": "2",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_CopyButton_1",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl03$CopyButton",
"label": "2",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_DeleteButton_2",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl04$DeleteButton",
"label": "3",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_CopyButton_2",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl04$CopyButton",
"label": "3",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_DeleteButton_3",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl05$DeleteButton",
"label": "4",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_CopyButton_3",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl05$CopyButton",
"label": "4",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_TextBoxExtWidth",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$TextBoxExtWidth",
"label": "",
"value": "1.44",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_TextBoxExtHeight",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$TextBoxExtHeight",
"label": "",
"value": "1.00",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_TextBoxExtArea",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$TextBoxExtArea",
"label": "",
"value": "1.44",
"disabled": true,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtOpeningType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtOpeningType",
"label": "",
"value": "Window",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "Window",
"text": "Window",
"selected": true
},
{
"value": "Roof window",
"text": "Roof window",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtGlazing",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtGlazing",
"label": "",
"value": "Double with unknown install date",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Single glazing",
"text": "Single glazing",
"selected": false
},
{
"value": "Double pre 2002",
"text": "Double pre 2002",
"selected": false
},
{
"value": "Double between 2002 and 2021",
"text": "Double between 2002 and 2021",
"selected": false
},
{
"value": "Double post or during 2022",
"text": "Double post or during 2022",
"selected": false
},
{
"value": "Double with unknown install date",
"text": "Double with unknown install date",
"selected": true
},
{
"value": "Secondary glazing",
"text": "Secondary glazing",
"selected": false
},
{
"value": "Triple pre 2002",
"text": "Triple pre 2002",
"selected": false
},
{
"value": "Triple between 2002 and 2021",
"text": "Triple between 2002 and 2021",
"selected": false
},
{
"value": "Triple post or during 2022",
"text": "Triple post or during 2022",
"selected": false
},
{
"value": "Triple with unknown install date",
"text": "Triple with unknown install date",
"selected": false
},
{
"value": "Single glazing, known data",
"text": "Single glazing, known data",
"selected": false
},
{
"value": "Double glazing, known data",
"text": "Double glazing, known data",
"selected": false
},
{
"value": "Triple glazing, known data",
"text": "Triple glazing, known data",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtFrameType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtFrameType",
"label": "",
"value": "PVC",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "PVC",
"text": "PVC",
"selected": true
},
{
"value": "Wood",
"text": "Wood",
"selected": false
},
{
"value": "Metal",
"text": "Metal",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtGlazingGap",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtGlazingGap",
"label": "",
"value": "12 mm",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "6 mm",
"text": "6 mm",
"selected": false
},
{
"value": "12 mm",
"text": "12 mm",
"selected": true
},
{
"value": "16 mm or more",
"text": "16 mm or more",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtBuildingPartId",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtBuildingPartId",
"label": "",
"value": "Main",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Main",
"text": "Main",
"selected": true
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtLocation",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtLocation",
"label": "",
"value": "External wall",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "External wall",
"text": "External wall",
"selected": true
},
{
"value": "Alternative wall 1",
"text": "Alternative wall 1",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtOrientation",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtOrientation",
"label": "",
"value": "North",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "North",
"text": "North",
"selected": true
},
{
"value": "North East",
"text": "North East",
"selected": false
},
{
"value": "East",
"text": "East",
"selected": false
},
{
"value": "South East",
"text": "South East",
"selected": false
},
{
"value": "South",
"text": "South",
"selected": false
},
{
"value": "South West",
"text": "South West",
"selected": false
},
{
"value": "West",
"text": "West",
"selected": false
},
{
"value": "North West",
"text": "North West",
"selected": false
},
{
"value": "Horizontal",
"text": "Horizontal",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_TextBoxExtUValue",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$TextBoxExtUValue",
"label": "",
"value": "2.80",
"disabled": true,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_TextBoxExtGValue",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$TextBoxExtGValue",
"label": "",
"value": "0.76",
"disabled": true,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_CheckBoxExtDraughtProofed",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$CheckBoxExtDraughtProofed",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": true
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_DropDownListExtPermanentShutters",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$DropDownListExtPermanentShutters",
"label": "",
"value": "None",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "None",
"text": "None",
"selected": true
},
{
"value": "Uninsulated",
"text": "Uninsulated",
"selected": false
},
{
"value": "Insulated",
"text": "Insulated",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelDoorsPanel_TextBoxDoors",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelDoorsPanel$TextBoxDoors",
"label": "",
"value": "2",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelDoorsPanel_TextBoxDoorsInsulated",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelDoorsPanel$TextBoxDoorsInsulated",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelDoorsPanel_TextBoxDraughtProofedDoors",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelDoorsPanel$TextBoxDraughtProofedDoors",
"label": "",
"value": "2",
"disabled": false,
"autopostback": true
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Add new",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$ButtonAddWindow','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_ButtonAddWindow"
},
{
"text": "Glazing Type",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl01$lnkSortGlazingType\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_lnkSortGlazingType"
},
{
"text": "Orientation",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl01$lnkSortOrientation\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_lnkSortOrientation"
},
{
"text": "Building Part",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWindowsPanel$GridViewExtendedWidows$ctl01$lnkSortBuildingPart\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWindowsPanel_GridViewExtendedWidows_lnkSortBuildingPart"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,328 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormPropertyDetails.aspx",
"title": "Elmhurst - Property Details",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListPurpose",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListPurpose",
"label": "Assessment Purpose",
"value": "None of the above",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Retrofit - Pre assessment",
"text": "Retrofit - Pre assessment",
"selected": false
},
{
"value": "Retrofit - Post assessment",
"text": "Retrofit - Post assessment",
"selected": false
},
{
"value": "Retrofit - Modelling",
"text": "Retrofit - Modelling",
"selected": false
},
{
"value": "Energy Modelling (Not Retrofit)",
"text": "Energy Modelling (Not Retrofit)",
"selected": false
},
{
"value": "None of the above",
"text": "None of the above",
"selected": true
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListTenure",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListTenure",
"label": "Property Tenure",
"value": "Owner-occupied",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "Owner-occupied",
"text": "Owner-occupied",
"selected": true
},
{
"value": "Rented (social)",
"text": "Rented (social)",
"selected": false
},
{
"value": "Rented (private)",
"text": "Rented (private)",
"selected": false
},
{
"value": "Unknown",
"text": "Unknown",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListTransactionType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListTransactionType",
"label": "Transaction type",
"value": "Marketed sale",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "Marketed sale",
"text": "Marketed sale",
"selected": true
},
{
"value": "Non-marketed sale",
"text": "Non-marketed sale",
"selected": false
},
{
"value": "Rental",
"text": "Rental",
"selected": false
},
{
"value": "Stock condition survey",
"text": "Stock condition survey",
"selected": false
},
{
"value": "Grant scheme",
"text": "Grant scheme",
"selected": false
},
{
"value": "Non-grant scheme",
"text": "Non-grant scheme",
"selected": false
},
{
"value": "Re-mortgaging",
"text": "Re-mortgaging",
"selected": false
},
{
"value": "None of the above",
"text": "None of the above",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TextBoxInspectionDate",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TextBoxInspectionDate",
"label": "Inspection Date",
"value": "25/06/2025",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_EPCCreationReasonDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$EPCCreationReasonDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$ButtonInspectionDate\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_ButtonInspectionDate"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,373 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormRoofs.aspx",
"title": "Elmhurst - Roofs",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlRoofMain_DropDownListType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlRoofMain$DropDownListType",
"label": "Type",
"value": "PA Pitched (slates/tiles), access to loft",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "PA Pitched (slates/tiles), access to loft",
"text": "PA Pitched (slates/tiles), access to loft",
"selected": true
},
{
"value": "PN Pitched (slates/tiles), no access",
"text": "PN Pitched (slates/tiles), no access",
"selected": false
},
{
"value": "PS Pitched, sloping ceiling",
"text": "PS Pitched, sloping ceiling",
"selected": false
},
{
"value": "PT Pitched (thatch)",
"text": "PT Pitched (thatch)",
"selected": false
},
{
"value": "F Flat",
"text": "F Flat",
"selected": false
},
{
"value": "A Another dwelling above",
"text": "A Another dwelling above",
"selected": false
},
{
"value": "NR Non-residential space above",
"text": "NR Non-residential space above",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlRoofMain_DropDownListInsulationAt",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlRoofMain$DropDownListInsulationAt",
"label": "Insulation",
"value": "J Joists",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "N None",
"text": "N None",
"selected": false
},
{
"value": "J Joists",
"text": "J Joists",
"selected": true
},
{
"value": "R Rafters",
"text": "R Rafters",
"selected": false
},
{
"value": "U Unknown",
"text": "U Unknown",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlRoofMain_DropDownListThickness",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlRoofMain$DropDownListThickness",
"label": "Insulation Thickness",
"value": "270 mm",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "12 mm",
"text": "12 mm",
"selected": false
},
{
"value": "25 mm",
"text": "25 mm",
"selected": false
},
{
"value": "50 mm",
"text": "50 mm",
"selected": false
},
{
"value": "75 mm",
"text": "75 mm",
"selected": false
},
{
"value": "100 mm",
"text": "100 mm",
"selected": false
},
{
"value": "125 mm",
"text": "125 mm",
"selected": false
},
{
"value": "150 mm",
"text": "150 mm",
"selected": false
},
{
"value": "175 mm",
"text": "175 mm",
"selected": false
},
{
"value": "200 mm",
"text": "200 mm",
"selected": false
},
{
"value": "225 mm",
"text": "225 mm",
"selected": false
},
{
"value": "250 mm",
"text": "250 mm",
"selected": false
},
{
"value": "270 mm",
"text": "270 mm",
"selected": true
},
{
"value": "300 mm",
"text": "300 mm",
"selected": false
},
{
"value": "350 mm",
"text": "350 mm",
"selected": false
},
{
"value": "400+ mm",
"text": "400+ mm",
"selected": false
},
{
"value": "Unknown",
"text": "Unknown",
"selected": false
}
]
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_WebUserControlRoofMain_CheckBoxUvalueKnown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$WebUserControlRoofMain$CheckBoxUvalueKnown",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,231 @@
{
"url": "https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormSummary.aspx?Guid=B44A0DB4-4C08-4241-B818-86F060172105",
"title": "Elmhurst - Energy Report Summary",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_DropDownListOperationDepartments",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$DropDownListOperationDepartments",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": true
},
{
"value": "56203",
"text": "Sciana Systems Ltd (Office Department)",
"selected": false
},
{
"value": "59085",
"text": "Osmosis ACD Ltd (Operations Department)",
"selected": false
}
]
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_ExceptionDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$ExceptionDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious','')",
"onclick": "waitForAction();",
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": null,
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonClose','')",
"onclick": "waitForAction();",
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonClose"
},
{
"text": "Cancel",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$LinkButtonCancel','')",
"onclick": "this.disabled = true;",
"id": "ContentBody_ContentPlaceHolderNavigations_LinkButtonCancel"
},
{
"text": "Submit",
"href": null,
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_LinkButtonSubmitEPR"
},
{
"text": "Overview Report",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$LinkButtonPreviewDraftEPR','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_LinkButtonPreviewDraftEPR"
},
{
"text": "Input Summary",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$LinkButtonSummary','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_LinkButtonSummary"
},
{
"text": "Evidence",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$LinkButtonEvidence','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_LinkButtonEvidence"
},
{
"text": "SAP Worksheets",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$ButtonDebugInforPdf','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_ButtonDebugInforPdf"
},
{
"text": "OK",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$ExceptionDialog$LinkButtonOK','')",
"onclick": "hideDialog($('.ees-exception-dialog')); return false;",
"id": "ContentBody_ContentPlaceHolder1_ExceptionDialog_LinkButtonOK"
},
{
"text": "Energy Report Address",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionDimensions$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatories",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionConservatories$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionFlats$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionWalls$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionRoofs$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionFloors$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionOpenings$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionRecommendations$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionAddenda$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionResults$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$buttonActionSummary$Link','')",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,502 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormVentilationAndCooling.aspx",
"title": "Elmhurst - Ventilation and Cooling",
"controls": [
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxOpenChimneys",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxOpenChimneys",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxOpenFlues",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxOpenFlues",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxChimneysFluesClosedFire",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxChimneysFluesClosedFire",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxFluesSolidFuelBoiler",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxFluesSolidFuelBoiler",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxFluesOtherHeater",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxFluesOtherHeater",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxBlockedChimneys",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxBlockedChimneys",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxIntermittentFans",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxIntermittentFans",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxPassiveVents",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxPassiveVents",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_TextBoxFluelessGasFires",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$TextBoxFluelessGasFires",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_CheckBoxFixedSpaceCooling",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$CheckBoxFixedSpaceCooling",
"label": "Fixed space cooling",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelVentilationPanel_DropDownListDraughtLobby",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelVentilationPanel$DropDownListDraughtLobby",
"label": "Draught Lobby",
"value": "Unable to determine",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "Present",
"text": "Present",
"selected": false
},
{
"value": "Not present",
"text": "Not present",
"selected": false
},
{
"value": "Unable to determine",
"text": "Unable to determine",
"selected": true
}
]
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMechVent_CheckBoxMechanicalVentilation",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMechVent$CheckBoxMechanicalVentilation",
"label": "Mechanical ventilation",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelAirPressureTest_DropDownListTestMethod",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelAirPressureTest$DropDownListTestMethod",
"label": "Test Method",
"value": "Not available",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "Not available",
"text": "Not available",
"selected": true
},
{
"value": "Blower Door",
"text": "Blower Door",
"selected": false
},
{
"value": "Pulse",
"text": "Pulse",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelLighting_TextBoxLightsTotal",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelLighting$TextBoxLightsTotal",
"label": "",
"value": "6",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelLighting_CheckBoxLedAndCflLightsKnown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelLighting$CheckBoxLedAndCflLightsKnown",
"label": "Number of LED and CFL Known",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelLighting_TextBoxLedLightsTotal",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelLighting$TextBoxLedLightsTotal",
"label": "",
"value": "6",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelLighting_TextBoxCflLightsTotal",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelLighting$TextBoxCflLightsTotal",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelLighting_TextBoxLelLightsTotal",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelLighting$TextBoxLelLightsTotal",
"label": "",
"value": "6",
"disabled": true,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelLighting_TextBoxIncandescentLights",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelLighting$TextBoxIncandescentLights",
"label": "",
"value": "0",
"disabled": true,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_TextBoxFullSearch",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$TextBoxFullSearch",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_DropDownListMVType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$DropDownListMVType",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_DropDownListCurrentObsoleteModels",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$DropDownListCurrentObsoleteModels",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_TextBoxManufacturerName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$TextBoxManufacturerName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_TextBoxBrandName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$TextBoxBrandName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_TextBoxModelName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$TextBoxModelName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_TextBoxModelQualifier",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$TextBoxModelQualifier",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "MV search",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$HyperLinkActionMVSearch\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_HyperLinkActionMVSearch"
},
{
"text": "Advanced MV search",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectMVDialog$HyperLinkActionAdvancedSearch\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectMVDialog_HyperLinkActionAdvancedSearch"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,317 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormWalls.aspx",
"title": "Elmhurst - Walls",
"controls": [
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_DropDownListType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$DropDownListType",
"label": "Type",
"value": "TI Timber Frame",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "SG Stone: granite or whinstone",
"text": "SG Stone: granite or whinstone",
"selected": false
},
{
"value": "SS Stone: sandstone or limestone",
"text": "SS Stone: sandstone or limestone",
"selected": false
},
{
"value": "SO Solid Brick",
"text": "SO Solid Brick",
"selected": false
},
{
"value": "CO Cob",
"text": "CO Cob",
"selected": false
},
{
"value": "CA Cavity",
"text": "CA Cavity",
"selected": false
},
{
"value": "TI Timber Frame",
"text": "TI Timber Frame",
"selected": true
},
{
"value": "SY System Build",
"text": "SY System Build",
"selected": false
},
{
"value": "CW Curtain Wall",
"text": "CW Curtain Wall",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_DropDownListInsulation",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$DropDownListInsulation",
"label": "Insulation",
"value": "A As Built",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "I Internal",
"text": "I Internal",
"selected": false
},
{
"value": "A As Built",
"text": "A As Built",
"selected": true
},
{
"value": "U Unknown",
"text": "U Unknown",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_TextBoxWallThickness",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$TextBoxWallThickness",
"label": "Wall Thickness [mm]",
"value": "400",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_CheckBoxWallThicknessUnknown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$CheckBoxWallThicknessUnknown",
"label": "Wall Thickness Unknown",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_CheckBoxUvalueKnown",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$CheckBoxUvalueKnown",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_TextBoxAddWallArea",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$TextBoxAddWallArea",
"label": "Wall Area [m2]",
"value": "0.00",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMain_InnerTabContainerMain_TabPanelExternalWallMain_WebUserControlWallMain_TextBoxSecondAddWallArea",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelMain$InnerTabContainerMain$TabPanelExternalWallMain$WebUserControlWallMain$TextBoxSecondAddWallArea",
"label": "Wall Area [m2]",
"value": "0.00",
"disabled": false,
"autopostback": true
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,911 @@
{
"url": "https://rdsap10.elmhurstenergy.co.uk/Processing/WebFormWaterHeating.aspx",
"title": "Elmhurst - Water Heating",
"controls": [
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_TextBoxWaterHeatingCode",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$TextBoxWaterHeatingCode",
"label": "15.0 Water Heating",
"value": "HWP",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_CheckBoxHotWaterCylinder",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$CheckBoxHotWaterCylinder",
"label": "Hot Water Cylinder Present",
"value": "on",
"disabled": true,
"autopostback": false,
"checked": true
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_DropDownListCylinderSize",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$DropDownListCylinderSize",
"label": "",
"value": "Large",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "No Access",
"text": "No Access",
"selected": false
},
{
"value": "Normal",
"text": "Normal",
"selected": false
},
{
"value": "Medium",
"text": "Medium",
"selected": false
},
{
"value": "Large",
"text": "Large",
"selected": true
},
{
"value": "Value known",
"text": "Value known",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_DropDownListInsulated",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$DropDownListInsulated",
"label": "",
"value": "Foam",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "No Insulation",
"text": "No Insulation",
"selected": false
},
{
"value": "Jacket",
"text": "Jacket",
"selected": false
},
{
"value": "Foam",
"text": "Foam",
"selected": true
},
{
"value": "Measured Loss",
"text": "Measured Loss",
"selected": false
}
]
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_DropDownListInsulationThickness",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$DropDownListInsulationThickness",
"label": "",
"value": "120 mm",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "",
"text": "",
"selected": false
},
{
"value": "None",
"text": "None",
"selected": false
},
{
"value": "12 mm",
"text": "12 mm",
"selected": false
},
{
"value": "25 mm",
"text": "25 mm",
"selected": false
},
{
"value": "38 mm",
"text": "38 mm",
"selected": false
},
{
"value": "50 mm",
"text": "50 mm",
"selected": false
},
{
"value": "80 mm",
"text": "80 mm",
"selected": false
},
{
"value": "120 mm",
"text": "120 mm",
"selected": true
},
{
"value": "160 mm",
"text": "160 mm",
"selected": false
}
]
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_CheckBoxCylinderThermostat",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$CheckBoxCylinderThermostat",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelCommunityHeating_WebUserControlCommunityHeating_TextBoxCommunityHeatingPCDFBoilerReference",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelCommunityHeating$WebUserControlCommunityHeating$TextBoxCommunityHeatingPCDFBoilerReference",
"label": "PCDF boiler Reference",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelSolarCylinder_TabContainerSolar_TabPanelSolarDetails_CheckBoxSolaWaterHeating",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelSolarCylinder$TabContainerSolar$TabPanelSolarDetails$CheckBoxSolaWaterHeating",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWWHRS_DropDownListWWHRSPresent",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWWHRS$DropDownListWWHRSPresent",
"label": "",
"value": "No / Unknown",
"disabled": false,
"autopostback": true,
"options": [
{
"value": "No / Unknown",
"text": "No / Unknown",
"selected": true
},
{
"value": "Yes - Instantaneous Type",
"text": "Yes - Instantaneous Type",
"selected": false
},
{
"value": "Yes - Storage Type",
"text": "Yes - Storage Type",
"selected": false
}
]
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWWHRS_TextBoxRoomsWithBath",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWWHRS$TextBoxRoomsWithBath",
"label": "",
"value": "2",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWWHRS_TextBoxRoomsWithShowerAndBath",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWWHRS$TextBoxRoomsWithShowerAndBath",
"label": "",
"value": "0",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "image",
"id": null,
"name": null,
"label": "1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNonElectric \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNone\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDescription1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tTypeNon-electric shower\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tConnected toNone",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": null,
"name": null,
"label": "1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNonElectric \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNone\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDescription1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tTypeNon-electric shower\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tConnected toNone",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "image",
"id": null,
"name": null,
"label": "1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNonElectric \n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tNone\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tDescription1\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tTypeNon-electric shower\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\tConnected toNone",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelFGHRS_FGHRSMhs1_CheckBoxFGHRSPresent",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelFGHRS$FGHRSMhs1$CheckBoxFGHRSPresent",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "input",
"type": "checkbox",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelFGHRS_FGHRSMhs2_CheckBoxFGHRSPresent",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelFGHRS$FGHRSMhs2$CheckBoxFGHRSPresent",
"label": "",
"value": "on",
"disabled": false,
"autopostback": false,
"checked": false
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_TextBoxFullSearch",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$TextBoxFullSearch",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListBoilerType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListBoilerType",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListCurrentObsoleteModels",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListCurrentObsoleteModels",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListMainType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListMainType",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListMountingPosition",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListMountingPosition",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListFlueType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListFlueType",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListFuel",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListFuel",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListCondensing",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListCondensing",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListEfficiencyBands",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListEfficiencyBands",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_DropDownListFanAssistance",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$DropDownListFanAssistance",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_TextBoxManufacturerName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$TextBoxManufacturerName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_TextBoxBrandName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$TextBoxBrandName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_TextBoxModelName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$TextBoxModelName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_TextBoxModelQualifier",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$TextBoxModelQualifier",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_TextBoxFullSearch",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$TextBoxFullSearch",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_DropDownListType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$DropDownListType",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_DropDownListCurrentObsoleteModels",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$DropDownListCurrentObsoleteModels",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_TextBoxManufacturerName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$TextBoxManufacturerName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_TextBoxBrandName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$TextBoxBrandName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_TextBoxModelName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$TextBoxModelName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_TextBoxModelQualifier",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$TextBoxModelQualifier",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_TextBoxFullSearch",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$TextBoxFullSearch",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_DropDownListType",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$DropDownListType",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_DropDownListCurrentObsoleteModels",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$DropDownListCurrentObsoleteModels",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_TextBoxManufacturerName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$TextBoxManufacturerName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_TextBoxBrandName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$TextBoxBrandName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_TextBoxModelName",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$TextBoxModelName",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "text",
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_TextBoxModelQualifier",
"name": "ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$TextBoxModelQualifier",
"label": "",
"value": "",
"disabled": false,
"autopostback": true
},
{
"tag": "input",
"type": "image",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_ImageButtonCloseDialog",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$ImageButtonCloseDialog",
"label": "",
"value": "",
"disabled": false,
"autopostback": false
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList1",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$DropDownList1",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList2",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$DropDownList2",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList3",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$DropDownList3",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList4",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$DropDownList4",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList5",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$DropDownList5",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
},
{
"tag": "select",
"type": "select-one",
"id": "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList6",
"name": "ctl00$ctl00$ContentBody$OutsideUpdatePanel$SelectHeatingDialog$DropDownList6",
"label": "",
"value": "",
"disabled": false,
"autopostback": true,
"options": []
}
],
"nav": [
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl00\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$ContentPlaceHolderNavigationsTop$ctl01\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": null
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentTopControls$LinkButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentTopControls_LinkButtonSaveClose"
},
{
"text": "< Previous",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonPrevious\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonPrevious"
},
{
"text": "Next >",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolderNavigations$ButtonNext\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolderNavigations_ButtonNext"
},
{
"text": "Save & Close",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonSaveClose\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonSaveClose"
},
{
"text": "Cancel",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ButtonCancel\", \"\", true, \"\", \"\", false, true))",
"onclick": "this.disabled = true;",
"id": "ContentBody_ButtonCancel"
},
{
"text": "",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWaterHeating$ButtonWaterHeatingCode','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWaterHeating_ButtonWaterHeatingCode"
},
{
"text": "",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelCommunityHeating$WebUserControlCommunityHeating$ButtonCommunityHeatingBoilerReference','')",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelCommunityHeating_WebUserControlCommunityHeating_ButtonCommunityHeatingBoilerReference"
},
{
"text": "Add Showers",
"href": "javascript:__doPostBack('ctl00$ctl00$ContentBody$ContentPlaceHolder1$TabContainer$TabPanelWWHRS$ButtonAddShower','')",
"onclick": "addFlag();",
"id": "ContentBody_ContentPlaceHolder1_TabContainer_TabPanelWWHRS_ButtonAddShower"
},
{
"text": "Boiler search",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$HyperLinkActionBoilerSearch\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_HyperLinkActionBoilerSearch"
},
{
"text": "Advanced boiler search",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$HyperLinkActionAdvancedSearch\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_HyperLinkActionAdvancedSearch"
},
{
"text": "Community heating networks",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectBoilerDialog$HyperLinkActionCommunityHeatingNetworks\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectBoilerDialog_HyperLinkActionCommunityHeatingNetworks"
},
{
"text": "WWHRS search",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectWwhrsDialog$HyperLinkActionSearch\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectWwhrsDialog_HyperLinkActionSearch"
},
{
"text": "FGHRS search",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$ContentPlaceHolder1$SelectFghrsDialog$HyperLinkActionSearch\", \"\", true, \"\", \"\", false, true))",
"onclick": null,
"id": "ContentBody_ContentPlaceHolder1_SelectFghrsDialog_HyperLinkActionSearch"
},
{
"text": "Energy Report Address",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionEPCAddress$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionEPCAddress_Link"
},
{
"text": "Property Details",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDetails$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDetails_Link"
},
{
"text": "Property Description",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionPropertyDescription$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionPropertyDescription_Link"
},
{
"text": "Dimensions",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionDimensions$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionDimensions_Link"
},
{
"text": "Conservatory",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionConservatories$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionConservatories_Link"
},
{
"text": "Flats",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFlats$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFlats_Link"
},
{
"text": "Walls",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWalls$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWalls_Link"
},
{
"text": "Roofs",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRoofs$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRoofs_Link"
},
{
"text": "Floors",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionFloors$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionFloors_Link"
},
{
"text": "Openings",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionOpenings$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionOpenings_Link"
},
{
"text": "Ventilation & Lighting",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionVentilationAndCooling$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionVentilationAndCooling_Link"
},
{
"text": "Space Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSpaceHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSpaceHeating_Link"
},
{
"text": "Water Heating",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionWaterHeating$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionWaterHeating_Link"
},
{
"text": "New Technologies",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionNewTechnologies$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionNewTechnologies_Link"
},
{
"text": "Recommendations",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionRecommendations$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionRecommendations_Link"
},
{
"text": "Addenda",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionAddenda$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionAddenda_Link"
},
{
"text": "Technical Advice",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionTechnicalAdvice$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionTechnicalAdvice_Link"
},
{
"text": "Results",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionResults$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionResults_Link"
},
{
"text": "Energy Report Summary",
"href": "javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(\"ctl00$ctl00$ContentBody$buttonActionSummary$Link\", \"\", true, \"\", \"\", false, true))",
"onclick": "waitForAction(this);",
"id": "ContentBody_buttonActionSummary_Link"
},
{
"text": "Useful Links",
"href": "http://www.elmhurstenergy.co.uk/useful-links",
"onclick": null,
"id": null
},
{
"text": "Contact Us",
"href": "http://www.elmhurstenergy.co.uk/contact-us",
"onclick": null,
"id": null
}
]
}

View file

@ -0,0 +1,103 @@
"""Download the Input Summary + SAP Worksheets PDFs from Elmhurst (POC).
Closes the validate-cert loop's only manual export: pulls the two PDFs off the
Energy Report Summary page and saves them where `compare_epc_paths.py` reads:
* Input Summary -> elmhurst_summary.pdf (inputs; parse_site_notes_pdf -> EpcPropertyData)
* SAP Worksheets -> elmhurst_worksheet.pdf (the SAP calculation)
DISPLAY=:99 python scripts/hyde/elmhurst_download.py
SAFETY: this script clicks ONLY the two report buttons below. It NEVER clicks
Submit (`LinkButtonSubmitEPR`) submitting lodges the assessment. The allow-list
is enforced in code.
"""
from __future__ import annotations
import sys
from pathlib import Path
from playwright.sync_api import (
Page,
TimeoutError as PlaywrightTimeoutError,
sync_playwright,
)
HERE = Path(__file__).parent
SESSION_DIR = HERE / ".elmhurst-session"
SAMPLE_DIR = (
HERE.parent.parent
/ "backend/epc_api/json_samples/real_life_examples"
/ "SAP-Schema-17.1/uprn_10092973954"
)
ASSESSMENT_GUID = "B44A0DB4-4C08-4241-B818-86F060172105"
ENTRY_URL = (
"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx"
f"?Guid={ASSESSMENT_GUID}"
)
# (button id, output filename). The ONLY buttons this script may click.
REPORTS: list[tuple[str, str]] = [
("ContentBody_ContentPlaceHolder1_LinkButtonSummary", "elmhurst_summary.pdf"),
("ContentBody_ContentPlaceHolder1_ButtonDebugInforPdf", "elmhurst_worksheet.pdf"),
]
# Buttons this script must NEVER touch (belt-and-braces).
_FORBIDDEN = {"ContentBody_ContentPlaceHolder1_LinkButtonSubmitEPR"}
def _download_one(page: Page, button_id: str, out: Path) -> bool:
assert button_id not in _FORBIDDEN, f"refusing to click forbidden {button_id}"
print(f" clicking {button_id} -> {out.name} ...", flush=True)
try:
with page.expect_download(timeout=60_000) as dl:
page.click(f"#{button_id}", timeout=20_000)
dl.value.save_as(str(out))
except PlaywrightTimeoutError:
# Some report buttons open the PDF in a popup rather than a download.
try:
with page.expect_popup(timeout=10_000) as pop:
page.click(f"#{button_id}", timeout=20_000)
popup = pop.value
with popup.expect_download(timeout=30_000) as dl2:
pass
dl2.value.save_as(str(out))
except PlaywrightTimeoutError:
print(f" !! no download/popup for {button_id}", flush=True)
return False
size = out.stat().st_size if out.exists() else 0
print(f" saved {out} ({size:,} bytes)", flush=True)
return out.exists() and size > 0
def download_reports() -> int:
SAMPLE_DIR.mkdir(parents=True, exist_ok=True)
ok = True
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir=str(SESSION_DIR),
headless=False,
accept_downloads=True,
viewport={"width": 1400, "height": 1000},
)
page = context.pages[0] if context.pages else context.new_page()
page.on("dialog", lambda d: d.accept())
print(f"entering assessment {ASSESSMENT_GUID} ...", flush=True)
page.goto(ENTRY_URL, wait_until="networkidle", timeout=60_000)
print("navigating to Energy Report Summary ...", flush=True)
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click("#ContentBody_buttonActionSummary_Link", timeout=15_000)
page.wait_for_timeout(600)
for button_id, fname in REPORTS:
ok = _download_one(page, button_id, SAMPLE_DIR / fname) and ok
page.wait_for_timeout(600)
context.close()
print("DONE." if ok else "DONE (with errors — see above).", flush=True)
return 0 if ok else 1
if __name__ == "__main__":
sys.exit(download_reports())

View file

@ -0,0 +1,186 @@
"""Dump the real DOM of an Elmhurst RdSAP-10-Online page (dev tool).
The entry tool is an ASP.NET WebForms app: field IDs are server-generated
(``ctl00_ctl00_ContentBody_...``) and many controls postback on change. We
can't guess selectors, so this reads them off the live page. Reuses the saved
persistent session (no login needed). Run it on the viewer display:
DISPLAY=:99 python scripts/hyde/elmhurst_explore.py "<assessment-url>"
Writes, next to this file:
* elmhurst_dom/<page>.png screenshot (confirms we're authenticated)
* elmhurst_dom/<page>.json every input/select/textarea + the left-nav links
It navigates, dumps, and exits (releasing the profile lock for the next step).
"""
from __future__ import annotations
import json
import re
import sys
from pathlib import Path
from typing import Any
from playwright.sync_api import sync_playwright
HERE = Path(__file__).parent
SESSION_DIR = HERE / ".elmhurst-session"
OUT_DIR = HERE / "elmhurst_dom"
# Runs in the page to harvest every form control + the section nav, with the
# label text an assessor reads — so we can tie markdown fields to server IDs.
_DUMP_JS = r"""
() => {
const labelFor = (el) => {
if (el.id) {
const l = document.querySelector(`label[for="${el.id}"]`);
if (l) return l.innerText.trim();
}
// WebForms often puts the caption in a sibling cell, not a <label>.
const row = el.closest('tr');
if (row) {
const firstCell = row.querySelector('td, th');
if (firstCell && !firstCell.contains(el)) return firstCell.innerText.trim();
}
return '';
};
const ctrl = (el) => {
const base = {
tag: el.tagName.toLowerCase(),
type: el.type || null,
id: el.id || null,
name: el.getAttribute('name') || null,
label: labelFor(el),
value: el.value ?? null,
disabled: el.disabled || false,
autopostback: /__doPostBack/.test(el.getAttribute('onchange') || ''),
};
if (el.tagName.toLowerCase() === 'select') {
base.options = Array.from(el.options).map(o => ({
value: o.value, text: o.text.trim(), selected: o.selected,
}));
}
if (el.type === 'checkbox' || el.type === 'radio') base.checked = el.checked;
return base;
};
const controls = Array.from(
document.querySelectorAll('input, select, textarea')
).filter(el => el.type !== 'hidden').map(ctrl);
// Capture every link/clickable with its RAW href + onclick so we can see
// how page nav works (URL vs __doPostBack) and the real .aspx page names.
const nav = Array.from(
document.querySelectorAll('a, input[type=button], input[type=submit]')
).map(a => ({
text: (a.innerText || a.value || '').trim(),
href: a.getAttribute('href') || null,
onclick: a.getAttribute('onclick') || null,
id: a.id || null,
})).filter(a => a.text || a.href || a.onclick);
return { url: location.href, title: document.title, controls, nav };
}
"""
def _slug(url: str) -> str:
m = re.search(r"WebForm(\w+)\.aspx", url)
return (m.group(1) if m else "page").lower()
def explore(url: str, click_id: str | None = None) -> dict[str, Any]:
OUT_DIR.mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir=str(SESSION_DIR),
headless=False,
accept_downloads=True,
viewport={"width": 1400, "height": 1000},
)
page = context.pages[0] if context.pages else context.new_page()
page.goto(url, wait_until="networkidle", timeout=60_000)
if click_id:
# Left-rail nav is a full-form __doPostBack: it navigates to
# rdsap10.elmhurstenergy.co.uk/Processing/WebForm<Section>.aspx
# (no Guid — the assessment is bound to the server session). Must
# wait for the navigation, not just networkidle.
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click(f"#{click_id}", timeout=15_000)
slug = _slug(page.url)
if click_id:
slug = click_id.split("buttonAction")[-1].split("_")[0].lower() or slug
shot = OUT_DIR / f"{slug}.png"
page.screenshot(path=str(shot))
dump: dict[str, Any] = page.evaluate(_DUMP_JS)
(OUT_DIR / f"{slug}.json").write_text(json.dumps(dump, indent=2))
context.close()
controls = dump["controls"]
print(f"landed on : {dump['url']}")
print(f"title : {dump['title']}")
print(f"screenshot: {shot}")
print(f"controls : {len(controls)} (json: {OUT_DIR / (slug + '.json')})")
if "Login" in dump["title"] or "login" in dump["url"].lower():
print("!! looks like a LOGIN page — session may have expired; re-run login.")
return dump
# Sections that aren't data-entry (or are terminal) — skip when dumping all.
_SKIP_SECTIONS = {
"EPCAddress", "Recommendations", "Addenda", "TechnicalAdvice",
"Results", "Summary",
}
def explore_all(url: str) -> None:
"""Enter once and click through every data section, dumping each. Read-only
(we don't change fields), though navigating re-saves the current page."""
OUT_DIR.mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir=str(SESSION_DIR),
headless=False,
accept_downloads=True,
viewport={"width": 1400, "height": 1000},
)
page = context.pages[0] if context.pages else context.new_page()
page.goto(url, wait_until="networkidle", timeout=60_000)
# Discover the section nav links in rail order.
links: list[dict[str, str]] = page.eval_on_selector_all(
"a[id^='ContentBody_buttonAction']",
"els => els.map(e => ({id: e.id, text: e.innerText.trim()}))",
)
targets = [
(re.sub(r"ContentBody_buttonAction(\w+)_Link", r"\1", lk["id"]), lk["id"])
for lk in links
if re.sub(r"ContentBody_buttonAction(\w+)_Link", r"\1", lk["id"])
not in _SKIP_SECTIONS
]
print(f"dumping {len(targets)} sections: {[t[0] for t in targets]}", flush=True)
for name, link_id in targets:
try:
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click(f"#{link_id}", timeout=15_000)
page.wait_for_timeout(500)
slug = name.lower()
page.screenshot(path=str(OUT_DIR / f"{slug}.png"))
dump: dict[str, Any] = page.evaluate(_DUMP_JS)
(OUT_DIR / f"{slug}.json").write_text(json.dumps(dump, indent=2))
n = len([c for c in dump["controls"] if c.get("type") != "hidden"])
print(f" {name:22s} -> {n:3d} controls", flush=True)
except Exception as exc: # keep going; one bad page shouldn't abort
print(f" {name:22s} -> FAILED: {repr(exc)[:80]}", flush=True)
context.close()
if __name__ == "__main__":
if len(sys.argv) < 2:
print("usage: elmhurst_explore.py <assessment-url> [nav-link-id | --all]")
raise SystemExit(2)
if sys.argv[-1] == "--all":
explore_all(sys.argv[1])
else:
explore(sys.argv[1], sys.argv[2] if len(sys.argv) > 2 else None)

View file

@ -0,0 +1,311 @@
"""Fill Elmhurst RdSAP-10-Online pages from known field values (POC).
Re-keys UPRN 10092973954 (the flat in elmhurst_inputs.md) into Elmhurst's web
entry tool. Reuses the saved persistent session and the viewer display.
# dry-run one page (fills, screenshots, does NOT navigate away => not saved):
DISPLAY=:99 python scripts/hyde/elmhurst_fill.py --page dimensions
# commit it (clicks Next > which saves AND advances):
DISPLAY=:99 python scripts/hyde/elmhurst_fill.py --page dimensions --commit
Mechanics learned from the live DOM (see elmhurst_explore.py):
* ASP.NET WebForms. Almost every control **AutoPostBacks** the whole page
reloads on change so we set ONE field, wait for the postback, then
re-locate the next field (old handles go stale). A short settle after each
interaction stops the next change being missed.
* Enter via the Guid URL; section nav is a full-form __doPostBack. Navigating
to another section **saves** the current page (so Next > = save + advance).
* NEVER re-click the section tab you're already on — it double-postbacks and
misbehaves. goto_section() checks the current URL and only clicks if the
target is a different page.
* Dropdown option values carry a code prefix ("F Flat", "L 2012-2022").
"""
from __future__ import annotations
import argparse
import sys
from dataclasses import dataclass
from pathlib import Path
from typing import Callable, Literal
from playwright.sync_api import (
Page,
TimeoutError as PlaywrightTimeoutError,
sync_playwright,
)
HERE = Path(__file__).parent
SESSION_DIR = HERE / ".elmhurst-session"
SHOT_DIR = HERE / "elmhurst_dom"
ASSESSMENT_GUID = "B44A0DB4-4C08-4241-B818-86F060172105"
ENTRY_URL = (
"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx"
f"?Guid={ASSESSMENT_GUID}"
)
FIELD_PREFIX = "ContentBody_ContentPlaceHolder1_"
NAV_PREFIX = "ContentBody_buttonAction"
# WebForms reattaches client JS after each postback; act too fast and the next
# change is missed. A short settle after every interaction fixes the flake.
SETTLE_MS = 600
@dataclass
class Field:
"""One value to set. ``suffix`` is appended to FIELD_PREFIX to form the id.
``kind`` selects how we set it; ``autopostback`` whether the page reloads."""
suffix: str
kind: Literal["text", "select", "checkbox"]
value: str # for checkbox: "on" to check, "off" to uncheck
autopostback: bool
note: str = ""
@dataclass
class PageSpec:
"""A section: how to reach it, how to know we're on it, and what to set."""
nav: str # the buttonAction<Section> id segment, e.g. "PropertyDescription"
url_fragment: str # appears in page.url when this section is showing
fields: list[Field]
# Dimensions Main-tab controls sit under a deep WebUserControl path.
_DIM_MAIN = "TabContainer_TabPanelMain_WebUserControlDimensionsMain_"
# Walls main external-wall controls sit under an even deeper nested-tab path.
_WALL_MAIN = (
"TabContainer_TabPanelMain_InnerTabContainerMain_"
"TabPanelExternalWallMain_WebUserControlWallMain_"
)
# UPRN 10092973954 (flat) — values from elmhurst_inputs.md.
# NOTE age band: 2020 build => Elmhurst "L 2012-2022" (by year), though our
# engine labels construction_age_band "M".
PAGES: dict[str, PageSpec] = {
"property_description": PageSpec(
nav="PropertyDescription",
url_fragment="WebFormPropertyDescription.aspx",
fields=[
Field("DropDownListPropertyType1", "select", "F Flat", True, "property_type 2"),
Field("DropDownListPropertyType2", "select", "D Detached", True, "built_form 1"),
Field("TextBoxStoreys", "text", "1", True, "single storey"),
Field("TextBoxHabitableRooms", "text", "3", False, "habitable_rooms 3"),
Field("TextBoxHeatedHabitableRooms", "text", "3", True, "all heated"),
Field("DropDownListDateBuiltMain", "select", "L 2012-2022", True, "2020 build"),
Field("DropDownListDateBuiltFirst", "select", "", True, "no 1st extension — clear"),
Field("DropDownListRoomInRoofMain", "select", "", True, "no room in roof — clear"),
],
),
"dimensions": PageSpec(
nav="Dimensions",
url_fragment="WebFormDimensions.aspx",
fields=[
# Single-storey ground-floor flat => everything on the Lowest Floor
# row of the Main tab. Heat-loss perimeter 38.14 m, no party wall.
# (Type is already "Internal" and locks once dimensions exist — skip.)
Field(f"{_DIM_MAIN}TextBoxFloorAreaLowestFloor", "text", "67.84", True, "engine TFA"),
Field(f"{_DIM_MAIN}TextBoxRoomHeightLowestFloor", "text", "2.40", True, "vol/area"),
Field(f"{_DIM_MAIN}TextBoxWallPerimeterLowestFloor", "text", "38.14", True, "heat-loss perimeter"),
Field(f"{_DIM_MAIN}TextBoxPartyWallLengthLowestFloor", "text", "0", True, "no party wall"),
# NB: Room-in-Roof area field is auto-DISABLED once Property
# Description declares no room-in-roof, so we don't (can't) set it.
],
),
"flats": PageSpec(
nav="Flats",
url_fragment="WebFormFlats.aspx",
fields=[
Field("DropDownListPositionOfFlat", "select", "Ground Floor", True, "ground-floor flat"),
Field("TextBoxFloor", "text", "0", True, "ground = storey 0"),
# Corridor None => all-exposed build (matches engine: stair wall is
# exposed, not sheltered). Leaving "Unheated corridor" forces a
# sheltered alternative wall on the Walls page (validation ✖).
Field("RadioButtonListFlatCoridor", "select", "None", True, "no unheated corridor — all-exposed"),
# 🔸 StoriesInBlock is assessor-only (EPC can't supply).
],
),
"space_heating": PageSpec(
nav="SpaceHeating",
url_fragment="WebFormSpaceHeating.aspx",
fields=[
# NB: PCDF boiler reference is READ-ONLY (set via SelectBoilerDialog,
# not typeable) — boiler PCDB 17929 must be driven through the dialog.
# Room-sealed boiler => Balanced flue (cert is_flue_fan_present true).
Field(
"TabPanelMainHeating1_MainHeating1_RadioButtonListFlueType",
"select", "Balanced", True, "room-sealed; main_heating_flue_type 2",
),
# secondary_heating_category 1 = None — clears the placeholder 'RWM'.
Field("DropDownListSecondaryHeatingPresent", "select", "No", True, "no secondary heating"),
# 🔸 boiler PCDB 17929 + control 2110 go via search dialogs (manual).
],
),
"water_heating": PageSpec(
nav="WaterHeating",
url_fragment="WebFormWaterHeating.aspx",
fields=[
# Combi / instantaneous — no cylinder (clears CylinderSize/Insulated/…).
Field("TabPanelWaterHeating_CheckBoxHotWaterCylinder", "checkbox", "off", True, "no cylinder"),
# 🔸 water-heating code (from main, 901) via its dialog (manual).
],
),
"walls": PageSpec(
nav="Walls",
url_fragment="WebFormWalls.aspx",
fields=[
# Main wall is already correct (TI Timber Frame / As Built). Just
# clear the leftover Alternative Wall 1 (Solid Brick placeholder) by
# zeroing its area — our wall is a single timber-frame element.
Field(f"{_WALL_MAIN}TextBoxAddWallArea", "text", "0", True, "clear placeholder alt wall"),
],
),
"roofs": PageSpec(
nav="Roofs",
url_fragment="WebFormRoofs.aspx",
fields=[
# roof = "(other premises above)" => no roof heat loss. Selecting
# this disables the insulation/thickness fields (nothing to clear).
Field(
"TabContainer_TabPanelMain_WebUserControlRoofMain_DropDownListType",
"select", "A Another dwelling above", True, "roof_w_per_k = 0",
),
],
),
}
def _commit(page: Page, action: Callable[[], object]) -> None:
"""Run a control change that triggers an ASP.NET postback and wait for the
page to come back: full-form AutoPostBack => navigation; fall back to
networkidle for a partial/no postback."""
try:
with page.expect_navigation(wait_until="load", timeout=8_000):
action()
except PlaywrightTimeoutError:
page.wait_for_load_state("networkidle", timeout=8_000)
def _set_field(page: Page, f: Field) -> None:
loc = page.locator(f"#{FIELD_PREFIX}{f.suffix}") # re-located each call
if f.kind == "select":
if f.autopostback:
_commit(page, lambda: loc.select_option(f.value))
else:
loc.select_option(f.value)
elif f.kind == "checkbox":
check = loc.check if f.value == "on" else loc.uncheck
if f.autopostback:
_commit(page, check)
else:
check()
else: # text
loc.fill(f.value)
if f.autopostback:
_commit(page, lambda: loc.press("Tab")) # blur fires onchange
page.wait_for_timeout(SETTLE_MS) # half-beat so WebForms reattaches
print(f" set {f.suffix.split('_')[-1]:32s} = {f.value!r} ({f.note})", flush=True)
def select_boiler_combi(page: Page) -> None:
"""Drive the Main-Heating cascade dialog to a mains-gas condensing combi
(EES code BGW = SAP 104). The exact-model PCDB path is disabled
(aspNetDisabled), so the cascade's generic combi is the automatable choice;
its efficiency barely moves SAP for fabric-dominated dwellings. Selecting a
combi also drops the HW cylinder on the Water Heating page."""
mh1 = (
"ContentBody_ContentPlaceHolder1_TabContainer_TabPanelMainHeating1_"
"WebUserControlMainHeating1_"
)
dd6 = "ContentBody_OutsideUpdatePanel_SelectHeatingDialog_DropDownList6"
page.click(f"#{mh1}ButtonMainHeatingCode", timeout=10_000) # open cascade
page.wait_for_timeout(SETTLE_MS)
# Levels 1-5 (Gas/Mains gas/Boilers/Post 1998/Condensing) are already the
# default path; only the leaf differs (regular BGB -> combi BGW).
page.select_option(f"#{dd6}", label="BGW Post 98 Combi condens. with auto ign.")
page.wait_for_timeout(SETTLE_MS)
page.get_by_text("OK", exact=True).first.click(timeout=10_000) # apply
page.wait_for_timeout(SETTLE_MS * 2)
print(" boiler -> BGW (SAP 104, condensing combi)", flush=True)
def goto_section(page: Page, spec: PageSpec) -> None:
"""Navigate to a section — but never re-click the tab we're already on
(that double-postbacks and misbehaves)."""
if spec.url_fragment in page.url:
print(f"already on {spec.nav}", flush=True)
return
print(f"navigating to {spec.nav} ...", flush=True)
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click(f"#{NAV_PREFIX}{spec.nav}_Link", timeout=15_000)
page.wait_for_timeout(SETTLE_MS)
def fill_page(page_key: str, commit: bool, commit_mode: str = "saveclose") -> None:
spec = PAGES[page_key]
SHOT_DIR.mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir=str(SESSION_DIR),
headless=False,
accept_downloads=True,
viewport={"width": 1400, "height": 1000},
)
page = context.pages[0] if context.pages else context.new_page()
page.on("dialog", lambda d: d.accept()) # auto-dismiss confirm dialogs
print(f"entering assessment {ASSESSMENT_GUID} ...", flush=True)
page.goto(ENTRY_URL, wait_until="networkidle", timeout=60_000)
goto_section(page, spec)
if page_key == "space_heating":
# Boiler is a cascade-dialog field — set it before the row fields
# (it postbacks and can reset flue, so flue is set after).
select_boiler_combi(page)
print(f"filling {page_key}:", flush=True)
for f in spec.fields:
_set_field(page, f)
page.screenshot(path=str(SHOT_DIR / f"fill_{page_key}.png"))
print(f"screenshot: {SHOT_DIR / f'fill_{page_key}.png'}", flush=True)
if commit:
# Save & Close commits to the DATABASE (visible to other sessions);
# Next > only saves into the in-progress server session. Default to
# Save & Close so saved results show up elsewhere.
# The body button's container path varies per page (Address nests
# it, content pages don't), so match by id suffix. The top-bar copy
# is a *Link*ButtonSaveClose, so "_ButtonSaveClose" hits only body.
suffix = "_ButtonSaveClose" if commit_mode == "saveclose" else "_ButtonNext"
print(f"committing ({commit_mode}) ...", flush=True)
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click(f"[id$='{suffix}']", timeout=15_000)
page.wait_for_timeout(SETTLE_MS)
print(f"saved. now on: {page.url}", flush=True)
page.screenshot(path=str(SHOT_DIR / f"after_{page_key}.png"))
else:
print("DRY-RUN: not saved. Re-run with --commit to persist.", flush=True)
context.close()
def main(argv: list[str] | None = None) -> int:
ap = argparse.ArgumentParser(description="Fill an Elmhurst RdSAP page (POC).")
ap.add_argument("--page", default="property_description", choices=sorted(PAGES))
ap.add_argument("--commit", action="store_true", help="persist (else dry-run)")
ap.add_argument(
"--commit-mode",
default="saveclose",
choices=("saveclose", "next"),
help="saveclose = DB commit (visible elsewhere); next = save + advance",
)
args = ap.parse_args(argv)
fill_page(args.page, commit=args.commit, commit_mode=args.commit_mode)
return 0
if __name__ == "__main__":
sys.exit(main())

View file

@ -0,0 +1,228 @@
"""Reusable Elmhurst RdSAP-10-Online automation helpers (campaign edition).
Why this exists: the per-cert build in the `expand-sap-accuracy-corpus` loop is
the slow, flaky part. `elmhurst_fill.py` hard-codes one cert's values and relies
on a *persisted* login session but Elmhurst's auth is a **session cookie** that
Playwright's persistent context does NOT reliably restore across process launches.
This module sidesteps both problems:
* **Log in fresh each run** (creds from env `ELM_ACCESS`/`ELM_PWD`, else a
gitignored `scripts/hyde/.elmhurst-creds.json` {"access","pwd"}). Assessment
DATA persists server-side via *Save & Close*, so re-login per run is fine and
you can build/verify one page at a time across separate processes.
* **Headed on the noVNC display** (`DISPLAY=:99`; run `start_viewer.sh` first).
Hard-won Elmhurst-DOM gotchas baked into the helpers below (see SKILL.md too):
* Most controls AutoPostBack set one field, wait for the postback, re-locate.
* Sub-tabs (Doors, Air Pressure Test, Lighting, Water-Heating FGHRS) are
AjaxControlToolkit tabs: their fields are in the DOM but NOT visible until the
tab span `#__tab_<panelId>` is clicked. Use `click_tab()`.
* Delete is a Yes/No MODAL (not a native dialog): click the row delete, then
`#..._LinkButtonYes`. Its ModalBackground intercepts clicks — use JS .click().
* The window grid will NOT delete the LAST row, and **each Add wipes the
previously-added row's editable cells** — so multi-row window entry via the
add-form does not stick. Enter ONE combined window row (total glazed area,
one orientation); per worked-ref guidance that's an accepted approximation.
* Window glazing: "...known data" enables per-window U/g but then DEMANDS
Frame Factor + Data-Source + Location + Building Part per row (Recommendations
validation fails otherwise). Prefer a standard band, e.g.
"Double post or during 2022" (auto-derives U1.4/g0.72), and still set
Orientation + Location="External wall" + Building Part="Main".
* The "U-value known" override checkboxes (walls/roof/floor) don't reliably
toggle via automation accept the natural RdSAP age-band U-value.
* The **Recommendations** page is the validation gate; it MUST show zero errors
before the Energy Report Summary / worksheet PDFs are downloadable.
Common required-but-blank fields: insulated-door U-value, air-pressure-test
certificate number (when method=Blower Door).
* Truth only after Save & Close + reload: the live (unsaved) grid mis-displays
older rows as 0.00 never delete a row by its *live* width; reload first.
Usage:
import elmhurst_lib as E
with E.session() as (ctx, page):
E.goto(page, "Dimensions", "WebFormDimensions.aspx")
E.set_text(page, E.FP + "...TextBoxFloorAreaLowestFloor", "44.93")
E.save_close(page)
"""
from __future__ import annotations
import json
import os
from contextlib import contextmanager
from pathlib import Path
from typing import Callable, Generator, Optional
from playwright.sync_api import (
BrowserContext,
Page,
TimeoutError as PlaywrightTimeoutError,
sync_playwright,
)
HERE = Path(__file__).parent
SESSION_DIR = HERE / ".elmhurst-session"
CREDS_FILE = HERE / ".elmhurst-creds.json" # gitignored; {"access":..,"pwd":..}
# The single reusable campaign assessment ("Khalim-test"). Overwrite it per UPRN.
ASSESSMENT_GUID = "B44A0DB4-4C08-4241-B818-86F060172105"
ENTRY_URL = (
"https://rdsap10online.elmhurstenergy.co.uk/Processing/WebFormAddress.aspx"
f"?Guid={ASSESSMENT_GUID}"
)
FP = "ContentBody_ContentPlaceHolder1_" # control-id prefix
NAV = "ContentBody_buttonAction" # left-rail section nav id prefix
SETTLE_MS = 700
def _creds() -> tuple[str, str]:
if CREDS_FILE.exists():
d = json.loads(CREDS_FILE.read_text())
return d["access"], d["pwd"]
access = os.environ.get("ELM_ACCESS")
pwd = os.environ.get("ELM_PWD")
if not access or not pwd:
raise SystemExit(
"No Elmhurst creds: set ELM_ACCESS/ELM_PWD or write "
f"{CREDS_FILE} = {{'access':..,'pwd':..}}"
)
return access, pwd
@contextmanager
def session() -> Generator[tuple[BrowserContext, Page], None, None]:
"""Launch headed on :99, log in fresh, land on the assessment. Closes on exit."""
with sync_playwright() as p:
ctx = p.chromium.launch_persistent_context(
user_data_dir=str(SESSION_DIR),
headless=False,
accept_downloads=True,
viewport={"width": 1400, "height": 1000},
)
page = ctx.pages[0] if ctx.pages else ctx.new_page()
page.on("dialog", lambda d: d.accept())
page.goto(ENTRY_URL, wait_until="networkidle", timeout=60_000)
if "WebFormLogin" in page.url:
access, pwd = _creds()
page.fill("#ctl00_ctl00_ContentBody_ContentBody_TextBoxAccessCode", access)
page.fill("#ctl00_ctl00_ContentBody_ContentBody_TextBoxPassword", pwd)
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click("#ctl00_ctl00_ContentBody_ContentBody_ImageButtonEnter")
page.wait_for_timeout(1000)
try:
yield ctx, page
finally:
ctx.close()
def commit(page: Page, action: Callable[[], object]) -> None:
"""Run a control change that triggers an ASP.NET postback; wait for it."""
try:
with page.expect_navigation(wait_until="load", timeout=8_000):
action()
except PlaywrightTimeoutError:
page.wait_for_load_state("networkidle", timeout=8_000)
page.wait_for_timeout(SETTLE_MS)
def goto(page: Page, nav: str, url_fragment: str) -> None:
"""Navigate to a left-rail section (no-op if already on it — re-clicking
double-postbacks). Navigating saves the current page into the server session."""
if url_fragment in page.url:
return
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click(f"#{NAV}{nav}_Link", timeout=15_000)
page.wait_for_timeout(SETTLE_MS)
def click_tab(page: Page, panel_id: str) -> None:
"""Activate an AjaxControlToolkit sub-tab by its panel id, e.g.
'TabContainer_TabPanelDoorsPanel'. Client-side; no postback."""
page.evaluate(
"(id)=>{const e=document.getElementById('__tab_'+id); if(e)e.click();}",
f"{FP}{panel_id}",
)
page.wait_for_timeout(500)
def set_text(page: Page, suffix: str, value: str, autopostback: bool = True) -> None:
loc = page.locator(f"#{FP}{suffix}")
loc.fill(value)
if autopostback:
commit(page, lambda: loc.press("Tab"))
else:
page.wait_for_timeout(150)
def set_select(page: Page, suffix: str, value: str, autopostback: bool = True) -> None:
loc = page.locator(f"#{FP}{suffix}")
if autopostback:
commit(page, lambda: loc.select_option(value))
else:
loc.select_option(value)
def save_close(page: Page) -> None:
"""Save & Close — commits the whole server session to the DB (so the data
survives the next fresh-login run). The body button id-suffix avoids the
top-bar LinkButton copy. NEVER touches Submit."""
with page.expect_navigation(wait_until="networkidle", timeout=60_000):
page.click("#ContentBody_ButtonSaveClose", timeout=15_000)
page.wait_for_timeout(SETTLE_MS)
# --- Window grid helpers (Openings page) ---------------------------------
_WP = "TabContainer_TabPanelWindowsPanel_"
_GRID = "GridViewExtendedWidows"
def window_row_count(page: Page) -> int:
return page.evaluate(
f"""()=>document.querySelectorAll("[id*='{_GRID}_DeleteButton_']").length"""
)
def _jsclick(page: Page, element_id: str) -> None:
page.evaluate("(id)=>{const e=document.getElementById(id); if(e)e.click();}", element_id)
def add_combined_window(
page: Page, total_area_m2: float, orientation: str,
glazing: str = "Double post or during 2022",
) -> None:
"""Add ONE window row of `total_area_m2` (width=area, height=1.0). Sets the
required per-row fields (orientation/location/building-part) so the
Recommendations validation passes. Caller then deletes the prior rows."""
set_select(page, f"{_WP}DropDownListExtGlazing", glazing)
page.locator(f"#{FP}{_WP}TextBoxExtWidth").fill(str(total_area_m2))
h = page.locator(f"#{FP}{_WP}TextBoxExtHeight")
h.fill("1.00")
commit(page, lambda: h.press("Tab"))
page.locator(f"#{FP}{_WP}DropDownListExtOrientation").select_option(orientation)
page.locator(f"#{FP}{_WP}DropDownListExtBuildingPartId").select_option("Main")
page.locator(f"#{FP}{_WP}DropDownListExtLocation").select_option("External wall")
page.wait_for_timeout(200)
before = window_row_count(page)
_jsclick(page, f"{FP}{_WP}ButtonAddWindow")
for _ in range(20):
page.wait_for_timeout(200)
if window_row_count(page) > before:
break
def delete_first_window(page: Page) -> None:
"""Delete the first window row via the Yes/No modal. Will refuse to drop the
LAST row (Elmhurst blocks it) so add the replacement BEFORE deleting."""
before = window_row_count(page)
first = page.evaluate(
f"""()=>{{const e=document.querySelector("[id*='{_GRID}_DeleteButton_']"); return e?e.id:null;}}"""
)
if not first:
return
_jsclick(page, first)
page.wait_for_selector(f"#{FP}DeleteWindowDialog_LinkButtonYes", state="visible", timeout=5_000)
_jsclick(page, f"{FP}DeleteWindowDialog_LinkButtonYes")
for _ in range(20):
page.wait_for_timeout(200)
if window_row_count(page) < before:
break

View file

@ -0,0 +1,175 @@
"""Elmhurst RdSAP entry-tool browser session (POC, step 1: login + navigate).
The slow part of the `validate-cert-sap-accuracy` loop is the manual step:
a human keys ~50 fields from `elmhurst_inputs.md` into Elmhurst's web RdSAP
entry tool, then exports the Input Summary + SAP Worksheets PDFs. This module
is the foundation for automating that with Playwright.
Design (agreed with the user):
* **Persistent browser session.** We launch a *headed* Chromium against a
persistent profile dir (`.elmhurst-session/`, gitignored). You log in to
Elmhurst once by hand MFA/captcha included and every later run reuses
that session, so no credentials live in the repo.
* **Iterative.** This first cut only proves login + session reuse +
navigation. Form-filling and PDF export land on top of `launch_session()`
in later steps (selectors to come from a recorded `playwright codegen`
session, since the Elmhurst DOM is login-gated).
Usage:
# First run — a real browser opens; log in by hand, then press Enter here.
python scripts/hyde/elmhurst_session.py login --url https://<elmhurst-tool-url>
# Later runs — session is reused; this just proves you're still logged in.
python scripts/hyde/elmhurst_session.py open --url https://<elmhurst-tool-url>
python scripts/hyde/elmhurst_session.py status
The tool URL can also come from the ELMHURST_URL env var instead of --url.
"""
from __future__ import annotations
import argparse
import logging
import os
import sys
from contextlib import contextmanager
from pathlib import Path
from typing import Generator, Optional
from playwright.sync_api import BrowserContext, Page, sync_playwright
HERE = Path(__file__).parent
SESSION_DIR = HERE / ".elmhurst-session"
DOWNLOADS_DIR = HERE / "elmhurst_downloads"
logging.basicConfig(
level=logging.INFO, format="%(asctime)s %(levelname)-7s %(message)s"
)
logger = logging.getLogger("elmhurst")
def _resolve_url(cli_url: Optional[str]) -> str:
"""Tool URL from --url, else ELMHURST_URL env. We never hardcode it: the
Elmhurst entry-tool URL isn't in the repo and may differ per account."""
url = cli_url or os.environ.get("ELMHURST_URL")
if not url:
logger.error(
"No Elmhurst URL given. Pass --url <url> or set ELMHURST_URL. "
"(Open the entry tool in your browser and copy the address.)"
)
sys.exit(2)
return url
@contextmanager
def launch_session(headless: bool = False) -> Generator[BrowserContext, None, None]:
"""Open the persistent Elmhurst profile as a Playwright context.
Headed by default Elmhurst login needs a human the first time. The
persistent ``user_data_dir`` is what makes the session survive across runs:
cookies and local storage are written into ``SESSION_DIR`` on disk, so a
later launch is already authenticated. ``accept_downloads`` is on so the
later PDF-export step can capture Input Summary / SAP Worksheets.
"""
SESSION_DIR.mkdir(parents=True, exist_ok=True)
with sync_playwright() as p:
context = p.chromium.launch_persistent_context(
user_data_dir=str(SESSION_DIR),
headless=headless,
accept_downloads=True,
viewport={"width": 1400, "height": 1000},
)
try:
yield context
finally:
context.close()
def _active_page(context: BrowserContext, url: Optional[str]) -> Page:
"""Reuse the profile's existing tab (persistent contexts open one) instead
of stacking new blank tabs on every run; navigate it if a URL is given."""
page = context.pages[0] if context.pages else context.new_page()
if url:
logger.info("Navigating to %s", url)
page.goto(url, wait_until="domcontentloaded", timeout=60_000)
return page
def _wait_for_operator(prompt: str) -> None:
"""Block until the human is done in the browser. Headed/interactive only."""
try:
input(f"\n>>> {prompt}\n>>> Press Enter here when done... ")
except EOFError:
# Non-interactive (piped) run: nothing to wait on.
logger.warning("No interactive stdin; not waiting.")
def cmd_login(args: argparse.Namespace) -> int:
"""First-run login: open the tool, let the human authenticate, persist it."""
url = _resolve_url(args.url)
with launch_session(headless=False) as context:
page = _active_page(context, url)
_wait_for_operator(
"Log in to Elmhurst in the opened browser (MFA included). "
"Leave the browser on a logged-in page."
)
logger.info("Final URL: %s", page.url)
logger.info("Session saved to %s", SESSION_DIR)
return 0
def cmd_open(args: argparse.Namespace) -> int:
"""Reuse the saved session and navigate — proves login survived a restart."""
if not _session_exists():
logger.error("No saved session. Run `login` first.")
return 1
url = _resolve_url(args.url)
with launch_session(headless=False) as context:
page = _active_page(context, url)
logger.info("Landed on: %s (title: %r)", page.url, page.title())
_wait_for_operator("Inspect the page. This confirms the session reused.")
return 0
def _session_exists() -> bool:
return SESSION_DIR.exists() and any(SESSION_DIR.iterdir())
def cmd_status(_args: argparse.Namespace) -> int:
if _session_exists():
logger.info("Session present at %s", SESSION_DIR)
else:
logger.info("No session yet. Run `login`.")
return 0
def build_parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(
prog="elmhurst_session",
description="Elmhurst RdSAP entry-tool session (login + navigate POC).",
)
sub = parser.add_subparsers(dest="command", required=True)
p_login = sub.add_parser("login", help="open browser, log in by hand, save session")
p_login.add_argument("--url", help="Elmhurst tool URL (or set ELMHURST_URL)")
p_login.set_defaults(func=cmd_login)
p_open = sub.add_parser("open", help="reuse session and navigate to a URL")
p_open.add_argument("--url", help="Elmhurst tool URL (or set ELMHURST_URL)")
p_open.set_defaults(func=cmd_open)
p_status = sub.add_parser("status", help="report whether a session is saved")
p_status.set_defaults(func=cmd_status)
return parser
def main(argv: Optional[list[str]] = None) -> int:
args = build_parser().parse_args(argv)
func = getattr(args, "func")
return int(func(args))
if __name__ == "__main__":
raise SystemExit(main())

View file

@ -0,0 +1,153 @@
# Handoff: build a full-SAP (`SAP-Schema-17.1`) → `EpcPropertyData` mapper
You are picking up a focused piece of work in `/workspaces/model` (a Python
repo, branch `feature/hyde_make_it_more_accurate_with_tests`). Read this whole
prompt before starting.
## Goal
Add support for **full-SAP** certificates (schema `SAP-Schema-17.1`) to the EPC
mapper so a lodged full-SAP cert can flow through the existing chain:
```
EpcClientService.get_by_certificate_number(cert)
→ EpcPropertyDataMapper.from_api_response(raw) # <-- the work is here
→ EpcPropertyData
→ Sap10Calculator().calculate(epc) → SapResult
```
Today `from_api_response` raises `ValueError: Unsupported EPC schema:
'SAP-Schema-17.1'`. There is a captured real cert and a strict-xfail test
waiting to flip to green (see Acceptance).
## Essential domain context (do not skip)
The GOV.UK EPB register holds **two different certificate families**:
- **RdSAP** (`RdSAP-Schema-*`) — *Reduced data* SAP, for existing dwellings.
The assessor records a reduced input set; the schema carries proxy/count
fields (`door_count`, `window`, `percent_draughtproofed`,
`low_energy_fixed_lighting_outlets_count`, …) and the mapper applies RdSAP
table defaults downstream.
- **full SAP** (`SAP-Schema-*`) — the full SAP calculation input set, typically
for new-build / on-construction assessments (`assessment_type: "SAP"`). It
carries *richer, measured* geometry instead of proxies: explicit `windows`,
`sap_opening_types`, `air_tightness`, `living_area`, `orientation`,
`sap_ventilation`, `sap_flat_details`.
**All 7 currently-supported schemas are RdSAP.** No full-SAP path exists
anywhere yet. This is net-new, not a tweak.
`EpcPropertyData` (the target domain aggregate) and `Sap10Calculator` already
consume RdSAP-derived data fine — your job is the *mapping*, not the
calculator. Where full SAP gives a measured value that RdSAP only approximated,
prefer the measured value; where full SAP omits something RdSAP supplied,
you'll need a sensible default (mirror the RdSAP mapper's defaulting and
document each with an `# ADR-...`-style comment as the existing methods do).
## Current state — exact files & line refs
- **Dispatch**: `datatypes/epc/domain/mapper.py`, `from_api_response`
(the `if schema == "...":` ladder, ~lines 22002261, ending in the
`raise ValueError(f"Unsupported EPC schema: {schema!r}")`). Each branch does
`from_dict(SchemaClass, data)` (dacite) then a `from_<schema>` static method.
- **RdSAP mapper methods**: same file — `from_rdsap_schema_17_1`
(~line 623) is the closest analogue; `from_rdsap_schema_18_0` (~814) etc.
Read 17.1 end-to-end first — it's your template. Note `AnyRdSapSchema`
union (~lines 98105) and shared helpers `_map_energy_elements`,
`_map_energy_element`, `_api_sheltered_sides`, `_clear_basement_flag_when_system_built`.
- **Schema models**: `datatypes/epc/schema/` — one dataclass module per schema
(`rdsap_schema_17_1.py`, …). You'll add `sap_schema_17_1.py` here, modelling
the full-SAP payload as frozen-ish dataclasses (`from dataclasses import
dataclass`), reusing `common.py` types where shapes match. `from_dict`
(dacite) builds it from the raw JSON, so the dataclass must match the JSON
field names exactly (with `Optional[...]` for anything not always present).
- **Captured sample** (your fixture + shape reference):
`backend/epc_api/json_samples/real_life_examples/SAP-Schema-17.1/uprn_10092973954/epc.json`
(cert `0862-3892-7875-2690-2325`, lodged `energy_rating_current` = **83**).
- **The waiting test**:
`tests/domain/sap10_calculator/test_real_cert_sap_accuracy.py` — the
`uprn_10092973954` case is a strict `xfail(raises=ValueError)` flagged via
`unsupported_schema=True` on its `RealCertExpectation`.
## The structural delta (full-SAP 17.1 vs RdSAP 18.0 top-level keys)
Full-SAP **has, RdSAP doesn't**: `windows` (dict), `sap_opening_types` (list),
`air_tightness` (dict), `sap_ventilation` (dict), `sap_flat_details` (dict),
`living_area`, `orientation`, `multiple_glazed_percentage`, `design_water_use`,
`data_type`, `sap_data_version`, `is_in_smoke_control_area`,
`seller_commission_report`, `assessment_date`, `address_line_2/3`.
RdSAP **has, full-SAP doesn't**: `window` (singular proxy), `door_count`,
`extensions_count`, `habitable_room_count`, `heated_room_count`,
`fixed_lighting_outlets_count`, `low_energy_fixed_lighting_outlets_count`,
`open_fireplaces_count`, `percent_draughtproofed`, `solar_water_heating`,
`mechanical_ventilation`, `glazed_area`, `glazing_gap`,
`multiple_glazed_proportion`, `pvc_window_frames`, `measurement_type`,
`insulated_door_count`, `suggested_improvements`.
`schema_version_original` is `LIG-17.0`; `assessment_type` is `SAP`.
Map the rich full-SAP fields onto the `EpcPropertyData` / `Sap*` fields the
RdSAP path populates. Inspect the nested shapes (`windows`,
`sap_opening_types`, `air_tightness`, `sap_ventilation`) directly in the JSON
sample and against what `Sap10Calculator`/`cert_to_inputs`
(`domain/sap10_calculator/rdsap/cert_to_inputs.py`) actually reads.
## Task
1. Inspect the sample JSON thoroughly; enumerate every full-SAP field and
nested object.
2. Add `datatypes/epc/schema/sap_schema_17_1.py` — dataclasses matching the
full-SAP payload (dacite-compatible, `Optional` where appropriate).
3. Add `EpcPropertyDataMapper.from_sap_schema_17_1(schema) -> EpcPropertyData`
in `mapper.py`, modelled on `from_rdsap_schema_17_1`. Comment every place
you default or reinterpret a field vs the RdSAP path.
4. Wire a `if schema == "SAP-Schema-17.1":` branch into `from_api_response`
(decide whether `_clear_basement_flag_when_system_built` applies — check
what it does).
5. Flip the test: in `test_real_cert_sap_accuracy.py` remove
`unsupported_schema=True` from the `uprn_10092973954` case and set its
`sap_score` to whatever the calculator now produces — BUT first sanity-check
that figure against the lodged rating (83) and, ideally, a domain expert.
If the calc score diverges materially from lodged, that's a finding to
report, not silently pin. Do NOT widen tolerances to force a pass.
## Constraints
- **Type safety**: all new code must pass `pyright` under
`typeCheckingMode = strict`, zero errors. Use `Optional[X]` not `X | None`.
Annotate all return types. No bare `dict` — use `dict[str, Any]` for raw
payloads.
- **TDD**: this repo uses vertical-slice TDD (`/tdd` skill). Prefer one failing
test → one impl increment → repeat. The end-to-end accuracy test is the
outer loop; add focused mapper unit tests under
`datatypes/epc/domain/tests/` as you go (see `test_from_rdsap_schema.py` for
the pattern).
- **Domain language / ADRs**: load-bearing mapping decisions (e.g. how full-SAP
`windows` collapse onto the calculator's window model, how `air_tightness`
feeds infiltration) should be recorded as ADRs in `docs/adr/` — the existing
mapper methods reference `ADR-0028` etc. Use the `/grill-with-docs` skill if
terminology is drifting.
- Run the suite with: `python -m pytest tests/domain/sap10_calculator/test_real_cert_sap_accuracy.py -q --no-cov -rxs`
## Acceptance criteria
- `from_api_response` maps a `SAP-Schema-17.1` payload to a valid
`EpcPropertyData` with no `ValueError`.
- `Sap10Calculator().calculate(epc)` runs end-to-end on cert
`0862-3892-7875-2690-2325` and produces a SAP score.
- The `uprn_10092973954` accuracy case is no longer xfail — it's a real pin,
with its score reconciled against the lodged 83 (divergence explained if
any).
- `pyright --strict` clean; new mapper unit tests cover the full-SAP field
mappings; no tolerance widening anywhere.
## Capturing more full-SAP samples
`scripts/fetch_real_life_epc_sample.py <uprn>` resolves a UPRN to its latest
cert, writes it under
`backend/epc_api/json_samples/real_life_examples/<schema_type>/uprn_<uprn>/epc.json`,
and prints schema + lodged rating + current calc output (or `NOT MAPPABLE`).
Use it to gather a small full-SAP cohort to harden the mapper against shape
variation before pinning scores.

312
scripts/hyde/main.py Normal file
View file

@ -0,0 +1,312 @@
"""Consolidate UPRN-matching attempts into a single domain-found result.
We have two independent attempts at resolving each property to a UPRN:
* ``address2uprn_*`` - from the address2uprn matching service
(lives in output.csv, the master file)
* ``ordnance_survey_*`` - from Ordnance Survey
(lives in address2uprn.csv, a 4k-row subset)
This script joins the Ordnance Survey columns onto the master by
``Organisation Reference`` and then collapses the two attempts into one
canonical result:
* domain_found_uprn
* domain_found_address
* domain_scoring_confidence (the winning source's lexiscore)
Tie-break: prefer Ordnance Survey whenever it produced a UPRN, otherwise
fall back to address2uprn.
"""
from __future__ import annotations
from copy import copy
from pathlib import Path
from typing import Any, Optional, cast
import openpyxl
import pandas as pd
from openpyxl.cell.cell import Cell
from openpyxl.worksheet.worksheet import Worksheet
HERE = Path(__file__).parent
MASTER_CSV = HERE / "output.csv"
ORDNANCE_CSV = HERE / "address2uprn.csv"
OUTPUT_CSV = HERE / "output_with_domain_uprn.csv"
BAD_POSTCODE_CSV = HERE / "bad_postcodes.csv"
# The original profiling export. We annotate a copy of it in place rather than
# rebuilding it, so every existing column, sheet and chart is preserved exactly.
ORIGINAL_XLSX = HERE / "ARA AddressProfiling_Download_28-04-2026_1050 (2).xlsx"
ANNOTATED_XLSX = HERE / "ARA AddressProfiling_with_domna.xlsx"
DATA_SHEET = "AddressProfilingResults"
DOMNA_UPRN_HEADER = "DOMNA FOUND UPRN"
DOMNA_ADDRESS_HEADER = "DOMNA FOUND ADDRESS"
JOIN_KEY = "Organisation Reference"
ORDNANCE_COLS = [
"ordnance_survey_uprn",
"ordnance_survey_address",
"ordnance_survey_lexiscore",
]
# Failure markers either matching service writes into its UPRN column when the
# postcode itself could not be resolved. These mean "the postcode was wrong",
# not "no UPRN" — we surface them to the user separately.
POSTCODE_FAIL_SENTINELS = {
"invalid postcode",
"postcode not found in ordnance survey",
}
def _as_text(series: "pd.Series[Any]") -> "pd.Series[str]":
"""Coerce any column to a stripped string Series (NA stays NA)."""
text: "pd.Series[str]" = series.astype("string")
return text.str.strip()
def _norm_key(series: "pd.Series[Any]") -> "pd.Series[str]":
"""Normalise the join key so int/float/str spellings of the same
Organisation Reference compare equal (e.g. ``13016`` vs ``13016.0``).
Also strips leading zeros: the original spreadsheet keeps the reference as
text (``08450115001``) while the CSV pipeline reads it as a number and drops
the leading zero (``8450115001``). Without this they would never join."""
text = (
_as_text(series).str.replace(r"\.0$", "", regex=True).str.lstrip("0")
)
# pandas-stubs types fillna's overload with Any, tripping strict's
# reportUnknownMemberType even though the result is a Series[str].
return text.fillna("") # pyright: ignore[reportUnknownMemberType]
def _is_real_uprn(series: "pd.Series[Any]") -> "pd.Series[bool]":
"""A real UPRN is numeric. The matching services write failure sentinels
(``invalid postcode``, ``postcode not found in ordnance survey``) into the
same column, which must NOT count as a found UPRN."""
# pd.to_numeric's stub return contains Any; cast pins it to a known dtype.
numeric = cast(
"pd.Series[float]",
pd.to_numeric(series, errors="coerce"), # pyright: ignore[reportUnknownMemberType]
)
return numeric.notna()
def _is_postcode_failure(series: "pd.Series[Any]") -> "pd.Series[bool]":
"""True where the value is a known postcode-resolution failure sentinel."""
return _as_text(series).str.lower().isin(POSTCODE_FAIL_SENTINELS)
def build_ordnance_lookup(ordnance: pd.DataFrame) -> pd.DataFrame:
"""Collapse address2uprn.csv to one row per Organisation Reference,
keeping the first row that actually has an Ordnance Survey UPRN."""
frame = ordnance.copy()
frame["_key"] = _norm_key(frame[JOIN_KEY])
frame = frame[frame["_key"] != ""]
# Sort rows with a real OS UPRN first, then keep the first row per key, so a
# real match always beats an empty/sentinel row for the same Organisation Ref.
frame["_has_uprn"] = _is_real_uprn(frame["ordnance_survey_uprn"])
frame = frame.sort_values("_has_uprn", ascending=False, kind="stable")
lookup = frame.drop_duplicates("_key", keep="first")
return lookup[["_key", *ORDNANCE_COLS]]
def consolidate(master: pd.DataFrame) -> pd.DataFrame:
"""Add domain_found_* columns, preferring Ordnance Survey over address2uprn.
Only a real (numeric) UPRN counts as found; failure sentinels in either
source are ignored. Where neither source resolved a real UPRN the
domain_found_* columns are left empty.
"""
os_real = _is_real_uprn(master["ordnance_survey_uprn"])
a2_real = _is_real_uprn(master["address2uprn_uprn"])
# Source selection per row: Ordnance Survey wins, else address2uprn, else none.
def _pick(os_col: str, a2_col: str) -> "pd.Series[Any]":
empty = pd.Series([pd.NA] * len(master), index=master.index, dtype="object")
chosen = empty.where(~a2_real, master[a2_col])
chosen = chosen.where(~os_real, master[os_col])
return chosen
master["domna_found_uprn"] = _pick("ordnance_survey_uprn", "address2uprn_uprn")
master["domna_found_address"] = _pick(
"ordnance_survey_address", "address2uprn_address"
)
master["domna_scoring_confidence"] = _pick(
"ordnance_survey_lexiscore", "address2uprn_lexiscore"
)
# Outcome of the lookup. A bad postcode (sentinel from either source) is only
# worth flagging when we did NOT otherwise find a real UPRN for the property.
found = os_real | a2_real
bad_postcode = _is_postcode_failure(master["ordnance_survey_uprn"]) | (
_is_postcode_failure(master["address2uprn_uprn"])
)
status = pd.Series(["unmatched"] * len(master), index=master.index, dtype="object")
status = status.where(~bad_postcode, "bad_postcode")
status = status.where(~found, "matched")
master["domna_match_status"] = status
return master
def _norm_scalar(value: object) -> str:
"""Scalar twin of :func:`_norm_key` for iterating worksheet cells.
Strips a trailing ``.0`` and leading zeros so the worksheet's text reference
(``08450115001``) matches the CSV's numeric one (``8450115001``)."""
if value is None:
return ""
text = str(value).strip()
text = text[:-2] if text.endswith(".0") else text
return text.lstrip("0")
def _build_domna_lookup(merged: pd.DataFrame) -> "dict[str, tuple[int, str]]":
"""Organisation Reference -> (found UPRN, found address) for every row where
we resolved a real UPRN. UPRNs are returned as ints so the spreadsheet shows
them whole rather than as ``2.02e+08``/``...0``."""
real = merged[merged["domna_found_uprn"].notna()]
out: "dict[str, tuple[int, str]]" = {}
for ref, uprn, addr in zip(
real[JOIN_KEY], real["domna_found_uprn"], real["domna_found_address"]
):
key = _norm_scalar(ref)
if not key:
continue
addr_text = str(addr) if addr is not None and addr == addr else ""
out[key] = (int(float(str(uprn))), addr_text)
return out
def _cell(ws: Worksheet, row: int, column: int) -> Cell:
"""Fetch a worksheet cell typed as ``Cell`` (openpyxl returns a wider union)."""
return cast(Cell, ws.cell(row=row, column=column))
def _locate_columns(ws: Worksheet) -> "tuple[int, int, int]":
"""Return (header_row, organisation-ref col, UPRN col) for the data sheet,
which sits below a metadata preamble rather than on row 1."""
header_row = 0
for row in range(1, 31):
if str(_cell(ws, row, 1).value).strip() == JOIN_KEY:
header_row = row
break
if header_row == 0:
raise ValueError(f"Could not find a '{JOIN_KEY}' header in {ws.title!r}")
uprn_col = 0
for col in range(1, ws.max_column + 1):
if str(_cell(ws, header_row, col).value).strip() == "UPRN":
uprn_col = col
break
if uprn_col == 0:
raise ValueError(f"Could not find a 'UPRN' header in {ws.title!r}")
return header_row, 1, uprn_col
def _copy_header_style(src: Cell, dst: Cell) -> None:
"""Make a new header cell look native by cloning the UPRN header's style.
openpyxl assigns these style attributes via descriptors that its stubs type
as read-only, so strict flags the (runtime-valid) assignments."""
dst.font = copy(src.font) # pyright: ignore[reportAttributeAccessIssue]
dst.fill = copy(src.fill) # pyright: ignore[reportAttributeAccessIssue]
dst.border = copy(src.border) # pyright: ignore[reportAttributeAccessIssue]
dst.alignment = copy(src.alignment) # pyright: ignore[reportAttributeAccessIssue]
dst.number_format = src.number_format
def annotate_original_excel(
merged: pd.DataFrame,
source: Optional[Path] = None,
dest: Optional[Path] = None,
) -> int:
"""Append DOMNA FOUND UPRN / ADDRESS columns to a copy of the original
workbook, filled only where the property had no UPRN and we found one.
Layout, formatting and other sheets are left untouched."""
source = source or ORIGINAL_XLSX
dest = dest or ANNOTATED_XLSX
lookup = _build_domna_lookup(merged)
workbook = openpyxl.load_workbook(source)
ws = cast(Worksheet, workbook[DATA_SHEET])
header_row, ref_col, uprn_col = _locate_columns(ws)
new_uprn_col = ws.max_column + 1
new_addr_col = new_uprn_col + 1
style_src = _cell(ws, header_row, uprn_col)
for col, title in (
(new_uprn_col, DOMNA_UPRN_HEADER),
(new_addr_col, DOMNA_ADDRESS_HEADER),
):
header_cell = _cell(ws, header_row, col)
header_cell.value = title
_copy_header_style(style_src, header_cell)
filled = 0
for row in range(header_row + 1, ws.max_row + 1):
if _cell(ws, row, uprn_col).value not in (None, ""):
continue # property already has a UPRN — leave it alone
match = lookup.get(_norm_scalar(_cell(ws, row, ref_col).value))
if match is None:
continue
uprn, address = match
uprn_cell = _cell(ws, row, new_uprn_col)
uprn_cell.value = uprn
uprn_cell.number_format = "0"
_cell(ws, row, new_addr_col).value = address
filled += 1
workbook.save(dest)
return filled
def main(
master_path: Optional[Path] = None,
ordnance_path: Optional[Path] = None,
output_path: Optional[Path] = None,
) -> None:
master_path = master_path or MASTER_CSV
ordnance_path = ordnance_path or ORDNANCE_CSV
output_path = output_path or OUTPUT_CSV
master = pd.read_csv(master_path, low_memory=False)
ordnance = pd.read_csv(ordnance_path, low_memory=False)
master["_key"] = _norm_key(master[JOIN_KEY])
lookup = build_ordnance_lookup(ordnance)
merged = master.merge(lookup, on="_key", how="left").drop(columns="_key")
merged = consolidate(merged)
merged.to_csv(output_path, index=False)
# Flag properties whose postcode could not be resolved by either service —
# this means the source postcode is wrong and needs correcting at source.
bad = merged[merged["domna_match_status"] == "bad_postcode"]
flag_cols = [c for c in [JOIN_KEY, "Address 1", "postcode"] if c in bad.columns]
bad[flag_cols].to_csv(BAD_POSTCODE_CSV, index=False)
# Annotate a copy of the original workbook: fill DOMNA columns only for
# properties that had no UPRN and where we found one.
annotated = annotate_original_excel(merged)
os_matched = int(_is_real_uprn(merged["ordnance_survey_uprn"]).sum())
found = int(merged["domna_found_uprn"].notna().sum())
print(f"rows : {len(merged)}")
print(f"ordnance survey matched : {os_matched}")
print(f"domna_found_uprn populated : {found}")
print(f"written to : {output_path}")
print(f"excel rows filled (no UPRN): {annotated}")
print(f"annotated workbook : {ANNOTATED_XLSX}")
if len(bad):
print()
print(f"⚠️ {len(bad)} properties have a BAD POSTCODE (could not be resolved).")
print(f" These postcodes are likely wrong — review: {BAD_POSTCODE_CSV.name}")
if __name__ == "__main__":
main()

View file

@ -0,0 +1,110 @@
# Full-SAP 17.1 → EpcPropertyData mapper — decisions log
Running log of load-bearing mapping decisions made during the grilling session.
Each becomes an ADR (`docs/adr/`) when the mapper lands. Corpus evidence:
`backend/epc_api/json_samples/SAP-Schema-17.1/corpus.jsonl` (1,000 real certs).
**Scope (locked):** map full-SAP 17.1 → a valid `EpcPropertyData` so the existing
RdSAP `Sap10Calculator` runs end-to-end. Accurate-enough geometry/inputs is the
bar; **score reconciliation vs lodged is a later, expert-led step** — do NOT tune
the mapping to hit the lodged rating, and do NOT widen tolerances.
---
## D1 — Heat-loss perimeter & party walls (from measured wall areas)
**Decision:** full-SAP lodges no perimeter; derive it from measured per-wall areas
classified by `wall_type`:
- `{1,2,3}` exposed → `heat_loss_perimeter_m` = Σarea ÷ storey_height
- `4` party → `party_wall_length_m` = Σarea ÷ storey_height
- `5` internal partition → discarded
- any other code → `raise UnmappedApiCode("wall_type", code)` (**fail loud**)
`wall_type` is a ~99%-clean classifier (corpus). Accept the ~1% tail where a party
wall is mis-typed as 2 (`Common wall`/`Stair Wall`); revisit with name hints only
if the later score comparison flags it. Geometric `4·√(footprint)` is fallback only
(no usable walls). Detail + worked examples: `perimeter_decision.md`.
## D2 — Window / door / roof opening collapse
**Decision:** join `sap_openings``sap_opening_types` by name (100% join in corpus),
then route by opening-type `.type`:
- `4` vertical window → `sap_windows` (`SapWindow`: width, height, `u_value`
`window_transmission_details`, orientation, glazing_type, frame_factor)
- `5` roof window / rooflight → `sap_roof_windows` (`SapRoofWindow`: area=w×h,
u_value, orientation, pitch, frame_factor, g⊥←solar_transmittance)
- `1,2,3` doors → `door_count` = #door-openings; `insulated_door_u_value` =
area-weighted door U (only 46/1000 certs lodge >1 distinct door U); doors treated
insulated (new-build)
- any other opening-type code → `raise UnmappedApiCode("sap_opening_type", code)`
Lower-risk than the handoff implied: the engine has first-class fields for all three
opening kinds, and full-SAP supplies richer per-opening geometry than RdSAP.
## D3 — Living-area fraction (back-solve room count)
**Decision:** full-SAP measures `living_area` but the engine only reads it via
`habitable_rooms_count` → Table 27. **Mapper-only:** set `habitable_rooms_count` to
the room count whose Table 27 fraction is closest to the measured `living_area/TFA`,
so the existing engine path reproduces the measured fraction.
**Known caveat (to go back to):** `habitable_rooms_count` is *also* read for the
Table 5 extract-fan minimum (`max(measured_fans, room_count_default)`,
`cert_to_inputs.py:4534`). A back-solved count can raise that floor. Bounded
(fans 14) and **moot for the 445/1000 mechanically-ventilated certs**; bites only
in the natural-vent subset where measured fans < default. **v1: accept** (keeps the
decision mapper-only). Principled future fix: suppress the Table-5 "unknown" default
for full-SAP, since its ventilation is measured, not unknown.
---
## D4 — Fabric U-values: carry descriptions through; age_band is fallback only
**Pivotal finding:** the engine's `u_wall`/`u_floor`/`u_roof` first parse the element
`description` for `"Average thermal transmittance X W/m²K"` and return that measured U
directly, bypassing the age-band cascade (`rdsap_uvalues.py:546`; wired at
`heat_transmission.py:589,779`). The parser docstring: *"On full-SAP certs the
assessor enters the BS EN ISO 6946 result directly here in lieu of using the cascade."*
Corpus: walls parse to measured U **984/1000**; floors 692 (rest = "(other premises
below)" internal, no loss); roofs 715 (rest = "(other premises above)" internal).
**Decision:** map full-SAP top-level `walls`/`floors`/`roofs` energy-element lists via
the existing `_map_energy_elements` (preserves `description`). The measured fabric U then
flows into the engine — it is NOT discarded. This reverses the initial "RdSAP engine
re-derives from fabricated band-M and over-rates" concern for ~98% of walls.
`construction_age_band` is therefore a **low-stakes fallback**, not the primary fabric
driver. Fabricate band **M** from `construction_year`/`assessment_date` (new-build era);
used only for the ~2% of walls with no parseable U and for secondary age-band logic
(cylinder-insulation default, suspended-timber-floor sealed/unsealed branch, Table 5 fan
default). **Fail loud** (`UnmappedApiCode`) only if neither a year nor a usable band can
be established. *(Note: this also shrinks the D3 living-area physics-gap framing — the
score is far more faithful than the early no-engine estimate suggested.)*
## Corpus validation (1,000 certs, full chain through Sap10Calculator)
Run after slices 17 + D5/D6 landed (`from_api_response``Sap10Calculator`):
- **727/1000 (72.7%) run end-to-end; 0 calculator failures** — where a cert maps,
it calculates cleanly (robust mapping, no engine crashes).
- **Initial 273 map-failures** were all one variant: code-based heating
(`main_heating_category` 6/10 — community heating, heat pumps) lodging
`main_heating_code` instead of explicit `heat_emitter_type`/`main_fuel_type`.
**RESOLVED (slice D6b):** mapped `main_heating_code → sap_main_heating_code`
(a known variant the calculator already consumes), defaulting the absent
explicit fields. **Corpus mappability now 1000/1000 (100%); calc 1000/1000.**
- **Score divergence (calc lodged, full mapping, n=1000):** median **8**,
mean **11.4**; within ±10 = 55%. The engine **systematically under-rates**
full-SAP certs. This is **deferred to a separate SAP-calc verification task**
(mapping fidelity is the deliverable here; the score is not). Known drivers,
in rough order: (a) measured **MEV** ventilation priced as added extract loss
(4 isolated on the sample); (b) **code-based heating** (276 certs) currently
defaults the absent fuel/emitter to 0 — these systems map (no crash) but are
not yet fully modelled, so their scores are unreliable *by mapping*, not calc;
(c) fabricated RdSAP proxies (age band, back-solved room count). The mapper is
**never tuned to the lodged value**; pins are the observed score.
## Open / not yet grilled
- D5 `ventilation_type` (1/5/6/8…) → `MechanicalVentilationKind` (NATURAL/MEV/MVHR/PIV); `air_permeability` → AP4
- D6 heating: full-SAP `sap_heating.main_heating_details` shape vs RdSAP field names
- D7 wall/roof/floor `construction` code mapping (full-SAP `wall_type` → domain `wall_construction` for U-derivation)
- D8 `_clear_basement_flag_when_system_built` applicability
- D9 dwelling_type/built_form/property_type/tenure code mapping; 11/1000 null `built_form`
- D10 schema dataclass optionality (corpus presence: `sap_flat_details` 44%, `design_water_use` 94%, etc.)

View file

@ -0,0 +1,122 @@
# Decision brief: deriving heat-loss perimeter for full-SAP 17.1
**For:** mapper design sign-off · **Date:** 2026-06-15 · **Corpus:** 1,000 real `SAP-Schema-17.1` certs (`backend/epc_api/json_samples/SAP-Schema-17.1/corpus.jsonl`)
---
## TL;DR — recommendation
Derive perimeter and party-wall length from the **measured per-wall areas full-SAP lodges**, classified by `wall_type`:
| `wall_type` | meaning | feeds | engine effect |
|---|---|---|---|
| 1, 2, 3 | **external / exposed** | `heat_loss_perimeter_m` = Σarea ÷ storey-height | wall + ground-floor heat loss |
| 4 | **party** | `party_wall_length_m` = Σarea ÷ storey-height | party-wall heat loss (≈0 to heated neighbour) |
| 5 | **internal partition** | *discarded* | none (not part of the envelope) |
Geometric `4·√(footprint)` is the **fallback only** (a part lodges no walls / no storey height).
**Why this and not geometric:** `wall_type` is a ~99%-clean classifier (evidence below), and for attached dwellings (flats + semis + terraces = the majority) the measured areas separate exposed from party, which geometric **cannot** — geometric assumes 4 exposed sides and over-states heat loss for anything sharing a wall.
---
## Why this is the #1 decision
The RdSAP engine reconstructs the *entire* envelope from perimeter:
- gross wall area = `Σ(heat_loss_perimeter × storey_height)``worksheet/dimensions.py:124`
- ground-floor heat loss = `f(area, perimeter)``rdsap/cert_to_inputs.py:4420`
- party walls billed separately via `party_wall_length_m``worksheet/dimensions.py:168`
The existing RdSAP path reads both straight from the cert (`mapper.py:3556-3557`). **RdSAP certs lodge them; full-SAP certs lodge neither.** So full-SAP *must* derive them, or the engine sees a wall-less dwelling → heat loss ≈ 0 → nonsense (band-A) score.
---
## Evidence 1 — `wall_type` cleanly classifies exposed / party / internal
Across all walls in the 1,000-cert corpus:
| `wall_type` | n | names containing party/common/etc | reading |
|---|---|---|---|
| 1 | 5 | 0% | external (basement) |
| **2** | 1,657 | 1% | **external** (`external wall 1/2/3`, `wall 1`) |
| 3 | 109 | 1% | external |
| **4** | 738 | **81%** | **party** (`party wall 0`, `party`, `common`) |
| **5** | 588 | 0% | **internal partition** (`internal wall`, `stud`, `block`) |
Type 4 → party and type 5 → internal are unambiguous; types 1/2/3 → external leak party names only ~1% of the time.
## Evidence 2 — total footprint is recoverable two independent ways
Geometric `4·√(footprint)·height` vs the measured wall-area footprint agree well, so the *total* envelope size is low-risk; the only thing that needs the `wall_type` split is **which part of it is exposed vs party**:
| stock | geometric ÷ measured (median) | p10p90 | off by >30% |
|---|---|---|---|
| flats (n=279) | 0.94 | 0.791.10 | 5% over / 5% under |
| houses (n=564) | 0.96 | 0.881.02 | 3% over / 2% under |
---
## Worked examples — Method A (geometric) vs Method B (measured areas) vs reality
**Reality** = the measured external-wall area the cert actually lodges (what we want the engine's `perimeter × height` to reproduce).
### House — *Semi-detached*, 69 m², 2 storeys, height 2.44 m
| wall (name / type) | area m² | class |
|---|---|---|
| External Wall 1 (t2) | 83.4 | **exposed** |
| Party Wall 0 (t4) | 37.3 | party |
| 3× Internal Wall (t5) | 155.4 | internal |
- **Reality (exposed only):** 83.4 m²
- **Method A geometric:** 23.5 m perim → implied wall **114.4 m²** ❌ (+37%: counts the party side as exposed)
- **Method B `wall_type`:** exposed 83.4 ÷ 2.44 → **17.1 m/storey**, implied wall **83.4 m²** ✅; party 37.3 → `party_wall_length`
### Flat — *Ground-floor flat*, 73 m², 1 storey, height 2.38 m
| wall (name / type) | area m² | class |
|---|---|---|
| walls (t2) | 50.9 | exposed |
| Common wall (t2) | 19.8 | exposed* |
| Part wall (t4) | 17.0 | party |
- **Method A geometric:** 34.2 m → implied wall 81.3 m²
- **Method B `wall_type`:** exposed 70.7 ÷ 2.38 → 29.7 m, party 17.0 → party length
- *Caveat:* "Common wall" is a party wall **mis-typed as 2** — the ~1% leakage case. Method B treats it as exposed (slightly over-counts); a name-hint refinement could catch it, at the cost of fragility.
### Sample cert `0862-…-2325` (lodged 83), Ground-floor flat, 68 m², height 2.4 m
| wall (name / type) | area m² | class |
|---|---|---|
| Brickwork (t2) | 13.1 | exposed |
| Weatherboarding (t2) | 47.0 | exposed |
| Sole Plate Detail (t2) | 3.1 | exposed* (junction detail) |
| Stair Wall (t2) | 28.4 | exposed* (likely party, mis-typed) |
| Stud Walls (t5) | 126.0 | internal |
- **Method B `wall_type`:** exposed 91.5 ÷ 2.4 → **38.1 m**. If "Stair Wall" is really party, true exposed ≈ 63 m² → 26 m. This single cert is one of the messy ~1%.
---
## The residual risk (and the open sub-question for you)
`wall_type` mis-labels a party wall as external ~1% of the time (the "Common wall" / "Stair Wall" cases). Options for that tail:
1. **Trust `wall_type` only** — simplest, ~1% of certs slightly over-count exposed area (conservative: under-rates a few flats). *Recommended for v1.*
2. **`wall_type` + name regex** (`party|common|separating`) to reclassify type-2 party walls — catches the tail, but free-text names are fragile and could mis-grab a genuinely-external "common entrance wall".
3. **Geometric for houses, measured for flats** — more code paths; the data shows measured wins for both, so this adds complexity without clear gain.
**My pick: option 1 for v1** (trust `wall_type`), revisit with name hints only if the score comparison later flags the affected certs.
---
## DECISION (2026-06-15) — trust `wall_type`, fail loudly
**Resolved:** Option 1. Classify by `wall_type` only:
- `{1, 2, 3}` → exposed (→ `heat_loss_perimeter_m`)
- `4` → party (→ `party_wall_length_m`)
- `5` → internal partition (discarded)
- **any other code → `raise UnmappedApiCode("wall_type", code)`** — the established strict-raise pattern (`mapper.py:3102` etc.). No silent default.
We deliberately accept the ~1% tail where a party wall is mis-typed as 2 (`Common wall` / `Stair Wall`) — it is *not* caught by a name heuristic in v1. The loud raise is reserved for genuinely unknown codes so new wall variants force an explicit decision rather than mis-routing.
**To revisit (the "go back to it" marker):** if the later expert score comparison flags certs with party walls mis-typed as 2, add the name-regex refinement (option 2). An ADR (`docs/adr/`) records this when the mapper lands. The exposed/party split is the load-bearing call; the ADR will cite this brief.

89
scripts/hyde/start_viewer.sh Executable file
View file

@ -0,0 +1,89 @@
#!/usr/bin/env bash
# Stand up a *viewable* desktop inside the dev container so you can see and
# click the headed Elmhurst browser. Pipeline:
#
# Xvfb (:99 virtual screen) -> fluxbox (window manager)
# -> x11vnc (exposes :99 over VNC on 5900)
# -> websockify/noVNC (serves VNC in a browser tab on 6080)
#
# Then: forward port 6080 (VS Code does this automatically), open it, and run
# Playwright with DISPLAY=:99 so the browser appears on this desktop.
#
# bash scripts/hyde/start_viewer.sh # start it
# bash scripts/hyde/start_viewer.sh stop # tear it down
#
# Idempotent: re-running won't stack duplicate servers.
set -euo pipefail
DISPLAY_NUM=":99"
SCREEN="1600x1000x24"
VNC_PORT=5900
WEB_PORT=6080
RUN_DIR="/tmp/hyde-viewer"
mkdir -p "$RUN_DIR"
_pids() { pgrep -f "$1" 2>/dev/null || true; }
stop() {
echo "Stopping viewer..."
for pat in "websockify.*$WEB_PORT" "x11vnc.*$DISPLAY_NUM" "fluxbox" "Xvfb $DISPLAY_NUM"; do
for pid in $(_pids "$pat"); do kill "$pid" 2>/dev/null || true; done
done
rm -f "/tmp/.X${DISPLAY_NUM#:}-lock" 2>/dev/null || true
echo "Stopped."
}
start() {
# Xvfb — the virtual screen everything draws into.
if [ -z "$(_pids "Xvfb $DISPLAY_NUM")" ]; then
Xvfb "$DISPLAY_NUM" -screen 0 "$SCREEN" -ac >"$RUN_DIR/xvfb.log" 2>&1 &
sleep 1
echo "Xvfb up on $DISPLAY_NUM ($SCREEN)"
else
echo "Xvfb already running on $DISPLAY_NUM"
fi
# fluxbox — a window manager so the browser window is movable/resizable.
if [ -z "$(_pids "fluxbox")" ]; then
DISPLAY="$DISPLAY_NUM" fluxbox >"$RUN_DIR/fluxbox.log" 2>&1 &
sleep 1
echo "fluxbox window manager up"
fi
# x11vnc — exposes the screen over VNC. -forever keeps it alive across
# client reconnects; -nopw is fine because the port is only reachable
# through the container's forwarded port, not the public internet.
if [ -z "$(_pids "x11vnc.*$DISPLAY_NUM")" ]; then
x11vnc -display "$DISPLAY_NUM" -rfbport "$VNC_PORT" -forever -shared \
-nopw -quiet -bg -o "$RUN_DIR/x11vnc.log"
echo "x11vnc up on VNC port $VNC_PORT"
else
echo "x11vnc already running"
fi
# noVNC/websockify — serves the VNC stream as a web page on WEB_PORT.
if [ -z "$(_pids "websockify.*$WEB_PORT")" ]; then
websockify --web=/usr/share/novnc "$WEB_PORT" "localhost:$VNC_PORT" \
>"$RUN_DIR/websockify.log" 2>&1 &
sleep 1
echo "noVNC up on web port $WEB_PORT"
fi
cat <<EOF
Desktop ready.
1. Open the forwarded port $WEB_PORT in your browser:
http://localhost:$WEB_PORT/vnc.html?autoconnect=1&resize=remote
(In VS Code: PORTS tab -> forward $WEB_PORT -> open in browser.)
2. Run the Playwright login pointing at this display:
DISPLAY=$DISPLAY_NUM python scripts/hyde/elmhurst_session.py login --url <elmhurst-url>
The browser window will appear on the desktop you opened in step 1.
EOF
}
case "${1:-start}" in
start) start ;;
stop) stop ;;
restart) stop; start ;;
*) echo "usage: $0 [start|stop|restart]"; exit 2 ;;
esac

View file

@ -92,18 +92,42 @@ _EXPECTATIONS: Final[tuple[RealCertExpectation, ...]] = (
# support has landed (datatypes/epc/domain/mapper.py from_sap_schema_17_1;
# design: scripts/hyde/mapping_decisions.md), so the chain now runs through
# the RdSAP SAP-10 engine end-to-end. Lodged rating is 83; the engine
# produces 77 (6). The mapper faithfully feeds the cert's measured
# decentralised MEV (ventilation_type 6 → EXTRACT_OR_PIV_OUTSIDE), which the
# engine prices as added extract-ventilation loss (the 4 driver isolated;
# measured air permeability / fabric drive the rest). PINNED TO THE OBSERVED
# 77, not the lodged 83 — the mapping is deliberately not tuned; the 6 (and
# the engine's full-SAP MEV treatment) is for the separate SAP-calc
# verification task to reconcile against a worksheet.
# produces 80. The mapper faithfully feeds the cert's measured decentralised
# MEV (ventilation_type 6 → EXTRACT_OR_PIV_OUTSIDE), priced as extract loss.
# WAS 77 until the air-permeability AP50 fix (uprn_10093116528 campaign):
# the lodged measured air permeability is a q50 Blower-Door result, so it now
# routes to the engine's AP50 path `(18)=AP50/20+(8)` instead of the AP4/Pulse
# formula `0.263×AP4^0.924` — see SapVentilation.air_permeability_ap50_m3_h_m2.
# That lifts this airtight (q50 2.6) cert 77→80. Its saved Elmhurst worksheet
# used the *design* AP50 15.0 (not the lodged 2.6), so it is no longer a clean
# infiltration comparison; the engine now correctly uses the lodged 2.6/20.
# PINNED TO THE OBSERVED 80, not lodged 83 — mapping deliberately untuned.
RealCertExpectation(
schema="SAP-Schema-17.1",
sample="uprn_10092973954",
cert_num="0862-3892-7875-2690-2325",
sap_score=77,
sap_score=80,
),
# UPRN 10093116528 → cert 8000-8495-2839-2607-9683. SAP-Schema-17.1 — a
# FULL-SAP cert (2017 new-build semi), forced through the RdSAP SAP-10 engine.
# Lodged 84. Built in Elmhurst RdSAP10 on the lodged inputs (evidence saved:
# elmhurst_summary.pdf / elmhurst_worksheet.pdf): Elmhurst worksheet SAP 81,
# HTC 121.1 W/K, with q50 Blower-Door AP50=4.5 → infiltration (18)=4.5/20+(8)
# =0.3475. This cert IS the air-permeability AP50 fix: the gov-API mapper was
# routing the q50 4.5 to the AP4/Pulse formula (0.263×4.5^0.924≈1.0 ach),
# over-counting infiltration ≈+60 W/K and pinning SAP at 78; routing it to the
# AP50/20 path (matching the worksheet) gives 82. Calculator confirmed faithful
# (engine on Elmhurst's own parsed inputs ≈ worksheet). The residual +1 (82 vs
# 81) is the inherent full-SAP-lodged-U vs RdSAP-age-band-U methodology gap
# (engine uses the cert's measured 0.19/0.11/0.11 U-values; Elmhurst uses
# age-band L proxies + party-wall default) plus FGHRS (cert idx 60031) omitted
# on BOTH sides (the engine can't yet model full-SAP FGHRS). PINNED TO THE
# OBSERVED 82, not lodged 84 — mapping deliberately untuned.
RealCertExpectation(
schema="SAP-Schema-17.1",
sample="uprn_10093116528",
cert_num="8000-8495-2839-2607-9683",
sap_score=82,
),
# UPRN 10002468137 → cert 0215-2818-7357-9703-2145. RdSAP-Schema-17.1,
# all-electric high-heat-retention storage heaters on Economy 7, solid-