# 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`:

```bash
# 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:

```bash
# 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:

```bash
# 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`:
   ```bash
   UPS_TYPE=pisugar
   ```

2. Restart Dangerous Pi:
   ```bash
   sudo systemctl restart dangerous-pi
   ```

3. Verify UPS status via API:
   ```bash
   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

```json
{
  "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

```bash
# 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

```bash
# 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

```bash
# 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:

```bash
# 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

```python
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

- [PiSugar GitHub](https://github.com/PiSugar/PiSugar)
- [PiSugar Wiki](https://github.com/PiSugar/PiSugar/wiki)
- [MAX17048 Datasheet](https://datasheets.maximintegrated.com/en/ds/MAX17048-MAX17049.pdf)

## 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
