feat(host_agent): a temperature sensor is judged by how it moves against the CPU (#5783)
CI / lint (push) Successful in 2s
CI / integration (push) Successful in 1m21s
CI / unit (push) Successful in 1m31s
CI / publish (push) Successful in 17s

A board's spare thermistor inputs report whatever an open input reads, and
the value rule from #5759 only catches the impossible ones. Once an hour,
sensors.refresh judges each sensor against the host's CPU (Package id N,
Tctl/Tdie/TccdN, PECI Agent N) over a week of hourly averages. A sensor is
ruled out if it falls as the CPU warms (r <= -0.5) or holds within 0.5 °C
while the CPU moved 10 °C or more. A judgment needs at least 72 shared hours.

The host temperature leaves judged sensors out at ingest. The host page
lists them under "Not counted", with each reason given once.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-14 21:24:34 -04:00
co-authored by Claude Opus 5.5
parent 72e754b580
commit 0b29cdf26c
9 changed files with 283 additions and 19 deletions
@@ -160,10 +160,12 @@
{% endfor %}
</div>
{% if unwired_temps %}
{# Board inputs with nothing wired to them, and readings at or below 0 °C:
constant at any load, left out of the host's temperature (#5759). #}
<p class="field-hint" style="margin:0.5rem 0 0;">Not counted, reading a constant with nothing wired to them:
{% for label, c in unwired_temps.items() %}{{ label }} {{ "%.0f"|format(c) }}°C{{ ", " if not loop.last }}{% endfor %}.</p>
{# Sensors that aren't thermometers: they run against the CPU or hold a
constant (#5783), or read a value no wired sensor gives (#5759). Left
out of the host's temperature. Each reason is said once, after its
sensors, hottest first within it. #}
<p class="field-hint" style="margin:0.5rem 0 0;">Not counted, likely nothing wired to them:
{% for why, group in unwired_temps.items()|groupby("1.1") %}{% for label, v in group %}{{ label }} {{ "%.0f"|format(v[0]) }}°C{{ ", " if not loop.last }}{% endfor %} ({{ why }}){{ "; " if not loop.last }}{% endfor %}.</p>
{% endif %}
</div>
{% endif %}