diff --git a/plugins/host_agent/routes.py b/plugins/host_agent/routes.py index 039002f..fe6620a 100644 --- a/plugins/host_agent/routes.py +++ b/plugins/host_agent/routes.py @@ -3,6 +3,7 @@ from __future__ import annotations import asyncio import hashlib +import re import time from datetime import datetime, timezone from typing import Any @@ -90,15 +91,24 @@ def pick_host_address(current: str | None, reported: str | None) -> str | None: return None +# A board's Super-I/O inputs (Nuvoton/ITE: SYSTIN, CPUTIN, AUXTIN0-4, PCH_*) +# are thermistor pins that are often left unwired, and a floating one reads a +# junk constant. Wired, they read the board, which runs far below this. +_BOARD_INPUT = re.compile(r"^(SYSTIN|CPUTIN|AUXTIN\d*|PCH_)", re.IGNORECASE) +BOARD_INPUT_CEILING_C = 100 + + def counts_as_hottest(label: str, celsius: float) -> bool: """Whether a sensor's reading may set the host's temperature (#5759). - A Super-I/O chip's AUXTIN inputs are spare thermistor pins, usually left - unconnected, and a floating one reads a junk constant (VDNT-Util01: 110 °C - flat at every load while its CPU package moved 49-87). No running host's - sensor reads 0 or below, and chips shut down before 125. Each sensor's own - row is kept either way, so a wired AUXTIN can still be charted by name.""" - return 0 < celsius < 125 and not label.upper().startswith("AUXTIN") + VDNT-Util01's SYSTIN read 114 °C and AUXTIN0-4 105-112, flat at every + load, while its CPU package moved 49-87 and CPUTIN read 49: unwired + inputs. A board input at or past 100 °C is one of those; below it, it + counts. No running host's sensor reads 0 or below, and chips shut down + before 125. Each sensor's own row is kept either way.""" + if not 0 < celsius < 125: + return False + return not (_BOARD_INPUT.match(label) and celsius >= BOARD_INPUT_CEILING_C) def _expand_sample_to_metrics( diff --git a/tests/plugins/host_agent/test_expand_metrics.py b/tests/plugins/host_agent/test_expand_metrics.py index 22a3b57..1116889 100644 --- a/tests/plugins/host_agent/test_expand_metrics.py +++ b/tests/plugins/host_agent/test_expand_metrics.py @@ -85,7 +85,8 @@ def test_a_sensor_with_nothing_wired_to_it_does_not_set_the_host_s_temperature() moved 49-87, so the host read critical all week. Every sensor keeps its own row; only readings that can be real set the max.""" sample = {"ts": "2026-10-14T21:00:00+00:00", - "temps": [{"label": "AUXTIN0", "celsius": 110.0}, + "temps": [{"label": "SYSTIN", "celsius": 114.0}, + {"label": "AUXTIN0", "celsius": 110.0}, {"label": "PCH_CHIP_CPU_MAX_TEMP", "celsius": 0.0}, {"label": "AUXTIN3", "celsius": -1.0}, {"label": "Package id 0", "celsius": 60.0}]} @@ -104,3 +105,11 @@ def test_stalled_mounts_are_counted_and_have_no_figures(): assert idx[("mounts_stalled", "d3")] == 1 assert idx[("disk_used_pct_worst", "d3")] == 50.0 assert ("disk_used_pct", "d3:/nfs/media") not in idx + + +def test_a_wired_board_input_still_counts(): + """#5759: below 100 °C a board input is a real reading.""" + from plugins.host_agent.routes import counts_as_hottest + assert counts_as_hottest("SYSTIN", 38.0) and counts_as_hottest("AUXTIN1", 60.0) + assert not counts_as_hottest("SYSTIN", 114.0) and not counts_as_hottest("PCH_CHIP_TEMP", 0.0) + assert counts_as_hottest("Package id 0", 101.0) # a CPU past 100 is a hot CPU