Security:
- Add token-based WebSocket authentication (closes critical security gap)
- In-memory token store with 24h TTL (token_store.py)
- POST /api/auth/token exchanges Basic Auth for WS token
- GET /api/auth/status public endpoint for auth check
- WebSocket validates token query param, rejects with close code 4401
- Frontend LoginPrompt modal for credential entry
- WebSocket manager handles full auth flow with auth_required state
- No-op when AUTH_ENABLED=false (preserves existing behavior)
HTTPS:
- Wire HTTPS toggle in Settings UI (POST /api/system/ssl/toggle)
- Add certificate regeneration button
- Display SSL info (expiration, SANs, SHA256 fingerprint)
Plugins:
- Wire trigger_hook("pm3_command") in PM3 service
- Wire trigger_hook("update_check") in update manager
Build/Infrastructure:
- Enable NetworkManager in pi-gen AP setup stage
- Add HF booster board detection patch for Proxmark3
- Update LED PWM control patch
- Fix BLE adapter, UPS drivers, WiFi manager improvements
- Update HTTPS support stage script
Documentation:
- Update PROJECT_STATUS.md and IMPLEMENTATION_PRIORITIES.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
97 lines
3.9 KiB
Python
97 lines
3.9 KiB
Python
"""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",
|
|
]
|