host_sensors: read extra hwmon chips (dell_smm) as env sensors
Boxes without IPMI (Dell workstations like dev-linux) expose CPU/ambient/ SODIMM/board temps via the BIOS SMM interface (dell_smm hwmon). Add read_hwmon_env(): labelled temps from chips in HOST_HWMON_CHIPS (default 'dell_smm') as env sensors, named '<chip> <label>' with index suffix for repeated labels. Merged into the host-poller env sweep. No-op on hosts without the configured chips.
This commit is contained in:
@@ -22,7 +22,7 @@ import time
|
|||||||
from services import store
|
from services import store
|
||||||
from services.cache import close_cache, init_cache, redis_available
|
from services.cache import close_cache, init_cache, redis_available
|
||||||
from services.host import get_host_drives
|
from services.host import get_host_drives
|
||||||
from services.host_sensors import read_coretemp, read_ipmi_temps
|
from services.host_sensors import read_coretemp, read_hwmon_env, read_ipmi_temps
|
||||||
|
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
level=logging.INFO,
|
level=logging.INFO,
|
||||||
@@ -47,7 +47,7 @@ async def sweep_env() -> None:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
errors.append(f"ipmi:{e}")
|
errors.append(f"ipmi:{e}")
|
||||||
ipmi = []
|
ipmi = []
|
||||||
env = [s for s in ipmi if s.get("kind") == "env"]
|
env = [s for s in ipmi if s.get("kind") == "env"] + read_hwmon_env()
|
||||||
cpu = read_coretemp() or [s for s in ipmi if s.get("kind") == "cpu"]
|
cpu = read_coretemp() or [s for s in ipmi if s.get("kind") == "cpu"]
|
||||||
|
|
||||||
await store.set_host_sensors({
|
await store.set_host_sensors({
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ coretemp is a cheap sysfs read.
|
|||||||
"""
|
"""
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import re
|
import re
|
||||||
|
from collections import Counter
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from services.hwgate import gate
|
from services.hwgate import gate
|
||||||
@@ -67,6 +69,46 @@ def _parse_ipmi(text: str) -> list[dict]:
|
|||||||
return sensors
|
return sensors
|
||||||
|
|
||||||
|
|
||||||
|
def read_hwmon_env() -> list[dict]:
|
||||||
|
"""Read labelled temps from extra hwmon chips as env sensors.
|
||||||
|
|
||||||
|
For boxes without IPMI (e.g. Dell workstations), the BIOS SMM interface
|
||||||
|
(`dell_smm`) exposes CPU/ambient/SODIMM/board temps. Chips are configurable
|
||||||
|
via HOST_HWMON_CHIPS (comma list; default "dell_smm"); set to "" to disable.
|
||||||
|
Names are "<chip> <label>", with the temp index appended when a label
|
||||||
|
repeats within a chip (e.g. dell_smm's multiple "Other" sensors).
|
||||||
|
"""
|
||||||
|
chips = [c.strip() for c in os.environ.get("HOST_HWMON_CHIPS", "dell_smm").split(",") if c.strip()]
|
||||||
|
if not chips or not HWMON.is_dir():
|
||||||
|
return []
|
||||||
|
out: list[dict] = []
|
||||||
|
for hw in sorted(HWMON.iterdir()):
|
||||||
|
try:
|
||||||
|
chip = (hw / "name").read_text().strip()
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
if chip not in chips:
|
||||||
|
continue
|
||||||
|
entries: list[tuple[str, str, int]] = [] # (idx, label, temp)
|
||||||
|
for label_f in sorted(hw.glob("temp*_label")):
|
||||||
|
try:
|
||||||
|
label = label_f.read_text().strip()
|
||||||
|
except OSError:
|
||||||
|
continue
|
||||||
|
input_f = label_f.with_name(label_f.name.replace("_label", "_input"))
|
||||||
|
try:
|
||||||
|
temp = round(int(input_f.read_text().strip()) / 1000)
|
||||||
|
except (OSError, ValueError):
|
||||||
|
continue
|
||||||
|
idx = label_f.name[len("temp"):-len("_label")]
|
||||||
|
entries.append((idx, label, temp))
|
||||||
|
dup = {lbl for lbl, n in Counter(l for _, l, _ in entries).items() if n > 1}
|
||||||
|
for idx, label, temp in entries:
|
||||||
|
name = f"{chip} {label}" + (f" {idx}" if label in dup else "")
|
||||||
|
out.append({"name": name, "temperature_c": temp, "status": "ok", "kind": "env"})
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def read_coretemp() -> list[dict]:
|
def read_coretemp() -> list[dict]:
|
||||||
"""CPU package temps from coretemp hwmon → [{name, temperature_c, kind}]."""
|
"""CPU package temps from coretemp hwmon → [{name, temperature_c, kind}]."""
|
||||||
cpus: list[dict] = []
|
cpus: list[dict] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user