mod controls;
mod monitoring;
pub mod types;
use std::sync::Arc;
use controls::DeviceController;
use derive_more::Debug;
use tokio_util::sync::CancellationToken;
use types::{DeviceParams, DeviceProps, LiveDeviceParams};
use wayle_core::{Property, unwrap_dbus, unwrap_dbus_or};
use wayle_traits::{ModelMonitoring, Reactive};
use zbus::{Connection, zvariant::OwnedObjectPath};
use crate::{
Error,
proxy::device::DeviceProxy,
types::{BatteryLevel, BatteryTechnology, DeviceState, DeviceType, WarningLevel},
};
#[derive(Debug, Clone)]
pub struct Device {
#[debug(skip)]
cancellation_token: Option<CancellationToken>,
#[debug(skip)]
pub(crate) zbus_connection: Connection,
#[debug(skip)]
pub(crate) device_path: OwnedObjectPath,
pub native_path: Property<String>,
pub vendor: Property<String>,
pub model: Property<String>,
pub serial: Property<String>,
pub update_time: Property<u64>,
pub device_type: Property<DeviceType>,
pub power_supply: Property<bool>,
pub has_history: Property<bool>,
pub has_statistics: Property<bool>,
pub online: Property<bool>,
pub energy: Property<f64>,
pub energy_empty: Property<f64>,
pub energy_full: Property<f64>,
pub energy_full_design: Property<f64>,
pub energy_rate: Property<f64>,
pub voltage: Property<f64>,
pub charge_cycles: Property<i32>,
pub luminosity: Property<f64>,
pub time_to_empty: Property<i64>,
pub time_to_full: Property<i64>,
pub percentage: Property<f64>,
pub temperature: Property<f64>,
pub is_present: Property<bool>,
pub state: Property<DeviceState>,
pub is_rechargeable: Property<bool>,
pub capacity: Property<f64>,
pub technology: Property<BatteryTechnology>,
pub warning_level: Property<WarningLevel>,
pub battery_level: Property<BatteryLevel>,
pub icon_name: Property<String>,
pub charge_start_threshold: Property<u32>,
pub charge_end_threshold: Property<u32>,
pub charge_threshold_enabled: Property<bool>,
pub charge_threshold_supported: Property<bool>,
pub charge_threshold_settings_supported: Property<u32>,
pub voltage_min_design: Property<f64>,
pub voltage_max_design: Property<f64>,
pub capacity_level: Property<String>,
}
impl Reactive for Device {
type Error = Error;
type LiveContext<'a> = LiveDeviceParams<'a>;
type Context<'a> = DeviceParams<'a>;
async fn get(context: Self::Context<'_>) -> Result<Self, Self::Error> {
let device_props = Self::from_connection(context.connection, context.device_path).await?;
Ok(Self::from_props(
device_props,
context.connection,
context.device_path.clone(),
None,
))
}
async fn get_live(context: Self::LiveContext<'_>) -> Result<Arc<Self>, Self::Error> {
let device_props = Self::from_connection(context.connection, context.device_path).await?;
let device = Self::from_props(
device_props,
context.connection,
context.device_path.clone(),
Some(context.cancellation_token.child_token()),
);
let device_arc = Arc::new(device);
device_arc.clone().start_monitoring().await?;
Ok(device_arc)
}
}
impl Device {
pub async fn refresh(&self) -> Result<(), Error> {
DeviceController::refresh(&self.zbus_connection, &self.device_path).await
}
pub async fn get_history(
&self,
history_type: &str,
timespan: u32,
resolution: u32,
) -> Result<Vec<(u32, f64, u32)>, Error> {
DeviceController::get_history(
&self.zbus_connection,
&self.device_path,
history_type,
timespan,
resolution,
)
.await
}
pub async fn get_statistics(&self, stat_type: &str) -> Result<Vec<(f64, f64)>, Error> {
DeviceController::get_statistics(&self.zbus_connection, &self.device_path, stat_type).await
}
pub async fn enable_charge_threshold(&self, enabled: bool) -> Result<(), Error> {
DeviceController::enable_charge_threshold(&self.zbus_connection, &self.device_path, enabled)
.await
}
#[allow(clippy::too_many_lines)]
async fn from_connection(
connection: &Connection,
device_path: &OwnedObjectPath,
) -> Result<DeviceProps, Error> {
let proxy = DeviceProxy::new(connection, device_path).await?;
let (
native_path,
vendor,
model,
serial,
update_time,
device_type,
power_supply,
has_history,
has_statistics,
online,
energy,
energy_empty,
energy_full,
energy_full_design,
energy_rate,
voltage,
charge_cycles,
luminosity,
time_to_empty,
time_to_full,
percentage,
temperature,
is_present,
state,
is_rechargeable,
capacity,
technology,
warning_level,
battery_level,
icon_name,
charge_start_threshold,
charge_end_threshold,
charge_threshold_enabled,
charge_threshold_supported,
charge_threshold_settings_supported,
voltage_min_design,
voltage_max_design,
capacity_level,
) = tokio::join!(
proxy.native_path(),
proxy.vendor(),
proxy.model(),
proxy.serial(),
proxy.update_time(),
proxy.device_type(),
proxy.power_supply(),
proxy.has_history(),
proxy.has_statistics(),
proxy.online(),
proxy.energy(),
proxy.energy_empty(),
proxy.energy_full(),
proxy.energy_full_design(),
proxy.energy_rate(),
proxy.voltage(),
proxy.charge_cycles(),
proxy.luminosity(),
proxy.time_to_empty(),
proxy.time_to_full(),
proxy.percentage(),
proxy.temperature(),
proxy.is_present(),
proxy.state(),
proxy.is_rechargeable(),
proxy.capacity(),
proxy.technology(),
proxy.warning_level(),
proxy.battery_level(),
proxy.icon_name(),
proxy.charge_start_threshold(),
proxy.charge_end_threshold(),
proxy.charge_threshold_enabled(),
proxy.charge_threshold_supported(),
proxy.charge_threshold_settings_supported(),
proxy.voltage_min_design(),
proxy.voltage_max_design(),
proxy.capacity_level(),
);
Ok(DeviceProps {
native_path: unwrap_dbus!(native_path),
vendor: unwrap_dbus!(vendor),
model: unwrap_dbus!(model),
serial: unwrap_dbus!(serial),
update_time: unwrap_dbus!(update_time),
device_type: unwrap_dbus!(device_type),
power_supply: unwrap_dbus!(power_supply),
has_history: unwrap_dbus!(has_history),
has_statistics: unwrap_dbus!(has_statistics),
online: unwrap_dbus!(online),
energy: unwrap_dbus!(energy),
energy_empty: unwrap_dbus!(energy_empty),
energy_full: unwrap_dbus!(energy_full),
energy_full_design: unwrap_dbus!(energy_full_design),
energy_rate: unwrap_dbus!(energy_rate),
voltage: unwrap_dbus!(voltage),
charge_cycles: unwrap_dbus_or!(charge_cycles, -1),
luminosity: unwrap_dbus!(luminosity),
time_to_empty: unwrap_dbus!(time_to_empty),
time_to_full: unwrap_dbus!(time_to_full),
percentage: unwrap_dbus!(percentage),
temperature: unwrap_dbus!(temperature),
is_present: unwrap_dbus!(is_present),
state: unwrap_dbus!(state),
is_rechargeable: unwrap_dbus!(is_rechargeable),
capacity: unwrap_dbus!(capacity),
technology: unwrap_dbus!(technology),
warning_level: unwrap_dbus!(warning_level),
battery_level: unwrap_dbus!(battery_level),
icon_name: unwrap_dbus!(icon_name),
charge_start_threshold: unwrap_dbus!(charge_start_threshold),
charge_end_threshold: unwrap_dbus!(charge_end_threshold),
charge_threshold_enabled: unwrap_dbus!(charge_threshold_enabled),
charge_threshold_supported: unwrap_dbus!(charge_threshold_supported),
charge_threshold_settings_supported: unwrap_dbus!(charge_threshold_settings_supported),
voltage_min_design: unwrap_dbus!(voltage_min_design),
voltage_max_design: unwrap_dbus!(voltage_max_design),
capacity_level: unwrap_dbus!(capacity_level),
})
}
fn from_props(
props: DeviceProps,
connection: &Connection,
device_path: OwnedObjectPath,
cancellation_token: Option<CancellationToken>,
) -> Self {
Self {
zbus_connection: connection.clone(),
device_path,
cancellation_token,
native_path: Property::new(props.native_path),
vendor: Property::new(props.vendor),
model: Property::new(props.model),
serial: Property::new(props.serial),
update_time: Property::new(props.update_time),
device_type: Property::new(DeviceType::from(props.device_type)),
power_supply: Property::new(props.power_supply),
has_history: Property::new(props.has_history),
has_statistics: Property::new(props.has_statistics),
online: Property::new(props.online),
energy: Property::new(props.energy),
energy_empty: Property::new(props.energy_empty),
energy_full: Property::new(props.energy_full),
energy_full_design: Property::new(props.energy_full_design),
energy_rate: Property::new(props.energy_rate),
voltage: Property::new(props.voltage),
charge_cycles: Property::new(props.charge_cycles),
luminosity: Property::new(props.luminosity),
time_to_empty: Property::new(props.time_to_empty),
time_to_full: Property::new(props.time_to_full),
percentage: Property::new(props.percentage),
temperature: Property::new(props.temperature),
is_present: Property::new(props.is_present),
state: Property::new(DeviceState::from(props.state)),
is_rechargeable: Property::new(props.is_rechargeable),
capacity: Property::new(props.capacity),
technology: Property::new(BatteryTechnology::from(props.technology)),
warning_level: Property::new(WarningLevel::from(props.warning_level)),
battery_level: Property::new(BatteryLevel::from(props.battery_level)),
icon_name: Property::new(props.icon_name),
charge_start_threshold: Property::new(props.charge_start_threshold),
charge_end_threshold: Property::new(props.charge_end_threshold),
charge_threshold_enabled: Property::new(props.charge_threshold_enabled),
charge_threshold_supported: Property::new(props.charge_threshold_supported),
charge_threshold_settings_supported: Property::new(
props.charge_threshold_settings_supported,
),
voltage_min_design: Property::new(props.voltage_min_design),
voltage_max_design: Property::new(props.voltage_max_design),
capacity_level: Property::new(props.capacity_level),
}
}
}