//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 }