Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed temperature sensors detection in Linux #905

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions host/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ type UserStat struct {
type TemperatureStat struct {
SensorKey string `json:"sensorKey"`
Temperature float64 `json:"sensorTemperature"`
High float64 `json:"sensorHigh"`
Critical float64 `json:"sensorCritical"`
}

func (h InfoStat) String() string {
Expand Down
101 changes: 76 additions & 25 deletions host/host_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@ type LSB struct {
}

// from utmp.h
const USER_PROCESS = 7
const (
USER_PROCESS = 7

hostTemperatureScale = 1000.0
)

func Info() (*InfoStat, error) {
return InfoWithContext(context.Background())
Expand Down Expand Up @@ -445,19 +449,27 @@ func SensorsTemperatures() ([]TemperatureStat, error) {
}

func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, error) {
var temperatures []TemperatureStat
files, err := filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_*"))
if err != nil {
var err error

var files []string

temperatures := make([]TemperatureStat, 0)

// Only the temp*_input file provides current temperature
// value in millidegree Celsius as reported by the temperature to the device:
// https://www.kernel.org/doc/Documentation/hwmon/sysfs-interface
if files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/temp*_input")); err != nil {
return temperatures, err
}

if len(files) == 0 {
// CentOS has an intermediate /device directory:
// https://github.com/giampaolo/psutil/issues/971
files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/device/temp*_*"))
if err != nil {
if files, err = filepath.Glob(common.HostSys("/class/hwmon/hwmon*/device/temp*_input")); err != nil {
return temperatures, err
}
}

var warns Warnings

if len(files) == 0 { // handle distributions without hwmon, like raspbian #391, parse legacy thermal_zone files
Expand Down Expand Up @@ -492,51 +504,90 @@ func SensorsTemperaturesWithContext(ctx context.Context) ([]TemperatureStat, err
return temperatures, warns.Reference()
}

temperatures = make([]TemperatureStat, 0, len(files))

// example directory
// device/ temp1_crit_alarm temp2_crit_alarm temp3_crit_alarm temp4_crit_alarm temp5_crit_alarm temp6_crit_alarm temp7_crit_alarm
// name temp1_input temp2_input temp3_input temp4_input temp5_input temp6_input temp7_input
// power/ temp1_label temp2_label temp3_label temp4_label temp5_label temp6_label temp7_label
// subsystem/ temp1_max temp2_max temp3_max temp4_max temp5_max temp6_max temp7_max
// temp1_crit temp2_crit temp3_crit temp4_crit temp5_crit temp6_crit temp7_crit uevent
for _, file := range files {
filename := strings.Split(filepath.Base(file), "_")
if filename[1] == "label" {
// Do not try to read the temperature of the label file
continue
}
var raw []byte

var temperature float64

// Get the base directory location
directory := filepath.Dir(file)

// Get the base filename prefix like temp1
basename := strings.Split(filepath.Base(file), "_")[0]

// Get the base path like <dir>/temp1
basepath := filepath.Join(directory, basename)

// Get the label of the temperature you are reading
var label string
c, _ := ioutil.ReadFile(filepath.Join(filepath.Dir(file), filename[0]+"_label"))
if c != nil {
//format the label from "Core 0" to "core0_"
label = fmt.Sprintf("%s_", strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(c))), " "), ""))
label := ""

if raw, _ = ioutil.ReadFile(basepath + "_label"); len(raw) != 0 {
// Format the label from "Core 0" to "core_0"
label = strings.Join(strings.Split(strings.TrimSpace(strings.ToLower(string(raw))), " "), "_")
}

// Get the name of the temperature you are reading
name, err := ioutil.ReadFile(filepath.Join(filepath.Dir(file), "name"))
if err != nil {
if raw, err = ioutil.ReadFile(filepath.Join(directory, "name")); err != nil {
warns.Add(err)
continue
}

name := strings.TrimSpace(string(raw))

if label != "" {
name = name + "_" + label
}

// Get the temperature reading
current, err := ioutil.ReadFile(file)
if err != nil {
if raw, err = ioutil.ReadFile(file); err != nil {
warns.Add(err)
continue
}
temperature, err := strconv.ParseFloat(strings.TrimSpace(string(current)), 64)
if err != nil {

if temperature, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil {
warns.Add(err)
continue
}

tempName := strings.TrimSpace(strings.ToLower(string(strings.Join(filename[1:], ""))))
// Add discovered temperature sensor to the list
temperatures = append(temperatures, TemperatureStat{
SensorKey: fmt.Sprintf("%s_%s%s", strings.TrimSpace(string(name)), label, tempName),
Temperature: temperature / 1000.0,
SensorKey: name,
Temperature: temperature / hostTemperatureScale,
High: optionalValueReadFromFile(basepath+"_max") / hostTemperatureScale,
Critical: optionalValueReadFromFile(basepath+"_crit") / hostTemperatureScale,
})
}

return temperatures, warns.Reference()
}

func optionalValueReadFromFile(filename string) float64 {
var raw []byte

var err error

var value float64

// Check if file exists
if _, err := os.Stat(filename); os.IsNotExist(err) {
return 0
}

if raw, err = ioutil.ReadFile(filename); err != nil {
return 0
}

if value, err = strconv.ParseFloat(strings.TrimSpace(string(raw)), 64); err != nil {
return 0
}

return value
}