Commit graph

15 commits

Author SHA1 Message Date
torlando-tech
b045ca3aed feat: add BLE peer RSSI signal tracking
Extends signal metrics support to BLE interfaces by implementing RSSI
tracking for BLE peer connections. Uses existing KotlinBLEBridge to
query the last RSSI value from connected peers via the Android GATT
connection.

Changes:
- Add getPeerRssi() method to KotlinBLEBridge for querying BLE RSSI
- Add get_peer_rssi() to AndroidBLEDriver with last-receive tracking
- Add get_rssi() to AndroidBLEInterface wrapper classes
- Handle BLEPeerInterface in signal_quality.py for proper RSSI extraction
- Add 16 comprehensive unit tests for new functionality

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 21:25:47 -05:00
torlando-tech
0bbf8d7038 refactor: implement hierarchical BLE logging tags
Add consistent Columba:BLE:<Layer>:<Component> log tag pattern across
all BLE components for improved debugging and log filtering.

Kotlin components now use abbreviated tags (K:Bridge, K:Scan, K:Client,
K:Adv, K:Server, K:Queue, K:ConnMgr, K:Pair) and Python driver uses
Py:Driver. Also fixes callback trace logging from WARNING to DEBUG level.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 13:41:35 -05:00
torlando-tech
019f88ea2b fix: convert Chaquopy jarray to Python bytes in BLE callbacks
When Kotlin passes ByteArray to Python via Chaquopy, it arrives as a
jarray('B') (Java array), not Python bytes. Java arrays don't have
Python methods like .hex(), so calling .hex() on identity bytes
caused "jarray('B')' object has no attribute 'hex'" errors.

Add ensure_bytes() helper function and apply it to:
- _handle_data_received: data parameter
- _handle_duplicate_identity_detected: identity_bytes parameter

This fixes the duplicate identity detection callback which was failing
silently and allowing connections that should have been rejected.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 01:10:23 -05:00
torlando-tech
d692b1171f feat(ble): add duplicate identity detection callback for Android
On Linux, BLEInterface sets driver.on_duplicate_identity_detected to
check if an identity is already connected at a different MAC address.
On Android, this callback was never wired up, allowing duplicate
connections during MAC rotation.

Changes:
- KotlinBLEBridge: Add onDuplicateIdentityDetected callback field
- KotlinBLEBridge: Add setOnDuplicateIdentityDetected setter method
- KotlinBLEBridge: Check for duplicates in handleIdentityReceived()
  before accepting connection, using safe message format
- AndroidBLEDriver: Wire up callback in _setup_kotlin_callbacks()
- AndroidBLEDriver: Add _handle_duplicate_identity_detected() method
- Update tests to verify callback is properly wired
- Update BLE architecture docs with callback flow

When duplicate detected, connection is rejected with safe log message
"Duplicate identity rejected for {address}" which doesn't trigger the
blacklist mechanism.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-17 16:19:17 -05:00
torlando-tech
0e58d3462b refactor: remove local BLEInterface.py copy
BLEInterface.py is provided by ble-reticulum pip dependency.
No need to maintain a duplicate local copy.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 20:03:45 -05:00
torlando-tech
4083eb2063 build: update ble-reticulum to main branch
The fix/ble-peer-interface-cleanup branch has been merged to main.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:59:06 -05:00
torlando-tech
43aad807fd style: fix ktlint formatting issues for CI
- Add ktlint_standard_function-naming = disabled for Compose functions
- Move inline comments to separate lines per ktlint rules
- Fix import ordering and multiline expression formatting
- Fix line length exceeding 160 characters
- Auto-format trailing commas and expression body placement

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 19:30:33 -05:00
torlando-tech
218fdee976 fix(ble): prevent interface/fragmenter loss during MAC rotation
- Rewrite _validate_spawned_interfaces() with 3-pass approach:
  - Pass 1: Collect orphaned addresses
  - Pass 2: Clean up address mappings, track interfaces to detach
  - Pass 3: Only detach interfaces with zero connected addresses
  - Fragmenters only cleaned up when interface fully detached

- Enhance _spawn_peer_interface() reuse logic:
  - Update address_to_identity and identity_to_address when reusing
  - Cancel pending detach for the identity
  - Mark interface as online

- Fix disconnect callbacks to preserve fragmenters:
  - _device_disconnected_callback: defer fragmenter cleanup to grace period
  - handle_central_disconnected: same fragmenter preservation
  - _process_pending_detaches: clean up fragmenters on actual detach

- Rename _cleanup_stale_interface() to _cleanup_stale_address():
  - No longer detaches interface during MAC rotation
  - Only cleans up stale address-specific mappings
  - Interface preserved for reuse with new address

Fixes orphaned peer interfaces and "No fragmenter for peer" warnings
during BLE MAC address rotation.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 13:31:42 -05:00
torlando-tech
ace9c86034 fix(ble): preserve peer interface across MAC rotations with grace period
When an address disconnects, check if other addresses still have the
same identity. Only detach the peer interface when ALL addresses for
that identity are disconnected.

Additionally, use a 2-second grace period before detaching to allow
new connections to establish during MAC rotation. If a new address
with the same identity connects within the grace period, cancel the
pending detachment.

This fixes the issue where peer interfaces were being rapidly created
and destroyed during MAC rotation, causing connection instability.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-01 01:44:38 -05:00
torlando-tech
94c3716757 fix(ble): identity timeout cleanup and UI improvements
BLE Connection Cleanup:
- Add pending identity timeout (30s) to disconnect non-Reticulum devices
  (e.g., AirTags, BLE scanners) that connect but never complete handshake
- Fix cancelConnection not triggering cleanup callback - manually clean up
  state and fire onCentralDisconnected after cancel
- Notify Python immediately for all peripheral connections (with or without
  identity) so it can track pending connections

UI Improvements:
- Add live-updating connection duration timer in BLE connections screen
  (updates every second using LaunchedEffect)

Build Changes:
- Point to ble-reticulum fix branch with identity timeout changes
- Load BLEInterface from local ble_modules for testing

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-31 23:07:31 -05:00
torlando-tech
d6515f8ef8 fix: add identity resync for BLE reconnection recovery
When Python's disconnect callback fires but the driver layer maintains
the GATT connection, data was being dropped because address_to_identity
was cleared.

Changes:
- Point ble-reticulum dependency to fix/identity-cache-on-disconnect branch
- Add requestIdentityResync() to KotlinBLEBridge for identity recovery
- Add request_identity_resync() to android_ble_driver.py as bridge method

The ble-reticulum fix adds identity caching (60s TTL) and cache lookup
in _handle_ble_data. When cache is also empty, it calls the driver's
request_identity_resync() method to recover identity from Kotlin.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 16:09:55 -05:00
torlando-tech
5baa34032e fix: add proactive BLE advertising refresh to prevent silent stops
Android silently stops BLE advertising when the app goes to background,
screen turns off, or device enters Doze mode - without calling any
callback. This leaves the app thinking it's advertising when it's not.

Add a proactive refresh mechanism that restarts advertising every 60
seconds to ensure the device remains discoverable. Also add bridge
methods to allow Python to check/ensure advertising is active.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:45:47 -05:00
torlando-tech
1f15d4742e refactor: use ble-reticulum as GitHub pip dependency
Replace submodule with pip install from GitHub. This simplifies
dependency management and avoids namespace collision with RNS.Interfaces.

Changes:
- Remove external/ble-reticulum submodule
- Update build.gradle.kts to install from GitHub branch
- Update reticulum_wrapper.py to use ble_reticulum package
- Remove duplicate BLE files from python/ble_modules/
- Fix KotlinBLEBridge address callback deduplication

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 23:50:10 -05:00
torlando-tech
0f29de2054 fix(ble): Fix MAC rotation reconnection and dual connection deduplication
Bug 1 - MAC Rotation:
- Bypass MAC sorting after MAC rotation cleanup to ensure reconnection
- When a peer's MAC address rotates, we must reconnect regardless of
  which device has the higher MAC address
- Updated ble-reticulum submodule with fix and tests

Bug 2 - Dual Connection Deduplication:
- Add onAddressChanged callback from Kotlin to Python
- When Kotlin deduplicates a dual connection (central + peripheral),
  Python now updates its address mappings so messages continue to flow
- Updates identity_to_address, address_to_identity, and fragmenter keys

Files changed:
- KotlinBLEBridge.kt: Add setOnAddressChanged callback
- bluetooth_driver.py: Add on_address_changed to abstract interface
- android_ble_driver.py: Register and handle address change events
- BLEInterface.py: Add _address_changed_callback to update mappings
- Added unit tests for both bugs

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-11 13:02:35 -05:00
torlando-tech
0ce4fba7a3 initial commit 2025-11-30 19:59:14 -05:00