SmartUPS is a real-time monitoring solution for the Waveshare UPS Module 3S on a Raspberry Pi running Linux. It provides detailed insights into your UPS status, including battery voltage, power consumption, CPU metrics, and more.
- Real-Time UPS Monitoring — voltage, current, power, and battery percentage with smoothed display values
- Charging Detection — automatically detects AC power vs battery with color-coded status
- Estimated Remaining Time — dynamically calculated from actual power draw and battery level
- Graceful Shutdown — safely powers down the Pi when battery gets critically low
- CSV Data Logging — daily auto-rotated CSV files with configurable retention
- System Tray Icon — optional battery indicator for desktop environments
- Optional Live Plot — real-time graphs of voltage, current, and power
- Auto-Start on Boot — systemd service with auto-restart on failure
- Raspberry Pi (tested on Raspberry Pi 4 and 5)
- Waveshare UPS Module 3S (other INA219-based UPS modules work with
--i2c-address)
The easiest way to get running — one command handles everything:
git clone https://github.com/Xza85hrf/SmartUPS.git
cd SmartUPS
chmod +x setup.sh
./setup.shThe setup script will:
- Check that Python 3 and I2C are available
- Create a virtual environment and install dependencies
- Optionally install a systemd service for auto-start on boot
That's it! Skip to Usage below.
If you prefer to set things up yourself, follow these steps.
sudo raspi-configNavigate to Interface Options → I2C → Enable, then reboot:
sudo rebootAfter reboot, verify I2C is working:
ls /dev/i2c-* # should show /dev/i2c-1
sudo i2cdetect -y 1 # should show your UPS at address 0x41sudo apt update
sudo apt install -y python3 python3-pip python3-venv gitgit clone https://github.com/Xza85hrf/SmartUPS.git
cd SmartUPSA virtual environment keeps SmartUPS dependencies isolated from your system Python:
python3 -m venv venvsource venv/bin/activateNote: You need to activate the venv every time you open a new terminal. Your prompt will show
(venv)when it's active.
pip install -r requirements.txtpython SmartUPS.pyTo deactivate the virtual environment when you're done:
deactivateIf you used setup.sh, the venv python is at ./venv/bin/python:
# Basic monitoring
./venv/bin/python SmartUPS.py
# With live graphs (needs a display)
./venv/bin/python SmartUPS.py --show-plot
# Headless background mode
./venv/bin/python SmartUPS.py --daemon
# Different UPS board at address 0x40
./venv/bin/python SmartUPS.py --i2c-address 0x40
# Custom battery capacity (e.g. larger 18650 cells)
./venv/bin/python SmartUPS.py --battery-capacity 35| Flag | Default | Description |
|---|---|---|
--i2c-bus |
1 |
I2C bus number |
--i2c-address |
0x41 |
INA219 I2C address (hex). Use sudo i2cdetect -y 1 to find yours |
--battery-capacity |
30 |
Battery capacity in Wh. Default fits 3× 18650 cells |
| Flag | Default | Description |
|---|---|---|
--log-interval |
2 |
Sampling interval in seconds |
--smoothing |
5 |
Rolling-average window for display. Raw values always go to CSV |
--show-plot |
off | Show real-time voltage/current/power graphs |
--daemon |
off | Background mode: no terminal output, log to file only |
--tray |
off | Show system-tray battery icon (needs pystray + Pillow) |
| Flag | Default | Description |
|---|---|---|
--shutdown-threshold |
20 |
Battery % at which shutdown arms |
--shutdown-consecutive |
3 |
Consecutive critical readings before shutdown fires |
--no-shutdown |
off | Disable automatic shutdown (monitoring only) |
| Flag | Default | Description |
|---|---|---|
--log-file |
~/.local/share/smartups/smartups.log |
Text log path. Rotates at 5 MB, keeps 3 backups |
--csv-file |
./ina219_data_log.csv |
CSV base path. Date stamp is appended automatically |
--csv-keep-days |
30 |
Auto-delete CSV files older than N days (0 = keep all) |
--version |
— | Print version and exit |
=============================================
[2026-04-25 01:59:14]
=============================================
Voltage: 12.368 V
Current: 0.0277 A (out)
Power: 0.344 W [Low]
Battery: 93.6% On Battery
CPU Temp: 64.8°C
CPU Usage: 51.4%
Memory: 15.2%
Remaining: More than 24 hrs
The display shows smoothed (rolling average) values for stable readings. Raw sensor values are always written to the CSV for accurate analysis.
CSV files are automatically date-stamped and rotated daily:
ina219_data_log_2026-04-25.csv
ina219_data_log_2026-04-26.csv
...
Files older than --csv-keep-days (default 30) are automatically pruned on startup. Set --csv-keep-days 0 to keep everything.
When running on battery and the charge drops to the configured threshold for the configured number of consecutive samples, SmartUPS invokes sudo shutdown -h now. The consecutive-reading requirement means a single transient dip will never trigger a shutdown — the condition has to persist across --shutdown-consecutive samples (default 3, so 6 seconds at the default 2s interval).
For the shutdown command to succeed non-interactively:
- Option A (recommended): Use the systemd service — it has
CAP_SYS_BOOTbuilt in. - Option B: Add a passwordless sudoers entry:
echo "$(whoami) ALL=(ALL) NOPASSWD: /sbin/shutdown" | sudo tee /etc/sudoers.d/smartups
Use --no-shutdown for monitoring only (no automated shutdown).
With --tray, SmartUPS shows a battery icon in your system tray:
| Color | Meaning |
|---|---|
| Blue | Charging / plugged in |
| Green | On battery, healthy (>50%) |
| Amber | On battery, low (21–50%) |
| Red | On battery, critical (≤20%) |
Install the optional dependencies:
./venv/bin/pip install pystray pillow./setup.shThis automatically generates a service file with your username and paths.
# 1. Create log directory
sudo mkdir -p /var/log/smartups
sudo chown "$(whoami):$(whoami)" /var/log/smartups
# 2. Copy and edit the service file
sudo cp systemd/smartups.service /etc/systemd/system/
# Edit User= and paths to match your setup:
sudo nano /etc/systemd/system/smartups.service
# 3. Enable and start
sudo systemctl daemon-reload
sudo systemctl enable --now smartups.service
# 4. Check status
systemctl status smartups.service
journalctl -u smartups.service -fsudo systemctl status smartups.service # check status
sudo systemctl restart smartups.service # restart after config change
sudo systemctl stop smartups.service # stop temporarily
journalctl -u smartups.service -f # watch live logsFor the tray icon in a desktop session, install the user service:
mkdir -p ~/.config/systemd/user
cp systemd/smartups-tray.service ~/.config/systemd/user/
# Edit WorkingDirectory if your clone isn't at ~/SmartUPS
systemctl --user daemon-reload
systemctl --user enable --now smartups-tray.serviceI2C is not enabled. Run sudo raspi-config → Interface Options → I2C → Enable, then reboot.
Add your user to the i2c group:
sudo usermod -aG i2c $(whoami)Then log out and back in.
Make sure you're using the correct I2C address. Check with:
sudo i2cdetect -y 1Then pass the address: python SmartUPS.py --i2c-address 0x41
You need to activate the virtual environment first:
source venv/bin/activate
python SmartUPS.pyOr run directly with the venv python:
./venv/bin/python SmartUPS.pyCheck the logs:
journalctl -u smartups.service --no-pager -n 50SmartUPS works with any INA219-based UPS module. If you're using different hardware:
- I2C Address — use
--i2c-address(e.g.--i2c-address 0x40) - I2C Bus — use
--i2c-bus(e.g.--i2c-bus 0) - Battery Capacity — use
--battery-capacity(in watt-hours)
SmartUPS is licensed under the MIT License. See LICENSE for details.
Feel free to open issues or submit pull requests!