mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +00:00
Slice 2 of the lighting generator (ADR-0023): detect non-LED bulbs (incandescent + CFL + low-energy-unknown > 0) and emit one "Lighting" Recommendation whose single low_energy_lighting Option converts every bulb to LED — the overlay sets led = total, the other three counts 0. Priced as a flat per-bulb average x the non-LED count, contingency 0.26; the description names "LED" while the measure_type stays MEASURE_MAP-aligned. None when already all-LED or no bulb counts are lodged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
63 lines
2.6 KiB
Python
63 lines
2.6 KiB
Python
"""The lighting Recommendation Generator (LED upgrade).
|
|
|
|
Detects a dwelling's non-LED fixed-lighting bulbs and emits one "Lighting"
|
|
Recommendation whose single Option converts **every** bulb to LED (ADR-0023).
|
|
SAP 10.2 RdSAP §12-1 rates lamp efficacy LED > low-energy-unknown > CFL >
|
|
incandescent, so converting every non-LED type — incandescent, CFL, and the
|
|
"low energy, type unknown" (LEL) bulbs alike — strictly improves the Appendix L
|
|
lighting energy (worksheet line (232)).
|
|
|
|
Unlike the fabric generators this is a **whole-dwelling** Measure: its overlay
|
|
writes the four top-level bulb counts directly (`led = total`, the rest 0). It
|
|
is a free Optimiser candidate — an LED upgrade improves SAP at low cost, so the
|
|
Optimiser keeps or leaves it for least-cost-to-target (contrast ventilation's
|
|
forced dependency). Detection + pricing only; impact is produced later by
|
|
scoring (ADR-0016).
|
|
"""
|
|
|
|
from typing import Final, Optional
|
|
|
|
from datatypes.epc.domain.epc_property_data import EpcPropertyData
|
|
from domain.modelling.recommendation import Cost, MeasureOption, Recommendation
|
|
from domain.modelling.simulation import EpcSimulation, LightingOverlay
|
|
from repositories.product.product_repository import ProductRepository
|
|
|
|
_LIGHTING_MEASURE_TYPE: Final[str] = "low_energy_lighting"
|
|
|
|
|
|
def recommend_lighting(
|
|
epc: EpcPropertyData, products: ProductRepository
|
|
) -> Optional[Recommendation]:
|
|
"""Return a lighting Recommendation upgrading every non-LED bulb to LED — its
|
|
single Option — else None when the dwelling has no non-LED bulbs (already
|
|
all-LED, or no bulb counts lodged)."""
|
|
led: int = epc.led_fixed_lighting_bulbs_count or 0
|
|
cfl: int = epc.cfl_fixed_lighting_bulbs_count or 0
|
|
incandescent: int = epc.incandescent_fixed_lighting_bulbs_count or 0
|
|
low_energy: int = epc.low_energy_fixed_lighting_bulbs_count or 0
|
|
|
|
non_led: int = cfl + incandescent + low_energy
|
|
if non_led == 0:
|
|
return None
|
|
|
|
product = products.get(_LIGHTING_MEASURE_TYPE)
|
|
overlay = EpcSimulation(
|
|
lighting=LightingOverlay(
|
|
led_fixed_lighting_bulbs_count=led + non_led,
|
|
cfl_fixed_lighting_bulbs_count=0,
|
|
incandescent_fixed_lighting_bulbs_count=0,
|
|
low_energy_fixed_lighting_bulbs_count=0,
|
|
)
|
|
)
|
|
cost = Cost(
|
|
total=non_led * product.unit_cost_per_m2,
|
|
contingency_rate=product.contingency_rate,
|
|
)
|
|
option = MeasureOption(
|
|
measure_type=_LIGHTING_MEASURE_TYPE,
|
|
description="Replace all non-LED bulbs with LED",
|
|
overlay=overlay,
|
|
cost=cost,
|
|
material_id=product.id,
|
|
)
|
|
return Recommendation(surface="Lighting", options=(option,))
|