Update button_controller.py
Fixed bug when running on a non-RPi board.
This commit is contained in:
@@ -9,7 +9,8 @@ This controller:
|
|||||||
|
|
||||||
Implementation note:
|
Implementation note:
|
||||||
- Uses a simple polling loop with RPi.GPIO instead of kernel edge detection.
|
- Uses a simple polling loop with RPi.GPIO instead of kernel edge detection.
|
||||||
- This avoids "Failed to add edge detection" errors on some HATs/overlays.
|
- On non-Raspberry Pi hosts (or where RPi.GPIO is unusable), the controller
|
||||||
|
cleanly disables itself and logs an info message.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
@@ -24,10 +25,13 @@ from .models import ServerState
|
|||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
try:
|
# Try to import RPi.GPIO, but gracefully handle *any* failure.
|
||||||
import RPi.GPIO as GPIO
|
# On non-RPi hosts, RPi.GPIO may be installed but will raise RuntimeError
|
||||||
except ImportError: # pragma: no cover - non-RPi hosts
|
# at import time ("This module can only be run on a Raspberry Pi!").
|
||||||
GPIO = None
|
try: # pragma: no cover - behavior depends on host platform
|
||||||
|
import RPi.GPIO as GPIO # type: ignore[import]
|
||||||
|
except Exception: # ImportError, RuntimeError, etc.
|
||||||
|
GPIO = None # type: ignore[assignment]
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -48,6 +52,8 @@ class ButtonController:
|
|||||||
- Interprets level transitions as press/release.
|
- Interprets level transitions as press/release.
|
||||||
- Schedules actions on the asyncio loop via loop.call_soon_threadsafe().
|
- Schedules actions on the asyncio loop via loop.call_soon_threadsafe().
|
||||||
- Uses the EventBus to toggle mic mute.
|
- Uses the EventBus to toggle mic mute.
|
||||||
|
|
||||||
|
On non-RPi hosts (or when RPi.GPIO isn't usable), it is effectively a no-op.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
@@ -84,13 +90,18 @@ class ButtonController:
|
|||||||
self._press_time: float | None = None
|
self._press_time: float | None = None
|
||||||
self._last_level: int | None = None
|
self._last_level: int | None = None
|
||||||
|
|
||||||
|
# If disabled in config, do nothing.
|
||||||
if not self._cfg.enabled:
|
if not self._cfg.enabled:
|
||||||
_LOGGER.info("ButtonController disabled in config; not initializing GPIO")
|
_LOGGER.info(
|
||||||
|
"ButtonController disabled in config; not initializing GPIO"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# If RPi.GPIO is unavailable or not usable on this host, also do nothing.
|
||||||
if GPIO is None:
|
if GPIO is None:
|
||||||
_LOGGER.warning(
|
_LOGGER.info(
|
||||||
"RPi.GPIO not available; hardware button support disabled"
|
"RPi.GPIO not available or not usable on this host; "
|
||||||
|
"hardware button support disabled"
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -107,7 +118,11 @@ class ButtonController:
|
|||||||
self._cfg.poll_interval_seconds,
|
self._cfg.poll_interval_seconds,
|
||||||
)
|
)
|
||||||
except Exception:
|
except Exception:
|
||||||
_LOGGER.exception("Failed to configure GPIO pin %s for button", self._cfg.pin)
|
_LOGGER.exception(
|
||||||
|
"Failed to configure GPIO pin %s for button; "
|
||||||
|
"hardware button support disabled",
|
||||||
|
self._cfg.pin,
|
||||||
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Start polling thread
|
# Start polling thread
|
||||||
@@ -128,7 +143,7 @@ class ButtonController:
|
|||||||
|
|
||||||
while not getattr(self.state, "shutdown", False):
|
while not getattr(self.state, "shutdown", False):
|
||||||
try:
|
try:
|
||||||
level = GPIO.input(self._cfg.pin)
|
level = GPIO.input(self._cfg.pin) # type: ignore[call-arg]
|
||||||
except Exception:
|
except Exception:
|
||||||
_LOGGER.exception("Error reading GPIO pin %s", self._cfg.pin)
|
_LOGGER.exception("Error reading GPIO pin %s", self._cfg.pin)
|
||||||
break
|
break
|
||||||
@@ -220,4 +235,3 @@ class ButtonController:
|
|||||||
"set_mic_mute",
|
"set_mic_mute",
|
||||||
{"state": new_state},
|
{"state": new_state},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user