diff --git a/bin/status-go b/bin/status-go index fa33d64..cb33370 100755 Binary files a/bin/status-go and b/bin/status-go differ diff --git a/cmd/status/metrics_battery.go b/cmd/status/metrics_battery.go index 8733a31..a698015 100644 --- a/cmd/status/metrics_battery.go +++ b/cmd/status/metrics_battery.go @@ -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)) diff --git a/cmd/status/view.go b/cmd/status/view.go index 898b7b9..8d20ea1 100644 --- a/cmd/status/view.go +++ b/cmd/status/view.go @@ -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} }