SI Units & the uom Crate
Relevant source files
The following files were used as context for generating this wiki page:
The battery crate is designed to provide cross-platform notebook battery information as strongly typed values. Its primary goal is to abstract away OS-specific interfaces and legacy data formats, recalculating raw hardware data into standardized SI measurement units. This ensures consistency across different operating systems like Linux, macOS, and Windows.
To achieve type safety and automatic unit conversion, the project leverages the uom (Units of Measurement) crate. By using uom, the library prevents common programming errors such as adding milliwatts to watts or confusing Celsius with Kelvin. All public API methods that return physical quantities use types exported from the units module, ensuring that callers always receive measurements in a well-defined, standardized format.
Sources: src/lib.rs:3-6, README.md:21-26, Cargo.toml:25
Core Architecture and uom Integration
The library integrates the uom crate to handle physical quantities. Internally, these values are stored as SI units (e.g., Joules for energy, Kelvins for temperature, Amperes for current). The uom crate provides the underlying engine for these types, while the battery crate re-exports a specific subset of quantities relevant to battery monitoring.
Re-exported Quantities
The src/units.rs file re-exports several f32-based SI quantities from uom. These types are used throughout the library's traits and implementations.
| Quantity | uom SI Type | Description |
|---|---|---|
| Energy | uom::si::f32::Energy | Used for battery capacity and current energy level. |
| Power | uom::si::f32::Power | Used for the rate of energy consumption or charging. |
| ElectricPotential | uom::si::f32::ElectricPotential | Used for battery voltage. |
| ElectricCharge | uom::si::f32::ElectricCharge | Used for capacity when reported in Ah/mAh. |
| ElectricCurrent | uom::si::f32::ElectricCurrent | Used for charge/discharge current. |
| Ratio | uom::si::f32::Ratio | Used for state of charge (percentage) and health. |
| ThermodynamicTemperature | uom::si::f32::ThermodynamicTemperature | Used for battery temperature. |
| Time | uom::si::f32::Time | Used for time-to-full or time-to-empty estimates. |
Sources: src/units.rs:82-93, src/platform/traits.rs:13-16
Internal Conversion Logic
To facilitate easy creation of these quantities from raw platform data (which often arrives as millivolts, microwatts, or milliamperes), the library defines an internal IntoQuantity trait and a set of utility macros.
This diagram shows how raw data is converted into SI quantities before being consumed by the user via the uom .get::<T>() method.
Sources: src/units.rs:104-131, src/units.rs:271-275
Platform Data Normalization
The SI unit system serves as the common denominator for all platform implementations. Each platform-specific module is responsible for reading data from its respective backend (e.g., sysfs on Linux, IOKit on macOS) and converting it into the appropriate SI type.
Linux (sysfs) Conversion
The Linux implementation reads values from files in /sys/class/power_supply/. These values are typically in micro-units (µV, µW, µAh). The DataBuilder uses macros to wrap these raw floating-point values into uom types.
- Voltage: Read from
voltage_nowas microvolts and wrapped usingmicrovolt!. - Power: Read from
power_nowas microwatts and wrapped usingmicrowatt!. - Energy: Calculated from charge and voltage if direct energy files are missing.
Sources: src/platform/linux/sysfs/source.rs:141-155, src/platform/linux/sysfs/fs.rs:48-59
macOS (IOKit) Conversion
On macOS, values are retrieved as CFNumber from the IOKit registry. These are often in milli-units (mV, mA, mAh).
- Voltage: Extracted and wrapped using
millivolt!. - Amperage: Extracted as mA and wrapped using
milliampere!. - Time Remaining: Extracted in minutes and wrapped using
minute!.
Sources: src/platform/darwin/iokit/power_source.rs:56-78
Calculated Ratios and Bounds
Certain battery metrics are expressed as ratios (fractions of 1.0). The library implements a Bound trait for the Ratio type to ensure that values like "State of Charge" or "State of Health" stay within the logical range of 0.0 to 1.0.
pub(crate) trait Bound: Sized {
fn into_bounded(self) -> Self;
}
impl Bound for Ratio {
fn into_bounded(mut self) -> Self {
self.value = self.value.clamp(0.0, 1.0);
self
}
}
The BatteryDevice trait uses these quantities to perform automatic calculations, such as estimating time remaining based on the current energy_rate and energy levels.
Sources: src/units.rs:279-289, src/platform/traits.rs:43-52
Summary of SI Macros
The units module provides several internal macros to simplify the instantiation of uom types from common platform units.
| Macro | Unit | Targeted uom Quantity |
|---|---|---|
volt! | Volts | ElectricPotential |
millivolt! | Millivolts | ElectricPotential |
watt! | Watts | Power |
microwatt! | Microwatts | Power |
milliampere! | Milliamperes | ElectricCurrent |
milliampere_hour! | mAh | ElectricCharge |
celsius! | °C | ThermodynamicTemperature |
percent! | % | Ratio |
minute! | Minutes | Time |
Sources: src/units.rs:163-269
Conclusion
By standardizing on SI units via the uom crate, the battery library provides a robust and type-safe interface for battery monitoring. This architecture shifts the complexity of unit conversion and platform-specific quirks (like micro-unit vs. milli-unit discrepancies) into the internal platform drivers, allowing users of the library to work with high-level, mathematically sound physical quantities.
Sources: src/lib.rs:3-8, README.md:21-26