hardware_query/
battery.rs1use crate::{HardwareQueryError, Result};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6pub enum BatteryStatus {
7 Charging,
8 Discharging,
9 Full,
10 NotCharging,
11 Unknown,
12}
13
14impl std::fmt::Display for BatteryStatus {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 match self {
17 BatteryStatus::Charging => write!(f, "Charging"),
18 BatteryStatus::Discharging => write!(f, "Discharging"),
19 BatteryStatus::Full => write!(f, "Full"),
20 BatteryStatus::NotCharging => write!(f, "Not Charging"),
21 BatteryStatus::Unknown => write!(f, "Unknown"),
22 }
23 }
24}
25
26#[derive(Debug, Clone, Serialize, Deserialize)]
28pub struct BatteryInfo {
29 pub percentage: f32,
31 pub status: BatteryStatus,
33 pub time_remaining_minutes: Option<u32>,
35 pub health_percent: Option<f32>,
37 pub design_capacity_wh: Option<f32>,
39 pub current_capacity_wh: Option<f32>,
41 pub cycle_count: Option<u32>,
43 pub temperature: Option<f32>,
45 pub voltage: Option<f32>,
47 pub current: Option<f32>,
49 pub manufacturer: Option<String>,
51 pub model: Option<String>,
53 pub serial_number: Option<String>,
55}
56
57impl BatteryInfo {
58 pub fn query() -> Result<Self> {
60 Err(HardwareQueryError::device_not_found("No battery detected"))
63 }
64
65 pub fn percentage(&self) -> f32 {
67 self.percentage
68 }
69
70 pub fn status(&self) -> &BatteryStatus {
72 &self.status
73 }
74
75 pub fn is_charging(&self) -> bool {
77 matches!(self.status, BatteryStatus::Charging)
78 }
79
80 pub fn is_discharging(&self) -> bool {
82 matches!(self.status, BatteryStatus::Discharging)
83 }
84
85 pub fn time_remaining_hours(&self) -> Option<f32> {
87 self.time_remaining_minutes
88 .map(|minutes| minutes as f32 / 60.0)
89 }
90
91 pub fn health_percent(&self) -> Option<f32> {
93 self.health_percent
94 }
95
96 pub fn wear_percent(&self) -> Option<f32> {
98 match (self.design_capacity_wh, self.current_capacity_wh) {
99 (Some(design), Some(current)) if design > 0.0 => {
100 Some(((design - current) / design) * 100.0)
101 }
102 _ => None,
103 }
104 }
105
106 pub fn needs_replacement(&self) -> bool {
108 if let Some(health) = self.health_percent {
109 health < 80.0
110 } else if let Some(wear) = self.wear_percent() {
111 wear > 20.0
112 } else {
113 false
114 }
115 }
116
117 pub fn capacity_wh(&self) -> Option<f32> {
119 self.current_capacity_wh
120 }
121
122 pub fn charge_percent(&self) -> f32 {
124 self.percentage
125 }
126}