package collect import ( "os" "path/filepath" "sort" "strconv" "strings" ) type Temp struct { Chip string `json:"chip"` Label string `json:"label"` C float64 `json:"c"` } // ReadTemps lists every hwmon temperature input; falls back to thermal zones. func ReadTemps() []Temp { temps := readHwmon("/sys/class/hwmon") if len(temps) == 0 { temps = readThermalZones("/sys/class/thermal") } sort.Slice(temps, func(i, j int) bool { if temps[i].Chip != temps[j].Chip { return temps[i].Chip < temps[j].Chip } return temps[i].Label < temps[j].Label }) return temps } func readHwmon(root string) []Temp { var out []Temp chips, _ := filepath.Glob(filepath.Join(root, "hwmon*")) for _, chip := range chips { name := readTrim(filepath.Join(chip, "name")) inputs, _ := filepath.Glob(filepath.Join(chip, "temp*_input")) for _, in := range inputs { v, err := strconv.ParseFloat(readTrim(in), 64) if err != nil { continue } base := strings.TrimSuffix(in, "_input") label := readTrim(base + "_label") if label == "" { label = filepath.Base(base) } out = append(out, Temp{Chip: name, Label: label, C: v / 1000}) } } return out } func readThermalZones(root string) []Temp { var out []Temp zones, _ := filepath.Glob(filepath.Join(root, "thermal_zone*")) for _, z := range zones { v, err := strconv.ParseFloat(readTrim(filepath.Join(z, "temp")), 64) if err != nil { continue } out = append(out, Temp{Chip: "thermal", Label: readTrim(filepath.Join(z, "type")), C: v / 1000}) } return out } // CPUTemp picks the most plausible CPU package temperature from the list. func CPUTemp(temps []Temp) (float64, bool) { best, found := 0.0, false for _, t := range temps { chip := strings.ToLower(t.Chip) lbl := strings.ToLower(t.Label) isCPU := chip == "coretemp" || chip == "k10temp" || chip == "zenpower" || strings.Contains(lbl, "package") || strings.Contains(lbl, "tctl") || strings.Contains(lbl, "tdie") || strings.Contains(lbl, "x86_pkg_temp") || strings.Contains(lbl, "cpu") if isCPU && (!found || t.C > best) { best, found = t.C, true } } return best, found } func readTrim(p string) string { b, err := os.ReadFile(p) if err != nil { return "" } return strings.TrimSpace(string(b)) }