homelab-brain/smart-home/scripts/check_april.py
root b61ac66367 docs(smart-home): dokumentiere Heizung/Brenner komplett, alle Zugänge in homelab.conf
- smart-home/HEIZUNG.md: komplette Doku zur Ölbrenner-Erkennung (brennerstarts.py),
  Schwellwerte, Rekonstruktion, Dashboard-Panels, Troubleshooting
- smart-home/STATE.md: klare Tabelle mit allen Dienst-URLs (public+intern) und
  Logins — Grafana/ioBroker/InfluxDB laufen ALLE in CT 143 auf pve-mu-3
- homelab.conf: CT_143_MU3 Beschreibung korrigiert (war "Raspi-Broker"),
  neue Variablen GRAFANA_URL_*/IOBROKER_URL_*/INFLUX_URL_INTERN + User/Pass
  (=PW_DEFAULT) damit beim nächsten Mal keine Fragen aufkommen
- smart-home/scripts/: alle relevanten Skripte ins Repo:
  grafana_shot.js (Puppeteer-Login mit admin/astral66)
  add_month_panel.py (idempotente Monatskacheln im Heizung-Dashboard)
  brenner_rekonstruktion.py + cleanup_reconstruct.py + check_april.py
  patch_brenner.sh (Anpassung der Schwellwerte nach Regelkurven-Änderung)
- MASTER_INDEX.md: Verweis auf HEIZUNG.md

Made-with: Cursor
2026-04-20 22:31:32 +02:00

62 lines
2.6 KiB
Python

#!/usr/bin/env python3
import json
from urllib.parse import quote
from urllib.request import urlopen
INFLUX = 'http://localhost:8086'
DB = 'iobroker'
def q(sql):
url = f'{INFLUX}/query?db={DB}&epoch=ns&q={quote(sql)}'
with urlopen(url, timeout=30) as r:
return json.loads(r.read().decode())
def rows(sql):
d = q(sql)
s = d['results'][0].get('series', [])
if not s:
return []
return s[0]['values']
from datetime import datetime, timezone, timedelta
TZ = timezone(timedelta(hours=2))
print('=== Starts im April (count) ===')
r = rows("SELECT count(value) FROM brennerstarts WHERE time >= '2026-04-01T00:00:00Z' AND time < '2026-05-01T00:00:00Z'")
print(r)
print('\n=== Laufzeit-Summe April (Stunden) ===')
r = rows("SELECT sum(value) FROM brennerlaufzeit WHERE time >= '2026-04-01T00:00:00Z' AND time < '2026-05-01T00:00:00Z'")
if r:
print(f' Summe = {r[0][1]:.1f} s = {r[0][1]/3600:.2f} h')
print('\n=== Pro Tag Starts und Laufzeit (April) ===')
starts = rows("SELECT count(value) FROM brennerstarts WHERE time >= '2026-04-01T00:00:00Z' AND time < '2026-05-01T00:00:00Z' GROUP BY time(1d,-2h) fill(0)")
lauf = rows("SELECT sum(value) FROM brennerlaufzeit WHERE time >= '2026-04-01T00:00:00Z' AND time < '2026-05-01T00:00:00Z' GROUP BY time(1d,-2h) fill(0)")
d_starts = {s[0]: s[1] or 0 for s in starts}
d_lauf = {s[0]: s[1] or 0 for s in lauf}
for ts in sorted(set(list(d_starts) + list(d_lauf))):
day = datetime.fromtimestamp(ts/1e9, TZ).date()
st = d_starts.get(ts, 0)
lf = d_lauf.get(ts, 0) / 3600
if st or lf:
print(f' {day} Starts={st:3d} Laufzeit={lf:5.2f}h Liter={lf*1.89:5.2f}')
print('\n=== verdächtig lange einzelne Laufzeiten > 1h ===')
r = rows("SELECT value FROM brennerlaufzeit WHERE value > 3600 AND time > '2026-03-01T00:00:00Z' ORDER BY time DESC LIMIT 20")
for ts, v in r:
t = datetime.fromtimestamp(ts/1e9, TZ)
print(f' {t.strftime("%Y-%m-%d %H:%M:%S")} {v:.0f}s = {v/60:.1f}min = {v/3600:.2f}h')
print('\n=== Daily max einzelne Laufzeit (wann >30min?) ===')
r = rows("SELECT max(value) FROM brennerlaufzeit WHERE time >= '2026-04-01T00:00:00Z' AND time < '2026-05-01T00:00:00Z' GROUP BY time(1d,-2h) fill(0)")
for ts, v in r:
if v and v > 30*60:
t = datetime.fromtimestamp(ts/1e9, TZ).date()
print(f' {t} max einzel-laufzeit = {v/60:.1f} min')
print('\n=== brennerstarts value-Verteilung April ===')
r = rows("SELECT value FROM brennerstarts WHERE time >= '2026-04-01T00:00:00Z' AND time < '2026-05-01T00:00:00Z'")
vals = [x[1] for x in r]
from collections import Counter
print(f' Anzahl Zeilen = {len(vals)}, Summe = {sum(vals)}, Counter = {Counter(vals)}')