🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
295 lines
7.8 KiB
Markdown
295 lines
7.8 KiB
Markdown
# 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
|