package drivers import ( "finally-a-monolithic-linux-hw-monitor/app/common" "fmt" "os" "path/filepath" "strconv" "strings" ) const milliCperC = 1000.0 type HwmonDriver struct { hwmonDir string hwmonDriver string } func NewHwmonDriver(expectedDrivers []string) (*HwmonDriver, error) { // Locate hwmon path dirs, err := filepath.Glob("/sys/class/hwmon/hwmon*") if err != nil { return nil, err } for _, dir := range dirs { nameRaw, err := os.ReadFile(filepath.Join(dir, "name")) name := strings.TrimSpace(string(nameRaw)) if err == nil { for _, driver := range expectedDrivers { if driver == name { return &HwmonDriver{ hwmonDir: dir, hwmonDriver: driver, }, nil } } } } return nil, fmt.Errorf("could not find %#v in /sys/class/hwmon", expectedDrivers) } func (r *HwmonDriver) Render(term common.Terminal) error { t, err := r.Read() if err != nil { return err } temps := t.([]TemperatureSensor) term.Subheader("Temperature") for _, sensor := range temps { tempC := sensor.TempC tempF := (tempC * 9 / 5) + 32 // \033[K clears from cursor to end of line (prevents lingering chars) term.Print(fmt.Sprintf("%-16s | %.2f °C (%.3f °F)", sensor.Name, tempC, tempF)) } return nil } func (r *HwmonDriver) Read() (any, error) { inputs, err := filepath.Glob(filepath.Join(r.hwmonDir, "temp*_input")) if err != nil || len(inputs) == 0 { return nil, fmt.Errorf("no temperature inputs found in %s", r.hwmonDir) } temps := make([]TemperatureSensor, 0, len(inputs)) for _, inputPath := range inputs { valBytes, err := os.ReadFile(inputPath) if err != nil { continue } milliC, err := strconv.ParseFloat(strings.TrimSpace(string(valBytes)), 64) if err != nil { continue } labelPath := strings.TrimSuffix(inputPath, "_input") + "_label" label := "" if lBytes, err := os.ReadFile(labelPath); err == nil { label = strings.TrimSpace(string(lBytes)) } else { label = filepath.Base(strings.TrimSuffix(inputPath, "_input")) } temps = append(temps, TemperatureSensor{ path: inputPath, Name: label, TempC: milliC / milliCperC, }) } return temps, nil }