Commit Graph

59 Commits

Author SHA1 Message Date
agessaman 1fe3fb1779 fix(storage): retain signed advert packets 2026-07-14 15:51:40 -07:00
Lloyd b2eb45b199 feat: Add LBT diagnostics endpoint with correlation analysis
- Implemented `lbt_diagnostics` API endpoint to return aggregated Listen Before Talk (LBT) diagnostics aligned with RF metrics.
- Introduced methods for calculating Pearson correlation coefficients and auto-bucket sizing for diagnostics.
- Enhanced data aggregation logic in `StorageCollector` for LBT diagnostics.
- Updated OpenAPI specification to include new endpoint and response schemas.
- Added comprehensive unit tests for LBT diagnostics, including validation of correlation calculations and data integrity.
2026-07-10 13:36:49 +01:00
Rightup 1906f576bb feat: add region/default-scope / cli commands update
standardize default region on mesh.default_region (remove legacy region_default_scope usage)
add/align CLI support for owner.info, path.hash.mode, and loop.detect with validation
wire UI terminal get/set + autocomplete/help for owner.info, path.hash.mode, loop.detect
extend update_radio_config to persist owner_info for UI set owner.info
add and use shared packet utility for advert creation + default-region transport scoping
refactor repeater and room-server advert paths to reuse shared packet logic
2026-07-08 17:25:35 +01:00
agessaman e22514882f perf: force timestamp range scan for windowed packet-stats GROUP BYs
The GROUP BY type and GROUP BY drop_reason sub-queries in
get_packet_stats (and get_packet_type_stats) filter by a time window but
let the planner pick idx_packets_type / idx_packets_transmitted to get
grouping for free. It then heap-checks the timestamp filter across the
entire table, turning a bounded window into a full scan: on a 1.5M-row
packets table the 24h stats load spent ~4.8s (type) + ~2.3s
(drop_reason) instead of ~0.1s each.

Pin these to idx_packets_timestamp with INDEXED BY so they range-scan the
window (~50k rows) and group via a small temp b-tree. Verified on the
live DB: 4.80s -> 0.10s and 2.32s -> 0.10s. Unlike a covering index this
adds no write-path cost on the packet-insert hot path.
2026-07-08 10:13:28 +01:00
agessaman 676e2cea30 perf: add covering index for airtime chart queries
The airtime/utilization chart queries (get_airtime_data and
get_airtime_buckets) range-scan and order packets by timestamp,
selecting only timestamp/length/payload_length/transmitted. On a large
packets table this forced a full scan of the row heap, saturating slow
storage (e.g. a Pi SD card): each dashboard poll took longer than the
client timeout, aborted polls stacked, and sustained I/O starved the
transmit queue.

Add a covering index on packets(timestamp, length, payload_length,
transmitted) so these queries run index-only, dropping the read from the
full row heap to just the index range. Verified via EXPLAIN QUERY PLAN
(COVERING INDEX idx_packets_airtime). Additive and idempotent.
2026-07-08 10:13:28 +01:00
agessaman 954150b2d8 merge: reconcile companion cleanup with fix-general-tidy
Merge the maintainer's fix-general-tidy branch (neighbor discovery,
keygen, API endpoints, web-asset rebuild, HTTP server config/control
commands, and an independent #286 room-server push/ACK/guest fix) into
the companion cleanup branch.

Both branches fixed #286 in parallel with byte-identical push-ACK CRC
logic. In the six overlapping files the maintainer's implementation is
kept (ACL replay-detection/session helpers, encoded path-len with legacy
fallback, expected_crc/ack_timeout_s injector API, dispatcher ACK
helpers); this branch's unique companion work is preserved on top
(sender_prefix persistence + migration, boot-state hardening /
CompanionStateLoadError, MessageQueue.max_size, older-core fallbacks).

Conflict resolution took the maintainer's side across the overlap, then
fixed two integration seams the merge introduced and updated this
branch's tests to the maintainer's API:
- room_server: timeout used undefined `hops`; aligned to `path_len`.
- packet_router: PATH helper was invoked twice (maintainer's
  unconditional call plus this branch's conditional local-identity
  call); dropped the now-redundant conditional block.

Pin openhop_core to @dev (was @feature/publish-workflow-message-handling)
so this can merge to the repeater's dev; core dev carries the required
sender_prefix and PathUtils.is_valid_path_len APIs.

Full suite green (1040 passed) against openhop_core dev and
refactor/companion-housekeeping; ruff clean.
2026-07-07 12:56:43 -07:00
agessaman e6d4b68d01 fix: fail companion init loudly when persisted state cannot be loaded
A transient SQLite error during boot made companion_load_channels/
contacts/messages swallow the exception and return [], which is
indistinguishable from "no data". The Public-channel backfill then ran
over the empty store, so clients saw their channels wiped and later
saves could overwrite the persisted state.

- companion_load_{contacts,channels,messages} now return None on error
  vs [] for genuinely empty, and log the companion hash
- add companion_count_{channels,messages} helpers
- extract shared _restore_companion_state used by both the boot and
  hot-reload companion paths; each load is cross-checked against the
  table's row count for the hash, retried once after a short delay,
  and raises CompanionStateLoadError if it still cannot load, aborting
  companion init (and the Public backfill) instead of starting empty
- log restored row counts per companion; log when the channel store
  rejects a persisted channel (unchecked channels.set return)
- trim_companion_contacts_to_fit refuses to trim on a failed load
2026-07-07 07:43:27 -07:00
agessaman fd43d86ea8 fix: persist sender_prefix for signed room posts
TXT_TYPE_SIGNED_PLAIN room posts carry a 4-byte author pubkey prefix
(QueuedMessage.sender_prefix, added in openhop_core). The SQLite
persistence path dropped it, so posts replayed from persistence showed
a zero-padded author prefix in the app frame while posts synced from
the live in-memory queue were correct.

- add sender_prefix column (hex text, default '') to companion_messages
  with an ALTER TABLE migration for existing databases
- store/return the prefix in companion_push/pop/load_messages
- pass sender_prefix when rebuilding QueuedMessage from persistence in
  the frame server and the startup preload paths
- add round-trip, default, migration, and rebuild tests
2026-07-06 22:46:49 -07:00
Rightup 229d71459f fix: improve upsert_client_sync to prevent over write. 2026-07-04 18:41:55 +01:00
Rightup 34747d2610 feat: add packet retrieval by ID endpoint and corresponding database methods 2026-07-02 16:18:54 +01:00
Lloyd 2b67dea96b refactor:rename-project-to-openhop 2026-06-24 23:27:49 +01:00
agessaman 2435757197 feat: enhance SQLiteHandler and StorageCollector for improved caching and async performance
- Added caching for packet type stats and cumulative counts in SQLiteHandler to reduce database load.
- Implemented a dedicated writer thread in StorageCollector to handle blocking storage operations, preventing asyncio event loop stalls.
- Updated record_packet method to utilize the new writer thread for efficient packet processing.
2026-06-18 21:25:19 -07:00
Lloyd 00682e8086 Merge pull request #282 from agessaman/companion/advanced-settings 2026-06-06 18:09:00 +01:00
agessaman dac60443f0 feat(companion): implement contact trimming and retention policies
- Introduced `enforce_companion_contact_capacity` to manage contact limits during companion loading, with an option to trim non-favourite contacts when exceeding capacity.
- Updated `SQLiteHandler` to support message retention limits, allowing for automatic trimming of older messages based on `offline_queue_size`.
- Enhanced API endpoints to handle contact trimming on overflow, providing feedback on trimmed contacts during updates.
- Added utility functions for selecting and trimming contacts while preserving favourites.
- Improved logging for contact management actions and errors related to capacity.
2026-06-05 21:39:11 -07:00
Rightup 14b4804c26 feat: Enhance logging system and introduce policy management endpoints
- Updated LogBuffer to support log entry IDs, enhanced log entry structure with additional metadata, and implemented subscriber management for real-time log streaming.
- Added OpenAPI specifications for new endpoints related to policy management, including retrieval, updating, validation, and group management for network policies.
- Implemented comprehensive tests for new policy endpoints, ensuring correct behavior for creating, updating, validating, and deleting policy groups and entries.
- Introduced policy evaluation tests to validate the functionality of the PolicyEngine, including various scenarios for action decisions based on defined rules.
- Enhanced packet routing tests to ensure proper handling of policy decisions in packet processing.
2026-06-04 15:53:17 +01:00
agessaman 499f871262 Merge upstream/dev into companion/advanced-settings
Integrate latest dev while preserving per-companion bridge settings
and contact capacity validation. Resolve import conflicts in main.py
and api_endpoints.py.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-02 15:34:52 -07:00
Adam Gessaman 7d57b34a04 feat(companion): enhance contact capacity management and bridge settings
- Introduced `CompanionContactCapacityError` to handle cases where persisted contacts exceed configured limits.
- Added utility functions for parsing companion bridge settings and validating contact capacity.
- Updated `RepeaterDaemon` to check contact capacity during companion loading and initialization.
- Enhanced API endpoints to validate companion settings and manage contact limits effectively.
- Implemented logging for bridge limits and errors related to contact capacity.
2026-06-02 07:42:40 -07:00
Rightup 60ca184dbd refactor: enhance security comments and error handling across multiple modules 2026-05-27 22:07:34 +01:00
Lloyd 45a44eb47b Refactor test cases and base code for consistency and readability
- Updated byte representations in tests to use lowercase hex format for consistency.
- Reformatted code for better readability, including line breaks and indentation adjustments.
- Consolidated multiple lines into single lines where appropriate to enhance clarity.
- Ensured that all test cases maintain consistent formatting and style across the test suite.
2026-05-27 20:15:10 +01:00
Lloyd 62f35c4b45 fix: update transport key generation to use 16-byte length and add corresponding test 2026-05-27 14:27:59 +01:00
Lloyd 941c355deb feat: add pagination support and count retrieval for adverts by contact type 2026-05-11 13:54:55 +01:00
TJ Downes 3397d972ce perf: thread-local SQLite connections, synchronous=NORMAL, dedup indexes
Five targeted changes to sqlite_handler.py, all in the same file.

1. Thread-local persistent connections
   _connect() previously opened a new sqlite3.connect() on every DB call and
   ran journal_mode + busy_timeout PRAGMAs each time.  On SD-card storage each
   connection open involves file-system operations; each PRAGMA is a round-trip.
   threading.local() now caches one connection per thread (write executor thread
   + event-loop/HTTP threads), eliminating per-call setup overhead.

2. PRAGMA synchronous=NORMAL
   Default synchronous=FULL flushes WAL frames to disk after every transaction.
   NORMAL flushes only at WAL checkpoints — safe for this workload (no data loss
   beyond the current transaction on power failure) and significantly faster on
   SD cards, which have slow fsync (5-20ms per flush).

3. Migration 8: UNIQUE index on companion_messages(companion_hash, packet_hash)
   companion_push_message previously deduped via SELECT + INSERT (two statements,
   two SD-card reads per message).  The new UNIQUE index enables INSERT OR IGNORE,
   replacing the round-trip with a single atomic statement.

4. Migration 9: UNIQUE index on adverts(pubkey)
   Without this index store_advert's ON CONFLICT clause cannot fire and each
   advert inserts a new row instead of updating the existing one — unbounded
   table growth on busy meshes.  The migration deduplicates existing rows
   (keeping the most-recently-seen per pubkey) before adding the index.

5. Remove duplicate get_unsynced_count definition
   The method was defined twice with the same signature.  Python silently uses
   the last definition; the first was dead code with reversed SQL parameter
   binding order.  Removed the first; added a note to the surviving definition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-21 19:41:50 -07:00
Lloyd be56e919fd feat: add server-side airtime bucket aggregation for optimized chart rendering 2026-04-21 14:46:30 +01:00
Lloyd 3df4b03fd9 feat: implement deferred network publishing for packets, adverts, and noise floor records 2026-04-21 09:49:12 +01:00
Lloyd c5fd41f28a feat: enhance task management in handlers with tracking and error logging 2026-04-21 09:38:03 +01:00
Lloyd 1883bc47be refactor: centralize database connection handling with WAL mode and busy timeout 2026-04-20 16:17:34 +01:00
Lloyd 5eb1fc47ca feat: add memory_debug endpoint for memory leak diagnostics and improve SSL context handling for GitHub requests 2026-04-20 14:51:48 +01:00
Rightup ffaaa76ea0 feat: add glass to repeater. 2026-04-17 23:51:04 +01:00
Lloyd 110d7c2aec feat: add airtime data retrieval functionality with API endpoint 2026-04-11 20:42:04 +01:00
Lloyd f5dbd83cda feat: add backup and restore and DB man 2026-03-27 11:15:53 +00:00
agessaman 9326868f6e Implement contact import functionality for companions
- Added `companion_import_repeater_contacts` method in `SQLiteHandler` to import repeater adverts into a companion's contact store, with options for filtering by contact types, last seen hours, and import limits.
- Introduced `_get_sqlite_handler` method in `CompanionAPIEndpoints` to ensure the SQLite handler is available for contact import operations.
- Created `import_repeater_contacts` endpoint to handle POST requests for importing contacts, validating input parameters, and returning the count of successfully imported contacts.
- Updated the frontend to reflect changes in the contact import process, ensuring a seamless user experience.
2026-03-12 15:39:04 -07:00
agessaman c150b9a9bf Merge upstream/feat/newRadios into dev-companion-v2-cleanup
- Keep our Vite-built assets and index.html script (index-DyUIpN7m.js)
- Remove upstream-only asset chunks and RoomServers-BxQ-0q-x.js
- README: keep two-backend intro, add upstream CAUTION/compatibility table
- manage.sh: keep dialog/gauge UX and .[hardware]; add CH341 udev, sudoers, libusb, polkit, silent upgrade
- sqlite_handler: add crc_errors table, index, and cleanup from upstream
- engine: add validate_packet and mark_seen in direct_forward; keep our path hash_size/hop_count logic
- advert: keep comment, use current_time = now
- api_endpoints: use restart_service() from service_utils
- config merge: strip user config comments before yq merge (upstream)

Made-with: Cursor
2026-03-05 16:43:14 -08:00
agessaman 1fbd99d52c Add JSON serialization support for companion preferences
- Introduced a new utility function, _to_json_safe, to ensure companion preferences are JSON-serializable, handling various data types including enums and dataclasses.
- Updated the RepeaterCompanionBridge to use the new serialization method when saving preferences to SQLite.
- Modified SQLiteHandler to ensure companion_hash is consistently converted to a string before database operations.
- Enhanced error handling for preference persistence in the RepeaterCompanionBridge.
2026-03-03 16:20:52 -08:00
agessaman 4f94b343cc Modify CompanionBridge integration to support persisting NodePrefs
- Added new methods to SQLiteHandler for loading and saving companion preferences as JSON, improving data persistence.
- Introduced a migration to create a companion_prefs table for storing preferences, ensuring compatibility with existing data.
- Refactored main.py to utilize RepeaterCompanionBridge instead of CompanionBridge, aligning with the new architecture.
2026-03-02 21:28:15 -08:00
Lloyd 4a05e20172 Add CRC error tracking and API endpoints for error count and history
- Create a new table for storing CRC errors in SQLite.
- Implement methods to store and retrieve CRC error counts and history.
- Update StorageCollector to record CRC errors and expose relevant methods.
- Enhance RepeaterHandler to track and record CRC error deltas from the radio hardware.
- Add API endpoints to fetch CRC error count and history.
2026-03-02 12:36:08 +00:00
agessaman d82ebc59b0 Normalize companion_hash format in SQLite migrations to include 0x prefix
- Updated the SQLiteHandler to apply a migration that prefixes companion_hash values with '0x' for consistency with room_hash patterns.
- Adjusted the main.py file to reflect the new formatting for companion_hash when generating its string representation.
2026-02-28 09:06:24 -08:00
agessaman 6fa85a832f Update packet type labels in rrdtool_handler and sqlite_handler for consistency
- Enhanced readability by adding descriptive suffixes to packet type labels in both rrdtool_handler.py and sqlite_handler.py.
- Aligned packet type definitions with the new naming conventions from pyMC_core, ensuring consistency across the codebase.
2026-02-27 21:18:29 -08:00
agessaman 789a2f27ea Enhance PacketRouter and CompanionFrameServer for improved packet delivery and contact persistence
- Updated PacketRouter to deliver packets to all companion bridges when the destination is not recognized, ensuring better handling of ephemeral destinations.
- Refactored CompanionFrameServer to separate contact serialization and persistence logic, allowing for non-blocking database operations.
- Introduced a unique index for companion contacts in SQLite to support upsert functionality, enhancing data integrity and performance.
- Improved AdvertHelper to run database operations in a separate thread, preventing event loop blocking and maintaining responsiveness.
2026-02-24 21:51:56 -08:00
agessaman c2f8a2e3cd refactor: companion FrameServer and related (substantive only, no Black)
Reapply refactor from ce8381a (replace monolithic FrameServer with thin
pymc_core subclass, re-export constants, SQLite persistence hooks) while
preserving pre-refactor whitespace where patch applied cleanly. Remaining
files match refactor commit exactly. Diff vs ce8381a is whitespace-only.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-21 15:35:47 -08:00
agessaman d5cabe831c Fix message persistence and deduplication in CompanionFrameServer
- Updated `_persist_companion_message` to clarify deduplication of messages in SQLite.
- Modified `on_message_received` and `on_channel_message_received` to include `packet_hash` for message identification.
- Enhanced `SQLiteHandler` to support deduplication by `packet_hash` when pushing messages, preventing duplicates in the database.
- Added `packet_hash` column to the `companion_messages` table and created an index for efficient lookups.
2026-02-14 20:53:25 -08:00
agessaman 15299bf374 Add companion module and API integration
- Add repeater/companion with frame server and constants
- Extend config, sqlite_handler, mesh_cli, packet_router for companion
- Update api_endpoints and auth_endpoints; adjust main entry

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-13 16:07:43 -08:00
Lloyd b0e19b13af Add bulk packet retrieval API with gzip compression and pagination support. 2026-02-03 10:21:59 +00:00
Lloyd 599e4628d9 Changes include:
Features

Neighbour details modal with full info and map view

WebSocket support with heartbeat and automatic reconnection

Improved signal quality calculations (SNR-based RSSI)

Route-based pagination for faster initial loads

UI

Mobile sidebar tweaks (logout, version info, lazy-loaded charts)

Sorting added to the neighbour table

Packet view now shows multi-hop paths

CAD calibration charts respect light/dark themes

Statistics charts now show the full requested time range

Performance

Reduced polling when WebSocket is active

Lazy loading for heavier components

Noise floor data capped to keep charts responsive

Technical

Improved type safety across API responses

Contrast improvements for accessibility

Cleaner WebSocket and MQTT reconnection handling

Additional metrics added to heartbeat stats

Bug fixes

Corrected noise floor history query

Fixed authentication for CAD calibration streams

Nothing major required from users — just update and carry on.
As always, shout if something looks off.
2026-01-18 20:15:50 +00:00
Paul Picazo 9288e070aa fix: Add missing Dict, Any import to sqlite_handler.py 2026-01-03 14:47:37 -08:00
Paul Picazo 942d4dfe28 Enhance advert storage logic: prioritize direct routes and handle zero-hop measurements
Refactor packet processing: use processed_packet for forwarding and drop reason checks

Fix: Update zero-hop determination logic in AdvertHelper

Fix: Clone packet in process_packet to prevent modification of the original

Fix: Import copy module for deep copying of packets in process_packet
2026-01-03 14:35:30 -08:00
Lloyd 7112da98c2 feat: Add authentication endpoints and JWT support
- Implemented JWT authentication with auto-generated secret if not provided.
- Added API token management functionality.
- Created authentication endpoints for login, token refresh, verification, and password change.
- Introduced API documentation endpoints for Swagger UI and OpenAPI spec.
- Enhanced CORS support for API and documentation endpoints.
- Updated OpenAPI specification to include new authentication and system endpoints.
2025-12-30 00:10:48 +00:00
Lloyd 9a56c03ae7 Add LBT metrics to packet storage and logging in RepeaterHandler 2025-12-21 20:41:22 +00:00
Lloyd f5daf41825 MeshCLI and RoomServer initialization with identity and storage handler support; update neighbor listing to filter repeaters and zero hop nodes. 2025-12-20 22:03:02 +00:00
Lloyd 9cd98cd7ad Add room server messaging endpoints and database functions
- Implemented functions to retrieve, post, delete, and clear messages in room servers.
- Added API endpoints for room message retrieval, posting, and management.
- added OpenAPI documentation to include new room server functionalities.
2025-12-18 11:21:38 +00:00
Lloyd 710ee5b666 Implement room server functionality: add database schema, message handling, and client synchronization 2025-12-18 10:44:00 +00:00