Files
2026-10-06 02:24:44 +02:00

88 lines
2.4 KiB
Go

//go:build windows
package temperature
import (
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
"github.com/yusufpapurcu/wmi"
)
type LHMSensor struct {
Value float32
}
type LHMNode struct {
Text string `json:"Text"`
Value string `json:"Value"`
Children []LHMNode `json:"Children"`
}
type MSAcpiThermalZone struct {
CurrentTemperature uint32
}
func findCPUTemp(node LHMNode) string {
if strings.Contains(node.Text, "CPU Package") && strings.Contains(node.Value, "°C") {
return node.Value
}
for _, child := range node.Children {
if val := findCPUTemp(child); val != "" {
return val
}
}
return ""
}
func getWinCPUTemperature() TemperatureInformation {
// check for preexisting monitoring tools
var lhm []LHMSensor
lhmQuery := "SELECT Value FROM Sensor WHERE SensorType = 'Temperature' AND Name LIKE '%CPU Package%'"
if err := wmi.QueryNamespace(lhmQuery, &lhm, `root\OpenHardwareMonitor`); err == nil && len(lhm) > 0 {
return TemperatureInformation{Celsius: float64(lhm[0].Value), Supported: true}
} else {
// Try LHM local webserver
client := http.Client{Timeout: 1 * time.Second}
resp, err := client.Get("http://localhost:8085/data.json")
if err == nil {
defer resp.Body.Close()
var root LHMNode
if json.NewDecoder(resp.Body).Decode(&root) == nil {
tempStr := findCPUTemp(root)
if tempStr != "" {
var temp float64
fmt.Sscanf(tempStr, "%f", &temp)
return TemperatureInformation{Celsius: temp, Supported: true}
}
}
}
}
// check native ACPI
var acpi []MSAcpiThermalZone
acpiQuery := "SELECT CurrentTemperature FROM MSAcpi_ThermalZoneTemperature"
if err := wmi.QueryNamespace(acpiQuery, &acpi, `root\wmi`); err == nil && len(acpi) > 0 {
kelvinTenths := float64(acpi[0].CurrentTemperature)
celsius := (kelvinTenths / 10.0) - 273.15
// Discard known fake motherboard values
if celsius != 27.8 && celsius != 29.8 && celsius != 24.05 && celsius > 0 && celsius < 150 {
return TemperatureInformation{Celsius: celsius, Supported: true}
}
}
return TemperatureInformation{0, false} // unsupported
}
// This is really finicky and is rarely working well due to windows
// temperature information being a RING0 feature. Maybe later this
// can be improved upon, but for now it's good enough as it is now.
func GetTemperatureInformation() (TemperatureInformation, error) {
return getWinCPUTemperature(), nil
}