"""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, i2c_retries: int = 5, i2c_retry_delay: float = 1.0 ) -> 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 i2c_retries: Number of I2C detection retries (for boot timing) i2c_retry_delay: Delay between I2C retries in seconds 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(f"UPS auto-detect: Trying PiSugar I2C (native, {i2c_retries} retries)...") detected, driver = await PiSugarI2CDriver.detect( retries=i2c_retries, retry_delay=i2c_retry_delay ) 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 after all retries") # 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", ]