Added logging for GPIO
Python CI / test (3.12) (push) Has been cancelled
Python CI / test (3.13) (push) Has been cancelled

This commit is contained in:
2025-11-23 14:24:23 +01:00
parent a1775baa76
commit 25b20fdbbd
4 changed files with 163 additions and 15 deletions
+95 -13
View File
@@ -57,6 +57,16 @@ from PIL import Image
from .hal import DisplayHAL
from .gesture import TouchEvent as AppTouchEvent, GestureType as AppGestureType
logger = logging.getLogger(__name__)
# Try to import GPIO button support (only available on Raspberry Pi)
try:
from .gpio_buttons import GPIOButtonHandler, load_button_config_from_dict
GPIO_BUTTONS_AVAILABLE = True
except (ImportError, RuntimeError) as e:
GPIO_BUTTONS_AVAILABLE = False
logger.debug(f"GPIO buttons not available: {e}")
# Import dreader-hal components
try:
from dreader_hal import (
@@ -72,8 +82,6 @@ except ImportError as e:
DREADER_HAL_AVAILABLE = False
_import_error = e
logger = logging.getLogger(__name__)
# Gesture type mapping between dreader-hal and dreader-application
GESTURE_TYPE_MAP = {
@@ -139,10 +147,16 @@ class HardwareDisplayHAL(DisplayHAL):
enable_power_monitor: bool = True,
shunt_ohms: float = 0.1,
battery_capacity_mah: float = 3000,
gpio_config: Optional[dict] = None,
config_file: Optional[str] = None,
):
"""
Initialize hardware HAL.
Args:
gpio_config: GPIO button configuration dict (optional)
config_file: Path to hardware_config.json file (optional, defaults to "hardware_config.json")
Raises:
ImportError: If dreader-hal library is not installed
"""
@@ -178,6 +192,36 @@ class HardwareDisplayHAL(DisplayHAL):
battery_capacity_mah=battery_capacity_mah,
)
# GPIO button handler (optional)
self.gpio_handler: Optional[GPIOButtonHandler] = None
# Load GPIO config from file if specified
if config_file or gpio_config is None:
config_path = Path(config_file or "hardware_config.json")
if config_path.exists():
try:
with open(config_path, 'r') as f:
full_config = json.load(f)
gpio_config = full_config
logger.info(f"Loaded hardware config from {config_path}")
except Exception as e:
logger.warning(f"Could not load hardware config from {config_path}: {e}")
# Initialize GPIO buttons if configured
if gpio_config and GPIO_BUTTONS_AVAILABLE:
try:
self.gpio_handler = load_button_config_from_dict(
gpio_config,
screen_width=width,
screen_height=height
)
if self.gpio_handler:
logger.info("GPIO button handler created")
except Exception as e:
logger.warning(f"Could not initialize GPIO buttons: {e}")
elif gpio_config and not GPIO_BUTTONS_AVAILABLE:
logger.info("GPIO buttons configured but RPi.GPIO not available (not on Raspberry Pi)")
self._initialized = False
async def initialize(self):
@@ -190,6 +234,7 @@ class HardwareDisplayHAL(DisplayHAL):
- Accelerometer (if enabled)
- RTC (if enabled)
- Power monitor (if enabled)
- GPIO buttons (if configured)
"""
if self._initialized:
logger.warning("Hardware HAL already initialized")
@@ -197,6 +242,12 @@ class HardwareDisplayHAL(DisplayHAL):
logger.info("Initializing hardware components...")
await self.hal.initialize()
# Initialize GPIO buttons
if self.gpio_handler:
logger.info("Initializing GPIO buttons...")
await self.gpio_handler.initialize()
self._initialized = True
logger.info("Hardware HAL initialized successfully")
@@ -206,6 +257,12 @@ class HardwareDisplayHAL(DisplayHAL):
return
logger.info("Cleaning up hardware HAL")
# Clean up GPIO buttons
if self.gpio_handler:
logger.info("Cleaning up GPIO buttons...")
await self.gpio_handler.cleanup()
await self.hal.cleanup()
self._initialized = False
logger.info("Hardware HAL cleaned up")
@@ -232,7 +289,7 @@ class HardwareDisplayHAL(DisplayHAL):
async def get_touch_event(self) -> Optional[AppTouchEvent]:
"""
Get the next touch event from hardware.
Get the next touch event from hardware (touch sensor or GPIO buttons).
Returns:
TouchEvent if available, None if no event
@@ -242,11 +299,20 @@ class HardwareDisplayHAL(DisplayHAL):
- LONG_PRESS: Hold (< 30px movement, >= 500ms)
- SWIPE_*: Directional swipes (>= 30px movement)
- PINCH_IN/OUT: Two-finger pinch gestures
GPIO buttons are also polled and generate TouchEvent objects.
"""
if not self._initialized:
return None
# Get event from dreader-hal
# Check GPIO buttons first (they're more responsive)
if self.gpio_handler:
button_event = await self.gpio_handler.get_button_event()
if button_event:
logger.info(f"GPIO button event: {button_event.gesture.value}")
return button_event
# Get event from dreader-hal touch sensor
hal_event = await self.hal.get_touch_event()
if hal_event is None:
@@ -564,13 +630,13 @@ class HardwareDisplayHAL(DisplayHAL):
async def get_event(self) -> Optional[AppTouchEvent]:
"""
Get the next event from any input source (touch or accelerometer).
Get the next event from any input source (GPIO, touch, or accelerometer).
This is a convenience method that polls both touch and accelerometer
in a single call, prioritizing touch events over tilt events.
This is a convenience method that polls all input sources in a single call.
Priority order: GPIO buttons > touch sensor > accelerometer tilt
Returns:
TouchEvent from either touch sensor or accelerometer, or None if no event
TouchEvent from GPIO, touch sensor, or accelerometer, or None if no event
Usage:
while running:
@@ -579,12 +645,28 @@ class HardwareDisplayHAL(DisplayHAL):
handle_gesture(event)
await asyncio.sleep(0.01)
"""
# Check touch first (higher priority)
touch_event = await self.get_touch_event()
if touch_event:
return touch_event
# Check GPIO buttons first (most responsive)
if self.gpio_handler:
button_event = await self.gpio_handler.get_button_event()
if button_event:
logger.info(f"GPIO button event: {button_event.gesture.value}")
return button_event
# Check accelerometer tilt
# Check touch sensor (second priority)
# Get event from dreader-hal touch sensor directly
hal_event = await self.hal.get_touch_event()
if hal_event is not None:
# Convert from dreader-hal TouchEvent to application TouchEvent
app_gesture = GESTURE_TYPE_MAP.get(hal_event.gesture)
if app_gesture is not None:
logger.debug(f"Touch event: {app_gesture.value} at ({hal_event.x}, {hal_event.y})")
return AppTouchEvent(
gesture=app_gesture,
x=hal_event.x,
y=hal_event.y
)
# Check accelerometer tilt (lowest priority)
if hasattr(self, 'accel_up_vector'):
tilt_event = await self.get_tilt_gesture()
if tilt_event: