Files
pi-pm3/PISUGAR_SUPPORT.md
michael 4f35df1781 Initial commit - Phase 3/4
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-06 13:46:22 -08:00

7.8 KiB

PiSugar UPS Support for Dangerous Pi

Dangerous Pi now supports PiSugar UPS HATs (PiSugar 2 and 3 series) in addition to generic I2C fuel gauge UPS HATs.

Overview

The UPS system has been refactored to use a driver-based architecture, allowing support for multiple UPS hardware types:

  • PiSugar - PiSugar 2/3 series (via pisugar-server daemon)
  • I2C Fuel Gauge - Generic MAX17040/MAX17048-based UPS HATs
  • None - Disable UPS monitoring

Architecture

UPSManager
    ├── UPSDriver (abstract base)
    │   ├── PiSugarDriver (TCP socket communication)
    │   └── I2CFuelGaugeDriver (I2C bus communication)
    └── Power management logic

Components

  • app/backend/managers/ups_drivers/base.py - Abstract driver interface
  • app/backend/managers/ups_drivers/pisugar_driver.py - PiSugar implementation
  • app/backend/managers/ups_drivers/i2c_driver.py - I2C fuel gauge implementation
  • app/backend/managers/ups_manager.py - Unified UPS management

Configuration

Environment Variables

Add these to /opt/dangerous-pi/.env or systemd/dangerous-pi.env.example:

# UPS Type Selection
UPS_TYPE=pisugar              # Options: "pisugar", "i2c", "none"
UPS_CHECK_INTERVAL=60         # Battery check interval in seconds

# I2C UPS Settings (when UPS_TYPE=i2c)
UPS_I2C_ADDRESS=0x36          # I2C address of fuel gauge chip

# PiSugar Settings (when UPS_TYPE=pisugar)
UPS_PISUGAR_HOST=127.0.0.1    # PiSugar server host
UPS_PISUGAR_PORT=8423         # PiSugar server port

Installation

Option 1: Build with PiSugar Support

Enable PiSugar installation during image build:

# Remove the SKIP file
rm pi-gen/stageDangerousPi/04-pisugar/SKIP

# Build the image
./build-image.sh

Option 2: Manual Installation

Install PiSugar server on an existing system:

# Official installation script
curl http://cdn.pisugar.com/release/pisugar-power-manager.sh | sudo bash

# Or install specific version manually
wget https://github.com/PiSugar/pisugar-power-manager-rs/releases/download/v1.7.6/pisugar-server_1.7.6_armhf.deb
sudo dpkg -i pisugar-server_1.7.6_armhf.deb

Usage

Enable PiSugar Support

  1. Edit /opt/dangerous-pi/.env:

    UPS_TYPE=pisugar
    
  2. Restart Dangerous Pi:

    sudo systemctl restart dangerous-pi
    
  3. Verify UPS status via API:

    curl http://localhost:8000/api/system/ups/status
    

API Endpoints

The UPS manager provides these endpoints (work with any UPS type):

  • GET /api/system/ups/status - Get battery status
  • GET /api/system/power/restrictions - Get power-based operation restrictions
  • POST /api/system/ups/thresholds - Set battery thresholds
  • POST /api/system/ups/shutdown - Trigger safe shutdown

Example Response

{
  "battery_percentage": 85.5,
  "voltage": 3842.0,
  "current": -245.0,
  "power_source": "battery",
  "battery_status": "discharging",
  "time_remaining": null,
  "temperature": null,
  "last_updated": "2024-11-28T12:00:00Z",
  "is_available": true,
  "error_message": null
}

PiSugar Communication

The PiSugar driver communicates with pisugar-server via TCP socket (default port 8423).

Supported Commands

  • get model - Get PiSugar model name
  • get battery - Get battery percentage (0-100)
  • get battery_v - Get battery voltage (mV)
  • get battery_i - Get battery current (mA)
  • get battery_power_plugged - Check if charging (true/false)

Power Management

The system enforces power restrictions based on battery level:

Battery Level Bootloader Flash Firmware Flash Intensive Ops
80%+ Allowed Allowed Allowed
50-80% Blocked Allowed Allowed
20-50% Blocked Blocked Allowed
10-20% Blocked Blocked Blocked
<10% Blocked Blocked Blocked

Supported Hardware

PiSugar Models

  • PiSugar 2 - For Raspberry Pi Zero / Zero W
  • PiSugar 2 Pro - For Pi 3/4 (with larger battery)
  • PiSugar 3 - For Pi Zero 2W
  • PiSugar 3 Plus - For Pi 4/5

I2C Fuel Gauge Models

  • MAX17040 / MAX17048
  • Other compatible fuel gauge chips at I2C address 0x36

Troubleshooting

PiSugar Server Not Running

# Check service status
sudo systemctl status pisugar-server

# Restart service
sudo systemctl restart pisugar-server

# Check logs
sudo journalctl -u pisugar-server -n 50

Test PiSugar Connection

# Test TCP connection
echo "get battery" | nc 127.0.0.1 8423

# Should return something like: "battery: 85.5"

UPS Not Detected

  1. Verify UPS_TYPE is set correctly in .env
  2. Check Dangerous Pi logs: sudo journalctl -u dangerous-pi -n 50
  3. Verify hardware is connected properly
  4. For I2C: Check i2cdetect -y 1 shows device at address 0x36
  5. For PiSugar: Verify pisugar-server is running

Dangerous Pi Logs

# View full logs
sudo journalctl -u dangerous-pi -f

# Check for UPS initialization
sudo journalctl -u dangerous-pi | grep -i ups

Testing

Run the test suite to verify UPS functionality:

# Run all tests
pytest tests/

# Run UPS-specific tests
pytest tests/test_ups_drivers.py -v

Migration from Old UPS Code

If you're upgrading from an older version with I2C-only UPS support:

  1. The old configuration still works (defaults to UPS_TYPE=i2c)
  2. Add UPS_TYPE=i2c explicitly to .env for clarity
  3. No code changes needed for I2C HAT users
  4. PiSugar users: Change to UPS_TYPE=pisugar

Development

Adding a New UPS Driver

  1. Create new driver in app/backend/managers/ups_drivers/

  2. Inherit from UPSDriver base class

  3. Implement required methods:

    • initialize() - Connect to hardware
    • read_data() - Read battery data
    • is_available() - Check hardware availability
    • close() - Clean up connections
    • get_model_name() - Return model name
  4. Add to _create_driver() in ups_manager.py

  5. Document configuration in this file

Example: Custom Driver

from .base import UPSDriver, UPSData

class CustomDriver(UPSDriver):
    async def initialize(self) -> bool:
        # Connect to your hardware
        return True

    async def read_data(self) -> UPSData:
        # Read battery data
        return UPSData(
            percentage=85.0,
            voltage=3800.0,
            current=-200.0,
            is_charging=False
        )

    async def is_available(self) -> bool:
        return True

    def close(self):
        pass

    def get_model_name(self) -> str:
        return "Custom UPS"

Scheduled Power Cycles (Alternative to Sleep Mode)

Dangerous Pi does not implement sleep mode (WiFi must stay active for remote access). For "power off overnight" scenarios, use shutdown combined with PiSugar RTC wake alarm:

  1. Set wake time via PiSugar web interface, API, or native I2C driver
  2. Shutdown: sudo shutdown -h now
  3. Device wakes automatically at the scheduled time

This approach is more power-efficient than any sleep mode—the device draws zero power while off, then boots fresh at the scheduled time.

Note: The native I2C driver (pisugar_i2c_driver.py) exposes set_wake_alarm() and clear_wake_alarm() methods, though API endpoints for these are not yet implemented.


Resources

Contributing

Contributions for additional UPS hardware support are welcome! Please:

  1. Follow the driver architecture pattern
  2. Add tests for your driver
  3. Update documentation
  4. Submit a PR with clear description