278 lines
15 KiB
Python
278 lines
15 KiB
Python
"""Markdown-Reporterzeugung fuer die Waermerueckgewinnung-Auslegung.
|
||
|
||
Einziger oeffentlicher Einstiegspunkt: report_md(e, cfg, quelldateien).
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
import datetime
|
||
|
||
|
||
def _h2(title: str) -> list[str]:
|
||
return ["", f"## {title}", ""]
|
||
|
||
|
||
def _h3(title: str) -> list[str]:
|
||
return [f"### {title}", ""]
|
||
|
||
|
||
def _tbl_header(cols: list[str]) -> list[str]:
|
||
return [" | ".join(cols),
|
||
" | ".join(["---"] * len(cols))]
|
||
|
||
|
||
def report_md(e: dict, cfg: dict, quelldateien: list[str] | None = None) -> str:
|
||
"""Vollstaendiger Markdown-Report: je Block erst Voraussetzungen, dann Ergebnisse."""
|
||
q = e["milch_kuehllast_kWh_tag"]
|
||
wp = e["waermepumpe"]
|
||
sp = e["speicher"]
|
||
pv = e["pv"]
|
||
netz = e["netzbezug"]
|
||
bat = e["batterie"]
|
||
hh = e["haushalte"]
|
||
m_cfg = cfg["milch"]
|
||
wp_cfg = cfg["waermepumpe"]
|
||
pcm_cfg = cfg["pcm"]
|
||
abh_cfg = cfg["abholung"]
|
||
pv_cfg = cfg["pv"]
|
||
bat_cfg = cfg["batterie"]
|
||
hh_cfg = cfg["haushalt"]
|
||
z = abh_cfg["zyklus_tage"]
|
||
milch = e["eingang"]["milch_l_tag"]
|
||
ts = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
|
||
|
||
L = []
|
||
L.append("# Auslegung Waermerueckgewinnung Milchkuehlung")
|
||
L.append("")
|
||
L.append(f"**Erstellt:** {ts}")
|
||
if quelldateien:
|
||
L.append(f"**Konfiguration:** {', '.join(quelldateien)}")
|
||
|
||
# ── Milchkühllast ────────────────────────────────────────────────
|
||
L.extend(_h2("Milchkuehllast"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| Milchmenge | {milch:.0f} L/Tag |")
|
||
L.append(f"| Eingangstemperatur | {m_cfg['temp_ein_C']:.0f} C (Eutertemperatur) |")
|
||
L.append(f"| Ausgangstemperatur | {m_cfg['temp_aus_C']:.0f} C (Lagertemperatur) |")
|
||
L.append(f"| Dichte | {m_cfg['dichte_kg_pro_L']:.2f} kg/L |")
|
||
L.append(f"| Spez. Waerme | {m_cfg['spez_waerme_kJ_pro_kgK']:.3f} kJ/(kg·K) |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| Taegl. Kuehllast | **{q:.1f} kWh/Tag** |")
|
||
|
||
# ── Wärmepumpe ───────────────────────────────────────────────────
|
||
L.extend(_h2("Waermepumpe"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| COP (Coefficient of Performance) | {wp_cfg['cop']:.2f} |")
|
||
L.append(f"| Laufzeit | {wp_cfg['laufzeit_h_pro_tag']:.0f} h/Tag |")
|
||
L.append(f"| Kuehllast (aus Milchblock) | {q:.1f} kWh/Tag |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| Kaelteleistung (Verdampfer) | {wp['kaelteleistung_kW']:.1f} kW |")
|
||
L.append(f"| Heizleistung (Kondensator) | {wp['heizleistung_kW']:.1f} kW |")
|
||
L.append(f"| el. Leistung | {wp['elektrische_leistung_kW']:.1f} kW |")
|
||
L.append(f"| Strombedarf | **{wp['strom_kWh_tag']:.1f} kWh/Tag** |")
|
||
L.append(f"| Waerme in den Speicher | **{wp['speicher_kWh_tag']:.1f} kWh/Tag** |")
|
||
|
||
# ── PV-Anlage ────────────────────────────────────────────────────
|
||
L.extend(_h2("PV-Anlage (Jahresbilanz)"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| Strombedarf WP (aus WP-Block) | {wp['strom_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| Spez. Jahresertrag | {pv_cfg['spez_ertrag_kWh_pro_kWp_jahr']} kWh/(kWp·a) |")
|
||
L.append(f"| Dachflaeche je kWp | {pv_cfg['flaeche_m2_pro_kWp']:.1f} m2/kWp |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| Jahresstrombedarf WP | {pv['jahresbedarf_kWh']:.0f} kWh/a |")
|
||
L.append(f"| PV-Leistung | **{pv['kWp']:.1f} kWp** |")
|
||
L.append(f"| Dachflaeche | **{pv['flaeche_m2']:.0f} m2** |")
|
||
|
||
# ── Netzbezug ────────────────────────────────────────────────────
|
||
L.extend(_h2("Netzbezug (Wintermonate, Monatsbilanz)"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| PV-Leistung (aus PV-Block) | {pv['kWp']:.1f} kWp |")
|
||
L.append(f"| Strombedarf WP | {wp['strom_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| Monatsprofil | Jan {pv_cfg['monatsertrag_kWh_pro_kWp']['Jan']},"
|
||
f" Feb {pv_cfg['monatsertrag_kWh_pro_kWp']['Feb']},"
|
||
f" ... Dez {pv_cfg['monatsertrag_kWh_pro_kWp']['Dez']} kWh/kWp |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| Netzbezug | **{netz['netzbezug_kWh']:.0f} kWh/a = {netz['netzbezug_anteil']*100:.0f} %** |")
|
||
L.append(f"| Sommerueberschuss | {netz['ueberschuss_kWh']:.0f} kWh/a |")
|
||
L.append("")
|
||
L.append("#### Monatsbilanz")
|
||
L.append("")
|
||
L.extend(_tbl_header(["Monat", "Bedarf kWh", "PV kWh", "Zukauf kWh"]))
|
||
for monat, werte in netz["monate"].items():
|
||
L.append(f"| {monat} | {werte['bedarf_kWh']:.0f} | {werte['pv_kWh']:.0f}"
|
||
f" | {werte['zukauf_kWh']:.0f} |")
|
||
|
||
# ── Batterie ─────────────────────────────────────────────────────
|
||
L.extend(_h2("Batterie (Tag-/Nacht-Ueberbrueckung)"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| Strombedarf WP | {wp['strom_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| Direkt-PV-Stunden (WP laeuft direkt aus PV) | {bat_cfg['direkt_pv_stunden']:.0f} h/Tag |")
|
||
L.append(f"| Nutzbarer Anteil (Entladetiefe LFP) | {bat_cfg['nutzbar_anteil']*100:.0f} % |")
|
||
L.append(f"| Reservefaktor | {bat_cfg['reserve_faktor']:.1f} |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| Nutzbare Kapazitaet | {bat['nutzbar_kWh']:.1f} kWh |")
|
||
L.append(f"| Nennkapazitaet | **{bat['nominal_kWh']:.1f} kWh** |")
|
||
|
||
# ── Latentspeicher ───────────────────────────────────────────────
|
||
passt = "ja" if sp["passt_in_einen_lkw"] else "NEIN - mehrere Behaelter noetig"
|
||
L.extend(_h2(f"Latentspeicher ({pcm_cfg['name']})"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| PCM | {pcm_cfg['name']} |")
|
||
L.append(f"| Schmelzpunkt | {pcm_cfg['schmelzpunkt_C']:.0f} C |")
|
||
L.append(f"| Latentwaerme | {pcm_cfg['latentwaerme_kJ_pro_kg']:.0f} kJ/kg |")
|
||
L.append(f"| Dichte | {pcm_cfg['dichte_kg_pro_L']:.1f} kg/L |")
|
||
L.append(f"| Modus | {pcm_cfg['modus']} |")
|
||
if pcm_cfg["modus"] == "latent_plus_hub":
|
||
L.append(f"| Ladetemperatur | {pcm_cfg['ladetemp_C']:.0f} C |")
|
||
L.append(f"| Entladetemperatur | {pcm_cfg['entladetemp_C']:.0f} C |")
|
||
L.append(f"| cp fluessig | {pcm_cfg['cp_fluessig_kJ_pro_kgK']:.1f} kJ/(kg·K) |")
|
||
L.append(f"| cp fest | {pcm_cfg['cp_fest_kJ_pro_kgK']:.1f} kJ/(kg·K) |")
|
||
L.append(f"| Abholzyklus | {z} Tage |")
|
||
L.append(f"| LKW-Nutzlast | {abh_cfg['lkw_nutzlast_kg']:,} kg |")
|
||
L.append(f"| LKW-Volumen | {abh_cfg['lkw_volumen_m3']} m3 |")
|
||
L.append(f"| Waerme je Tag (aus WP-Block) | {wp['speicher_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| Energiedichte | {sp['energiedichte_kWh_pro_kg']*1000:.1f} Wh/kg |")
|
||
L.append(f"| Energie je Zyklus ({z} Tage) | {sp['energie_pro_zyklus_kWh']:.0f} kWh |")
|
||
L.append(f"| Masse | **{sp['masse_kg']:.0f} kg** |")
|
||
L.append(f"| Volumen | **{sp['volumen_m3']:.1f} m3** |")
|
||
L.append(f"| LKW-Auslastung Gewicht | {sp['auslastung_gewicht']*100:.0f} % |")
|
||
L.append(f"| LKW-Auslastung Volumen | {sp['auslastung_volumen']*100:.0f} % |")
|
||
L.append(f"| Bindende Grenze | {sp['bindende_grenze']} |")
|
||
L.append(f"| Passt in einen LKW | {passt} |")
|
||
L.append(f"| Voller LKW nach | {sp['voller_lkw_tausch_tage']:.1f} Tagen |")
|
||
L.append(f"| Energieinhalt voller LKW | {sp['voller_lkw_energie_kWh']:.0f} kWh |")
|
||
|
||
# ── Haushalte ────────────────────────────────────────────────────
|
||
L.extend(_h2(f"Versorgte Haushalte"
|
||
f" ({hh_cfg['erwachsene']} Erw. + {hh_cfg['kinder']} Kinder)"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| Erwachsene je Haushalt | {hh_cfg['erwachsene']} |")
|
||
L.append(f"| Kinder je Haushalt | {hh_cfg['kinder']} |")
|
||
L.append(f"| WW-Bedarf Erwachsener | {hh_cfg['ww_erwachsener_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| WW-Bedarf Kind | {hh_cfg['ww_kind_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| Heizbedarf Winter | {hh_cfg['heizbedarf_winter_kWh_tag']:.0f} kWh/Tag/HH |")
|
||
L.append(f"| Waerme je Tag (aus WP-Block) | {wp['speicher_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kenngroesse", "Wert"]))
|
||
L.append(f"| WW-Bedarf je Haushalt | {hh['ww_pro_haushalt_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| Winterbedarf je Haushalt (Heiz+WW) | {hh['winter_pro_haushalt_kWh_tag']:.1f} kWh/Tag |")
|
||
L.append(f"| Versorgte HH (Warmwasser, ganzjaehrig) | **{hh['haushalte_warmwasser']:.1f}** |")
|
||
L.append(f"| Versorgte HH (Heizung + WW, Winter) | **{hh['haushalte_winter']:.1f}** |")
|
||
|
||
# ── Wert beim Käufer ─────────────────────────────────────────────
|
||
bk = e.get("brennstoffkosten")
|
||
if bk and bk["vergleich"]:
|
||
L.extend(_h2("Wert der Waerme beim Kaeufer (Ersatzkosten fossil/Holz)"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Brennstoff", "Preis ct/kWh", "Kesselwirkungsgrad"]))
|
||
for b in cfg.get("brennstoffe", []):
|
||
L.append(f"| {b['name']} | {b['preis_ct_kWh']:.1f} | {b['wirkungsgrad']*100:.0f} % |")
|
||
L.append("")
|
||
L.append("*Nutzwaermekosten = Brennstoffpreis ÷ Kesselwirkungsgrad*")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.append(f"Bewertet: voller LKW **{bk['energie_lkw_kWh']:.0f} kWh**,"
|
||
f" Jahreserzeugung **{bk['energie_jahr_kWh']:.0f} kWh/a**")
|
||
L.append("")
|
||
L.extend(_tbl_header(["Brennstoff", "ct/kWh (Nutzw.)", "EUR/LKW", "EUR/Jahr"]))
|
||
for v in bk["vergleich"]:
|
||
L.append(f"| {v['name']} | {v['nutzwaerme_ct_kWh']:.1f} |"
|
||
f" {v['eur_pro_lkw']:.0f} | {v['eur_pro_jahr']:.0f} |")
|
||
|
||
# ── Gestehungskosten Anbieter ────────────────────────────────────
|
||
ak = e.get("anbieter")
|
||
if ak:
|
||
inv = cfg["anbieter"]["invest"]
|
||
ci = ak["container_invest"]
|
||
sd = ak["kosten_strom_detail"]
|
||
L.extend(_h2("Waerme-Gestehungskosten Anbieter"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| Transport je Fuhre | {cfg['anbieter']['transport_eur_pro_fuhre']:.0f} EUR |")
|
||
L.append(f"| Netzstrompreis | {cfg['anbieter']['netzstrompreis_ct_kWh']:.0f} ct/kWh |")
|
||
L.append(f"| PV-Gestehungskosten (LCOE) | {cfg['anbieter']['pv_gestehung_ct_kWh']:.0f} ct/kWh |")
|
||
L.append(f"| Wartung pauschal | {cfg['anbieter']['wartung_eur_pro_jahr']:.0f} EUR/a |")
|
||
L.append(f"| PV-Invest | {inv['pv_eur_pro_kWp']} EUR/kWp,"
|
||
f" {inv['pv_nutzungsdauer_jahre']} J Nutzung |")
|
||
L.append(f"| Batterie-Invest | {inv['batterie_eur_pro_kWh']} EUR/kWh,"
|
||
f" {inv['batterie_nutzungsdauer_jahre']} J |")
|
||
L.append(f"| WP-Invest | {inv['waermepumpe_eur']:,} EUR,"
|
||
f" {inv['waermepumpe_nutzungsdauer_jahre']} J |")
|
||
L.append(f"| Speicher-Invest | {ci['anzahl_module']} Module,"
|
||
f" {inv['speicher_nutzungsdauer_jahre']} J Nutzung |")
|
||
L.append("")
|
||
L.append("**Aufschluesselung Speicher-Invest**")
|
||
L.append("")
|
||
L.extend(_tbl_header(["Komponente", "EUR (alle Module)"]))
|
||
L.append(f"| PCM ({sp['masse_kg']:.0f} kg × {ci['anzahl_module']} Module)"
|
||
f" | {ci['pcm_eur']:,.0f} |")
|
||
L.append(f"| Behaelter (isoliert, LKW-tauglich) | {ci['behaelter_eur']:,.0f} |")
|
||
L.append(f"| Waermetauscher + Hydraulik | {ci['wt_hydraulik_eur']:,.0f} |")
|
||
L.append(f"| Elektronik / Regelung | {ci['elektronik_eur']:,.0f} |")
|
||
L.append(f"| Montage + Inbetriebnahme | {ci['montage_eur']:,.0f} |")
|
||
L.append(f"| **Gesamt** | **{ci['gesamt_eur']:,.0f}** |")
|
||
L.append(f"| entspricht | {ci['eur_pro_kwh_kapazitaet']:.0f} EUR/kWh Speicherkapazitaet |")
|
||
L.append("")
|
||
L.append("*Abschreibung: linear, kein Kapitalzins.*")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.extend(_tbl_header(["Kostenblock", "EUR/Jahr"]))
|
||
L.append(f"| Transport ({ak['fuhren_jahr']:.0f} Fuhren/a)"
|
||
f" | {ak['kosten_transport_eur']:.0f} |")
|
||
L.append(f"| WP-Strom ({sd['netz_kWh']:.0f} kWh Netz"
|
||
f" + {sd['pv_kWh']:.0f} kWh PV-Eigen) | {ak['kosten_strom_eur']:.0f} |")
|
||
L.append(f"| Wartung | {ak['kosten_wartung_eur']:.0f} |")
|
||
L.append(f"| Kapital PV ({pv['kWp']:.1f} kWp) | {ak['kapital_pv_eur']:.0f} |")
|
||
L.append(f"| Kapital Batterie ({bat['nominal_kWh']:.0f} kWh)"
|
||
f" | {ak['kapital_batterie_eur']:.0f} |")
|
||
L.append(f"| Kapital Waermepumpe | {ak['kapital_waermepumpe_eur']:.0f} |")
|
||
L.append(f"| Kapital Speicher ({ci['anzahl_module']} Module)"
|
||
f" | {ak['kapital_speicher_eur']:.0f} |")
|
||
L.append(f"| **Jahreskosten gesamt** | **{ak['jahreskosten_eur']:.0f}** |")
|
||
L.append("")
|
||
L.append(f"**Jahreserzeugung:** {ak['energie_jahr_kWh']:.0f} kWh/a")
|
||
L.append("")
|
||
L.append(f"**Mindestverkaufspreis: {ak['gestehungskosten_ct_kWh']:.1f} ct/kWh**")
|
||
|
||
# ── Marge ────────────────────────────────────────────────────
|
||
if ak["marge"]:
|
||
L.extend(_h2("Marge gegen Ersatzbrennstoff"))
|
||
L.extend(_h3("Voraussetzungen"))
|
||
L.extend(_tbl_header(["Parameter", "Wert"]))
|
||
L.append(f"| Mindestverkaufspreis (aus Gestehungskosten)"
|
||
f" | {ak['gestehungskosten_ct_kWh']:.1f} ct/kWh |")
|
||
for m in ak["marge"]:
|
||
L.append(f"| Nutzwaerme {m['name']} | {m['nutzwaerme_ct_kWh']:.1f} ct/kWh |")
|
||
L.append("")
|
||
L.extend(_h3("Ergebnisse"))
|
||
L.append("Marge = Nutzwaermekosten Brennstoff − Mindestverkaufspreis."
|
||
" Positiv = System kostendeckend.")
|
||
L.append("")
|
||
L.extend(_tbl_header(
|
||
["Brennstoff", "ct/kWh (Nutzw.)", "Marge ct/kWh", "Marge EUR/Jahr"]))
|
||
for m in ak["marge"]:
|
||
L.append(f"| {m['name']} | {m['nutzwaerme_ct_kWh']:.1f} |"
|
||
f" {m['marge_ct_kWh']:+.1f} | {m['marge_eur_jahr']:+.0f} |")
|
||
|
||
return "\n".join(L)
|