1
0
mirror of https://github.com/tw93/Mole.git synced 2026-02-04 19:09:43 +00:00

feat(status): add temperature display via osx-cpu-temp or powermetrics

This commit is contained in:
Tw93
2025-12-11 13:53:59 +08:00
parent dc0b4fb59d
commit d7bf52a397
3 changed files with 64 additions and 21 deletions

View File

@@ -177,12 +177,54 @@ func collectThermal() ThermalStatus {
}
}
// Try to get CPU temperature using sudo powermetrics (may not work without sudo)
// Fallback: use SMC reader or estimate from thermal pressure
// 1. Try osx-cpu-temp (most accurate for users without sudo)
if commandExists("osx-cpu-temp") {
ctxTemp, cancelTemp := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancelTemp()
if out, err := runCmd(ctxTemp, "osx-cpu-temp"); err == nil {
valStr := strings.TrimSpace(out)
valStr = strings.TrimSuffix(valStr, "°C")
valStr = strings.TrimSuffix(valStr, "C")
valStr = strings.TrimSpace(valStr)
if t, err := strconv.ParseFloat(valStr, 64); err == nil && t > 0 {
thermal.CPUTemp = t
return thermal
}
}
}
// 2. Try powermetrics (requires sudo, works on Apple Silicon)
if commandExists("powermetrics") {
// Only run if we are effectively root to avoid password prompt/failure delays
if os.Geteuid() == 0 {
ctxPower, cancelPower := context.WithTimeout(context.Background(), 2*time.Second)
defer cancelPower()
// Use thermal sampler
out, err := runCmd(ctxPower, "powermetrics", "-n", "1", "--samplers", "thermal", "-i", "100")
if err == nil {
lines := strings.Split(out, "\n")
for _, line := range lines {
if strings.Contains(line, "CPU die temperature") {
// Format: "CPU die temperature: 35.43 C"
parts := strings.Split(line, ":")
if len(parts) == 2 {
valStr := strings.TrimSpace(parts[1])
valStr = strings.TrimSuffix(valStr, " C")
if t, err := strconv.ParseFloat(valStr, 64); err == nil {
thermal.CPUTemp = t
return thermal
}
}
}
}
}
}
}
// 3. Try thermal level as a proxy (fallback)
ctx2, cancel2 := context.WithTimeout(context.Background(), 500*time.Millisecond)
defer cancel2()
// Try thermal level as a proxy
out2, err := runCmd(ctx2, "sysctl", "-n", "machdep.xcpm.cpu_thermal_level")
if err == nil {
level, _ := strconv.Atoi(strings.TrimSpace(out2))

View File

@@ -542,25 +542,26 @@ func renderBatteryCard(batts []BatteryStatus, thermal ThermalStatus) cardData {
if len(healthParts) > 0 {
lines = append(lines, subtleStyle.Render(strings.Join(healthParts, " · ")))
}
// Line 4: Temp + Fan combined
var thermalParts []string
if thermal.CPUTemp > 0 {
tempStyle := okStyle
if thermal.CPUTemp > 80 {
tempStyle = dangerStyle
} else if thermal.CPUTemp > 60 {
tempStyle = warnStyle
}
thermalParts = append(thermalParts, tempStyle.Render(fmt.Sprintf("%.0f°C", thermal.CPUTemp)))
}
if thermal.FanSpeed > 0 {
thermalParts = append(thermalParts, fmt.Sprintf("%d RPM", thermal.FanSpeed))
}
if len(thermalParts) > 0 {
lines = append(lines, strings.Join(thermalParts, " · "))
}
}
// Line 4: Temp + Fan combined
var thermalParts []string
if thermal.CPUTemp > 0 {
tempStyle := okStyle
if thermal.CPUTemp > 80 {
tempStyle = dangerStyle
} else if thermal.CPUTemp > 60 {
tempStyle = warnStyle
}
thermalParts = append(thermalParts, tempStyle.Render(fmt.Sprintf("%.0f°C", thermal.CPUTemp)))
}
if thermal.FanSpeed > 0 {
thermalParts = append(thermalParts, fmt.Sprintf("%d RPM", thermal.FanSpeed))
}
if len(thermalParts) > 0 {
lines = append(lines, strings.Join(thermalParts, " · "))
}
return cardData{icon: iconBattery, title: "Power", lines: lines}
}