Temperatures against the hardware's own thresholds, fans, each drive's health and the kernel's error counts, read-only. A root watch reads SMART so the tools need no root and never wake a sleeping drive; smartd and the watch carry the health that raises a condition when the hardware says it is failing.
sensors
The condition of a machine's own hardware: temperatures with the thresholds the hardware gives for itself, fans, each drive's health, and the kernel's counts of memory and PCIe errors (novox/hq ADR 0256). It reads, and changes nothing on the hardware. Every flag is measured against the hardware's own threshold, never one the mesh chose. A class the machine does not have is said as not present, never as an error, so the module can be assigned to every machine: a laptop, a desktop, a server, a virtual machine.
Why it exists, and why here
The operator set the boundary on 2026-10-08. What hardware a machine has is a node-engine fact. A module holding a generic role reads and provides it. A vendor module adds only vendor-specific extras.
Before this module, only the laptop's vendor module read a temperature, and no module read a drive's
health. The machines' 20 drives, 15 of them spinning, were watched by nothing. power keeps the battery
and the power draw. disk-load keeps how busy the disks are. This module keeps everything else the
kernel says about the hardware's condition.
It holds no seat. A seat is a role that callers reach without knowing the module, and nothing asks for this role yet. A new seat would also be a controller change first (ADR 0246). When a caller needs to ask by role, such as the bar's temperature blocks or a vendor module's fan policy, these tools become the seat's verbs. The full reasoning is in ADR 0256.
What runs
| resource | what | as |
|---|---|---|
smartmontools |
the package: smartctl and smartd |
|
/etc/smartd.conf |
every drive (DEVICESCAN), every check, never waking a drive in standby, no mail |
written whole |
smartd.service drop-in |
runs on a virtual machine too, and stays up with no drive to watch (-q never) |
written whole |
smartd |
watches every drive between looks, and logs what it finds to the journal | root, the package's unit |
watch (sensors watch) |
every 10 min each drive's health with smartctl --json -a -n standby; every 30 s which fans turn; one file, /run/mesh-sensors/readings.json (0644) |
root, the node-engine's process |
| the tools | read /sys, /proc and the watch's file |
the operator account, in the tool runner |
The tools need no root, because the watch has already read what only root may read. A drive in standby is never woken. The watch keeps its last reading of that drive and says that it was asleep.
Tools
All six only read.
| tool | what | replaces |
|---|---|---|
sensors_summary |
one line per finding, flagged CRITICAL, HIGH, FAILING or STOPPED; then one line per class: temperatures with the hottest, fans, drives, memory and PCIe errors | sensors, smartctl -H |
sensors_temperatures |
every thermal zone with its trip points, and every hwmon temperature with its label, its kind (cpu, gpu, drive, board, network), the drive it sits in, and its own maximum and critical values | sensors |
sensors_fans |
every fan's RPM, its chip's minimum and alarm, and whether the watch saw it turn since boot | sensors |
sensors_drives |
each drive: model, serial, size, whether it spins, the SMART verdict; for NVMe the critical warning bits, spare, endurance used and media errors; for SATA the reallocated, pending and unreadable sectors, the error log and the last self-test | smartctl -a, nvme smart-log |
sensors_faults |
EDAC memory errors per controller and module, PCIe AER errors per device, and how often an Intel CPU was slowed for heat | edac-util |
sensors_health |
the module's health check: healthy or not, with why |
The flags
| flag | when |
|---|---|
| temperature HIGH | at or above its own maximum, or a zone's hot trip (without one, its lowest passive trip) |
| temperature CRITICAL | at or above its own critical or emergency value, or a zone's critical trip |
| drive FAILING | SMART's overall verdict failed, an attribute is failing now, or an NVMe critical warning bit is set |
| drive HIGH | reallocated, pending or unreadable sectors; an attribute that failed in the past; NVMe media errors or 90 % of rated endurance used; errors in the error log; a last self-test that did not pass |
| fan STOPPED | its chip's alarm, or under its own minimum, once it has been seen turning; or it ran since boot and reads 0 while a temperature is at or above its own maximum |
| memory HIGH / CRITICAL | corrected / uncorrectable errors since boot |
| PCIe HIGH | fatal or non-fatal errors since boot |
What is no threshold. A threshold given as the format's largest value is no threshold. The laptop's
NVMe drive gives 65261.85 °C as the maximum of two of its sensors. A threshold of 0 is no threshold
either, and neither is anything outside −40 to 200 °C. The reading is then said without a flag. A CPU
sensor that gives no threshold, such as AMD's Tctl, is never flagged.
Why a fan at 0 is not enough. Laptop fans and GPU fans in zero-fan mode stop on purpose when the machine is cool. A board header with nothing on it reads 0, and may carry an alarm or a minimum that the firmware set. So a fan is judged only once it has been seen turning.
Health
The module declares its health under ADR 0240:
smartdhas theunitkind: the unit's own readiness, which the module does not judge itself.- The watch has the
toolkind:sensors_health, every 60 s, unhealthy after 2 looks in a row, with a 60 s grace.
sensors_health is unhealthy when:
- a temperature is at or above its own critical value;
- a drive says it is failing;
- a fan that ran has stopped while the machine is hot;
- memory reports an uncorrectable error.
Its why is one plain sentence per finding, for the operator. For example: "The drive sdb (WDC
WUH722222ALE6L4) says it is failing: its overall SMART health check failed." HIGH readings raise nothing.
A drive whose health was not read is said in why and does not make the check unhealthy. The watch not
running is caught by the watch's own liveness.
The condition this raises is module.sensors.<machine>.unhealthy. ADR 0256 records what this costs:
- the condition names the module, not the machine;
- a standing hardware fault holds this module's own new builds at their gate on that machine.
The machine judging its own hardware, as it judges its network, is the follow-up.
Tests
go test ./.... The tests read a tree standing in for /sys, /proc and /run, and smartctl answers
recorded as smartmontools 7 writes them. There are three machines:
- a laptop, as the laptop showed itself on 2026-10-08;
- a server with ECC memory, three SATA drives read by drivetemp and a board chip with an empty fan header;
- a virtual machine with no sensor at all.
They cover:
- thresholds taken from the hardware only, and a zone's hwmon copy left out;
- HIGH at the maximum and CRITICAL at the critical value; a zone's passive trip as its high;
- a sensor that gives no reading said as not read;
- every class not present on the virtual machine, which is healthy;
- a failing SATA drive, an NVMe critical warning, and early signs that are HIGH and raise nothing;
- a missing, stale or earlier-boot reading said as such;
- a fan at rest, a fan that stopped while hot, an empty header, and a fan under its minimum;
- memory and PCIe errors, and CPU throttling;
- the watch reading as root without waking a drive, keeping a reading for a drive asleep, reading drives only every 10 min, and keeping what it saw across a restart;
- a watch that is not root asking through
sudo -n, and saying what stops it; - the health answer in the shape the node-engine reads;
- the manifest: the tools listed are the tools served, all read-only, no seat claimed, no machine named, and the two health checks.
Follow-ups
- The machine's hardware judged by the node-engine, raising a machine condition, instead of this module's health (ADR 0256).
- The module-health condition carrying the tool check's
whyas its plain words (ADR 0253). - Temperature blocks for the bar, once there is a generic way for a module to provide bar blocks.
- The laptop vendor module's
zephyrus_thermalskeeps only what is the vendor's.