Build optimization: pre-built PM3 binaries, ARM64 CI, base image caching
Replace PM3 compile-from-source in pi-gen with pre-built tarball extraction (saves 43-58 min). Merge stagePM3 into stageDangerousPi as 02-pm3-install substage, renumber all subsequent substages. Switch CI PM3 build to native ARM64 runner (ubuntu-24.04-arm64) eliminating QEMU overhead. Add weekly base-image workflow for pre-baking stages 0-2. Support PM3_TARBALL, BASE_IMAGE, and APT_PROXY env vars in build-image.sh. Also includes prior Phase 5 work: theme system, design system integration, component update system, OS updates, CI build pipeline, and test results. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -210,7 +210,7 @@ class BLEManager:
|
||||
}
|
||||
|
||||
async def _check_bluetooth_adapter(self) -> bool:
|
||||
"""Check if Bluetooth adapter is available.
|
||||
"""Check if Bluetooth adapter is available, unblocking and powering on if needed.
|
||||
|
||||
Returns:
|
||||
True if adapter is available, False otherwise
|
||||
@@ -224,8 +224,20 @@ class BLEManager:
|
||||
)
|
||||
stdout, stderr = await process.communicate()
|
||||
|
||||
# If we get output with "Controller", we have an adapter
|
||||
return b"Controller" in stdout
|
||||
if b"Controller" not in stdout:
|
||||
return False
|
||||
|
||||
# Unblock Bluetooth if soft-blocked by rfkill
|
||||
await self._run_cmd("rfkill", "unblock", "bluetooth")
|
||||
|
||||
# Power on the adapter via bluetoothctl
|
||||
out = await self._run_cmd("bluetoothctl", "power", "on")
|
||||
if b"succeeded" in out.lower() or b"yes" in out.lower():
|
||||
logger.info("Bluetooth adapter powered on")
|
||||
else:
|
||||
logger.warning("Bluetooth power on response: %s", out.decode(errors='replace').strip())
|
||||
|
||||
return True
|
||||
|
||||
except FileNotFoundError:
|
||||
logger.warning("bluetoothctl not found - BlueZ not installed")
|
||||
@@ -234,6 +246,19 @@ class BLEManager:
|
||||
logger.error("Error checking Bluetooth adapter: %s", e)
|
||||
return False
|
||||
|
||||
async def _run_cmd(self, *args: str) -> bytes:
|
||||
"""Run a command and return stdout."""
|
||||
try:
|
||||
process = await asyncio.create_subprocess_exec(
|
||||
*args,
|
||||
stdout=asyncio.subprocess.PIPE,
|
||||
stderr=asyncio.subprocess.PIPE
|
||||
)
|
||||
stdout, _ = await process.communicate()
|
||||
return stdout
|
||||
except FileNotFoundError:
|
||||
return b""
|
||||
|
||||
async def _set_device_name(self, name: str):
|
||||
"""Set the Bluetooth device name.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user