Temperature Monitoring on Linux
PhotoStructure monitors hardware temperatures on Linux. It treats each
sensor’s hardware- or driver-reported max limit as its normal stop-work
boundary and keeps the later hardware critical limit as an emergency
boundary. If a sensor does not publish max,
recognized disks and SSDs use
maxStorageTempCelsius as a fallback
(default: 65°C / 149°F), while every other sensor uses
maxTempCelsius (default: 85°C / 185°F). Warnings begin
warningCelsiusDelta below that boundary (default:
10°C / 18°F).
Sync pauses when an allowlisted sensor reaches its effective max or hardware critical limit, and resumes once it cools below that boundary’s hysteresis. Other hot or critical sensors stay visible and warn without pausing anything.
A hot CPU during a large import is normal, and usually not worth acting on. Modern processors are designed to keep boosting until they reach 90–95°C (194–203°F) under sustained load, and your hardware and firmware enforce the real protection limits no matter what PhotoStructure does. The pause exists to stop PhotoStructure from being the reason a machine sits at its thermal ceiling for hours, not to keep the hardware alive.
PhotoStructure uses one of two views of Linux’s hwmon sensors:
- lm-sensors — the standard Linux sensor package, including its configured labels, conversions, and ignored inputs
- hwmon sysfs — direct kernel readings from
/sys/class/hwmon/
On its first read, PhotoStructure tries sensors -j. If that succeeds, it uses
lm-sensors until the process restarts. Otherwise it uses direct hwmon for the
rest of the process. It does not merge or switch between them because they are
normally two views of the same hardware, and switching can rename sensors or
bring back inputs that the local lm-sensors configuration intentionally hid.
Thermal zones from /sys/class/thermal/ are a separate kernel subsystem.
PhotoStructure adds zones whose type is not already represented by its selected
hwmon source. If that source later fails or times out, the health check warns
and retries without silently switching sources; a one-shot info --temps
command reports the failure. Restarting PhotoStructure runs the selection
again.
PhotoStructure does not need root access to read these sources. Running
sensors-detect and loading kernel modules are host administration tasks.
Checking what PhotoStructure sees
info --temps prints every sensor PhotoStructure found, sorted by how little
headroom it has left, and colored by tier: green has room to spare, yellow has
entered its derived warning band, orange is at or above its max stop-work
boundary, and red is at or above its hardware critical limit.
./photostructure info --temps
For Docker:
docker exec -u photostructure -it photostructure /ps/app/photostructure info --temps
If PhotoStructure runs as root with an effective PUID of 0, omit
-u photostructure.
The DEVICE column says what kind of hardware the chip is — CPU, SSD,
GPU, mainboard — and is blank for drivers PhotoStructure doesn’t
recognize. Note that it describes the chip, not the individual channel: a
mainboard chip’s channel names (CPUTIN, AUXTIN0) are the chip’s pin names,
not what your board’s vendor wired to them, so a row labeled Mainboard may
well be measuring your CPU socket — or nothing at all.
The PAUSE SYNC column describes capability, not the current temperature:
🔔 means the sensor may pause sync when it reaches max or critical, 🔕
means it is allowlisted but has no stop limit, and - means it is not
permitted to pause. The health check table uses the same symbols and legend.
An orange or red row means the reading reached a stop-work or emergency limit.
It does not always mean sync paused: only names matching
stopSyncSensorNames may pause it. Add --json for machine-readable output;
each sensor row includes stopSyncEligible so scripts can tell the difference.
If a sensor you expect is missing, check the source setup below. Add a sensor
you trust to stopSyncSensorNames to let it pause sync. To hide an unreliable
sensor entirely, use excludedSensorNames.
lm-sensors
lm-sensors helps in two ways.
sensors-detect finds sensor chips and recommends the kernel modules that
expose them through /sys/class/hwmon/. This benefits both lm-sensors and
PhotoStructure’s direct hwmon reader. The sensors command then applies
configured labels, conversions, and ignore rules to those readings.
When sensors -j works on PhotoStructure’s first temperature read, this is the
selected source for the life of that process. PhotoStructure therefore honors
the labels, conversions, and ignore rules in your lm-sensors configuration
instead of reading the same chips again through direct hwmon.
Installation
On Debian/Ubuntu:
sudo apt install lm-sensors
sudo sensors-detect
On Fedora/RHEL:
sudo dnf install lm_sensors
sudo sensors-detect
On Arch Linux:
sudo pacman -S lm_sensors
sudo sensors-detect
The sensors-detect command
scans your hardware and recommends the appropriate kernel modules. Answer
“yes” when it offers to configure the detected modules to load at boot, then
load them or reboot.
After setup, verify it’s working:
sensors
You should see output listing your CPU, motherboard, and other sensor temperatures.
References
hwmon sysfs
The Linux kernel exposes hardware sensor data directly through the
hwmon sysfs interface
at /sys/class/hwmon/. PhotoStructure reads these files directly, so
temperature monitoring works even without lm-sensors installed.
This is especially useful in Docker containers and minimal Linux installs where installing additional packages may not be desirable.
Each sensor chip gets a directory like /sys/class/hwmon/hwmon0/ containing:
name— the kernel driver name (e.g.,k10temp,nct6798,nvme)temp1_input,temp2_input, … — temperatures in millidegrees Celsiustemp1_label,temp2_label, … — what the driver calls that channel (Tctl,Composite,SYSTIN). PhotoStructure uses these when they exist, so a sensor readsk10temp/Tctl/temp1_inputrather than the barek10temp/temp1_input.temp1_max,temp1_max_hyst,temp1_crit,temp1_crit_hyst— the maximum normal operating boundary, its recovery boundary, the emergency critical limit, and its recovery boundary. Drivers publish these when the hardware reports them; NVMe SSDs anddrivetempdrives usually do, and many CPU sensors don’t.
PhotoStructure reads all available hwmon sensors when lm-sensors is unavailable or fails on the first attempt. Once it selects direct hwmon, it keeps using it until the process restarts.
Limits well outside the plausible range are ignored because some chips publish placeholders rather than real values. Generic mainboard chips can expose unwired inputs stuck near 127–128°C, but 127°C is also a real critical shutdown trip on some CPU and GPU thermal zones. PhotoStructure therefore keeps critical limits through that value and does not discard a reading based on temperature alone. Only known dedicated component sensors may pause sync by default, as described below; ambiguous readings remain visible.
Docker
There is nothing to configure. A container already sees the host’s /sys, so
PhotoStructure reads hwmon without bind mounts, added capabilities, or
--privileged, and it works for the container’s unprivileged user.
PhotoStructure’s Docker image reads hwmon directly and does not include the
sensors command. If expected sensors are missing, install lm-sensors and run
sudo sensors-detect on the native Linux Docker host, then load its recommended
modules or reboot. Run this on the host, not inside the container.
Docker Desktop on macOS and Windows runs containers inside a Linux VM that cannot access the physical host’s temperature sensors.
NVMe drives
NVMe SSDs typically expose their temperatures through hwmon automatically via the kernel’s NVMe driver, with no additional configuration needed.
References
Thermal zones
The Linux kernel’s
thermal framework
exposes temperature data at /sys/class/thermal/thermal_zone*/. This
interface is commonly used by:
- ACPI thermal zones on x86 systems (type:
acpitz) - Realtek SoCs in some Synology NAS models
- ARM platforms like Raspberry Pi
Each thermal zone directory contains:
type— a label likeacpitz,x86_pkg_temp, orcpu-thermaltemp— the current temperature in millidegrees Celsiustrip_point_0_type,trip_point_0_temp, … — the zone’s declared thresholds. PhotoStructure uses the highest sanepassivetrip as the normal max boundary and keepscriticalas the later emergency limit. It does not treathotas an ordinary operating max: the kernel may use that trip for actions such as hibernation.
After each successful lm-sensors or hwmon read, PhotoStructure adds thermal zones whose type is not already represented by that source.
Docker
Thermal zones need no bind mount either — /sys/class/thermal arrives
with the rest of the host’s /sys. A zone that depends on a kernel module
needs that module loaded on the host.
References
SATA/SAS drive temperatures
SATA and SAS hard drives report their temperatures through
S.M.A.R.T.
monitoring. On Linux, the
drivetemp
kernel module exposes these temperatures through the hwmon sysfs interface,
making them readable without root access.
Enabling drivetemp
Load the module:
sudo modprobe drivetemp
To load it automatically on boot, create a module configuration file (see
modules-load.d(5)):
echo drivetemp | sudo tee /etc/modules-load.d/drivetemp.conf
Verify it’s working:
# Look for drivetemp entries in hwmon
for h in /sys/class/hwmon/hwmon*; do
name=$(cat "$h/name" 2>/dev/null)
if [ "$name" = "drivetemp" ]; then
temp=$(cat "$h/temp1_input" 2>/dev/null)
echo "$h: ${temp%???}.${temp: -3}°C"
fi
done
Why not smartctl?
The traditional tool for reading drive temperatures is
smartctl, but it
requires root access
to query SATA/SCSI devices. The drivetemp kernel module provides the same
temperature data through hwmon sysfs files that are readable by any user.
Docker
Load the drivetemp module on the host, not inside the container. Your
drives then appear in the container’s /sys/class/hwmon with no further
configuration.
Synology NAS
Synology DSM may already expose drive temperatures through hwmon. If not, you can load the module via SSH:
sudo modprobe drivetemp
Note that Synology DSM may reset loaded modules after a reboot or DSM update. You may need to use a scheduled task to re-load the module on boot.
References
macOS
The macOS desktop app doesn’t read sensors directly. macOS reports its own thermal pressure — accounting for fan state, chassis design, and workload in ways raw sensor readings can’t — and PhotoStructure uses that instead. There’s nothing to install or configure.
PhotoStructure warns when macOS reports serious thermal pressure, and
pauses sync at critical. The Linux sensor-limit fallback settings don’t
apply.
PhotoStructure settings
Breaking change:
maxTempCelsius = 0andmaxStorageTempCelsius = 0each disable only their corresponding fallback, not temperature monitoring. SetskipHealthCheckIds = ["system-temp"]to disable the check. The prerelease-onlycriticalTempCelsiusandwarnTempCelsiusaliases were removed before release.
maxTempCelsius
The fallback stop-work boundary for non-storage and unrecognized sensors that
don’t publish a hwmon temp*_max or thermal passive limit. Default:
85°C (185°F). Recognized disks and SSDs use
maxStorageTempCelsius instead.
Set it to 0 to disable only this fallback. Hardware max and critical limits
remain active. PhotoStructure never invents a critical limit: crit always
means a value published by the hardware or kernel.
maxStorageTempCelsius
The fallback stop-work boundary for sensors PhotoStructure recognizes as
Disk or SSD. Default: 65°C (149°F). nvme sensors are classified as
SSD; drivetemp sensors are classified as Disk and may represent a spinning
disk or a SATA/SAS SSD. Unknown drivers use maxTempCelsius.
An allowlisted sensor may pause sync at its applicable fallback and resumes
after cooling 5°C below it. A hardware max and max_hyst always take
precedence. If a configured fallback would exceed a published critical limit,
PhotoStructure omits the fallback and keeps the critical boundary. Set this
setting to 0 to disable only the storage fallback; hardware max and critical
limits remain active.
warningCelsiusDelta
How far below each sensor’s effective max PhotoStructure begins warning.
Default: 10°C (18°F). For example, a sensor with an 85°C max enters its
warning band at 75°C, while a storage sensor using the 65°C fallback enters at
55°C. This setting changes only the early warning band, not when sync pauses.
Set it to 0 to disable the separate early warning band.
stopSyncSensorNames
A list of sensor-name glob patterns that may pause sync after reaching their
effective max or hardware critical limit. An unmatched sensor still appears in
info --temps, and a hot or critical reading still appears orange or red, but
the aggregate health level stays at warn unless an allowlisted sensor also
reaches one of those boundaries.
The defaults cover known dedicated CPU, GPU, storage, memory, and explicit SoC/core thermal-zone families:
stopSyncSensorNames = [
"k10temp*/*", "coretemp*/*", "zenpower*/*", "via_cputemp*/*",
"peci_cputemp*/*", "cpu*thermal*/*", "soc*thermal*/*",
"package*thermal*/*", "bigcore*thermal*/*", "littlecore*thermal*/*",
"x86_pkg_temp*/*",
"amdgpu*/*", "radeon*/*", "nouveau*/*", "i915*/*", "xe/*",
"xe-*/*", "gpu*thermal*/*", "nvme*/*", "drivetemp*/*",
"jc42*/*", "spd5118*/*", "peci_dimmtemp*/*",
]
Unknown and generic mainboard sensors warn by default because an unwired or
unreliable input could otherwise pause sync forever. This means a genuine
critical event from a new or unlisted driver won’t pause PhotoStructure until
you add it. The thermal-zone defaults are explicit rather than a broad
*thermal* glob, so generic ACPI/DPTF zones are not trusted merely because of
their names. Your firmware and kernel still enforce the hardware’s real thermal
limits; PhotoStructure’s pause is an extra courtesy. Use "*" to let every
sensor pause sync, or clear the list to keep temperature warnings without any
temperature-based pauses.
Patterns are case-insensitive and must match the whole sensor name. Only *
and ? are wildcards.
excludedSensorNames
A list of glob patterns for sensor names to hide entirely. Default:
["*calibration*", "*fan*"]. Useful for filtering out sensors that report
incorrect or irrelevant readings.
Patterns match the full sensor name as info --temps prints it —
chip/channel/tempN_input, like nct6798-isa-0290/AUXTIN0/temp3_input. Run
info --temps first and copy the name you want gone.
Copy it from the machine you’re configuring, because the two sources name the
same hardware differently: one drive is drivetemp-scsi-0-0/temp1/temp1_input
under lm-sensors but drivetemp-hwmon4/temp1_input when PhotoStructure reads
hwmon directly. When two chips share a name, the hwmonN suffix that tells
them apart follows kernel probe order and can change after a reboot. Unless
lm-sensors is your selected source, prefer a chip-level glob like
drivetemp*/* over a pinned exact name. The same applies to
stopSyncSensorNames.
This is stronger than leaving a sensor out of stopSyncSensorNames: excluded
sensors do not appear in the health check, terminal output, or machine-readable
results.
See advanced settings for how to configure these values.

