Commit graph

263 commits

Author SHA1 Message Date
torlando-tech
44077010d4 feat(11.6-01): add Kotlin audio active check to LineSource instrumentation
- Check is_kotlin_audio_active() in instrumented_ingest_job()
- Skip frame processing when Kotlin audio active
- Log skip every 100 frames for verification
- Maintain timing with sleep(frame_time)
- Provides additional safety layer beyond recorder silence
2026-02-07 16:02:33 -05:00
torlando-tech
b405dfa462 feat(11.6-01): add set_kotlin_audio_active() to CallManager
- Add set_kotlin_audio_active() method to CallManager
- Delegates to chaquopy_audio_backend.set_kotlin_audio_active()
- Provides Kotlin-accessible method to control Python audio disable
- Logs state change for debugging
2026-02-07 16:02:33 -05:00
torlando-tech
a28e7db15f feat(11.6-01): add _kotlin_audio_active flag to disable Python LXST audio
- Add global _kotlin_audio_active flag (default False)
- Add set_kotlin_audio_active() and is_kotlin_audio_active() functions
- ChaquopyRecorder._record_chunk() returns silence when flag True
- ChaquopyPlayer.play() drops frames when flag True
- Prevents dual audio pipeline conflict during Kotlin calls
2026-02-07 16:02:33 -05:00
torlando-tech
f2fb803e5b feat(11.5-01): wire INTEGER signals from Python to Kotlin
- Add STATUS_* signalling constants (0x00-0x06) to CallManager
- Send INTEGER signals via send_signal() in all LXST callbacks:
  - _handle_ringing() -> STATUS_RINGING (0x04)
  - _handle_established() -> STATUS_CONNECTING (0x05) + STATUS_ESTABLISHED (0x06)
  - _handle_ended() -> STATUS_AVAILABLE (0x03)
  - _handle_busy() -> STATUS_BUSY (0x00)
  - _handle_rejected() -> STATUS_REJECTED (0x01)
- Preserve existing _notify_kotlin() string events for UI

This fixes the signal type mismatch (Gap 1 from 11-VERIFICATION.md)
where Kotlin Telephone expected INTEGER signals but Python only sent
STRING events. Kotlin Telephone can now transition to ESTABLISHED state
and open audio pipelines.
2026-02-07 16:02:33 -05:00
torlando-tech
d5615bae86 feat(11-04): add Kotlin Telephone integration to call_manager.py
- Add on_state_changed() for Kotlin state notifications
- Add on_profile_changed() for profile sync
- Add set_kotlin_telephone_callback() for callback registration
- Add _notify_kotlin() for Python->Kotlin event notifications
- Update receive_audio_packet() to forward to LXST Packetizer
- Update receive_signal() to forward to LXST signalling
- Wire existing handlers to notify Kotlin Telephone
2026-02-07 16:02:33 -05:00
torlando-tech
b53df88c45 feat(10-05): initialize NetworkPacketBridge in PythonWrapperManager
- Add NetworkPacketBridge import
- Add networkPacketBridge instance variable
- Initialize NetworkPacketBridge in setupCallManager()
- Pass bridge to Python via set_network_bridge()
- Add shutdown cleanup for networkPacketBridge
- Add set_network_bridge() method to reticulum_wrapper.py
- Pass kotlin_network_bridge to initialize_call_manager()
2026-02-07 16:02:33 -05:00
torlando-tech
cae71db622 feat(10-05): add network bridge methods to call_manager.py
- Add _kotlin_network_bridge instance variable
- Update initialize() to accept kotlin_network_bridge parameter
- Update initialize_call_manager() to pass network bridge
- Add send_audio_packet() for Python->Kotlin packets
- Add send_signal() for Python->Kotlin signalling
- Add receive_audio_packet() stub for Kotlin->Python (Phase 11)
- Add receive_signal() stub for Kotlin->Python (Phase 11)
2026-02-07 16:02:33 -05:00
torlando-tech
a745afd43a chore(07-02): add opus-jni dependency to build.gradle.kts
- Added cn.entertech.android:wuqi-opus:1.0.3 from Maven Central
- Library wraps theeasiestway/android-opus-codec (libopus 1.3.1)
- Provides OpusEncoder/OpusDecoder with JNI bindings
- Native .so libraries for arm64-v8a and x86_64 ABIs
2026-02-07 16:02:33 -05:00
torlando-tech
86252a908e fix(python): make display_name optional in create_identity()
The second create_identity() method at line 7376 shadows the first one at
line 2338. Making display_name optional allows callers that don't pass a
name to work correctly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 10:31:56 -05:00
torlando-tech
153112dbc1 docs(deps): document RPC exception handling fix in requirements.txt
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:49:23 -05:00
torlando-tech
f4a8fe8658 fix(deps): update RNS to fix socket leak in TCPInterface
Update Reticulum fork from rebase-1.1.3 to fix/socket-leak-1.1.3 branch.

The fix closes sockets on connection failure in TCPInterface.connect() and
BackboneInterface.connect() to prevent resource leak during reconnection
attempts (~780 leaked sockets/hour, ~4.3 MB/hour native memory growth).

Addresses memory growth identified during Phase 9 profiling investigation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:29:03 -05:00
torlando-tech
dd416490a2 docs(05-02): audit PyObject lifecycle for memory leaks
- Comprehensive review of all PyObject usage in Kotlin code
- Confirmed no PyObject storage beyond method scope
- All PyObjects immediately converted to Kotlin types
- Chaquopy automatic reference counting handles cleanup
- Documented findings in memory_profiler.py comments

Files audited:
- PythonWrapperManager.kt ✓
- EventHandler.kt ✓
- IdentityManager.kt ✓
- RoutingManager.kt ✓
- PythonResultConverter.kt ✓

Conclusion: No PyObject reference leaks in Kotlin code.
2026-01-29 18:41:10 -05:00
torlando-tech
42667c8308 test(05-02): add unit tests for memory profiler
Cover start/stop, snapshots, periodic scheduling, and thread safety.
13 test cases for ~90% coverage of memory_profiler.py.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 17:33:04 -05:00
torlando-tech
9899f10ad0 fix(05-02): prevent race condition in memory profiler timer
Add threading.Lock to synchronize access to _profiling_active and
_snapshot_timer between stop_profiling() and timer callback.

Prevents orphaned timer continuing after stop_profiling() returns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-29 17:29:26 -05:00
torlando-tech
9355889a31 feat(05-01): add Python memory profiler module
- Create memory_profiler.py with tracemalloc snapshot comparison
- Add enable_memory_profiling() method to ReticulumWrapper
- Schedule periodic snapshots using threading.Timer (Chaquopy-compatible)
- Filter frozen importlib and unknown traces to reduce noise
- Log top 10 growing allocations to Android logcat via logging_utils
- Provide get_memory_profile() for current stats query
- Zero overhead when disabled (lazy import pattern)
2026-01-29 17:08:16 -05:00
Torlando
c0529dc307
Merge pull request #284 from torlando-tech/feature/issue-216-rns-discovery
feat: add RNS 1.1.x bootstrap and interface discovery support
2026-01-22 13:48:06 -05:00
torlando-tech
bb601d071b test: add comprehensive tests for get_discovered_interfaces()
Add 27 tests covering:
- get_discovered_interfaces(): TCP interfaces, radio interfaces with LoRa
  params, interfaces with location data, multiple interfaces sorted by
  status and stamp value, bytes/string transport_id handling, None value
  filtering, exception handling
- _get_discovery_status_name(): status code to name conversion
- _create_config_file() discovery options: discover_interfaces,
  autoconnect_discovered_interfaces, interface_discovery_sources,
  required_discovery_value, bootstrap_only for TCP clients

This improves patch coverage from ~56% to target higher coverage.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 23:19:20 -05:00
torlando-tech
02b53b64a8 test: add comprehensive unit tests for RNS discovery feature
Add unit tests for the RNS 1.1.x discovery functionality:

Python tests:
- test_autoconnected_endpoints.py: 14 tests for get_autoconnected_interface_endpoints()
- test_discovery_enabled.py: 12 tests for is_discovery_enabled()

Kotlin tests:
- DiscoveredInterfacesViewModelTest.kt: 22 tests covering autoconnected endpoints
  state, isAutoconnected() helper, and discovery settings loading
- DiscoveredInterfacesScreenTest.kt: 29 tests for UI helpers including
  isYggdrasilAddress(), formatInterfaceType(), and icon/badge visibility

Also fixes:
- Fix detekt ComplexCondition issues in RNodeWizardScreen, MapScreen, MainActivity
- Fix detekt LongMethod in ColumbaApplication by extracting restorePeerIdentities()
- Fix detekt SwallowedException in InterfaceRepository with verbose logging
- Fix detekt MatchingDeclarationName by moving FocusInterfaceDetails to own file
- Fix detekt ReturnCount in isYggdrasilAddress and ViewModel helper functions
- Update StartupConfigLoaderTest for new discovery settings
- Update TcpClientWizardViewModelTest for allInterfaceEntities changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 22:58:08 -05:00
torlando-tech
53fa9f24e0 feat: add connected indicator and improved icons for discovered interfaces
- Add "Connected" badge showing which discovered interfaces are currently
  auto-connected by RNS discovery
- Add getAutoconnectedEndpoints() API to fetch active auto-connected interfaces
- Use type-specific icons: globe for TCP, antenna for radio, incognito for I2P,
  tree-pine for Yggdrasil (detected via 0200::/7 IPv6 range)
- Show I2P b32 addresses with .b32.i2p suffix
- Display human-readable interface type labels (e.g., "Backbone (TCP)")

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:12:05 -05:00
torlando-tech
8bc1d054d4 feat: add discovery toggle and fix discovered interfaces display
- Add toggle in Discovered Interfaces screen to enable/disable discovery
- Service auto-restarts when toggle is changed (no app restart needed)
- Show bootstrap-enabled interface names in settings card
- Add discovery settings to SettingsRepository and StartupConfigLoader
- Include discover_interfaces and autoconnect_discovered_interfaces in config
- Include bootstrap_only for TCPClient interfaces in buildConfigJson
- Fix Python wrapper bug: discovered_interfaces() returns list, not dict
- Add bottom padding to list to avoid nav bar overlap

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 19:49:16 -05:00
torlando-tech
c40f7425ca test: Add comprehensive tests for interface name extraction
Add unit tests for ReceivingInterfaceInfo:
- 25 Kotlin tests covering TCP, Auto, BLE, RNode, Serial, and unknown interfaces
- Tests for friendly name extraction, interface type parsing, and edge cases

Refactor ReceivingInterfaceInfo to reduce cyclomatic complexity:
- Extract InterfaceCategory enum for display properties
- Extract categorizeInterface() and looksLikeAddress() helper functions
- Main function now delegates to smaller, focused functions

Add 2 additional Python tests for interface name formatting:
- Test interface.name same as class name returns class only
- Test interface.name being None returns class only

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 19:07:22 -05:00
torlando-tech
66982b18de feat: Show user-configured interface name in Node Details
Update the "Received Via" card in Node Details to show the user-configured
interface name (e.g., "Sideband Server") instead of generic type names
(e.g., "TCP/IP").

Python changes:
- Build formatted interface string "ClassName[UserConfiguredName]" from
  the interface object's type and .name attribute
- This allows Kotlin to extract both the friendly name and interface type

Kotlin changes:
- Add extractFriendlyName() to parse user-configured name from brackets
- Add extractInterfaceType() to parse class name before brackets
- Display friendly name as main text, interface type as subtitle

The card now shows:
- Title: "Received Via"
- Content: "Sideband Server" (user-configured name)
- Subtitle: "TCPClientInterface" (interface type)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 19:02:43 -05:00
torlando-tech
93d794c1fd feat: extend DiscoveredInterface data model with full RNS 1.1.x fields
Add comprehensive discovery data to DiscoveredInterface including:
- Transport/network IDs and status info (statusCode, lastHeard, hops)
- TCP-specific fields (reachableOn, port)
- Radio-specific fields (frequency, bandwidth, SF, CR, modulation)
- Location fields (latitude, longitude, height)
- Helper properties for interface type detection

Update Python bridge to return full discovery data from RNS 1.1.x API.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 18:11:18 -05:00
torlando-tech
e0dae212dc feat: add RNS 1.1.x bootstrap and interface discovery support (#216)
Add support for RNS 1.1.0+ interface discovery and bootstrap features,
enabling new users to connect without relying on deprecated public
infrastructure.

Changes:
- Add discovery settings to ReticulumConfig (discoverInterfaces,
  autoconnectDiscoveredInterfaces, interfaceDiscoverySources,
  requiredDiscoveryValue)
- Add bootstrapOnly option to TCPClient interface config
- Update Python config generation for discovery and bootstrap options
- Add get_discovered_interfaces() and is_discovery_enabled() API methods
- Extend AIDL interface with discovery methods
- Mark 3 reliable community servers as bootstrap candidates (Beleth,
  Quad4, FireZen)
- Add bootstrap toggle to TCP Client wizard UI

Note: The RNS fork needs to be rebased on 1.1.2 to enable the actual
discovery features. The code is ready but awaiting the dependency update.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 16:45:38 -05:00
Torlando
3ca089d02c
Merge pull request #97 from torlando-tech/dependabot/gradle/cameraX-1.5.2
deps(deps): bump cameraX from 1.4.1 to 1.5.2
2026-01-21 14:11:47 -05:00
torlando-tech
975c8c003a Fix flaky tests and improve CI failure visibility
- Harden 4 Python tests that were flaky due to mock object identity
  comparisons by using explicit sentinel values for link status constants
- Add failure annotations to CI workflow so root cause job is clearly
  marked when fail-fast cancels sibling jobs

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:52:47 -05:00
Torlando
4af51e7c8a
Merge pull request #311 from torlando-tech/feature/issue-215-telemetry-collector-api
Add telemetry collector API with group tracking features
2026-01-21 13:49:52 -05:00
torlando-tech
7e95f278b3 Add tests for set_telemetry_allowed_requesters method
Cover all branches: success with items, empty list, lowercase
normalization, empty string filtering, set storage, deduplication,
and list replacement.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 13:32:29 -05:00
torlando-tech
9bf59cbec6 Fix telemetry request tests and add blocked requester tests
- Add requester to allowed list in tests that expect requests to succeed
- Add test_blocks_request_from_non_allowed_requester to verify blocking
- Add test_blocks_request_when_allowed_list_empty to verify empty = block all

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 12:44:42 -05:00
torlando-tech
2a79ed2613 Fix empty telemetry stream responses appearing in chat
Empty telemetry stream responses (0 entries from collector) were
appearing as blank messages in chat because is_location_only was
only set when the stream had entries. Now telemetry stream messages
are always marked as location-only regardless of whether they
contain data.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 11:28:37 -05:00
torlando-tech
b060512aee Add allowed telemetry requesters feature for host mode
Implements the ability to control which contacts can request telemetry
when acting as a collector (host mode). Users can select specific
contacts who are allowed to request their group's location data.
Requests from non-allowed contacts are silently blocked.

Changes:
- Add telemetry_allowed_requesters state and filtering in Python layer
- Add AIDL interface and bridge for setTelemetryAllowedRequesters
- Add SettingsRepository storage with DataStore persistence
- Add TelemetryCollectorManager state flow and Python sync
- Add SettingsViewModel state management with ContactRepository
- Add UI components: AllowedRequestersSection and AllowedRequestersDialog
- Fix ArrayList to Python list conversion in ReticulumServiceBinder
- Fix state preservation in SettingsViewModel.loadSettings()
- Add CLAUDE.md with Chaquopy ArrayList pitfall documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 10:39:49 -05:00
Torlando
3fe17c2ff9
Merge pull request #243 from torlando-tech/feature/issue-215-telemetry-collector-api
Add Telemetry Collector API support
2026-01-21 00:28:51 -05:00
Torlando
3657c288fe
Merge pull request #280 from torlando-tech/feature/usb-rnode-support
feat: USB RNode support (Issue #173)
2026-01-21 00:24:41 -05:00
torlando-tech
a05e26194c Add comprehensive tests for unpack_telemetry_stream
Add 16 new tests for unpack_telemetry_stream covering:
- Empty stream handling
- Bytes and string source hash conversion
- Entries with too few elements (validation)
- Invalid telemetry data handling
- Valid timestamp application (converted to milliseconds)
- Future timestamp rejection (>1 hour ahead)
- Zero/None timestamp handling
- Valid appearance parsing (icon, fg/bg colors)
- Invalid icon name formats (special chars, too long)
- Invalid color bytes (too short, non-bytes)
- Multiple entry processing
- Exception handling during entry processing

Total Python tests: 61

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 00:15:16 -05:00
torlando-tech
4282e99f7c Add comprehensive tests for send_telemetry_request and FIELD_COMMANDS handling
Expand Python test coverage to include:

TestSendTelemetryRequestSuccess (6 tests):
- Successful send with immediate identity recall
- Successful send with cached identity
- Error when local_lxmf_destination is missing
- Error when identity cannot be resolved after path request
- jarray conversion handling
- Correct FIELD_COMMANDS structure building

TestOnLxmfDeliveryFieldCommands (4 tests):
- FIELD_COMMANDS handling when collector enabled
- Skipping FIELD_COMMANDS when collector disabled
- Identity retry mechanism in delivery handler
- Ignoring non-collector requests

Total Python tests: 45 (up from 35)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 00:12:56 -05:00
torlando-tech
9b6452660c Expand Python test coverage for telemetry host mode
Add 14 new tests covering:
- _send_telemetry_stream_response: filtering by timebase, LXMF message
  creation, handling empty telemetry, cleanup of expired entries
- send_telemetry_request: error handling for uninitialized states
- FIELD_COMMANDS constants: verify all protocol constants exist
- Timebase filtering: verify received_at vs timestamp filtering

These tests improve coverage for the Python telemetry collector
implementation, specifically the FIELD_TELEMETRY_STREAM response
generation and FIELD_COMMANDS request handling paths.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 23:06:28 -05:00
torlando-tech
5b724e34fd Add comprehensive unit tests for telemetry collector host mode
- Add 4 tests to SettingsRepositoryTest for host mode persistence
- Add 7 tests to TelemetryCollectorManagerTest for host mode management
- Add 6 tests to SettingsViewModelTest for host mode UI state
- Create test_telemetry_host_mode.py with 21 Python tests for:
  - pack_telemetry_stream function
  - set_telemetry_collector_enabled method
  - _store_telemetry_for_collector method
  - _cleanup_expired_telemetry method
  - Integration tests for full workflow
- Fix detekt issues with appropriate suppressions
- Fix SwallowedException by including exception in log

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:30:04 -05:00
torlando-tech
ba2cf44dea Add telemetry collector (host mode) for Group Tracker
Enable Columba to act as a telemetry collector compatible with Sideband's
protocol. When Host Group mode is enabled, Columba will:

- Store incoming FIELD_TELEMETRY (0x02) location data from peers
- Handle FIELD_COMMANDS (0x09) telemetry requests
- Respond with FIELD_TELEMETRY_STREAM (0x03) containing all stored entries

Implementation details:
- In-memory storage with 24-hour TTL, keeping latest per source
- Uses received_at timestamp for timebase filtering (handles clock skew)
- Follows Sideband's identity recall + path request pattern
- UI toggle in Location Sharing settings card

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 22:04:13 -05:00
torlando-tech
2a19d58f1d Add telemetry request functionality to Group Tracker
Enable requesting location data from group host (telemetry collector):

- Add send_telemetry_request() to Python wrapper using FIELD_COMMANDS
- Add path request retry logic when identity not immediately known
- Add request toggle and interval settings to UI
- TelemetryCollectorManager handles periodic location requests
- New AIDL/protocol methods for sendTelemetryRequest

UI renamed from "Telemetry Collector" to "Group Tracker" with
user-friendly labels (Group Host, Share with group, etc.)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 20:22:54 -05:00
torlando-tech
049424f75f Add FIELD_COMMANDS constant for LXMF telemetry requests
Previously Columba was using FIELD_IMAGE (0x06) for telemetry
commands, causing Sideband to interpret requests as image
attachments. Add the correct FIELD_COMMANDS constant (0x09)
per the LXMF specification.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 20:22:13 -05:00
torlando-tech
130bd1a723 fix: abort USB start if old read thread won't stop
Prevents race condition where two threads compete for USB reads
if the previous thread doesn't terminate within timeout.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:37:34 -05:00
torlando-tech
93bdec9ebd fix: address code review feedback for USB bridge
- Set readTimeout=100ms to reduce CPU usage from continuous polling
- Escalate thread leak warning to ERROR level for visibility
- Capture deviceId early in detach handler for stability across Android versions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 19:30:53 -05:00
torlando-tech
a4959d4b4a Address PR review comments for telemetry collector
- Add hex character validation for collector address (prevents crash)
- Fix periodic send race condition by awaiting in-progress sends
- Fix auto-confirm timing using LaunchedEffect for state sync
- Optimize SQL queries from O(n²) to O(n) using JOIN
- Add future timestamp rejection (>1hr) to prevent UI issues
- Add icon name validation (alphanumeric/underscore, max 50 chars)
- Add comprehensive tests for Python validation logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 18:40:47 -05:00
torlando-tech
f0bd380a4e Add comprehensive unit tests for Greptile review fixes
- Add Python tests for unpack_telemetry_stream function (464 lines)
  - Tests basic unpacking, timestamp handling, source hash conversion
  - Tests appearance data parsing and error handling
  - Tests Sideband format compatibility
  - Verifies None/0/negative timestamp validation

- Add Kotlin tests for location.time timestamp semantics
  - LocationTelemetryTest: Verifies timestamp represents capture time
  - LocationTelemetryTest: Verifies millisecond precision preservation
  - LocationTelemetryTest: Verifies collector API serialization compatibility
  - TelemetryCollectorManagerTest: Documents expected timestamp behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 18:40:47 -05:00
torlando-tech
c1090423d6 Address remaining Greptile review comments
- Use location.time instead of System.currentTimeMillis() for accurate
  location capture timestamp in TelemetryCollectorManager
- Add timestamp validation in Python to prevent issues with None/0 values

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 18:40:47 -05:00
torlando-tech
a4db8fc4fb Add Telemetry Collector API support (#215)
Implements support for sending location telemetry to a collector and
receiving bulk telemetry streams from multiple sources.

Features:
- TelemetryCollectorManager for scheduled/manual telemetry sends
- TelemetryCollectorCard UI for configuration in Settings
- FIELD_TELEMETRY_STREAM (0x03) handling in Python layer
- Database migration for appearanceJson field on received locations
- SettingsRepository preferences for collector address, intervals, etc.

Testing:
- TelemetryCollectorManagerTest with mockk and Turbine
- TelemetryCollectorCardTest with Compose testing
- SettingsViewModelTest telemetry method tests
- SettingsRepositoryTest telemetry preference tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 18:40:47 -05:00
torlando-tech
49d6321ae0 refactor: extract testable utilities to improve test coverage
Extracted business logic from ViewModels and UI components into testable utility classes (InterfaceFormattingUtils, DeviceNameValidator, RssiThrottler, DeviceClassifier) to enable comprehensive unit testing without platform dependencies. Added 116 new tests covering formatting, validation, throttling, and device classification logic, increasing patch coverage from 23.5% to approximately 35-40%.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-20 17:46:09 -05:00
torlando-tech
df4e7761f0 feat: add USB-assisted Bluetooth pairing with device selection
When pairing a USB-connected RNode via Bluetooth, the wizard now:
- Adds "Pair via USB" option to the Bluetooth tab
- Receives PIN from RNode over USB connection
- Scans for unbonded RNodes and shows device selection list
- Auto-selects if only one unbonded RNode is found
- Uses BroadcastReceiver to properly detect bond state changes

This solves the issue where multiple RNodes in range would cause
pairing failures because the PIN belongs to the USB-connected device,
not necessarily the first discovered one.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 12:21:04 -05:00
torlando-tech
07893238cd test: improve rnode_interface.py coverage and fix PIN parsing
Test coverage improvements (26% -> 47%):
- Add tests for _get_usb_bridge() success/failure cases
- Add tests for _start_usb() VID/PID lookup, connection, callbacks
- Add tests for _on_usb_connection_state_changed() callback
- Add tests for USB VID/PID config attributes
- Add tests for start() routing to correct implementation

PIN parsing fix:
- Fix CMD_BT_PIN parsing to use 4-byte big-endian integer format
- Matches Kotlin KotlinUSBBridge implementation
- Update test to verify correct frame structure

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 00:52:45 -05:00
torlando-tech
2b87931f01 fix: resolve detekt issues and update tests for USB RNode support
- Fix SwallowedException in KotlinUSBBridge by adding verbose logging
- Fix ImplicitDefaultLocale by using Locale.US for PIN formatting
- Add @Suppress for NestedBlockDepth in KISS protocol parser
- Remove unused generateDefaultInterfaceName and waitForBondState functions
- Add @Suppress for loadExistingConfig complexity (inherent to config mapping)
- Update DebugViewModelEventDrivenTest with interfaceRepository parameter
- Update ReviewConfigStepTest with isUsbMode and getConnectionTypeString mocks
- Fix test_usb_bridge.py mock to use Chaquopy getter methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 00:24:53 -05:00