mirror of
https://github.com/henrygd/beszel.git
synced 2026-08-18 00:07:47 +02:00
- Report battery data for individual devices - Select a representative battery for legacy fields and alerts - Average named battery data independently - Display multiple batteries in system charts - Add cross-platform coverage and transport tests
86 lines
2.1 KiB
Go
86 lines
2.1 KiB
Go
//go:build linux
|
|
|
|
package battery
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strconv"
|
|
|
|
"github.com/henrygd/beszel/agent/utils"
|
|
)
|
|
|
|
var batteryRoot = "/sys/class/power_supply"
|
|
|
|
// HasReadableBattery reports whether collection currently finds a readable battery.
|
|
func HasReadableBattery() bool {
|
|
batteries, _ := GetBatteryStats()
|
|
return len(batteries) > 0
|
|
}
|
|
|
|
func parseSysfsState(status string) uint8 {
|
|
switch status {
|
|
case "Empty":
|
|
return stateEmpty
|
|
case "Full":
|
|
return stateFull
|
|
case "Charging":
|
|
return stateCharging
|
|
case "Discharging":
|
|
return stateDischarging
|
|
case "Not charging":
|
|
return stateIdle
|
|
default:
|
|
return stateUnknown
|
|
}
|
|
}
|
|
|
|
// GetBatteryStats re-enumerates power supplies and returns every readable battery.
|
|
func GetBatteryStats() ([]Battery, error) {
|
|
entries, err := os.ReadDir(batteryRoot)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
batteries := make([]Battery, 0, len(entries))
|
|
for _, entry := range entries {
|
|
path := filepath.Join(batteryRoot, entry.Name())
|
|
if utils.ReadStringFile(filepath.Join(path, "type")) != "Battery" {
|
|
continue
|
|
}
|
|
capStr, ok := utils.ReadStringFileOK(filepath.Join(path, "capacity"))
|
|
if !ok {
|
|
continue
|
|
}
|
|
cap, parseErr := strconv.Atoi(capStr)
|
|
if parseErr != nil {
|
|
continue
|
|
}
|
|
cap = min(max(cap, 0), 100)
|
|
name := utils.ReadStringFile(filepath.Join(path, "model_name"))
|
|
if name == "" {
|
|
name = utils.ReadStringFile(filepath.Join(path, "model"))
|
|
}
|
|
if name == "" {
|
|
name = entry.Name()
|
|
}
|
|
battery := Battery{
|
|
Name: name,
|
|
Percent: uint8(cap),
|
|
State: parseSysfsState(utils.ReadStringFile(filepath.Join(path, "status"))),
|
|
System: utils.ReadStringFile(filepath.Join(path, "scope")) != "Device",
|
|
}
|
|
for _, fullName := range []string{"charge_full", "energy_full"} {
|
|
if parsed, ok := utils.ReadUintFile(filepath.Join(path, fullName)); ok && parsed > 0 {
|
|
battery.FullChargeCapacity = parsed
|
|
battery.HasFullChargeCapacity = true
|
|
break
|
|
}
|
|
}
|
|
batteries = append(batteries, battery)
|
|
}
|
|
if len(batteries) == 0 {
|
|
return nil, errNoBatteries
|
|
}
|
|
return normalizeBatteries(batteries), nil
|
|
}
|