From 4d38c5302cc0557fb3fb4901ddf8da4302bf2b77 Mon Sep 17 00:00:00 2001 From: Homelab Cursor Date: Sat, 21 Mar 2026 02:02:29 +0100 Subject: [PATCH] =?UTF-8?q?fix(grafana):=20Umlaute,=20=C2=B0C,=20saubere?= =?UTF-8?q?=20Formatierung=20fuer=20Temperaturen/Energie/Heizung?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - SENSOR_MAP Labels mit echten Umlauten (Außen, Küche, Ölkessel) - Gradzeichen °C statt nur C - Listenformat mit Bindestrich statt Einrueckung - Abschnitte Räume & Außen / Heizung & Puffer - Energie-Tool mit passenden Einheiten (W, kWh, %) - SYSTEM_PROMPT_EXTRA: LLM soll Tool-Output 1:1 weitergeben --- homelab-ai-bot/tools/grafana.py | 83 +++++++++++++++++++-------------- 1 file changed, 49 insertions(+), 34 deletions(-) diff --git a/homelab-ai-bot/tools/grafana.py b/homelab-ai-bot/tools/grafana.py index c840af38..e5b8b849 100644 --- a/homelab-ai-bot/tools/grafana.py +++ b/homelab-ai-bot/tools/grafana.py @@ -10,29 +10,40 @@ INFLUX_URL = "http://100.66.78.56:8086" INFLUX_DB = "iobroker" SENSOR_MAP = { - "aussen": ("mqtt.0.Holzvergaser_Sensoren_6.Aussenfühler.temperature", "Aussen"), + "aussen": ("mqtt.0.Holzvergaser_Sensoren_6.Aussenfühler.temperature", "Außen"), "wohnstube": ("mqtt.0.Wohnstube_Temperatur_1.Wohnstube.Wohnstube_Temperatur", "Wohnstube"), - "kueche": ("mqtt.0.ESP_Kücheneu_2.Sensor_Küche.Küche", "Kueche"), + "kueche": ("mqtt.0.ESP_Kücheneu_2.Sensor_Küche.Küche", "Küche"), "garage": ("mqtt.0.ESP_Easy_3.Garage_neu.Garage", "Garage"), "puffer_oben": ("mqtt.0.ESP_Easy_Display_4.oben.temperature", "Puffer oben"), "puffer_unten": ("mqtt.0.ESP_Easy_Display_4.Unten.temperature", "Puffer unten"), "garten": ("mqtt.0.ESP_Easy_schwimmbad_neu.Lufttemperatur.Lufttemperatur_Garten", "Garten/Luft"), "schwimmbad": ("mqtt.0.ESP_Easy_schwimmbad_neu.Schwimmbad.Wassertemperatur_", "Schwimmbad"), - "oelkessel_vl": ("mqtt.0.Oelkessel.Oelkessel_VL.Vorlauf", "Oelkessel Vorlauf"), + "oelkessel_vl": ("mqtt.0.Oelkessel.Oelkessel_VL.Vorlauf", "Ölkessel Vorlauf"), "brunnen_vl": ("mqtt.0.Brunnenwasser.Oelkessel_VL.Vorlauf", "Brunnenwasser Vorlauf"), "holzvergaser_1": ("mqtt.0.Holzvergaser_Sensoren_6.temp1.temperature1", "Holzvergaser Sensor 1"), "holzvergaser_2": ("mqtt.0.Holzvergaser_Sensoren_6.temp2.temperature2", "Holzvergaser Sensor 2"), } ENERGIE_MEASUREMENTS = { - "pv_leistung": ("mqtt.1.openWB.pv.W", "PV Leistung (W)"), - "pv_tagesertrag": ("mqtt.1.openWB.pv.DailyYieldKwh", "PV Tagesertrag (kWh)"), - "netz_bezug": ("mqtt.1.openWB.evu.W", "Netz Bezug/Einspeisung (W)"), - "hausverbrauch": ("mqtt.1.openWB.global.WHouseConsumption", "Hausverbrauch (W)"), - "batterie_soc": ("mqtt.1.openWB.housebattery.%Soc", "Batterie SoC (%)"), - "ueberschuss": ("mqtt.1.openWB.SmartHome.Status.uberschuss", "Ueberschuss (W)"), + "pv_leistung": ("mqtt.1.openWB.pv.W", "PV Leistung"), + "pv_tagesertrag": ("mqtt.1.openWB.pv.DailyYieldKwh", "PV Tagesertrag"), + "netz_bezug": ("mqtt.1.openWB.evu.W", "Netz Bezug/Einspeisung"), + "hausverbrauch": ("mqtt.1.openWB.global.WHouseConsumption", "Hausverbrauch"), + "batterie_soc": ("mqtt.1.openWB.housebattery.%Soc", "Batterie SoC"), + "ueberschuss": ("mqtt.1.openWB.SmartHome.Status.uberschuss", "Überschuss"), } +_ENERGIE_UNITS = { + "PV Leistung": "W", + "PV Tagesertrag": "kWh", + "Netz Bezug/Einspeisung": "W", + "Hausverbrauch": "W", + "Batterie SoC": "%", + "Überschuss": "W", +} + +_HEIZUNG_KEYS = {"puffer", "vorlauf", "holz", "brunnen", "öl"} + TOOLS = [ { "type": "function", @@ -46,7 +57,7 @@ TOOLS = [ "type": "function", "function": { "name": "get_temperaturen", - "description": "Aktuelle Temperaturen aus dem Haus in Muldenstein: Raeume, Aussen, Puffer, Heizung. Nutze bei Fragen zu Temperatur, Heizung, Puffer, Raumklima, 'wie warm ist es'.", + "description": "Aktuelle Temperaturen aus dem Haus in Muldenstein: Räume, Außen, Puffer, Heizung. Nutze bei Fragen zu Temperatur, Heizung, Puffer, Raumklima, 'wie warm ist es'.", "parameters": {"type": "object", "properties": {}, "required": []}, }, }, @@ -62,18 +73,21 @@ TOOLS = [ "type": "function", "function": { "name": "get_heizung", - "description": "Heizungsstatus: Brenner, Puffertemperaturen, Vorlauf, Holzvergaser. Nutze bei Fragen zu Heizung, Brenner, Puffer, Holzvergaser, Oelkessel.", + "description": "Heizungsstatus: Brenner, Puffertemperaturen, Vorlauf, Holzvergaser. Nutze bei Fragen zu Heizung, Brenner, Puffer, Holzvergaser, Ölkessel.", "parameters": {"type": "object", "properties": {}, "required": []}, }, }, ] -SYSTEM_PROMPT_EXTRA = """Fuer Smart-Home-Daten (Temperaturen, Energie, Heizung) im Haus Muldenstein: -- get_temperaturen: alle Raumtemperaturen + Aussen +SYSTEM_PROMPT_EXTRA = """Für Smart-Home-Daten (Temperaturen, Energie, Heizung) im Haus Muldenstein: +- get_temperaturen: alle Raumtemperaturen + Außen - get_energie: PV, Batterie, Netz, Hausverbrauch - get_heizung: Brenner, Puffer, Vorlauf, Holzvergaser -- get_grafana_status: Dashboard-Uebersicht und Alerts +- get_grafana_status: Dashboard-Übersicht und Alerts Grafana-URL: https://grafana.orbitalo.net/ + +WICHTIG: Die Tool-Ergebnisse sind bereits fertig formatiert. +Gib sie 1:1 weiter, NICHT umformulieren oder kürzen. """ @@ -162,41 +176,42 @@ def handle_get_grafana_status(**kw): def handle_get_temperaturen(**kw): data = _query_latest(SENSOR_MAP) if not data: - return "Keine Temperaturdaten verfuegbar (InfluxDB nicht erreichbar?)" + return "Keine Temperaturdaten verfügbar (InfluxDB nicht erreichbar?)" raeume = [] heizung = [] for name, val, ts in data: - entry = f" {name}: {val:.1f} C ({ts})" - if any(k in name.lower() for k in ["puffer", "vorlauf", "holz", "brunnen", "oel"]): + entry = f"- {name}: {val:.1f} °C" + if any(k in name.lower() for k in _HEIZUNG_KEYS): heizung.append(entry) else: raeume.append(entry) - lines = ["Temperaturen Muldenstein (live):"] + lines = ["Temperaturen Muldenstein:"] if raeume: - lines.append("\nRaeume & Aussen:") + lines.append("\nRäume & Außen:") lines.extend(raeume) if heizung: lines.append("\nHeizung & Puffer:") lines.extend(heizung) - lines.append(f"\nGrafana: https://grafana.orbitalo.net/d/solar/raumtemperaturen") + lines.append("\nGrafana: https://grafana.orbitalo.net/d/solar/raumtemperaturen") return "\n".join(lines) def handle_get_energie(**kw): data = _query_latest(ENERGIE_MEASUREMENTS) if not data: - return "Keine Energiedaten verfuegbar (InfluxDB nicht erreichbar?)" + return "Keine Energiedaten verfügbar (InfluxDB nicht erreichbar?)" - lines = ["Energie Muldenstein (live):\n"] + lines = ["Energie Muldenstein:"] for name, val, ts in data: - if "%" in name or "kWh" in name: - lines.append(f" {name}: {val:.1f} ({ts})") + unit = _ENERGIE_UNITS.get(name, "") + if unit in ("%", "kWh"): + lines.append(f"- {name}: {val:.1f} {unit}") else: - lines.append(f" {name}: {val:.0f} ({ts})") + lines.append(f"- {name}: {val:.0f} {unit}") - lines.append(f"\nGrafana: https://grafana.orbitalo.net/d/solar/energie-uebersicht") + lines.append("\nGrafana: https://grafana.orbitalo.net/d/solar/energie-uebersicht") return "\n".join(lines) @@ -216,30 +231,30 @@ def handle_get_heizung(**kw): laufzeit_q = 'SELECT last(value) FROM "brenner_heute" WHERE time > now() - 2h' starts_q = 'SELECT last(value) FROM "brennerstarts" WHERE time > now() - 24h' - lines = ["Heizung Muldenstein (live):\n"] + lines = ["Heizung Muldenstein:"] brenner = _influx_query(brenner_q) if brenner and brenner.get("results", [{}])[0].get("series"): val = brenner["results"][0]["series"][0]["values"][0][1] - status = "AN" if val else "AUS" - lines.append(f" Brenner: {status}") + status = "🔥 AN" if val else "⏸ AUS" + lines.append(f"\nBrenner: {status}") laufzeit = _influx_query(laufzeit_q) if laufzeit and laufzeit.get("results", [{}])[0].get("series"): val = laufzeit["results"][0]["series"][0]["values"][0][1] - lines.append(f" Brenner heute: {val:.0f} min") + lines.append(f"Brenner heute: {val:.0f} min") starts = _influx_query(starts_q) if starts and starts.get("results", [{}])[0].get("series"): val = starts["results"][0]["series"][0]["values"][0][1] - lines.append(f" Brennerstarts: {val:.0f}") + lines.append(f"Brennerstarts (24h): {val:.0f}") if data: - lines.append("") + lines.append("\nTemperaturen:") for name, val, ts in data: - lines.append(f" {name}: {val:.1f} C ({ts})") + lines.append(f"- {name}: {val:.1f} °C") - lines.append(f"\nGrafana: https://grafana.orbitalo.net/d/heizung/heizung-and-puffer") + lines.append("\nGrafana: https://grafana.orbitalo.net/d/heizung/heizung-and-puffer") return "\n".join(lines)