Skip to content

Commit bac14f3

Browse files
authored
Add power usage support via corsair rmi sensors in linux (#3539)
1 parent d73deda commit bac14f3

4 files changed

Lines changed: 74 additions & 1 deletion

File tree

data/module/system.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,14 +180,17 @@ func (sm SystemModule) Update(ctx context.Context) (any, error) {
180180
systemData.RunMode = types.RunModeStandalone // Always set RunMode to standalone
181181

182182
// Populate optional fields when available per-OS
183-
// Linux: detect camera usage processes and pending reboot via subpackage helpers
183+
// Linux: detect camera usage processes, pending reboot, and PSU power usage via subpackage helpers
184184
if infoStat.OS == "linux" || infoStat.Platform == "linux" || strings.Contains(strings.ToLower(infoStat.Platform), "arch") || strings.Contains(strings.ToLower(infoStat.Platform), "ubuntu") || strings.Contains(strings.ToLower(infoStat.Platform), "debian") {
185185
if cu := system.GetCameraUsage(); len(cu) > 0 {
186186
systemData.CameraUsage = cu
187187
}
188188
if pr := system.GetPendingReboot(); pr != nil {
189189
systemData.PendingReboot = pr
190190
}
191+
if pu := system.GetPSUPowerUsage(); pu != nil {
192+
systemData.PowerUsage = pu
193+
}
191194
}
192195

193196
// Get version information

data/module/system/system_linux.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package system
66
import (
77
"os"
88
"path/filepath"
9+
"strconv"
910
"strings"
1011

1112
"log/slog"
@@ -96,3 +97,67 @@ func GetPendingReboot() *bool {
9697
}
9798
return nil
9899
}
100+
101+
// GetPSUPowerUsage attempts to read PSU power usage from hwmon interfaces on Linux.
102+
// This function specifically looks for Corsair PSU sensors via the corsair_psu driver.
103+
// Returns power usage in watts, or nil if not available.
104+
func GetPSUPowerUsage() *float64 {
105+
// Look for hwmon directories that might contain PSU power sensors
106+
hwmonDirs, err := filepath.Glob("/sys/class/hwmon/hwmon*")
107+
if err != nil {
108+
slog.Debug("Failed to glob hwmon directories", "error", err)
109+
return nil
110+
}
111+
112+
for _, hwmonDir := range hwmonDirs {
113+
// Check if this is a Corsair PSU by looking at the name file
114+
nameFile := filepath.Join(hwmonDir, "name")
115+
nameData, err := os.ReadFile(nameFile)
116+
if err != nil {
117+
continue
118+
}
119+
name := strings.TrimSpace(string(nameData))
120+
121+
// Look for corsair_psu driver or similar PSU-related names
122+
if strings.Contains(strings.ToLower(name), "corsair") ||
123+
strings.Contains(strings.ToLower(name), "psu") ||
124+
strings.Contains(strings.ToLower(name), "rmi") {
125+
126+
// Try to read power1_input (total power consumption)
127+
powerFile := filepath.Join(hwmonDir, "power1_input")
128+
if powerData, err := os.ReadFile(powerFile); err == nil {
129+
valueStr := strings.TrimSpace(string(powerData))
130+
if value, err := strconv.ParseFloat(valueStr, 64); err == nil {
131+
// Convert from microwatts to watts
132+
powerWatts := value / 1_000_000
133+
slog.Info("Found PSU power usage", "hwmon", hwmonDir, "name", name, "power_watts", powerWatts)
134+
return &powerWatts
135+
}
136+
}
137+
}
138+
}
139+
140+
// Fallback: try to find any power1_input file in hwmon directories
141+
// This covers cases where the PSU might not be properly identified by name
142+
for _, hwmonDir := range hwmonDirs {
143+
powerFile := filepath.Join(hwmonDir, "power1_input")
144+
if powerData, err := os.ReadFile(powerFile); err == nil {
145+
// Check if there's a corresponding power1_label to see if it's PSU-related
146+
labelFile := filepath.Join(hwmonDir, "power1_label")
147+
if labelData, err := os.ReadFile(labelFile); err == nil {
148+
label := strings.ToLower(strings.TrimSpace(string(labelData)))
149+
if strings.Contains(label, "psu") || strings.Contains(label, "power") {
150+
valueStr := strings.TrimSpace(string(powerData))
151+
if value, err := strconv.ParseFloat(valueStr, 64); err == nil {
152+
powerWatts := value / 1_000_000
153+
slog.Debug("Found PSU power usage via label", "hwmon", hwmonDir, "label", label, "power_watts", powerWatts)
154+
return &powerWatts
155+
}
156+
}
157+
}
158+
}
159+
}
160+
161+
slog.Debug("No PSU power usage sensors found")
162+
return nil
163+
}

data/module/system/system_other.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,7 @@ func GetCameraUsage() []string {
1010
func GetPendingReboot() *bool {
1111
return nil
1212
}
13+
14+
func GetPSUPowerUsage() *float64 {
15+
return nil
16+
}

types/system.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ type SystemData struct {
2626
MACAddress string `json:"mac_address" mapstructure:"mac_address"`
2727
PlatformVersion string `json:"platform_version" mapstructure:"platform_version"`
2828
Platform string `json:"platform" mapstructure:"platform"`
29+
PowerUsage *float64 `json:"power_usage" mapstructure:"power_usage"`
2930
Uptime uint64 `json:"uptime" mapstructure:"uptime"`
3031
Users []SystemUser `json:"users" mapstructure:"users"`
3132
UUID string `json:"uuid" mapstructure:"uuid"`

0 commit comments

Comments
 (0)