mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Blend an off-peak meter's day/night rate by high-rate fraction 🟥
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
eab979e686
commit
4641717c90
2 changed files with 50 additions and 1 deletions
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
|||
|
||||
from collections.abc import Mapping
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional
|
||||
|
||||
from domain.fuel_rates.fuel import Fuel, UnpricedFuel
|
||||
|
||||
|
|
@ -18,6 +19,25 @@ class FuelRate:
|
|||
standing_charge_p_per_day: float
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OffPeakRate:
|
||||
"""An Off-Peak Meter's dual-rate tariff — a cheaper ``night`` (low) rate and
|
||||
a dearer ``day`` (high) rate, plus the daily standing charge (ADR-0014).
|
||||
|
||||
Off-peak electricity has no single unit rate, so it does not live in the
|
||||
single-rate ``FuelRates.rates`` map; each end use blends day/night by its own
|
||||
High-Rate Fraction (a calculator output)."""
|
||||
|
||||
day_p_per_kwh: float
|
||||
night_p_per_kwh: float
|
||||
standing_charge_p_per_day: float
|
||||
|
||||
def blended_p_per_kwh(self, high_rate_fraction: float) -> float:
|
||||
"""Effective p/kWh for an end use billing ``high_rate_fraction`` of its
|
||||
kWh at the day (high) rate and the remainder at the night (low) rate."""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class FuelRates:
|
||||
"""A current Fuel Rates snapshot — the rate per billing Fuel plus the SEG
|
||||
|
|
@ -32,6 +52,13 @@ class FuelRates:
|
|||
period: str
|
||||
seg_export_p_per_kwh: float
|
||||
rates: Mapping[Fuel, FuelRate]
|
||||
off_peak: Optional[OffPeakRate] = None
|
||||
|
||||
def off_peak_blended_p_per_kwh(self, high_rate_fraction: float) -> float:
|
||||
"""Blended day/night p/kWh for an Off-Peak Meter end use at the given
|
||||
High-Rate Fraction. Raises ``UnpricedFuel`` when the snapshot carries no
|
||||
off-peak entry."""
|
||||
raise NotImplementedError
|
||||
|
||||
def unit_rate_p_per_kwh(self, fuel: Fuel) -> float:
|
||||
return self._rate(fuel).unit_rate_p_per_kwh
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
import pytest
|
||||
|
||||
from domain.fuel_rates.fuel import Fuel, UnpricedFuel
|
||||
from domain.fuel_rates.fuel_rates import FuelRate, FuelRates
|
||||
from domain.fuel_rates.fuel_rates import FuelRate, FuelRates, OffPeakRate
|
||||
|
||||
|
||||
def _rates() -> FuelRates:
|
||||
|
|
@ -14,6 +14,28 @@ def _rates() -> FuelRates:
|
|||
)
|
||||
|
||||
|
||||
def _off_peak_rates() -> FuelRates:
|
||||
return FuelRates(
|
||||
period="test",
|
||||
seg_export_p_per_kwh=15.0,
|
||||
rates={},
|
||||
off_peak=OffPeakRate(
|
||||
day_p_per_kwh=29.73, night_p_per_kwh=13.89, standing_charge_p_per_day=56.99
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def test_off_peak_blended_rate_at_zero_high_fraction_is_the_night_rate() -> None:
|
||||
# Arrange — an all-night load (storage heating, high-rate fraction 0.0).
|
||||
rates = _off_peak_rates()
|
||||
|
||||
# Act
|
||||
blended = rates.off_peak_blended_p_per_kwh(high_rate_fraction=0.0)
|
||||
|
||||
# Assert — every kWh bills at the cheap night rate.
|
||||
assert blended == 13.89
|
||||
|
||||
|
||||
def test_unit_rate_and_standing_charge_read_back_for_a_priced_fuel() -> None:
|
||||
# Arrange
|
||||
rates = _rates()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue