Skip to content

CPU temperature always returns empty on MediaTek MT7981 (ImmortalWrt 24.10.1 #108

Description

@meotao

Environment

Item Value
Device BeeconMini SEED AC2
SoC MediaTek MT7981B (Filogic 820)
OS ImmortalWrt 24.10.1 r33048-cc720ea55a71
Kernel 6.6.86
quickstart binary /usr/sbin/quickstart (served at 127.0.0.1:3038)
autocore version 42

Bug description

The CPU temperature widget on the QuickStart homepage always shows 0 (or blank).

The temperature API endpoint returns an empty result object:

# From browser console (authenticated session)
fetch('/cgi-bin/luci/istore/system/cpu/temperature/')
  .then(r => r.json()).then(d => console.log(JSON.stringify(d)))

# Response:
{"result":{}}

Root cause analysis

The quickstart binary implements three temperature strategies, tried in order. All three fail on this platform.

Strategy 1 — thermalZoneTemperature

The binary reads /sys/class/thermal/thermal_zone*/type to find a zone whose type contains "cpu", then constructs the temperature path using the type value (not the directory name):

Step 1: read /sys/class/thermal/thermal_zone0/type  → "cpu-thermal"  ✓
Step 2: read /sys/class/thermal/cpu-thermal/temp    → does not exist ✗

On this device, /sys/class/thermal/ only contains thermal_zone0 as a directory entry. There is no symlink or directory named cpu-thermal, so step 2 fails:

$ ls -la /sys/class/thermal/
lrwxrwxrwx  thermal_zone0 -> ../../devices/virtual/thermal/thermal_zone0

$ cat /sys/class/thermal/thermal_zone0/type
cpu-thermal

$ cat /sys/class/thermal/cpu-thermal/temp
cat: can't open '/sys/class/thermal/cpu-thermal/temp': No such file or directory

The actual temperature is readable at:

$ cat /sys/class/thermal/thermal_zone0/temp
62767   # millidegrees Celsius → 62.7°C

sysfs does not permit creating symlinks or directories inside /sys/class/thermal/:

$ ln -sf /sys/class/thermal/thermal_zone0 /sys/class/thermal/cpu-thermal
ln: /sys/class/thermal/cpu-thermal: Operation not permitted

Strategy 2 — hwmonTemperature

Same pattern: the binary reads /sys/class/hwmon/hwmon*/name, finds a match, then constructs the path using the name value:

$ cat /sys/class/hwmon/hwmon1/name
cpu_thermal

$ cat /sys/class/hwmon/hwmon1/temp1_input
62918   # correct value ✓

$ cat /sys/class/hwmon/cpu_thermal/temp1_input
# does not exist ✗

Again, no cpu_thermal directory exists under /sys/class/hwmon/, and sysfs rejects any attempt to create one:

$ ln -sf /sys/class/hwmon/hwmon1 /sys/class/hwmon/cpu_thermal
ln: /sys/class/hwmon/cpu_thermal: Operation not permitted

Strategy 3 — autocoreTemperature

The binary calls ubus call luci getTempInfo, which returns a human-readable string:

$ ubus call luci getTempInfo
{ "tempinfo": "CPU: 63.1°C" }

The binary apparently cannot parse a numeric temperature from this string format, so this strategy also returns empty.


Verification

The ubus interface itself and the underlying /sbin/tempinfo script work correctly:

$ /sbin/tempinfo
CPU: 62.9°C

$ ubus call luci getTempInfo
{ "tempinfo": "CPU: 63.1°C" }

$ ubus call luci getCPUInfo
{ "cpuinfo": "ARMv8 Processor rev 4 (v8l) x 2" }

Note: /sbin/cpuinfo intentionally skips temperature for mediatek/* targets:

# from /sbin/cpuinfo:
case "$DISTRIB_TARGET" in
"ipq40xx"/*|"ipq806x"/*|"mediatek"/*|"qualcommax"/*) ;;  # no cpu_temp set

Suggested fix

The binary's temperature discovery logic assumes that after finding a thermal zone or hwmon node by name, the path can be constructed from that name string. On platforms where the kernel only exposes numbered entries (thermal_zone0, hwmon1) without corresponding named symlinks, this breaks.

Option A — Use the directory path directly, not the name value

When iterating /sys/class/thermal/thermal_zone*/type, once a matching zone is found, read the temperature from the same directory (thermal_zone0/temp), not from a path derived from the type string.

Similarly for hwmon: once a matching hwmon*/name is found, read hwmon*/temp1_input from the same hwmon* directory.

Option B — Fall back to thermal_zone0/temp when named path fails

If the constructed path (e.g., /sys/class/thermal/cpu-thermal/temp) does not exist, fall back to reading directly from the zone that had the matching type.

Option C — Parse temperature from ubus call luci getTempInfo output

The autocoreTemperature strategy already has the correct data ("CPU: 63.1°C"). Extracting the numeric value with a simple regex (e.g., (\d+\.?\d*)°C) would make this strategy work on any platform supported by autocore.

Option C is the most robust since it delegates platform-specific logic to autocore, which already handles the per-target differences correctly.


Additional info

Confirmed via strings /usr/sbin/quickstart:

/sys/class/thermal/thermal_zone%v/type
/sys/class/thermal/%v/temp
/sys/class/hwmon/hwmon%d/name
/sys/class/hwmon/hwmon%d/temp%d_input
thermalZoneTemperature default
hwmonTemperature default
hwmonTemperature candidate

The %v in /sys/class/thermal/%v/temp is filled with the type value (cpu-thermal), not the zone index — this is the source of the mismatch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions