mirror of
https://github.com/henrygd/beszel.git
synced 2025-10-30 18:17:13 +00:00
Implement battery error reporting mechanism Added error reporting for battery information retrieval. Handles cases like bluetooth devices where `battery` finds it but it has incomplete information about that battery, which would have otherwise caused a null pointer error. Related: #1254
82 lines
2.5 KiB
Go
82 lines
2.5 KiB
Go
//go:build !freebsd
|
|
|
|
// Package battery provides functions to check if the system has a battery and to get the battery stats.
|
|
package battery
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"log/slog"
|
|
|
|
"github.com/distatus/battery"
|
|
)
|
|
|
|
var systemHasBattery = false
|
|
var haveCheckedBattery = false
|
|
|
|
// HasReadableBattery checks if the system has a battery and returns true if it does.
|
|
func HasReadableBattery() bool {
|
|
if haveCheckedBattery {
|
|
return systemHasBattery
|
|
}
|
|
haveCheckedBattery = true
|
|
batteries,err := battery.GetAll()
|
|
if err != nil {
|
|
// even if there's errors getting some batteries, the system
|
|
// definitely has a battery if the list is not empty.
|
|
// This list will include everything `battery` can find,
|
|
// including things like bluetooth devices.
|
|
fmt.Fprintln(os.Stderr, err)
|
|
}
|
|
systemHasBattery = len(batteries) > 0
|
|
if !systemHasBattery {
|
|
slog.Debug("No battery found", "err", err)
|
|
}
|
|
return systemHasBattery
|
|
}
|
|
|
|
// GetBatteryStats returns the current battery percent and charge state
|
|
// percent = (current charge of all batteries) / (sum of designed/full capacity of all batteries)
|
|
func GetBatteryStats() (batteryPercent uint8, batteryState uint8, err error) {
|
|
if !HasReadableBattery() {
|
|
return batteryPercent, batteryState, errors.ErrUnsupported
|
|
}
|
|
batteries, err := battery.GetAll()
|
|
// we'll handle errors later by skipping batteries with errors, rather
|
|
// than skipping everything because of the presence of some errors.
|
|
if len(batteries) == 0 {
|
|
return batteryPercent, batteryState, errors.New("no batteries")
|
|
}
|
|
|
|
totalCapacity := float64(0)
|
|
totalCharge := float64(0)
|
|
errs, partialErrs := err.(battery.Errors)
|
|
|
|
for i, bat := range batteries {
|
|
if partialErrs && errs[i] != nil {
|
|
// if there were some errors, like missing data, skip it
|
|
continue
|
|
}
|
|
if bat.Full == 0 {
|
|
// skip batteries with no capacity. Charge is unlikely to ever be zero, but
|
|
// we can't guarantee that, so don't skip based on charge.
|
|
continue
|
|
}
|
|
totalCapacity += bat.Full
|
|
totalCharge += bat.Current
|
|
}
|
|
|
|
if totalCapacity == 0 {
|
|
// for macs there's sometimes a ghost battery with 0 capacity
|
|
// https://github.com/distatus/battery/issues/34
|
|
// Instead of skipping over those batteries, we'll check for total 0 capacity
|
|
// and return an error. This also prevents a divide by zero.
|
|
return batteryPercent, batteryState, errors.New("no battery capacity")
|
|
}
|
|
|
|
batteryPercent = uint8(totalCharge / totalCapacity * 100)
|
|
batteryState = uint8(batteries[0].State.Raw)
|
|
return batteryPercent, batteryState, nil
|
|
}
|