diff --git a/Cargo.lock b/Cargo.lock index eea4a09..d15591d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -746,12 +746,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "cfg_aliases" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" - [[package]] name = "cfg_aliases" version = "0.2.1" @@ -3152,13 +3146,13 @@ dependencies = [ [[package]] name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ "bitflags 2.6.0", "cfg-if", - "cfg_aliases 0.1.1", + "cfg_aliases", "libc", ] @@ -5063,7 +5057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d623bff5d06f60d738990980d782c8c866997d9194cfe79ecad00aa2f76826dd" dependencies = [ "bytemuck", - "cfg_aliases 0.2.1", + "cfg_aliases", "core-graphics 0.23.2", "foreign-types 0.5.0", "js-sys", @@ -5135,19 +5129,20 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "starship-battery" -version = "0.8.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725bc1c7374f435ef65746eb1a5789cb7d02b8e997f9a3edf979bfb42da68311" +checksum = "9017a937879cf3db80807fa7c28f09eafd4981c998265233028ee7b75f898ed2" dependencies = [ "cfg-if", - "core-foundation 0.9.4", + "core-foundation 0.10.0", "lazycell", "libc", "mach2", - "nix 0.28.0", + "nix 0.29.0", "num-traits", + "plist", "uom", - "winapi", + "windows-sys 0.59.0", ] [[package]] diff --git a/platforms/unix/daemon/src/main.rs b/platforms/unix/daemon/src/main.rs index 5ac942d..e45ebb2 100644 --- a/platforms/unix/daemon/src/main.rs +++ b/platforms/unix/daemon/src/main.rs @@ -11,7 +11,7 @@ use axum::{ use ezrtc::host::EzRTCHost; use ezrtc::socket::DataChannelHandler; use futures::{sink::SinkExt, stream::StreamExt}; -use hardwareinfo::settings::get_settings; +use hardwareinfo::settings::{get_settings, Settings}; use hardwareinfo::{refresh_hardware_info, Data, HardwareInfo, Networks, Nvml, System}; use log::{error, info, warn, LevelFilter}; use serde::{Deserialize, Serialize}; @@ -41,6 +41,7 @@ pub struct AppState { hardware_info_receiver: async_channel::Receiver, last_60s_hardware_info: Mutex>, last_60m_hardware_info: Mutex>, + settings: Settings, } #[tokio::main] @@ -54,6 +55,10 @@ async fn main() { )]) .unwrap(); + // Get settings + let settings = get_settings(); + info!("Connection code: {:?}", settings.connection_code); + // Hardware info channel let (s, r) = async_channel::unbounded(); @@ -64,12 +69,14 @@ async fn main() { hw_info: HardwareInfo::default(), nvml: Nvml::init(), nvml_available: true, + interval: settings.interval as f64, }; let app_state = Arc::new(AppState { hardware_info_receiver: r.clone(), last_60s_hardware_info: Mutex::new(Vec::new()), last_60m_hardware_info: Mutex::new(Vec::new()), + settings: settings.clone(), }); // Setup HTTP server routes @@ -127,7 +134,7 @@ async fn main() { .push(data.hw_info.clone()); } - tokio::time::sleep(std::time::Duration::from_secs(5)).await; + tokio::time::sleep(std::time::Duration::from_secs(settings.interval as u64)).await; } }); @@ -347,10 +354,6 @@ async fn main() { } } - // Get settings - let settings = get_settings(); - info!("Connection code: {:?}", settings.connection_code); - // Start the connection let _host = EzRTCHost::new( "wss://rtc-usw.levminer.com/one-to-many".to_string(), @@ -485,7 +488,7 @@ async fn handle_socket(mut socket: WebSocket, addr: SocketAddr, state: Arc, pub nvml_available: bool, + pub interval: f64, } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -173,6 +176,15 @@ pub struct CoresMotherboard { pub name: String, } +#[derive(Debug, Serialize, Deserialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CoresBattery { + pub cycle_count: String, + pub level: Vec, + pub remaining_time: CoresSensor, + pub capacity: Vec, +} + #[derive(Debug, Serialize, Deserialize, Clone)] pub struct CoresBIOS { pub vendor: String, @@ -198,6 +210,7 @@ pub struct CoresSystem { pub bios: CoresBIOS, pub superIO: CoresSuperIO, pub monitor: CoresMonitor, + pub battery: CoresBattery, } #[derive(Debug, Serialize, Deserialize, Clone)] @@ -267,6 +280,12 @@ impl HardwareInfo { monitor: CoresMonitor { monitors: Vec::new(), }, + battery: CoresBattery { + cycle_count: "N/A".to_string(), + level: Vec::new(), + remaining_time: CoresSensor::default(), + capacity: Vec::new(), + }, }, } } @@ -303,7 +322,6 @@ fn compare_sensor(prev_sensor: &CoresSensor, value: f64) -> CoresSensor { pub fn refresh_hardware_info(data: &mut Data) { let gb = 1024_f64.powi(3); let _mb = 1024_f64.powi(2); - let interval = 5.0; // OS Info if data.first_run { @@ -605,8 +623,8 @@ pub fn refresh_hardware_info(data: &mut Data) { let download_data = (net_data.total_received() as f64 / gb).fmt_num(); let upload_data = (net_data.total_transmitted() as f64 / gb).fmt_num(); - let throughput_download = net_data.received() as f64 / interval; - let throughput_upload = net_data.transmitted() as f64 / interval; + let throughput_download = net_data.received() as f64 / data.interval; + let throughput_upload = net_data.transmitted() as f64 / data.interval; data.hw_info.system.network.interfaces[0].download_data = download_data; data.hw_info.system.network.interfaces[0].upload_data = upload_data; @@ -665,6 +683,77 @@ pub fn refresh_hardware_info(data: &mut Data) { } } + // Battery + if data.first_run { + let manager = starship_battery::Manager::new(); + + match manager { + Ok(manager) => { + if let Ok(batteries) = manager.batteries() { + for battery in batteries { + if let Ok(battery) = battery { + let cycle_count = battery.cycle_count().unwrap_or(0); + let charge_level = battery.state_of_charge().get::(); + let design_capacity = + battery.energy_full_design().get::(); + let full_charge_capacity = + battery.energy_full().get::(); + let remaining_capacity = battery.energy().get::(); + let health = battery.state_of_health().get::(); + + data.hw_info.system.battery = CoresBattery { + cycle_count: cycle_count.to_string(), + level: Vec::new(), + remaining_time: CoresSensor::default(), + capacity: Vec::new(), + }; + + data.hw_info.system.battery.level.push(CoresSensor { + name: "Charge level".to_string(), + value: charge_level as f64, + min: charge_level as f64, + max: charge_level as f64, + }); + + data.hw_info.system.battery.level.push(CoresSensor { + name: "Health".to_string(), + value: 100.0 - health as f64, + min: 100.0 - health as f64, + max: 100.0 - health as f64, + }); + + data.hw_info.system.battery.capacity.push(CoresSensor { + name: "Design capacity".to_string(), + value: design_capacity as f64, + min: design_capacity as f64, + max: design_capacity as f64, + }); + + data.hw_info.system.battery.capacity.push(CoresSensor { + name: "Full charge capacity".to_string(), + value: full_charge_capacity as f64, + min: full_charge_capacity as f64, + max: full_charge_capacity as f64, + }); + + data.hw_info.system.battery.capacity.push(CoresSensor { + name: "Remaining capacity".to_string(), + value: remaining_capacity as f64, + min: remaining_capacity as f64, + max: remaining_capacity as f64, + }); + } else { + error!("Error getting specific battery info"); + } + } + } + } + Err(_err) => { + error!("Error getting battery info"); + } + }; + } + // END data.first_run = false; } diff --git a/platforms/unix/hardwareinfo/src/linux/drive.rs b/platforms/unix/hardwareinfo/src/linux/drive.rs index 8a54fd6..5b80fab 100644 --- a/platforms/unix/hardwareinfo/src/linux/drive.rs +++ b/platforms/unix/hardwareinfo/src/linux/drive.rs @@ -1,9 +1,11 @@ use anyhow::{Context, Result}; +use core::str; use regex::Regex; use std::{ collections::HashMap, fmt::Display, path::{Path, PathBuf}, + process::Command, sync::LazyLock, }; @@ -289,3 +291,29 @@ impl Drive { } } } + +pub fn get_free_space(path: &PathBuf) -> u64 { + // Define the device path as a variable + let path_str = path.to_str().unwrap_or("").replace("/sys/block/", "/dev/"); + + // Construct the command string + let command = format!( + "lsblk -bno FSAVAIL,MOUNTPOINT {} | awk '{{sum += $1}} END {{print sum / (1024^3) \"\"}}'", + path_str + ); + + // Execute the command + let output = Command::new("sh").arg("-c").arg(&command).output(); + + // Check if the command was successful + if let Ok(output) = output { + // Print the command's standard output + if let Ok(result) = str::from_utf8(&output.stdout) { + return (result.trim().parse::().unwrap_or(0.0) * 1.074) as u64; + } else { + return 0; + } + } else { + return 0; + } +} diff --git a/platforms/unix/hardwareinfo/src/linux/mod.rs b/platforms/unix/hardwareinfo/src/linux/mod.rs index ac564d0..2edf987 100644 --- a/platforms/unix/hardwareinfo/src/linux/mod.rs +++ b/platforms/unix/hardwareinfo/src/linux/mod.rs @@ -1,8 +1,6 @@ +use log::debug; use std::{sync::LazyLock, time::SystemTime}; -use drive::DriveData; -use log::{debug, info}; - use crate::{compare_sensor, CoresDisk, CoresRAMInfo, CoresSensor, Data, Round}; pub mod cpu; @@ -33,12 +31,14 @@ pub fn linux_hardware_info(data: &mut Data) { if let Ok(mem) = mem { for mem_device in mem { - data.hw_info.ram.info.push(CoresRAMInfo { - manufacturer_name: mem_device.manufacturer.unwrap_or("Drive".to_string()), - configured_speed: mem_device.speed_mts.unwrap_or(0), - configured_voltage: mem_device.configured_voltage.unwrap_or(0.0) * 1000.0, - size: mem_device.size.unwrap_or(1) / 1024 / 1024, - }); + if mem_device.size.unwrap_or(0) > 0 { + data.hw_info.ram.info.push(CoresRAMInfo { + manufacturer_name: mem_device.manufacturer.unwrap_or("Drive".to_string()), + configured_speed: mem_device.speed_mts.unwrap_or(0), + configured_voltage: mem_device.configured_voltage.unwrap_or(0.0) * 1000.0, + size: mem_device.size.unwrap_or(1) / 1024 / 1024, + }); + } } } @@ -64,10 +64,12 @@ pub fn linux_hardware_info(data: &mut Data) { if !d.is_virtual { let inner = &d.inner; + let drive_space = drive::get_free_space(path); + data.hw_info.system.storage.disks.push(CoresDisk { name: inner.clone().model.unwrap_or("N/A".to_string()), total_space: inner.clone().capacity().unwrap_or(1) / 1000 / 1000 / 1000, - free_space: 0, + free_space: drive_space, throughput_read: 0.0, throughput_write: 0.0, data_read: 0.0, @@ -104,12 +106,14 @@ pub fn linux_hardware_info(data: &mut Data) { } } else { // CPU - let logical_cpus = data.sys.cpus().len(); - let prev_temp = data.hw_info.cpu.temperature[0].clone(); + if data.hw_info.cpu.temperature.len() > 0 { + let logical_cpus = data.sys.cpus().len(); + let prev_temp = data.hw_info.cpu.temperature[0].clone(); - let cpu_data = cpu::CpuData::new(logical_cpus); - if let Ok(temp) = cpu_data.temperature { - data.hw_info.cpu.temperature[0] = compare_sensor(&prev_temp, temp as f64); + let cpu_data = cpu::CpuData::new(logical_cpus); + if let Ok(temp) = cpu_data.temperature { + data.hw_info.cpu.temperature[0] = compare_sensor(&prev_temp, temp as f64); + } } // Drives @@ -151,11 +155,4 @@ pub fn linux_hardware_info(data: &mut Data) { } } } - - // let disks = &data.hw_info.system.storage.disks; - // for disk in disks { - // let inner = &disk.inner; - // let time_passed = 5.0; - // let delta_write_sectors = inner.clone().sys_stats().unwrap().get("write_sectors").unwrap_or(&0).saturating_sub(rhs); - // } } diff --git a/platforms/unix/hardwareinfo/src/main.rs b/platforms/unix/hardwareinfo/src/main.rs index 70cf7f2..9d58f5c 100644 --- a/platforms/unix/hardwareinfo/src/main.rs +++ b/platforms/unix/hardwareinfo/src/main.rs @@ -10,6 +10,7 @@ fn main() { hw_info: HardwareInfo::default(), nvml: Nvml::init(), nvml_available: true, + interval: 5.0, }; loop { diff --git a/platforms/unix/hardwareinfo/src/settings.rs b/platforms/unix/hardwareinfo/src/settings.rs index e8117db..10a30b2 100644 --- a/platforms/unix/hardwareinfo/src/settings.rs +++ b/platforms/unix/hardwareinfo/src/settings.rs @@ -33,14 +33,14 @@ pub fn default_connection_code() -> String { format!("crs_{}", id) } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct ConnectionCode { pub name: String, pub code: String, pub mac: String, } -#[derive(Serialize, Deserialize, Debug)] +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct Settings { #[serde(rename = "interval", default = "default_value")] pub interval: u32,