Initial commit - Phase 3/4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
michael
2026-01-06 13:45:29 -08:00
parent 1da6730735
commit 4f35df1781
323 changed files with 98287 additions and 1195 deletions

View File

@@ -0,0 +1,89 @@
"""UPS driver implementations for different hardware.
Supports multiple UPS types:
- pisugar: PiSugar 2/3 via native I2C (no daemon needed)
- pisugar-daemon: PiSugar via pisugar-server TCP daemon (legacy)
- i2c: Generic I2C fuel gauge (MAX17040/MAX17048)
- auto: Automatically detect available UPS hardware
"""
from typing import Optional, Tuple
from .base import UPSDriver, UPSData
from .pisugar_driver import PiSugarDriver # TCP daemon driver (legacy)
from .pisugar_i2c_driver import PiSugarI2CDriver, PiSugarModel, ButtonEvent
from .i2c_driver import I2CFuelGaugeDriver
async def auto_detect_driver(
pisugar_host: str = "127.0.0.1",
pisugar_port: int = 8423,
prefer_native_i2c: bool = True
) -> Tuple[Optional[UPSDriver], str]:
"""Auto-detect available UPS hardware and return appropriate driver.
Detection order (first match wins):
1. PiSugar via native I2C (preferred - no daemon overhead)
2. PiSugar via TCP daemon (fallback if I2C fails)
3. I2C Fuel Gauge (MAX17040/MAX17048 at 0x36 or other addresses)
Args:
pisugar_host: PiSugar server host for daemon detection (legacy)
pisugar_port: PiSugar server port (legacy)
prefer_native_i2c: If True, prefer native I2C driver over daemon
Returns:
Tuple of (driver_instance or None, detection_message)
"""
print("UPS auto-detect: Starting detection...")
# Try native PiSugar I2C first (no daemon overhead, minimal CPU)
if prefer_native_i2c:
print("UPS auto-detect: Trying PiSugar I2C (native)...")
detected, driver = await PiSugarI2CDriver.detect()
if detected and driver:
model = driver.get_model_name()
print(f"UPS auto-detect: SUCCESS - PiSugar I2C: {model}")
return (driver, f"Detected PiSugar UPS via I2C: {model}")
print("UPS auto-detect: PiSugar I2C not detected")
# Try PiSugar daemon (legacy fallback)
print("UPS auto-detect: Trying PiSugar daemon...")
detected, model = await PiSugarDriver.detect(host=pisugar_host, port=pisugar_port)
if detected:
driver = PiSugarDriver(host=pisugar_host, port=pisugar_port)
print(f"UPS auto-detect: SUCCESS - PiSugar daemon: {model}")
return (driver, f"Detected PiSugar UPS via daemon: {model}")
print("UPS auto-detect: PiSugar daemon not detected")
# Try native I2C again if we skipped it earlier
if not prefer_native_i2c:
print("UPS auto-detect: Trying PiSugar I2C (second attempt)...")
detected, driver = await PiSugarI2CDriver.detect()
if detected and driver:
model = driver.get_model_name()
print(f"UPS auto-detect: SUCCESS - PiSugar I2C: {model}")
return (driver, f"Detected PiSugar UPS via I2C: {model}")
# Try generic I2C fuel gauge (exclude PiSugar I2C addresses)
print("UPS auto-detect: Trying generic I2C fuel gauge...")
exclude_addrs = list(PiSugarI2CDriver.KNOWN_ADDRESSES.keys()) + [PiSugarI2CDriver.RTC_ADDRESS]
detected, i2c_addr = await I2CFuelGaugeDriver.detect(exclude_addresses=exclude_addrs)
if detected:
driver = I2CFuelGaugeDriver(i2c_address=i2c_addr)
print(f"UPS auto-detect: SUCCESS - I2C fuel gauge at 0x{i2c_addr:02X}")
return (driver, f"Detected I2C fuel gauge at address 0x{i2c_addr:02X}")
print("UPS auto-detect: No I2C fuel gauge detected")
print("UPS auto-detect: No UPS hardware found")
return (None, "No UPS hardware detected")
__all__ = [
"UPSDriver",
"UPSData",
"PiSugarDriver",
"PiSugarI2CDriver",
"PiSugarModel",
"ButtonEvent",
"I2CFuelGaugeDriver",
"auto_detect_driver",
]