using System;
using System.Globalization;
using System.IO;
public class BatteryStatus
{
public bool Present;
public int Percent = -1;
public bool Charging;
public bool Full;
}
public static class BatteryMonitor
{
private const string Root = "/sys/class/power_supply";
private static string _path; // cached battery directory
public static BatteryStatus Read()
{
var s = new BatteryStatus();
string dir = FindBattery();
if (dir == null) return s;
int pct = ReadPercent(dir);
if (pct < 0) return s;
string status = ReadValue(dir, "status") ?? "Unknown";
s.Present = true;
s.Percent = Math.Max(0, Math.Min(100, pct));
s.Charging = string.Equals(status, "Charging", StringComparison.OrdinalIgnoreCase);
s.Full = string.Equals(status, "Full", StringComparison.OrdinalIgnoreCase);
return s;
}
private static string FindBattery()
{
if (_path != null && Directory.Exists(_path)) return _path;
_path = null;
if (!Directory.Exists(Root)) return null;
try
{
foreach (string dir in Directory.GetDirectories(Root))
{
if (!string.Equals(ReadValue(dir, "type"), "Battery",
StringComparison.OrdinalIgnoreCase)) continue;
// "scope" is Device on peripherals (stylus, BT mouse) — skip those
string scope = ReadValue(dir, "scope");
if (scope != null && !string.Equals(scope, "System",
StringComparison.OrdinalIgnoreCase)) continue;
if (ReadPercent(dir) < 0) continue;
_path = dir;
break;
}
}
catch (Exception ex)
{
Console.WriteLine("Battery scan failed: " + ex.Message);
}
return _path;
}
private static int ReadPercent(string dir)
{
long pct = ParseLong(ReadValue(dir, "capacity"));
if (pct >= 0) return (int)pct;
// some firmwares expose energy/charge only
long now = ParseLong(ReadValue(dir, "energy_now"));
long full = ParseLong(ReadValue(dir, "energy_full"));
if (now < 0 || full <= 0)
{
now = ParseLong(ReadValue(dir, "charge_now"));
full = ParseLong(ReadValue(dir, "charge_full"));
}
if (now >= 0 && full > 0) return (int)Math.Round(now * 100.0 / full);
return -1;
}
private static string ReadValue(string dir, string file)
{
try
{
string p = Path.Combine(dir, file);
return File.Exists(p) ? File.ReadAllText(p).Trim() : null;
}
catch { return null; }
}
private static long ParseLong(string s)
{
long v;
if (s != null && long.TryParse(s, NumberStyles.Integer,
CultureInfo.InvariantCulture, out v)) return v;
return -1;
}
}