Commit graph

354 commits

Author SHA1 Message Date
torlando-tech
6bc154ee70 feat(ble): Add scanner callback watchdog to detect Bluetooth stack corruption
Detect when Bluetooth/BlueZ/D-Bus enters corrupted state where scanner
starts successfully but callbacks are never invoked. This manifests as
Bleak working in standalone scripts but failing within RNS's async context.

Detection mechanism:
- Track callback invocations during each scan cycle
- Count consecutive scans with 0 callbacks
- Log WARNING after first empty scan
- Log CRITICAL ERROR after 3 consecutive empty scans
- Invoke on_error callback with "reboot required" message
- Reset counter when callbacks resume

This provides clear diagnostics instead of silent failure, allowing users
to identify the issue and take corrective action (system reboot).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 17:21:08 -05:00
torlando-tech
e6c01db317 fix(ble): Filter invalid RSSI sentinel values and add scanner debug logging
Prevent invalid RSSI values (-127, -128, 0) from causing connection issues
by filtering them at three stages: scanner detection, discovery handler, and
peer scoring. These sentinel values indicate Bleak cache/state issues rather
than actual signal strength.

Add comprehensive debug logging to scanner lifecycle for troubleshooting:
- Callback invocations with device details
- Scanner start/stop/duration events
- Filtering stages (UUID matching, RSSI thresholds)
- Device discovery counts

Logging uses INFO level (via "EXTRA" fallback) for visibility without
requiring DEBUG log level configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 15:00:11 -05:00
torlando-tech
59fef38196 fix(ble): Filter invalid RSSI sentinel values and add scanner debug logging
Prevent invalid RSSI values (-127, -128, 0) from causing connection issues
by filtering them at three stages: scanner detection, discovery handler, and
peer scoring. These sentinel values indicate Bleak cache/state issues rather
than actual signal strength.

Add comprehensive debug logging to scanner lifecycle for troubleshooting:
- Callback invocations with device details
- Scanner start/stop/duration events
- Filtering stages (UUID matching, RSSI thresholds)
- Device discovery counts

Logging uses INFO level (via "EXTRA" fallback) for visibility without
requiring DEBUG log level configuration.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 15:00:11 -05:00
torlando-tech
5af6b67e6a feat(install): Add BlueZ LE-only mode configuration
Adds Step 5C to install.sh to automatically configure BlueZ for
LE-only mode by setting ControllerMode=le in /etc/bluetooth/main.conf.

This prevents "br-connection-profile-unavailable" errors on dual-mode
Bluetooth hardware (e.g., Raspberry Pi Zero 2 W with BCM43430).

Fixes issue where dual-mode adapters advertise as "CLASSIC and LE"
without the "BR\EDR Not Supported" BLE flag, causing connection
failures from BLE-only devices.

The configuration step:
- Checks prerequisites (bluetoothctl, main.conf exists)
- Is idempotent (detects existing configuration)
- Creates timestamped backup before modification
- Handles commented/existing ControllerMode settings
- Adds [General] section if missing
- Restarts BlueZ service to apply changes
- Verifies configuration was applied

Generated with Claude Code https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 12:33:23 -05:00
torlando-tech
24d8c1caed feat(install): Add BlueZ LE-only mode configuration
Adds Step 5C to install.sh to automatically configure BlueZ for
LE-only mode by setting ControllerMode=le in /etc/bluetooth/main.conf.

This prevents "br-connection-profile-unavailable" errors on dual-mode
Bluetooth hardware (e.g., Raspberry Pi Zero 2 W with BCM43430).

Fixes issue where dual-mode adapters advertise as "CLASSIC and LE"
without the "BR\EDR Not Supported" BLE flag, causing connection
failures from BLE-only devices.

The configuration step:
- Checks prerequisites (bluetoothctl, main.conf exists)
- Is idempotent (detects existing configuration)
- Creates timestamped backup before modification
- Handles commented/existing ControllerMode settings
- Adds [General] section if missing
- Restarts BlueZ service to apply changes
- Verifies configuration was applied

Generated with Claude Code https://claude.com/claude-code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 12:33:23 -05:00
torlando-tech
99ca8d4606 fix(ble): Add D-Bus verification to prevent GATT server initialization race
Fixed race condition where started_event fires before peripheral.publish()
fully exports GATT services to D-Bus, causing "Reticulum service not found"
errors when central devices connect immediately after server startup.

Root cause:
- started_event.set() called on line 1665
- peripheral_obj.publish() called on line 1669 (exports to D-Bus)
- 50-200ms gap where server thinks it's ready but services aren't on D-Bus yet
- Central connects during gap -> "service not found" error

Fix:
- Added _verify_services_on_dbus() method to poll D-Bus adapter introspection
- Polls every 200ms with 5-second timeout after started_event fires
- Only returns from start() after confirming services are exported
- Graceful degradation: warns on timeout but doesn't fail startup

Impact:
- Eliminates "service not found" errors during server startup
- Ensures services are actually available before accepting connections
- Typical verification time: 100-300ms
- No runtime performance impact (only affects startup)

Files changed:
- src/RNS/Interfaces/linux_bluetooth_driver.py: Add D-Bus polling
- tests/test_gatt_server_readiness.py: Add test coverage
- BLE_PROTOCOL_v2.2.md: Document initialization race fix
- CHANGELOG.md: Record fix details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:51:23 -05:00
torlando-tech
11b4004c5e fix(ble): Add D-Bus verification to prevent GATT server initialization race
Fixed race condition where started_event fires before peripheral.publish()
fully exports GATT services to D-Bus, causing "Reticulum service not found"
errors when central devices connect immediately after server startup.

Root cause:
- started_event.set() called on line 1665
- peripheral_obj.publish() called on line 1669 (exports to D-Bus)
- 50-200ms gap where server thinks it's ready but services aren't on D-Bus yet
- Central connects during gap -> "service not found" error

Fix:
- Added _verify_services_on_dbus() method to poll D-Bus adapter introspection
- Polls every 200ms with 5-second timeout after started_event fires
- Only returns from start() after confirming services are exported
- Graceful degradation: warns on timeout but doesn't fail startup

Impact:
- Eliminates "service not found" errors during server startup
- Ensures services are actually available before accepting connections
- Typical verification time: 100-300ms
- No runtime performance impact (only affects startup)

Files changed:
- src/RNS/Interfaces/linux_bluetooth_driver.py: Add D-Bus polling
- tests/test_gatt_server_readiness.py: Add test coverage
- BLE_PROTOCOL_v2.2.md: Document initialization race fix
- CHANGELOG.md: Record fix details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:51:23 -05:00
torlando-tech
acac473e65 fix(ble): Clarify ConnectDevice() object path return as success
ConnectDevice() D-Bus method returns an object path (signature 'o') which
should be treated as success, not error. Previously, the return value was
not captured or logged, causing confusion when error messages like
"br-connection-profile-unavailable" appeared (which is expected for LE-only
connections).

Changes:
- Capture object path returned by call_connect_device()
- Log object path for debugging visibility
- Document that object path indicates successful LE connection initiation
- Clarify that BR/EDR profile unavailable is expected for BLE-only connections

Impact:
- Eliminates confusion from "profile unavailable" error messages
- Confirms LE connection was successfully initiated
- Improved debugging visibility through object path logging

Files changed:
- src/RNS/Interfaces/linux_bluetooth_driver.py: Capture and log object path
- tests/test_breddr_fallback_prevention.py: Add test coverage
- BLE_PROTOCOL_v2.2.md: Document object path behavior
- CHANGELOG.md: Record fix details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:47:34 -05:00
torlando-tech
e7d2057666 fix(ble): Clarify ConnectDevice() object path return as success
ConnectDevice() D-Bus method returns an object path (signature 'o') which
should be treated as success, not error. Previously, the return value was
not captured or logged, causing confusion when error messages like
"br-connection-profile-unavailable" appeared (which is expected for LE-only
connections).

Changes:
- Capture object path returned by call_connect_device()
- Log object path for debugging visibility
- Document that object path indicates successful LE connection initiation
- Clarify that BR/EDR profile unavailable is expected for BLE-only connections

Impact:
- Eliminates confusion from "profile unavailable" error messages
- Confirms LE connection was successfully initiated
- Improved debugging visibility through object path logging

Files changed:
- src/RNS/Interfaces/linux_bluetooth_driver.py: Capture and log object path
- tests/test_breddr_fallback_prevention.py: Add test coverage
- BLE_PROTOCOL_v2.2.md: Document object path behavior
- CHANGELOG.md: Record fix details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:47:34 -05:00
torlando-tech
d2f75c0f39 fix(ble): Add scanner-connection coordination to prevent "InProgress" errors
Scanner was calling BleakScanner.start() during active connection attempts,
causing BlueZ "Operation already in progress" errors. This fix adds coordination
between scanner and connection operations:

- Add _should_pause_scanning() method to check for active connections
- Modify _perform_scan() to skip scan cycle when connections in progress
- Scanner automatically pauses when _connecting_peers is not empty
- Scanner automatically resumes when connections complete

Impact:
- Eliminates scan-induced connection failures
- Reduces BlueZ error log spam
- Improves overall connection reliability

Files changed:
- src/RNS/Interfaces/linux_bluetooth_driver.py: Add pause logic
- tests/test_scanner_connection_coordination.py: Add test coverage
- BLE_PROTOCOL_v2.2.md: Document scanner coordination
- CHANGELOG.md: Record fix details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:44:20 -05:00
torlando-tech
4366707abc fix(ble): Add scanner-connection coordination to prevent "InProgress" errors
Scanner was calling BleakScanner.start() during active connection attempts,
causing BlueZ "Operation already in progress" errors. This fix adds coordination
between scanner and connection operations:

- Add _should_pause_scanning() method to check for active connections
- Modify _perform_scan() to skip scan cycle when connections in progress
- Scanner automatically pauses when _connecting_peers is not empty
- Scanner automatically resumes when connections complete

Impact:
- Eliminates scan-induced connection failures
- Reduces BlueZ error log spam
- Improves overall connection reliability

Files changed:
- src/RNS/Interfaces/linux_bluetooth_driver.py: Add pause logic
- tests/test_scanner_connection_coordination.py: Add test coverage
- BLE_PROTOCOL_v2.2.md: Document scanner coordination
- CHANGELOG.md: Record fix details

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 19:44:20 -05:00
torlando-tech
1849053d3d fix(changelog): Mark unreleased versions correctly
Remove inaccurate release dates from unreleased versions.
Only v0.1.1 has an actual release date (2025-11-10).

Changes:
- [0.1.0]: Never released, marked as Unreleased
- [2.2.0]: Not yet released, marked as Unreleased
- [2.1.0]: Not yet released, marked as Unreleased
- [0.1.1]: Keep actual release date (2025-11-10)

Dates will be added when versions are actually released.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 18:27:24 -05:00
torlando-tech
7688d1f37c fix(changelog): Mark unreleased versions correctly
Remove inaccurate release dates from unreleased versions.
Only v0.1.1 has an actual release date (2025-11-10).

Changes:
- [0.1.0]: Never released, marked as Unreleased
- [2.2.0]: Not yet released, marked as Unreleased
- [2.1.0]: Not yet released, marked as Unreleased
- [0.1.1]: Keep actual release date (2025-11-10)

Dates will be added when versions are actually released.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 18:27:24 -05:00
torlando-tech
621e2d0c50 Merge branch 'main' into refactor/abstraction-layer
Resolve merge conflicts by:
- Keeping version 0.2.2 from refactor branch (next release)
- Using fixed gh CLI release workflow from main (atomic release creation)
- Merging CHANGELOG histories: installer releases (0.1.x) and protocol work (2.x)

Conflicts resolved:
- .github/workflows/release.yml: Use gh CLI for atomic releases
- CHANGELOG.md: Merged both release histories chronologically
- pyproject.toml: Keep 0.2.2 for next refactor release

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 16:58:01 -05:00
torlando-tech
061afccc8c Merge branch 'main' into refactor/abstraction-layer
Resolve merge conflicts by:
- Keeping version 0.2.2 from refactor branch (next release)
- Using fixed gh CLI release workflow from main (atomic release creation)
- Merging CHANGELOG histories: installer releases (0.1.x) and protocol work (2.x)

Conflicts resolved:
- .github/workflows/release.yml: Use gh CLI for atomic releases
- CHANGELOG.md: Merged both release histories chronologically
- pyproject.toml: Keep 0.2.2 for next refactor release

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 16:58:01 -05:00
torlando-tech
ff410b6817 Merge pull request #19 from torlando-tech/release/v0.1.1
chore: Bump version to 0.1.1
2025-11-10 16:02:06 -05:00
torlando-tech
88a9882786 Merge pull request #19 from torlando-tech/release/v0.1.1
chore: Bump version to 0.1.1
2025-11-10 16:02:06 -05:00
torlando-tech
fb31d0c200 chore: Bump version to 0.1.1
Bump version to test fixed release workflow with atomic release creation.

Changes:
- Update pyproject.toml version from 0.1.0 to 0.1.1
- Add CHANGELOG entry documenting release workflow fix

This allows testing the corrected workflow (gh release create) without
being blocked by v0.1.0 tag recreation restrictions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 15:40:23 -05:00
torlando-tech
31291852f9 chore: Bump version to 0.1.1
Bump version to test fixed release workflow with atomic release creation.

Changes:
- Update pyproject.toml version from 0.1.0 to 0.1.1
- Add CHANGELOG entry documenting release workflow fix

This allows testing the corrected workflow (gh release create) without
being blocked by v0.1.0 tag recreation restrictions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 15:40:23 -05:00
torlando-tech
b703dea8c9 Merge pull request #18 from torlando-tech/fix/atomic-release-creation
fix(ci): Use gh CLI for atomic release creation
2025-11-10 15:30:14 -05:00
torlando-tech
2c49cbb978 Merge pull request #18 from torlando-tech/fix/atomic-release-creation
fix(ci): Use gh CLI for atomic release creation
2025-11-10 15:30:14 -05:00
torlando-tech
bb89096e95 fix(ci): Use gh CLI for atomic release creation
Replace softprops/action-gh-release with gh CLI to create releases
and upload assets in a single atomic operation. This prevents issues
with repository rules that make releases immutable immediately,
which was causing asset upload failures.

Previous error:
- Release created successfully but became immutable
- Asset upload failed with "Cannot upload assets to an immutable release"

Solution:
- gh release create uploads all assets in one operation
- Avoids the gap between release creation and asset upload

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 14:46:22 -05:00
torlando-tech
fcb54c9de1 fix(ci): Use gh CLI for atomic release creation
Replace softprops/action-gh-release with gh CLI to create releases
and upload assets in a single atomic operation. This prevents issues
with repository rules that make releases immutable immediately,
which was causing asset upload failures.

Previous error:
- Release created successfully but became immutable
- Asset upload failed with "Cannot upload assets to an immutable release"

Solution:
- gh release create uploads all assets in one operation
- Avoids the gap between release creation and asset upload

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 14:46:22 -05:00
torlando-tech
bc7d3958f5 Merge pull request #17 from torlando-tech/release/v0.1.0-prep
Add release infrastructure for v0.1.0
2025-11-10 14:35:08 -05:00
torlando-tech
29b1d6cf9f Merge pull request #17 from torlando-tech/release/v0.1.0-prep
Add release infrastructure for v0.1.0
2025-11-10 14:35:08 -05:00
torlando-tech
ca0885c919 feat: Add release infrastructure for v0.1.0
Add Python packaging and automated release workflow to enable
versioned releases of the BLE interface.

Changes:
- Add pyproject.toml with package metadata and dependencies
- Add GitHub Actions release workflow with validation and artifact generation
- Add CHANGELOG.md documenting v0.1.0 installation system features

The release workflow validates version consistency, runs tests,
generates release artifacts (installer, config, source tarball),
and creates GitHub releases automatically from git tags.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 14:10:08 -05:00
torlando-tech
fd9e8019c1 feat: Add release infrastructure for v0.1.0
Add Python packaging and automated release workflow to enable
versioned releases of the BLE interface.

Changes:
- Add pyproject.toml with package metadata and dependencies
- Add GitHub Actions release workflow with validation and artifact generation
- Add CHANGELOG.md documenting v0.1.0 installation system features

The release workflow validates version consistency, runs tests,
generates release artifacts (installer, config, source tarball),
and creates GitHub releases automatically from git tags.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 14:10:08 -05:00
torlando-tech
9a3bfec5c7 fix(ble): Add BlueZ state cleanup to prevent persistent "Operation already in progress" errors
Implements comprehensive BlueZ device state cleanup after connection failures
to prevent persistent "Operation already in progress" errors. This addresses
the issue where BlueZ maintains stale connection state after timeouts or
failures, preventing successful reconnection even after blacklist periods expire.

BlueZ State Cleanup Implementation:
- **Explicit client disconnect**: Call client.disconnect() in timeout and failure
  exception handlers to release BlueZ resources
- **D-Bus device removal**: New _remove_bluez_device() method removes stale device
  objects via BlueZ RemoveDevice() API
- **Post-blacklist cleanup**: Trigger BlueZ cleanup when peer is blacklisted after
  reaching max_connection_failures (7 failures)

Impact:
- Enables successful reconnection after temporary connection failures
- Fixes persistent errors across blacklist periods
- Prevents BlueZ from maintaining corrupted connection state
- Particularly important for Android devices with MAC address rotation

Implementation Details:
- linux_bluetooth_driver.py:786-830: New _remove_bluez_device() method
- linux_bluetooth_driver.py:1029-1044: Timeout cleanup (disconnect + removal)
- linux_bluetooth_driver.py:1051-1066: Failure cleanup (disconnect + removal)
- BLEInterface.py:1270-1285: Post-blacklist cleanup hook
- tests/test_bluez_state_cleanup.py: 10 new tests (all passing)

Documentation Updates:
- BLE_PROTOCOL_v2.2.md: New troubleshooting section for persistent InProgress errors
- CLAUDE.md: Added to recent fixes list
- CHANGELOG.md: Comprehensive fix description

Related Issues:
- Addresses "Operation already in progress" errors persisting after connection timeouts
- Fixes reconnection failures after peer blacklisting
- Prevents BlueZ state machine corruption from abandoned BleakClient instances

Testing:
- All 10 new unit tests pass
- Cleanup methods properly handle missing devices and D-Bus unavailability
- Integration testing on Raspberry Pi pending

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 00:51:27 -05:00
torlando-tech
558d89de9c fix(ble): Add BlueZ state cleanup to prevent persistent "Operation already in progress" errors
Implements comprehensive BlueZ device state cleanup after connection failures
to prevent persistent "Operation already in progress" errors. This addresses
the issue where BlueZ maintains stale connection state after timeouts or
failures, preventing successful reconnection even after blacklist periods expire.

BlueZ State Cleanup Implementation:
- **Explicit client disconnect**: Call client.disconnect() in timeout and failure
  exception handlers to release BlueZ resources
- **D-Bus device removal**: New _remove_bluez_device() method removes stale device
  objects via BlueZ RemoveDevice() API
- **Post-blacklist cleanup**: Trigger BlueZ cleanup when peer is blacklisted after
  reaching max_connection_failures (7 failures)

Impact:
- Enables successful reconnection after temporary connection failures
- Fixes persistent errors across blacklist periods
- Prevents BlueZ from maintaining corrupted connection state
- Particularly important for Android devices with MAC address rotation

Implementation Details:
- linux_bluetooth_driver.py:786-830: New _remove_bluez_device() method
- linux_bluetooth_driver.py:1029-1044: Timeout cleanup (disconnect + removal)
- linux_bluetooth_driver.py:1051-1066: Failure cleanup (disconnect + removal)
- BLEInterface.py:1270-1285: Post-blacklist cleanup hook
- tests/test_bluez_state_cleanup.py: 10 new tests (all passing)

Documentation Updates:
- BLE_PROTOCOL_v2.2.md: New troubleshooting section for persistent InProgress errors
- CLAUDE.md: Added to recent fixes list
- CHANGELOG.md: Comprehensive fix description

Related Issues:
- Addresses "Operation already in progress" errors persisting after connection timeouts
- Fixes reconnection failures after peer blacklisting
- Prevents BlueZ state machine corruption from abandoned BleakClient instances

Testing:
- All 10 new unit tests pass
- Cleanup methods properly handle missing devices and D-Bus unavailability
- Integration testing on Raspberry Pi pending

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 00:51:27 -05:00
torlando-tech
cf1c7f70e4 fix(ci): Add -s flag to rnsd to enable log file creation
The validation script checks ~/.reticulum/logfile for BLE interface
status, but this file is only created when rnsd is started with the
-s (service/syslog) flag.

Without -s flag:
- rnsd runs but doesn't write to ~/.reticulum/logfile
- Validation script fails: "Log file not found"
- Deployment appears successful but validation always fails

With -s flag:
- rnsd writes logs to ~/.reticulum/logfile
- Validation can check for "interface online" message
- Full deployment + validation cycle works

Note: Only affects manual rnsd startup (non-systemd path). Systemd
installations should have -s configured in the service file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 20:14:13 -05:00
torlando-tech
156eb0ae36 fix(ci): Add -s flag to rnsd to enable log file creation
The validation script checks ~/.reticulum/logfile for BLE interface
status, but this file is only created when rnsd is started with the
-s (service/syslog) flag.

Without -s flag:
- rnsd runs but doesn't write to ~/.reticulum/logfile
- Validation script fails: "Log file not found"
- Deployment appears successful but validation always fails

With -s flag:
- rnsd writes logs to ~/.reticulum/logfile
- Validation can check for "interface online" message
- Full deployment + validation cycle works

Note: Only affects manual rnsd startup (non-systemd path). Systemd
installations should have -s configured in the service file.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 20:14:13 -05:00
torlando-tech
e66d145b7e feat: Add driver_class override pattern for platform-specific BLE drivers
Enable subclassing BLEInterface with custom platform-specific drivers by
  introducing a class-level driver_class attribute that can be overridden.

  Changes:
  - Import LinuxBluetoothDriver optionally with HAS_LINUX_DRIVER flag
  - Add driver_class class attribute (defaults to LinuxBluetoothDriver)
  - Check driver_class is not None before instantiation
  - Use self.driver_class() instead of hardcoded LinuxBluetoothDriver()
  - Log which driver is being used at initialization

  This pattern enables platform-specific implementations like:
    class AndroidBLEInterface(BLEInterface):
        driver_class = AndroidBLEDriver

  Without this pattern, subclasses would need to override __init__ entirely
  to use a different driver, duplicating all initialization logic.

  Implementation details:
  - LinuxBluetoothDriver import wrapped in try/except with fallback to None
  - Raises ImportError if driver_class is None and no override provided
  - Maintains backward compatibility (LinuxBluetoothDriver used by default)
  - All production features preserved (logging redirect, blacklist, rate
    limiting, service UUID filtering, connection management)

  Use case:
  This pattern is used by the Columba Android app to integrate the Android
  BLE stack via Chaquopy, overriding driver_class with AndroidBLEDriver
  that bridges to Kotlin BLE APIs.

  Testing:
  - Default behavior unchanged (uses LinuxBluetoothDriver)
  - Subclass override tested in columba/python/android_ble_interface.py
  - No functional changes to existing BLE interface behavior
2025-11-08 19:52:46 -05:00
torlando-tech
521746197c feat: Add driver_class override pattern for platform-specific BLE drivers
Enable subclassing BLEInterface with custom platform-specific drivers by
  introducing a class-level driver_class attribute that can be overridden.

  Changes:
  - Import LinuxBluetoothDriver optionally with HAS_LINUX_DRIVER flag
  - Add driver_class class attribute (defaults to LinuxBluetoothDriver)
  - Check driver_class is not None before instantiation
  - Use self.driver_class() instead of hardcoded LinuxBluetoothDriver()
  - Log which driver is being used at initialization

  This pattern enables platform-specific implementations like:
    class AndroidBLEInterface(BLEInterface):
        driver_class = AndroidBLEDriver

  Without this pattern, subclasses would need to override __init__ entirely
  to use a different driver, duplicating all initialization logic.

  Implementation details:
  - LinuxBluetoothDriver import wrapped in try/except with fallback to None
  - Raises ImportError if driver_class is None and no override provided
  - Maintains backward compatibility (LinuxBluetoothDriver used by default)
  - All production features preserved (logging redirect, blacklist, rate
    limiting, service UUID filtering, connection management)

  Use case:
  This pattern is used by the Columba Android app to integrate the Android
  BLE stack via Chaquopy, overriding driver_class with AndroidBLEDriver
  that bridges to Kotlin BLE APIs.

  Testing:
  - Default behavior unchanged (uses LinuxBluetoothDriver)
  - Subclass override tested in columba/python/android_ble_interface.py
  - No functional changes to existing BLE interface behavior
2025-11-08 19:52:46 -05:00
torlando-tech
119cdac598 feat(ci): Refactor deployment to use matrix strategy with per-Pi nodes
Completely refactored the deployment workflow to create separate
GitHub Actions nodes for each Pi, with independent deploy and
validation steps. This provides much better visibility and control.

New Architecture:
1. **setup** job: Parses PI_HOSTS into JSON matrix
2. **deploy** job: Matrix execution (one instance per Pi)
3. **validate** job: Matrix execution (one instance per Pi)
4. **summary** job: Aggregate results

GitHub Actions Graph View (2 Pis):
```
setup ━┳━> deploy-pi-0 ━> validate-pi-0
       ┗━> deploy-pi-1 ━> validate-pi-1
```

Features:
- **Parallel execution**: All Pis deploy simultaneously
- **Independent nodes**: Each Pi has its own deploy + validate node
- **fail-fast: false**: One Pi failure doesn't block others
- **Per-Pi logs**: Clean, isolated logs for each device
- **Comprehensive validation**:
  * Wait 5s for startup
  * Check rnsd process
  * Verify BLE interface online (retry 3x with 3s delay)
  * Check Bluetooth adapter powered
  * Display adapter MAC address
- **Better error reporting**: Shows which specific Pi failed
- **Granular status**: See each Pi's status independently

Validation Checks:
✓ rnsd process running
✓ Log file exists
✓ No critical errors in logs
✓ "interface online" message found
✓ Bluetooth adapter powered
✓ Retry logic for startup delays

Benefits:
- Easier to identify which Pi has issues
- Can re-run individual Pi jobs
- Faster deployment (parallel vs sequential)
- Clearer progression in GitHub UI
- Each Pi's logs are isolated and clean

Example UI with failure:
```
setup               ✓
├─ deploy-pi-0      ✓
│  └─ validate-pi-0 ✗ (BLE failed to start)
└─ deploy-pi-1      ✓
   └─ validate-pi-1 ✓ (BLE online)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 19:08:35 -05:00
torlando-tech
02858b7393 feat(ci): Refactor deployment to use matrix strategy with per-Pi nodes
Completely refactored the deployment workflow to create separate
GitHub Actions nodes for each Pi, with independent deploy and
validation steps. This provides much better visibility and control.

New Architecture:
1. **setup** job: Parses PI_HOSTS into JSON matrix
2. **deploy** job: Matrix execution (one instance per Pi)
3. **validate** job: Matrix execution (one instance per Pi)
4. **summary** job: Aggregate results

GitHub Actions Graph View (2 Pis):
```
setup ━┳━> deploy-pi-0 ━> validate-pi-0
       ┗━> deploy-pi-1 ━> validate-pi-1
```

Features:
- **Parallel execution**: All Pis deploy simultaneously
- **Independent nodes**: Each Pi has its own deploy + validate node
- **fail-fast: false**: One Pi failure doesn't block others
- **Per-Pi logs**: Clean, isolated logs for each device
- **Comprehensive validation**:
  * Wait 5s for startup
  * Check rnsd process
  * Verify BLE interface online (retry 3x with 3s delay)
  * Check Bluetooth adapter powered
  * Display adapter MAC address
- **Better error reporting**: Shows which specific Pi failed
- **Granular status**: See each Pi's status independently

Validation Checks:
✓ rnsd process running
✓ Log file exists
✓ No critical errors in logs
✓ "interface online" message found
✓ Bluetooth adapter powered
✓ Retry logic for startup delays

Benefits:
- Easier to identify which Pi has issues
- Can re-run individual Pi jobs
- Faster deployment (parallel vs sequential)
- Clearer progression in GitHub UI
- Each Pi's logs are isolated and clean

Example UI with failure:
```
setup               ✓
├─ deploy-pi-0      ✓
│  └─ validate-pi-0 ✗ (BLE failed to start)
└─ deploy-pi-1      ✓
   └─ validate-pi-1 ✓ (BLE online)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 19:08:35 -05:00
torlando-tech
b590db32bc fix(ci): Use full path to rnsd in deployment script
The deploy workflow was failing to start rnsd because the SSH session's
PATH doesn't include ~/.local/bin where rnsd is installed.

Issue:
- rnsd installed at ~/.local/bin/rnsd (pip install --user)
- Non-interactive SSH session doesn't have ~/.local/bin in PATH
- Command "nohup rnsd" failed: "command not found"
- Deployment reported "Failed to start rnsd"

Fix:
- Define RNSD_BIN="$HOME/.local/bin/rnsd"
- Use full path when starting rnsd via nohup
- Works regardless of SSH session PATH configuration

Now deployment will successfully restart rnsd after copying updated files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 18:49:43 -05:00
torlando-tech
425460998f fix(ci): Use full path to rnsd in deployment script
The deploy workflow was failing to start rnsd because the SSH session's
PATH doesn't include ~/.local/bin where rnsd is installed.

Issue:
- rnsd installed at ~/.local/bin/rnsd (pip install --user)
- Non-interactive SSH session doesn't have ~/.local/bin in PATH
- Command "nohup rnsd" failed: "command not found"
- Deployment reported "Failed to start rnsd"

Fix:
- Define RNSD_BIN="$HOME/.local/bin/rnsd"
- Use full path when starting rnsd via nohup
- Works regardless of SSH session PATH configuration

Now deployment will successfully restart rnsd after copying updated files.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 18:49:43 -05:00
torlando-tech
a109ae83f9 fix(ci): Fix deploy workflow branch detection for manual triggers
The deploy workflow was failing when manually triggered via workflow_dispatch
because it only checked for github.event.workflow_run.head_branch, which is
empty for manual triggers.

Issue:
- Manual trigger: gh workflow run deploy.yml --ref refactor/abstraction-layer
- BRANCH_NAME was empty ("")
- git checkout "" failed: "empty string is not a valid pathspec"
- Deployment failed on all Pis

Fix:
- Use fallback operator: github.event.workflow_run.head_branch || github.ref_name
- workflow_run trigger: uses head_branch (branch that triggered the tests)
- workflow_dispatch trigger: uses ref_name (branch being run on)

Now works for both:
- Automatic deployment after tests complete
- Manual deployment via workflow_dispatch or gh CLI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 18:43:31 -05:00
torlando-tech
71edbc87f8 fix(ci): Fix deploy workflow branch detection for manual triggers
The deploy workflow was failing when manually triggered via workflow_dispatch
because it only checked for github.event.workflow_run.head_branch, which is
empty for manual triggers.

Issue:
- Manual trigger: gh workflow run deploy.yml --ref refactor/abstraction-layer
- BRANCH_NAME was empty ("")
- git checkout "" failed: "empty string is not a valid pathspec"
- Deployment failed on all Pis

Fix:
- Use fallback operator: github.event.workflow_run.head_branch || github.ref_name
- workflow_run trigger: uses head_branch (branch that triggered the tests)
- workflow_dispatch trigger: uses ref_name (branch being run on)

Now works for both:
- Automatic deployment after tests complete
- Manual deployment via workflow_dispatch or gh CLI

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 18:43:31 -05:00
torlando-tech
dba7624be0 feat(ci): Add automated release pipeline
Implemented comprehensive CI/CD release workflow with automated
validation, testing, and GitHub release creation.

Release Workflow Features:
- Tag-triggered releases (v0.2.3, v1.0.0, etc.)
- Pre-release validation:
  * Version consistency (pyproject.toml vs tag)
  * CHANGELOG.md entry required and non-empty
  * Must be from main branch
  * Semantic versioning format
- Full test suite execution (all Python versions)
- Automated artifact generation:
  * install.sh (standalone installer)
  * config_example.toml (example config)
  * Source archive (tar.gz)
  * SHA256SUMS.txt (checksums)
- Release notes extracted from CHANGELOG.md
- GitHub release auto-creation with all assets

Release Process (Maintainers):
1. Update pyproject.toml version
2. Update CHANGELOG.md (move [Unreleased] → [version])
3. Commit: "chore: Bump version to X.Y.Z"
4. Tag: git tag vX.Y.Z && git push origin vX.Y.Z
5. Workflow automatically validates and creates release

Documentation:
- Added "Creating Releases" section to CONTRIBUTING.md
- Includes release checklist, version numbering guide
- Troubleshooting common release issues
- Complete step-by-step instructions

Workflow File: .github/workflows/release.yml
- 4 jobs: validate → test → build → release
- Concurrency control (one release at a time)
- Manual dispatch option for re-runs
- Comprehensive validation and error messages

Benefits:
- Eliminates manual release errors
- Ensures version consistency
- Requires tests to pass
- Standardized release format
- Complete audit trail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 18:32:41 -05:00
torlando-tech
3546595c66 feat(ci): Add automated release pipeline
Implemented comprehensive CI/CD release workflow with automated
validation, testing, and GitHub release creation.

Release Workflow Features:
- Tag-triggered releases (v0.2.3, v1.0.0, etc.)
- Pre-release validation:
  * Version consistency (pyproject.toml vs tag)
  * CHANGELOG.md entry required and non-empty
  * Must be from main branch
  * Semantic versioning format
- Full test suite execution (all Python versions)
- Automated artifact generation:
  * install.sh (standalone installer)
  * config_example.toml (example config)
  * Source archive (tar.gz)
  * SHA256SUMS.txt (checksums)
- Release notes extracted from CHANGELOG.md
- GitHub release auto-creation with all assets

Release Process (Maintainers):
1. Update pyproject.toml version
2. Update CHANGELOG.md (move [Unreleased] → [version])
3. Commit: "chore: Bump version to X.Y.Z"
4. Tag: git tag vX.Y.Z && git push origin vX.Y.Z
5. Workflow automatically validates and creates release

Documentation:
- Added "Creating Releases" section to CONTRIBUTING.md
- Includes release checklist, version numbering guide
- Troubleshooting common release issues
- Complete step-by-step instructions

Workflow File: .github/workflows/release.yml
- 4 jobs: validate → test → build → release
- Concurrency control (one release at a time)
- Manual dispatch option for re-runs
- Comprehensive validation and error messages

Benefits:
- Eliminates manual release errors
- Ensures version consistency
- Requires tests to pass
- Standardized release format
- Complete audit trail

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 18:32:41 -05:00
torlando-tech
c4f9381c6b docs: Remove automated deployment section from README
Remove GitHub workflow documentation as it was specific to personal infrastructure setup and not relevant for general users of the BLE interface.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 17:45:27 -05:00
torlando-tech
20c8716755 docs: Remove automated deployment section from README
Remove GitHub workflow documentation as it was specific to personal infrastructure setup and not relevant for general users of the BLE interface.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 17:45:27 -05:00
torlando-tech
fe37363ab5 chore: Bump version to 0.2.2
Update version to align with BLE Protocol v2.2 implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 00:30:49 -05:00
torlando-tech
2252870fdc chore: Bump version to 0.2.2
Update version to align with BLE Protocol v2.2 implementation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 00:30:49 -05:00
torlando-tech
97e7017411 feat: Add pyproject.toml for Python packaging
Added pyproject.toml to enable pip installation and proper Python
packaging of the BLE interface. This file defines:

- Project metadata (name, version, description, authors)
- Python version support (3.8-3.13)
- Optional dependencies for Linux platform (bleak, bluezero, dbus-python)
- Development dependencies (pytest, coverage, async support)
- setuptools configuration for package structure
- pytest configuration

Benefits:
- Makes the package pip-installable: pip install .
- Enables optional extras: pip install .[linux] or pip install .[dev]
- Standardizes project metadata and dependencies
- Provides pytest configuration for consistent test runs

Usage:
  pip install .              # Core package only
  pip install .[linux]       # With Linux/BlueZ dependencies
  pip install .[dev]         # With development tools
  pip install .[full]        # Everything

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 00:28:13 -05:00
torlando-tech
3eaa4dc9ff feat: Add pyproject.toml for Python packaging
Added pyproject.toml to enable pip installation and proper Python
packaging of the BLE interface. This file defines:

- Project metadata (name, version, description, authors)
- Python version support (3.8-3.13)
- Optional dependencies for Linux platform (bleak, bluezero, dbus-python)
- Development dependencies (pytest, coverage, async support)
- setuptools configuration for package structure
- pytest configuration

Benefits:
- Makes the package pip-installable: pip install .
- Enables optional extras: pip install .[linux] or pip install .[dev]
- Standardizes project metadata and dependencies
- Provides pytest configuration for consistent test runs

Usage:
  pip install .              # Core package only
  pip install .[linux]       # With Linux/BlueZ dependencies
  pip install .[dev]         # With development tools
  pip install .[full]        # Everything

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 00:28:13 -05:00
torlando-tech
7ac9f79d41 feat(ci): Add manual workflow dispatch to deployment workflow
Added workflow_dispatch trigger to allow manual deployment without
waiting for test workflow completion. This is useful for:
- Testing the deployment workflow
- Deploying when automatic trigger doesn't fire
- Re-deploying without pushing new code

Usage:
- Go to Actions → Deploy to Raspberry Pi → Run workflow
- Or via CLI: gh workflow run deploy.yml

Updated the if condition to run on either:
- Automatic trigger when tests complete successfully
- Manual trigger via workflow_dispatch

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 00:17:19 -05:00
torlando-tech
be564646d9 feat(ci): Add manual workflow dispatch to deployment workflow
Added workflow_dispatch trigger to allow manual deployment without
waiting for test workflow completion. This is useful for:
- Testing the deployment workflow
- Deploying when automatic trigger doesn't fire
- Re-deploying without pushing new code

Usage:
- Go to Actions → Deploy to Raspberry Pi → Run workflow
- Or via CLI: gh workflow run deploy.yml

Updated the if condition to run on either:
- Automatic trigger when tests complete successfully
- Manual trigger via workflow_dispatch

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 00:17:19 -05:00
torlando-tech
955fb868fd fix(ci): Remove branches filter from workflow_run trigger
The branches filter in workflow_run triggers can cause workflow validation
errors: "The workflow must contain at least one job with no dependencies."

According to GitHub Actions documentation, the branches/branches-ignore
filters are not well-supported in workflow_run triggers and can cause
validation issues.

Removed the branches filter - the workflow will now trigger when the
"Tests" workflow completes on any branch, which is the intended behavior.

Fixes workflow validation error on Line 11, Col 3.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-07 23:54:31 -05:00