BEK 563 § 13 — estimering ved manglende aflæsninger
BEK 563 § 13 om estimeret forbrug: hvornår må udlejer estimere, 3 estimeringsmetoder (historisk gennemsnit, graddage-normaliseret, nabointerpolering), platform-automatik og revisordokumentation.
Af M-Bus Gateway
Afregning skal udsendes selv når en måler er defekt eller gateway-signal mangler. BEK 563 § 13 angiver rammerne — og platform-automatik sikrer korrekt dokumentation.
§ 13 — lovgrundlaget
BEK 563 § 13 — Manglende aflæsninger:
"Kan forbrugsmåling ikke finde sted, fordi måleren er defekt,
bortkommen eller utilgængelig, kan udlejeren anslå forbruget
for den pågældende boligenhed på grundlag af:
1. Det tidligere forbrug i boligenheden
2. Forbruget i sammenlignelige boligenheder
3. En skønsmæssig vurdering"
Nøgleprincipper:
→ Estimat er LOVPLIGTIGT — afregning kan ikke udskydes pga. manglende data
→ 4-måneders-fristen (§ 9) gælder også ved estimat
→ Lejer skal orienteres om at aflæsning er estimeret (ikke faktisk)
→ Estimat-metode skal dokumenteres i regnskabet
→ Lejer kan bestride estimat (§ 18 indsigelsesret)
Hvornår bruges § 13:
→ Måler defekt eller stjålet
→ wM-Bus signal utilstrækkeligt (RSSI < -110 dBm)
→ Gateway offline i del af perioden
→ Måler-udskiftning uden aflæsning af gammel måler
→ HCA pludselig 0 ved ellers aktiv radiator
Metode 1 — Historisk gennemsnit
# server/src/distribution/estimation.py
from decimal import Decimal
from datetime import date, timedelta
from sqlalchemy import text
from sqlalchemy.ext.asyncio import AsyncSession
async def estimate_by_historical_average(
meter_installation_id: str,
period_start: date,
period_end: date,
db: AsyncSession,
) -> Decimal:
"""
§ 13 stk. 1: Estimér baseret på forrige periodes faktiske forbrug.
Normaliserer pr. dag for at håndtere perioder af forskellig længde.
"""
period_days = (period_end - period_start).days
# Hent forbrug fra de seneste 3 regnskabsperioder
result = await db.execute(
text("""
SELECT
SUM(r.value_kwh) AS total_kwh,
COUNT(*) AS reading_count,
MIN(r.timestamp) AS first_ts,
MAX(r.timestamp) AS last_ts
FROM readings r
WHERE r.meter_installation_id = :mi_id
AND r.timestamp >= :lookback_start
AND r.timestamp < :period_start
"""),
{
"mi_id": meter_installation_id,
"lookback_start": period_start - timedelta(days=3 * 365),
"period_start": period_start,
},
)
row = result.fetchone()
if not row or not row.total_kwh or row.reading_count < 10:
return None # Ikke nok historik — brug nabointerpolering
# Historisk dagsforbrug × antal dage i estimeringsperiode
historical_days = (row.last_ts.date() - row.first_ts.date()).days or 1
daily_avg = Decimal(str(row.total_kwh)) / Decimal(historical_days)
estimate = daily_avg * Decimal(period_days)
return estimate.quantize(Decimal("0.1"))
Metode 2 — Graddage-normaliseret estimat
# server/src/distribution/estimation.py
async def estimate_by_degree_days(
meter_installation_id: str,
period_start: date,
period_end: date,
zip_code: str,
db: AsyncSession,
) -> Decimal | None:
"""
§ 13 stk. 1 + DMI-graddage: Temperaturnormaliseret historisk forbrug.
Mere præcist end simpelt gennemsnit ved milde/kolde perioder.
"""
# Hent graddage for estimeringsperiode og historisk periode
result = await db.execute(
text("""
WITH current_dd AS (
SELECT COALESCE(SUM(heating_degree_days), 0) AS hdd
FROM degree_days
WHERE zip_code = :zip_code
AND date BETWEEN :period_start AND :period_end
),
historical_dd AS (
SELECT COALESCE(SUM(heating_degree_days), 1) AS hdd
FROM degree_days
WHERE zip_code = :zip_code
AND date BETWEEN :hist_start AND :period_start
),
historical_kwh AS (
SELECT COALESCE(SUM(value_kwh), 0) AS kwh
FROM readings
WHERE meter_installation_id = :mi_id
AND timestamp BETWEEN :hist_start AND :period_start
)
SELECT
current_dd.hdd AS current_hdd,
historical_dd.hdd AS hist_hdd,
historical_kwh.kwh AS hist_kwh
FROM current_dd, historical_dd, historical_kwh
"""),
{
"zip_code": zip_code,
"period_start": period_start,
"period_end": period_end,
"hist_start": period_start - timedelta(days=3 * 365),
"mi_id": meter_installation_id,
},
)
row = result.fetchone()
if not row or row.hist_hdd == 0 or row.hist_kwh == 0:
return None
# Estimer: historisk forbrug × (nuværende HDD / historisk HDD)
correction = Decimal(str(row.current_hdd)) / Decimal(str(row.hist_hdd))
estimate = Decimal(str(row.hist_kwh)) * correction
return estimate.quantize(Decimal("0.1"))
Metode 3 — Nabointerpolering
# server/src/distribution/estimation.py
async def estimate_by_neighbor_interpolation(
unit_id: str,
property_id: str,
period_start: date,
period_end: date,
floor_area_m2: Decimal,
db: AsyncSession,
) -> Decimal | None:
"""
§ 13 stk. 2: Sammenlignelige boligenheder i samme ejendom.
Bruges når historik mangler (ny installation, ny lejer).
Normaliserer pr. m² → estimér for defekt enhed.
"""
result = await db.execute(
text("""
SELECT
AVG(r.value_kwh / u.floor_area_m2) AS kwh_per_m2
FROM readings r
JOIN meter_installations mi ON mi.id = r.meter_installation_id
JOIN units u ON u.id = mi.unit_id
WHERE u.property_id = :property_id
AND mi.unit_id != :unit_id -- Ekskludér defekt enhed
AND mi.removed_at IS NULL
AND u.deleted_at IS NULL
AND r.timestamp BETWEEN :period_start AND :period_end
AND u.floor_area_m2 > 0
"""),
{
"property_id": property_id,
"unit_id": unit_id,
"period_start": period_start,
"period_end": period_end,
},
)
row = result.fetchone()
if not row or not row.kwh_per_m2:
return None
estimate = Decimal(str(row.kwh_per_m2)) * floor_area_m2
return estimate.quantize(Decimal("0.1"))
Platform-automatik og dokumentation
# server/src/distribution/estimation.py
async def auto_estimate(
meter_installation_id: str,
unit_id: str,
property_id: str,
zip_code: str,
floor_area_m2: Decimal,
period_start: date,
period_end: date,
db: AsyncSession,
) -> dict:
"""
Prøv estimeringsmetoder i prioriteret rækkefølge:
1. Graddage-normaliseret (mest præcis)
2. Historisk gennemsnit (fallback)
3. Nabointerpolering (ved manglende historik)
Returnér estimat + metode-dokumentation til BEK 563 § 13 audit.
"""
# Metode 1: Graddage
estimate = await estimate_by_degree_days(
meter_installation_id, period_start, period_end, zip_code, db
)
if estimate:
return {"value_kwh": estimate, "method": "degree_day_normalized", "confidence": "high"}
# Metode 2: Historisk gennemsnit
estimate = await estimate_by_historical_average(
meter_installation_id, period_start, period_end, db
)
if estimate:
return {"value_kwh": estimate, "method": "historical_average", "confidence": "medium"}
# Metode 3: Nabointerpolering
estimate = await estimate_by_neighbor_interpolation(
unit_id, property_id, period_start, period_end, floor_area_m2, db
)
if estimate:
return {"value_kwh": estimate, "method": "neighbor_interpolation", "confidence": "low"}
# Ingen data → manuel vurdering krævet
return {"value_kwh": Decimal("0"), "method": "manual_required", "confidence": "none"}
Revisor-dokumentation i PDF
BEK 563 § 13 dokumentation i årsafregning:
Obligatorisk indhold ved estimat:
→ "Forbrug estimeret — måler defekt/signal manglende"
→ Estimeringsmetode: "Graddage-normaliseret historisk gennemsnit"
→ Estimeringsgrundlag: "Aflæsninger 2023-06-01 til 2025-05-31"
→ Estimeret forbrug: 1.234 kWh (± 15%)
→ Faktisk forbrug (øvrige enheder): Angivet separat
Platform PDF-noter pr. lejlighed:
Unit.status = "estimated"
DistributionResult.estimation_method = "degree_day_normalized"
DistributionResult.estimation_confidence = "high"
PDF: Notationseksempel i bilag A
Lejerrettigheder ved estimat:
→ § 18: 6 ugers indsigelsesret (som normalt)
→ Lejer kan kræve faktisk aflæsning hvis måler nu virker
→ Ved repareret måler: Korrektionsafregning mulig (aftale)
→ Huslejenævn: Kan kræve gentagen målbar data
Konklusion
BEK 563 § 13 giver tre lovlige estimeringsmetoder ved manglende aflæsning: historisk gennemsnit, graddage-normaliseret historik og nabointerpolering. Platformen prøver dem i prioriteret rækkefølge og dokumenterer metode + konfidensgrad i regnskabet. 4-måneders-fristen gælder fuldt ud — estimat er ikke undskyldning for forsinket afregning. Lejer skal orienteres om estimatet og har normal 6-ugers indsigelsesret. PDF-dokumentation med estimeringsmetode og grundlag er det stærkeste forsvar ved huslejenævnssag.
Se wM-Bus signal troubleshooting guide eller pro-rata guide.