Grafana: Heizraum I/O Eingänge und Ausgänge auf Heizung-Dashboard
This commit is contained in:
parent
82e42a8ad1
commit
068dde4574
1 changed files with 163 additions and 0 deletions
163
smart-home/scripts/add_heizraum_io_panels.py
Executable file
163
smart-home/scripts/add_heizraum_io_panels.py
Executable file
|
|
@ -0,0 +1,163 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Heizraum I/O Zeilen am Heizung-Dashboard (idempotent)."""
|
||||
import json
|
||||
import subprocess
|
||||
|
||||
BASE = "http://100.66.78.56:3000"
|
||||
DS_UID = "ffptl25vzylfke" # InfluxDB-sensors
|
||||
ROW_IN = "⚡ Heizraum Eingänge (Optokoppler)"
|
||||
ROW_OUT = "🔌 Heizraum Ausgänge"
|
||||
PANEL_IDS = list(range(910, 920))
|
||||
|
||||
|
||||
def curl(path, method="GET", body=None):
|
||||
cmd = ["curl", "-s", "-u", "admin:astral66", "-X", method, f"{BASE}{path}"]
|
||||
if body is not None:
|
||||
cmd += ["-H", "Content-Type: application/json", "-d", json.dumps(body)]
|
||||
r = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
|
||||
return json.loads(r.stdout) if r.stdout.startswith(("{", "[")) else r.stdout
|
||||
|
||||
|
||||
def io_stat(pid, title, signal, x, y, w=4, h=4, on_text="AN", off_text="AUS"):
|
||||
return {
|
||||
"id": pid,
|
||||
"type": "stat",
|
||||
"title": title,
|
||||
"description": (
|
||||
f"Heizraum-Knoten Eingang `{signal}` (GPIO Optokoppler, active-low). "
|
||||
f"MQTT: heizraum/io/{signal}" if signal != "kessel" else
|
||||
"Kessel-Schaltausgang GPIO16 (Relais). 1=abgeschaltet, 0=freigegeben. "
|
||||
"MQTT: heizraum/state/kessel"
|
||||
),
|
||||
"datasource": {"type": "influxdb", "uid": DS_UID},
|
||||
"gridPos": {"h": h, "w": w, "x": x, "y": y},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"mappings": [
|
||||
{
|
||||
"type": "value",
|
||||
"options": {
|
||||
"1": {"text": on_text, "color": "green" if signal != "kessel" else "red", "index": 0},
|
||||
"0": {"text": off_text, "color": "red" if signal != "kessel" else "green", "index": 1},
|
||||
},
|
||||
},
|
||||
],
|
||||
"noValue": off_text,
|
||||
"color": {"mode": "thresholds"},
|
||||
"thresholds": {
|
||||
"mode": "absolute",
|
||||
"steps": [
|
||||
{"color": "red" if signal != "kessel" else "green", "value": None},
|
||||
{"color": "green" if signal != "kessel" else "red", "value": 1},
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"reduceOptions": {"values": False, "calcs": ["lastNotNull"]},
|
||||
"colorMode": "background",
|
||||
"graphMode": "none",
|
||||
},
|
||||
"targets": [{
|
||||
"refId": "A",
|
||||
"rawQuery": True,
|
||||
"query": (
|
||||
f'SELECT last("value") FROM "io_state" '
|
||||
f"WHERE \"node\"='heizraum' AND \"signal\"='{signal}'"
|
||||
),
|
||||
}],
|
||||
}
|
||||
|
||||
|
||||
d = curl("/api/dashboards/uid/heizung")
|
||||
dash = d["dashboard"]
|
||||
|
||||
remove_titles = {
|
||||
ROW_IN, ROW_OUT,
|
||||
"Pumpe 1", "Pumpe 2", "Pumpe 3", "Pumpe 4", "Brenner",
|
||||
"Kessel (Ausgang)",
|
||||
}
|
||||
dash["panels"] = [
|
||||
p for p in dash["panels"]
|
||||
if p.get("title") not in remove_titles and p.get("id") not in PANEL_IDS
|
||||
]
|
||||
|
||||
max_y = 0
|
||||
for p in dash["panels"]:
|
||||
gp = p.get("gridPos", {})
|
||||
max_y = max(max_y, gp.get("y", 0) + gp.get("h", 0))
|
||||
|
||||
y = max_y
|
||||
|
||||
# --- Eingänge ---
|
||||
dash["panels"].append({
|
||||
"id": 910,
|
||||
"type": "row",
|
||||
"title": ROW_IN,
|
||||
"gridPos": {"h": 1, "w": 24, "x": 0, "y": y},
|
||||
"collapsed": False,
|
||||
})
|
||||
y += 1
|
||||
|
||||
inputs = [
|
||||
(911, "Pumpe 1", "pumpe1", 0),
|
||||
(912, "Pumpe 2", "pumpe2", 4),
|
||||
(913, "Pumpe 3", "pumpe3", 8),
|
||||
(914, "Pumpe 4", "pumpe4", 12),
|
||||
(915, "Brenner", "brenner", 16),
|
||||
]
|
||||
for pid, title, signal, x in inputs:
|
||||
dash["panels"].append(io_stat(pid, title, signal, x, y))
|
||||
y += 4
|
||||
|
||||
# --- Ausgänge ---
|
||||
dash["panels"].append({
|
||||
"id": 916,
|
||||
"type": "row",
|
||||
"title": ROW_OUT,
|
||||
"gridPos": {"h": 1, "w": 24, "x": 0, "y": y},
|
||||
"collapsed": False,
|
||||
})
|
||||
y += 1
|
||||
|
||||
dash["panels"].append(
|
||||
io_stat(917, "Kessel (Ausgang)", "kessel", 0, y, on_text="ABGESCHALTET", off_text="FREIGEGEBEN")
|
||||
)
|
||||
|
||||
# Verlauf aller IO-Signale
|
||||
dash["panels"].append({
|
||||
"id": 918,
|
||||
"type": "timeseries",
|
||||
"title": "Heizraum I/O Verlauf",
|
||||
"description": "Eingänge (Pumpen/Brenner) und Kessel-Ausgang über Zeit.",
|
||||
"datasource": {"type": "influxdb", "uid": DS_UID},
|
||||
"gridPos": {"h": 8, "w": 24, "x": 0, "y": y + 4},
|
||||
"fieldConfig": {
|
||||
"defaults": {
|
||||
"custom": {"drawStyle": "line", "lineWidth": 2, "spanNulls": 60000, "showPoints": "never"},
|
||||
"min": 0,
|
||||
"max": 1,
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"legend": {"displayMode": "table", "placement": "bottom", "calcs": ["last"]},
|
||||
},
|
||||
"targets": [{
|
||||
"refId": "A",
|
||||
"rawQuery": True,
|
||||
"query": (
|
||||
'SELECT mean("value") FROM "io_state" '
|
||||
"WHERE \"node\"='heizraum' AND $timeFilter "
|
||||
"GROUP BY time($__interval), \"signal\" fill(null)"
|
||||
),
|
||||
}],
|
||||
})
|
||||
|
||||
dash["version"] = dash.get("version", 0) + 1
|
||||
resp = curl("/api/dashboards/db", "POST", {
|
||||
"dashboard": dash,
|
||||
"folderId": 0,
|
||||
"overwrite": True,
|
||||
"message": "Heizraum I/O Eingänge und Ausgänge",
|
||||
})
|
||||
print(json.dumps(resp, indent=2)[:600])
|
||||
Loading…
Add table
Reference in a new issue