finished temperature querying
This commit is contained in:
1 parent
b1d4f3565d
commit
be44d008c7
7 files changed
+168
-3
No files matched your search
@@ -25,3 +25,4 @@ go.work.sum
|
|||||||
# env file
|
# env file
|
||||||
.env
|
.env
|
||||||
|
|
||||||
|
!lhm/*
|
||||||
@@ -2,4 +2,9 @@ module rpi5-health
|
|||||||
|
|
||||||
go 1.26.4
|
go 1.26.4
|
||||||
|
|
||||||
require golang.org/x/sys v0.48.0
|
require (
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4
|
||||||
|
golang.org/x/sys v0.48.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
@@ -1,2 +1,7 @@
|
|||||||
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo=
|
||||||
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og=
|
||||||
+19
-2
@@ -8,6 +8,7 @@ import (
|
|||||||
loadaverage "rpi5-health/internal/load_average"
|
loadaverage "rpi5-health/internal/load_average"
|
||||||
"rpi5-health/internal/memory"
|
"rpi5-health/internal/memory"
|
||||||
"rpi5-health/internal/processor"
|
"rpi5-health/internal/processor"
|
||||||
|
"rpi5-health/internal/temperature"
|
||||||
"rpi5-health/internal/uptime"
|
"rpi5-health/internal/uptime"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -15,10 +16,10 @@ import (
|
|||||||
func Listen() {
|
func Listen() {
|
||||||
reader := bufio.NewScanner(os.Stdin)
|
reader := bufio.NewScanner(os.Stdin)
|
||||||
|
|
||||||
fmt.Print("> ")
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|
||||||
|
fmt.Print("\n> ")
|
||||||
|
|
||||||
if !reader.Scan() {
|
if !reader.Scan() {
|
||||||
log.Println("Program terminated (SIGINT)")
|
log.Println("Program terminated (SIGINT)")
|
||||||
return
|
return
|
||||||
@@ -34,6 +35,14 @@ func Listen() {
|
|||||||
switch text {
|
switch text {
|
||||||
case "exit":
|
case "exit":
|
||||||
return
|
return
|
||||||
|
case "help":
|
||||||
|
fmt.Print(`
|
||||||
|
exit - Exit the program
|
||||||
|
meminfo - Print memory information
|
||||||
|
cpuinfo - Print cpu information
|
||||||
|
uptime - Print system uptime
|
||||||
|
loadavg - Print cpu load average information`)
|
||||||
|
fmt.Println()
|
||||||
case "meminfo":
|
case "meminfo":
|
||||||
memInfo, _ := memory.GetRamInformation()
|
memInfo, _ := memory.GetRamInformation()
|
||||||
|
|
||||||
@@ -56,6 +65,14 @@ func Listen() {
|
|||||||
loadAvg, _ := loadaverage.GetLoadAverage()
|
loadAvg, _ := loadaverage.GetLoadAverage()
|
||||||
|
|
||||||
fmt.Printf("Load average: L1: %.2f | L5: %.2f | L15: %.2f\n", loadAvg.Load1, loadAvg.Load5, loadAvg.Load15)
|
fmt.Printf("Load average: L1: %.2f | L5: %.2f | L15: %.2f\n", loadAvg.Load1, loadAvg.Load5, loadAvg.Load15)
|
||||||
|
case "temperature":
|
||||||
|
temp, _ := temperature.GetTemperatureInformation()
|
||||||
|
|
||||||
|
if temp.Supported {
|
||||||
|
fmt.Printf("Current temperature: %.2fC°", temp.Celsius)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("Temperature reading is unsupported. Try installing Libre Hardware Monitor, or running as Administrator.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
//go:build linux
|
||||||
|
|
||||||
|
package temperature
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLinuxCPUTemperature() (TemperatureInformation, error) {
|
||||||
|
tempFile, err := os.Open("/sys/class/thermal/thermal_zone0/temp")
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("Could not find /sys/class/thermal/thermal_zone0/temp. Trying /sys/class/hwmon/hwmon0/temp1_input...")
|
||||||
|
tempFile, err = os.Open("/sys/class/hwmon/hwmon0/temp1_input")
|
||||||
|
if err != nil {
|
||||||
|
return TemperatureInformation{0, false}, fmt.Errorf("Couldn't find temperature information. System is unsupported.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer tempFile.Close()
|
||||||
|
|
||||||
|
fileReader := bufio.NewScanner(tempFile)
|
||||||
|
|
||||||
|
var celsius float64
|
||||||
|
|
||||||
|
fileReader.Scan()
|
||||||
|
if fileReader.Err() != nil {
|
||||||
|
return TemperatureInformation{0, false}, fmt.Errorf("Could not read temperature.")
|
||||||
|
}
|
||||||
|
|
||||||
|
data := fileReader.Text()
|
||||||
|
celsius, _ = strconv.ParseFloat(data, 64)
|
||||||
|
|
||||||
|
return TemperatureInformation{
|
||||||
|
Celsius: celsius / 1000.0,
|
||||||
|
Supported: true,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTemperatureInformation() (TemperatureInformation, error) {
|
||||||
|
return getLinuxCPUTemperature()
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package temperature
|
||||||
|
|
||||||
|
type TemperatureInformation struct {
|
||||||
|
Celsius float64
|
||||||
|
|
||||||
|
Supported bool
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
//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
|
||||||
|
}
|
||||||
Reference in new issue
Block a user