Commit Graph

485 Commits

Author SHA1 Message Date
MarekWo
2c73e20775 fix(backup): use DB filename as backup prefix instead of hardcoded 'mc-webui'
Backup filenames now derive from the active DB stem (e.g. mc_9cebbd27.2026-03-24.db).
Listing and cleanup glob *.db so existing mc-webui.* backups remain visible.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 08:42:31 +01:00
MarekWo
f9bcbabb86 fix: use Flask current_app for DB access in read_status and contacts_cache
'from app.main import db' gets None because python -m app.main loads the
module as __main__, creating a separate module instance from app.main.
Use current_app.db (Flask app context) instead — same pattern as api.py.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 08:26:07 +01:00
MarekWo
5ccd882c5a refactor: eliminate JSONL companion files, delegate to DB
Remove contacts_cache.jsonl and adverts.jsonl file I/O — all contact
data is already in the SQLite contacts/advertisements tables. Clean up
stale JSONL files (acks, echoes, path, dm_sent) at startup.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 08:16:41 +01:00
MarekWo
2a9f90c01d refactor: migrate read_status from JSON file to SQLite database
Replace file-based .read_status.json with DB-backed read_status table.
One-time migration imports existing data at startup. The read_status.py
module keeps the same public API so route handlers need no changes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 08:13:26 +01:00
MarekWo
acfa5d3550 refactor: use public key prefix for DB filename instead of device name
DB filename changes from {device_name}.db to mc_{pubkey[:8]}.db,
making it stable across device renames and preparing for multi-device support.
Existing databases are auto-migrated at startup by probing the device table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 08:11:20 +01:00
MarekWo
92a88cae22 fix: persist channel secrets to DB at startup for pkt_payload computation
_load_channel_secrets() cached secrets in memory only. After dfc3b14
switched /api/messages to use DB channels instead of device calls,
the empty channels table caused Route info and Analyzer links to
disappear from message bubbles.

Now upserts each channel (name + secret) to DB during startup so
the API can compute pkt_payload without hitting the device.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:51:34 +01:00
MarekWo
1684f9f3ff fix: disable buggy library auto-reconnect, handle reconnection ourselves
meshcore 2.3.0's ConnectionManager has a bug: when auto-reconnect creates
a new TCP connection, the old connection's connection_lost callback fires,
triggering another reconnect cycle. Since each success resets the attempt
counter, this loops forever (~1 TCP connection/second).

Disabled library auto_reconnect and added reconnection logic to
_on_disconnected() with 3 attempts and increasing backoff (5/10/15s).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:31:45 +01:00
MarekWo
dfc3b1403a fix: prevent page hang when device channel queries block
/api/messages and /api/messages/updates called get_channels_cached()
which blocks on device communication when cache is cold (up to 240s).
Now uses DB-cached channels for pkt_payload computation instead.

Frontend loadMessages() now has a 15s timeout with auto-retry
and clears the loading spinner on error instead of leaving it
spinning indefinitely.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:26:26 +01:00
MarekWo
343b6f40a8 fix(ui): rename 'No Flood' toggle to 'Keep path'
'No Flood' was confusing next to the 'Reset to FLOOD' button.
'Keep path' better describes the behavior: don't auto-reset
the path to FLOOD after failed direct retries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 21:12:31 +01:00
MarekWo
aa2ba0a5c8 fix(dm): prioritize primary (starred) path in retry rotation
PATH_ROTATION now has 3 phases:
1. Exhaust retries on primary path first (initial send + retries_per_path-1)
2. Rotate through remaining non-primary paths
3. Optional FLOOD fallback (if no_auto_flood=False)

Previously, retry iterated all paths in sort_order giving the primary
path only the initial send attempt before switching to the first path
on the list, which was often an older/worse path.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 20:33:36 +01:00
MarekWo
bdcc68513d fix(paths): use library's change_contact_path to avoid negative int error
_change_path_async manually set out_path and out_path_len on the contact
dict then called update_contact(contact) with path=None. This path reads
out_path_hash_mode from the contact dict, which is -1 when the contact
is in flood mode (after reset_path or device read with plen=255).
The encoding then produced: hop_count | (-1 << 6) = negative number,
causing "can't convert negative int to unsigned" in to_bytes().

Fix: use mc.commands.change_contact_path() which properly computes all
fields including out_path_hash_mode, avoiding the negative value issue.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 20:07:35 +01:00
MarekWo
8fd918d39b feat(dm): add DEBUG logging for individual retry attempts
Enables detailed tracking of each DM retry step: send attempt,
ACK wait timeout, and ACK timeout results. device_manager logger
set to DEBUG level so these messages appear in System Log.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 19:42:17 +01:00
MarekWo
23687b2973 fix(paths): use _get_dm() instead of nonexistent cli.get_device_manager()
The reset_flood endpoint was calling cli.get_device_manager() which
doesn't exist. All other endpoints use the local _get_dm() helper.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 10:39:07 +01:00
MarekWo
c82fb9f334 fix(paths): fix reset_flood endpoint error handling and add logging
Endpoint now returns error if device reset fails instead of always
returning success:true. Added logging to both endpoint and
device_manager.reset_path to diagnose reset failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 10:32:56 +01:00
MarekWo
08b972b891 fix(paths): separate Reset to FLOOD from Clear Paths
Reset to FLOOD now only resets the device path without deleting
configured paths from the database. New Clear Paths button deletes
all configured paths from DB without touching the device. This lets
users reset to FLOOD to discover new paths while keeping their
configured alternatives intact.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 10:10:40 +01:00
MarekWo
08ba91b9ba fix(paths): allow non-adjacent duplicate hops for 1-byte paths
For 1B hash size, duplicate repeater IDs are valid as long as they
don't appear consecutively (e.g. AA->BB->CC->AA->EE works fine).
For 2B/3B, duplicates remain fully blocked. Applied to all three
input methods: list picker, map picker, and manual entry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 09:38:29 +01:00
MarekWo
ba26b3dc3a fix(paths): prevent duplicate repeater IDs in path
Blocks adding the same hop prefix twice via all three methods:
- List picker: shows warning notification, ignores click
- Map picker: shows warning notification, keeps selection
- Manual entry: validates on Add Path, rejects with error

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 09:19:55 +01:00
MarekWo
796fb917e4 refactor(paths): move Add Path form into its own modal
The path creation form is now a separate modal (z-index 1070) that
opens above Contact Info with its own backdrop, making the UI layers
clearly distinguishable. Map picker modal bumped to z-index 1080 so
it stacks correctly above both Contact Info and Add Path modals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 08:48:38 +01:00
MarekWo
0bca19e936 fix(paths): add backdrop between map picker and Contact Info modal
Raises the z-index of the map modal (1070) and its backdrop (1060)
so the Contact Info modal behind is visually grayed out, making it
clear which modal is active.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 08:38:25 +01:00
MarekWo
a0a957289e feat(paths): keep map picker open after adding repeater
Map modal no longer closes on Add - resets selection instead so user
can pick multiple repeaters in sequence. Cancel button renamed to Close.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 08:23:21 +01:00
MarekWo
bf00e7c7d3 feat(paths): add repeater map picker for path configuration
Adds a map button (geo icon) next to the list picker in the path form.
Clicking it opens a modal with a Leaflet map showing repeater locations.
User clicks a repeater marker, then clicks Add to append its ID prefix
to the path hex. Includes Cached toggle to show all DB repeaters vs
only device-known ones. Respects current hash size setting (1B/2B/3B).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 08:13:20 +01:00
MarekWo
8aff9be570 fix(map): show correct "Last seen" for cached contacts
Used c.last_advert (numeric Unix timestamp) instead of c.last_seen
(ISO 8601 string) which caused formatTimeAgo() to return "Invalid Date".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-23 07:50:46 +01:00
MarekWo
aa1a1b203c feat(paths): add import button for current device path
Shows a download icon next to the device path display in Contact Info.
Clicking it imports the current device path into configured paths as
primary, with hash_size properly decoded from out_path_len.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:51:53 +01:00
MarekWo
b6dc03dce5 feat(paths): add Name/ID search mode toggle in repeater picker
ID mode searches by first N hex chars of public key (2/4/6 chars
depending on selected hash size). Placeholder updates dynamically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:38:41 +01:00
MarekWo
d6b2d01e2c fix(paths): use correct type=2 for repeater contacts
Type 1 is COM (companion), type 2 is REP (repeater).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:25:24 +01:00
MarekWo
8cc67f77d5 feat(dm): add multi-path management and per-contact no-flood toggle
- New `contact_paths` table for storing multiple user-configured paths per contact
- New `no_auto_flood` column on contacts to prevent automatic DIRECT→FLOOD reset
- Path rotation during DM retry: cycles through configured paths before optional flood fallback
- REST API for path CRUD, reorder, reset-to-flood, repeater listing
- Path management UI in Contact Info modal: add/delete/reorder paths, repeater picker with uniqueness warnings, hash size selector (1B/2B/3B)
- "No Flood" per-contact toggle in modal footer

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 21:20:51 +01:00
MarekWo
dd81fbf0b7 fix(console): add min_timeout=15s to binary repeater requests
req_status, req_acl, req_neighbours, req_mma use send_binary_req
which calculates timeout from suggested_timeout/800. After firmware
updates this can be too short, causing instant timeouts. Adding
min_timeout=15 ensures we wait at least 15 seconds for a response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-22 14:01:44 +01:00
MarekWo
88d805dd3a docs: upgrade diagram 2026-03-21 16:37:35 +01:00
MarekWo
66ada3d03c docs: comprehensive documentation update for v2 features
Update all documentation to reflect features added since last doc update:
- README: new features list, gallery screenshots, development status
- User Guide: global search, console commands, device dashboard, settings,
  system log, backup, updated DM and contact management sections
- Architecture: complete API reference, WebSocket namespaces, updated
  project structure and database tables
- Troubleshooting: remove v1 bridge references, add UI-based backup,
  system log references
- Gallery: add 4 new screenshots (search, filtering, settings, system log),
  update 12 existing screenshots

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 16:26:52 +01:00
MarekWo
ce8227247f feat(chat): add quote dialog with configurable quote length
Add Group Chat tab in Settings with configurable quote byte limit.
When quoting a message longer than the limit, a dialog asks whether
to use full or truncated quote (with editable byte count).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 15:25:38 +01:00
MarekWo
33a71bed17 refactor(ui): rename contact type label CLI to COM (companion)
The MeshCore community uses "companion" not "client" for type 1 nodes.
Rename the CLI label to COM across all UI, API, JS, and docs to align
with official terminology. Includes cache migration for old CLI entries.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 14:37:30 +01:00
MarekWo
8ba5381921 fix(settings): add note clarifying retry count includes initial send
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:57:23 +01:00
MarekWo
9e90e30d9f refactor(settings): compact table layout with tooltip info icons
Replace vertical form fields with table rows for less screen space.
Descriptions moved to (i) tooltip icons on hover/touch.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:33:19 +01:00
MarekWo
6f1a5462e9 feat(settings): add Settings modal with configurable DM retry parameters
Replace hardcoded DM retry logic with user-configurable settings stored
in app_settings DB. Settings modal opens from menu with tab-based UI
(ready for future settings tabs). Defaults: 3 direct + 1 flood retries
(was 8+2), 30s/60s intervals, 60s grace period.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:18:03 +01:00
MarekWo
0108ea9149 refactor(menu): reorganize menu into logical sections + larger touch targets
Reorganize menu from 2 sections (Network Commands, Configuration) into 4:
- Messages (top, no header) - daily actions
- Network - advert commands
- Tools - Map, Console
- System - Device Info, System Log, Backup, Settings placeholder

Increase navbar button/select touch targets (min 40px) for mobile usability.
Widen offcanvas menu from 280px to 300px.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 07:55:59 +01:00
MarekWo
c48666843a fix(contacts): show ignored/blocked contacts in All Sources filter
Previously ignored and blocked contacts were hidden from the "All Sources"
view, making them only discoverable via dedicated Ignored/Blocked filters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:22:52 +01:00
MarekWo
a1f2a1c5ef feat: name database file after device name for multi-device support
Database file is now named {device_name}.db (e.g. MarWoj.db) instead of
the generic mc-webui.db. On first boot, mc-webui.db is automatically
renamed once the device name is detected. On subsequent boots, the
existing device-named DB is found by scanning the config directory.

This enables future multi-device support where each MeshCore device
has its own separate database file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 21:07:58 +01:00
MarekWo
ca0ba37be5 fix(logs): open System Log as fullscreen modal like Console
Changed from target="_blank" link to fullscreen modal with iframe,
matching the pattern used by Console, DM, and Contacts modals.
Iframe loads on open and clears on close to manage WebSocket lifecycle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:41:20 +01:00
MarekWo
0110e65b97 feat: add System Log viewer with real-time streaming
In-memory ring buffer (2000 entries) captures all Python log records.
New /logs page streams entries via WebSocket in real-time with:
- Level filter (DEBUG/INFO/WARNING/ERROR)
- Module filter (auto-populated from seen loggers)
- Text search with highlighting
- Auto-scroll with pause/resume
- Dark theme matching Console style

Menu entry added under Configuration section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:34:29 +01:00
MarekWo
4f25d244b1 refactor: migrate .webui_settings.json to database + fix NEW_CONTACT edge case
All settings (protected_contacts, cleanup_settings, retention_settings,
manual_add_contacts) moved from .webui_settings.json file to SQLite database.
Startup migration auto-imports existing file and renames it to .json.bak.

Added safeguard in _on_new_contact: if firmware fires NEW_CONTACT for a
contact already on the device, skip pending and log a warning. Also added
diagnostic logging showing previous DB state (source, protected) when
contacts reappear as pending.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 20:14:15 +01:00
MarekWo
e106b5493b fix(contacts): dynamic list height and tighter card spacing
- Replace fixed calc() heights with flexbox layout so the contact list
  fills all remaining viewport space on any screen size
- Make body/main/container chain flex columns so the list can grow
- Reduce vertical spacing between contact name, public key, and
  last advert rows for more compact cards

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 12:55:33 +01:00
MarekWo
670715f57f fix(contacts): disable ignore/block buttons for protected contacts
- Existing Contacts: Ignore and Block buttons are now disabled when
  contact is protected, matching the existing Delete button behavior
- updateProtectionUI: toggling protection now also enables/disables
  Ignore, Block, and Delete buttons dynamically
- Chat: Ignore and Block buttons are hidden in message bubbles for
  protected contacts (loads protected pubkeys on init)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 09:15:44 +01:00
MarekWo
3337e3fdff feat(contacts): compact pending filters with batch ignore
- Remove redundant 'Contact Types:' label
- Move type badges above search input
- Place search, Approve, and Ignore buttons in single responsive row
- Add tooltip (i) on Filters header with usage hint
- Add batch Ignore button to ignore all filtered pending contacts
- Remove duplicate filtered count badge from Approve button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 08:30:32 +01:00
MarekWo
39a0e944a7 fix(console): correct trace display order
SNR precedes the hop hash: 12.50 > [5e]12.25 > [d1]-8.25 > [e7]-3.00
(each SNR shows link quality, hash shows the next relay node)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:29:53 +01:00
MarekWo
4b4e71f5bd fix(console): correct trace output format
Format: 12.50 > [5e]12.25 > [d1]-8.25 > [e7]-3.00
(SNR first, then each hop shows [hash]SNR)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:17:40 +01:00
MarekWo
20924d134d fix(console): trace path support, stats field names, self_telemetry format
- trace: accepts comma-separated hex path (e.g. "trace 5e,d1,e7"),
  waits for TRACE_DATA response with proper timeout from device
- stats: fix field names (uptime_secs, queue_len, battery_mv, etc.),
  show all radio/packet stats with detail breakdown
- self_telemetry: format LPP sensor data nicely instead of raw dict

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 17:03:35 +01:00
MarekWo
019d351ab7 fix(console): req_regions and req_owner output formatting
- req_regions: library returns string, not dict — was crashing
  with "'str' object has no attribute 'items'"
- req_owner: format like meshcore-cli ("X is owned by Y")

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 16:17:42 +01:00
MarekWo
3057882f20 fix(console): get/set help formatting, fix get path_hash_mode
- get help / set help: detailed parameter descriptions with
  explanations, matching meshcore-cli style
- get path_hash_mode: library returns int not Event, fixed check
- set help: now reachable (was behind len(args)>=3 guard)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 13:42:31 +01:00
MarekWo
5a4c259c0b fix(console): ver command now queries firmware info properly
Was using self_info (which has no firmware data). Now uses
send_device_query() like meshcore-cli, showing model, version,
build date and repeat mode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 13:23:56 +01:00
MarekWo
3acdc7a402 feat(console): fix req_clock format, add req_neighbours command
- req_clock: parse timestamp from binary hex data (little-endian)
  and display as human-readable datetime, matching meshcore-cli
- req_neighbours: new command that fetches neighbour list from
  repeater with formatted output (name resolution from device
  contacts and DB cache, time ago, SNR)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 12:25:28 +01:00