ups_monitor/
ups_monitor.rs

1// Copyright (c) 2025 Stuart Stock
2// SPDX-License-Identifier: MIT OR Apache-2.0
3
4//! A "top" like monitor for the Waveshare UPS Hat E.
5//!
6use std::io::{self, Write};
7use std::thread;
8use std::time::{Duration, SystemTime, UNIX_EPOCH};
9use waveshare_ups_hat_e::UpsHatE;
10
11const CLEAR_SCREEN: &str = "\x1b[2J";
12const CURSOR_HOME: &str = "\x1b[H";
13const BOLD: &str = "\x1b[1m";
14const RESET: &str = "\x1b[0m";
15
16fn main() -> Result<(), Box<dyn std::error::Error>> {
17    let mut ups = UpsHatE::new();
18    let mut stdout = io::stdout();
19
20    let software_revision = ups.get_software_revision()?;
21
22    loop {
23        let battery = ups.get_battery_state()?;
24        let power = ups.get_power_state()?;
25        let comm = ups.get_communication_state()?;
26        let vbus = ups.get_usbc_vbus()?;
27        let cells = ups.get_cell_voltage()?;
28        let battery_low = ups.is_battery_low()?;
29        let power_off_pending = ups.is_power_off_pending()?;
30
31        print!("{CLEAR_SCREEN}{CURSOR_HOME}");
32
33        let epoch_secs = SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs();
34
35        println!("{BOLD}UPS HAT (E) Monitor{RESET}");
36        println!("═══════════════════════════════════════════");
37        println!("Unix time: {epoch_secs}");
38        println!();
39
40        println!("{BOLD}UPS Info{RESET}");
41        println!("  Software Rev:  {:?}", software_revision);
42        println!();
43
44        // Power state
45        println!("{BOLD}Power{RESET}");
46        println!("  State:         {:?}", power.charging_state);
47        println!("  Activity:      {:?}", power.charger_activity);
48        println!("  USB-C In:      {:?}", power.usbc_input_state);
49        println!("  USB-C PD:      {:?}", power.usbc_power_delivery);
50        println!("  Off Pending?   {}", if power_off_pending { "Yes" } else { "No" });
51        println!();
52
53        // Communication state
54        println!("{BOLD}Communication{RESET}");
55        println!("  BQ4050:        {:?}", comm.bq4050);
56        println!("  IP2368:        {:?}", comm.ip2368);
57        println!();
58
59        // Battery
60        println!("{BOLD}Battery{RESET}");
61        println!("  Charge:        {}%", battery.remaining_percent);
62        println!("  Voltage:       {} mV", battery.millivolts);
63        println!("  Current:       {} mA", battery.milliamps);
64        println!("  Est. Capacity: {} mAh", battery.remaining_capacity_milliamphours);
65        if battery.milliamps < 0 {
66            println!("  Est. Runtime:  {} min", battery.remaining_runtime_minutes);
67        } else if battery.time_to_full_minutes > 0 {
68            println!("  Time To Full:  {} min", battery.time_to_full_minutes);
69        }
70        println!("  Low Battery?   {}", if battery_low { "Yes" } else { "No" });
71        println!();
72
73        // USB-C VBUS
74        println!("{BOLD}USB-C VBUS{RESET}");
75        println!("  Voltage:      {} mV", vbus.millivolts);
76        println!("  Current:      {} mA", vbus.milliamps);
77        println!("  Power:        {} mW", vbus.milliwatts);
78        println!();
79
80        // Cell voltages
81        println!("{BOLD}Cell Voltages{RESET}");
82        println!("  Cell 1:       {} mV", cells.cell_1_millivolts);
83        println!("  Cell 2:       {} mV", cells.cell_2_millivolts);
84        println!("  Cell 3:       {} mV", cells.cell_3_millivolts);
85        println!("  Cell 4:       {} mV", cells.cell_4_millivolts);
86        println!();
87
88        println!("Press Ctrl+C to exit");
89
90        stdout.flush()?;
91        thread::sleep(Duration::from_secs(2));
92    }
93}