#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# 14-temp — 42i-hc Drop-in: höchste Hardware-Temperatur des Hosts.
# hc-tags: cheap, metrics, local, host, sensor
# hc-ttl: 60
#
# Liefert {"metrics": {"temp": {...}}, "checks": [{"name": "Temperatur", ...}]}.
# Temperatur ändert sich träge genug für eine 60-s-TTL. Quelle in dieser
# Reihenfolge: lm-sensors JSON (`sensors -j`), sonst der Sysfs-Thermal-Zonen
# (`/sys/class/thermal/thermal_zone*/temp`, Milli-Grad). Bewertet wird nur die
# HÖCHSTE gemessene Temperatur gegen HC_TEMP_WARN/HC_TEMP_FAIL (Default 80/90 °C).
# Fehlt jede Quelle (z. B. LXC ohne Sensor-Durchgriff), gibt es KEINEN Check —
# der Host bleibt „ok" statt fälschlich „fail" (Temperatur ist kein Pflichtsignal).
#
# Geliefert von 42i-hc.

import json
import os
import subprocess
import sys
import glob

WARN = float(os.environ.get("HC_TEMP_WARN") or 80)
FAIL = float(os.environ.get("HC_TEMP_FAIL") or 90)


def classify(celsius):
    """Bildet eine Temperatur (°C) auf ok/warn/fail nach den Schwellen ab."""
    if celsius >= FAIL:
        return "fail"
    if celsius >= WARN:
        return "warn"
    return "ok"


def from_sensors():
    """Höchste Temperatur aus `sensors -j` (lm-sensors), oder None.

    Durchläuft alle Chips/Features und sammelt jeden `*_input`-Wert, dessen
    Schlüssel auf eine Temperatur deutet (Werte in °C). Defensiv: fehlt das
    Binary oder ist die Ausgabe unbrauchbar, wird None geliefert.
    """
    try:
        out = subprocess.run(["sensors", "-j"], capture_output=True,
                             text=True, timeout=5)
        if out.returncode != 0 or not out.stdout.strip():
            return None
        data = json.loads(out.stdout)
    except Exception:
        return None
    best = None
    label = None
    for chip, features in (data.items() if isinstance(data, dict) else []):
        if not isinstance(features, dict):
            continue
        for feat, sub in features.items():
            if not isinstance(sub, dict):
                continue
            for key, val in sub.items():
                if not isinstance(val, (int, float)):
                    continue
                # lm-sensors nennt Temperatur-Inputs "tempN_input"; nur die,
                # nicht Lüfter (fanN_input) oder Spannungen (inN_input).
                if key.endswith("_input") and key.startswith("temp"):
                    if best is None or val > best:
                        best = float(val)
                        label = "%s/%s" % (chip, feat)
    if best is None:
        return None
    return best, label


def from_sysfs():
    """Höchste Temperatur aus /sys/class/thermal/thermal_zone*/temp, oder None.

    Sysfs liefert Milli-Grad (z. B. 82000 = 82,0 °C). Zonen-Typ dient als Label.
    """
    best = None
    label = None
    for zone in glob.glob("/sys/class/thermal/thermal_zone*"):
        try:
            with open(os.path.join(zone, "temp")) as fh:
                milli = int(fh.read().strip())
        except Exception:
            continue
        celsius = milli / 1000.0
        # Unplausible Werte (0 oder > 150 °C) ignorieren — kaputte Zonen.
        if celsius <= 0 or celsius > 150:
            continue
        if best is None or celsius > best:
            best = celsius
            try:
                with open(os.path.join(zone, "type")) as fh:
                    label = fh.read().strip()
            except Exception:
                label = os.path.basename(zone)
    if best is None:
        return None
    return best, label


def main():
    """Ermittelt die höchste Temperatur und gibt Metrik + Check als JSON aus."""
    result = from_sensors() or from_sysfs()
    if result is None:
        # Keine Quelle -> gar nichts emittieren (kein Check = kein Signal).
        json.dump({"metrics": {}}, sys.stdout, ensure_ascii=False)
        sys.stdout.write("\n")
        return
    celsius, label = result
    celsius = round(celsius, 1)
    status = classify(celsius)
    out = {
        "metrics": {"temp": {"max_c": celsius, "status": status,
                             "sensor": label}},
        "checks": [{"name": "Temperatur", "status": status, "type": "sensor",
                    "message": "%.1f °C (%s)" % (celsius, label or "?")}],
    }
    json.dump(out, sys.stdout, ensure_ascii=False)
    sys.stdout.write("\n")


if __name__ == "__main__":
    main()
