Commit Graph

27 Commits

Author SHA1 Message Date
MarekWo d6a7354f06 fix(channels): use device-reported max_channels instead of hardcoded 8
Firmware reports MAX_GROUP_CHANNELS (typically 40 for companion builds)
in the DEVICE_INFO response. Fetch it at startup and use it in all
channel iteration loops. Previously hardcoded range(8) prevented
channels 8+ from appearing and blocked adding new channels.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:38:15 +01:00
MarekWo 9b206beeac fix(echo): validate channel hash before correlating echo with sent message
Pending echo correlation was assigning ANY first echo to the sent message,
even if it came from a different channel. This caused cross-channel mismatches
(e.g., Public channel echo assigned to #krakow message).

Fix: check that pkt_payload's first byte (channel_hash = sha256(secret)[0])
matches the channel we sent on before accepting correlation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 20:18:32 +01:00
MarekWo ba990b155f fix(ui): fix leading pipe separator when SNR is missing from message
Use array-based metaParts.join(' | ') instead of string concatenation
to avoid ugly leading "| Hops: 0" when meshcore lib doesn't provide SNR.
Also revert temporary INFO-level debug logging back to DEBUG.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:19:09 +01:00
MarekWo 7bcd6bd216 debug: add INFO logging for RX_LOG_DATA events and subscriptions 2026-03-02 16:56:43 +01:00
MarekWo 9f249a4521 feat(echoes): add RX_LOG_DATA echo tracking + sent message pkt_payload correlation
- Subscribe to RX_LOG_DATA events to capture repeated radio packets
- Parse GRP_TXT (0x05) payload to extract pkt_payload and path
- Classify echoes as sent (pending echo correlation) or incoming
- Register pending echo when sending channel messages for pkt_payload capture
- Add update_message_pkt_payload() DB method for sent message correlation
- Return echo_paths/echo_snrs for ALL messages (not just own) in GET /messages
- Frontend: build paths from echo_paths for incoming message route display
- Emit SocketIO 'echo' event for real-time badge updates

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 16:53:12 +01:00
MarekWo 2a3a00e654 fix(contacts): refresh contacts on unknown advert + cleanup fixes
When an ADVERTISEMENT arrives for a pubkey not in mc.contacts, the
firmware has auto-added a new contact. Trigger ensure_contacts() to
refresh the contact list and get the name. Also: remove contacts from
mc.contacts cache on delete, add reject/clear pending API endpoints,
promote advert logging to INFO level.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:30:07 +01:00
MarekWo 37694dde09 fix(contacts): remove from pending list after approve + add reject/clear
approve_contact now removes the contact from mc.pending_contacts after
successful approval. Added reject_contact (remove without adding) and
clear_pending_contacts methods with API endpoints.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 08:14:10 +01:00
MarekWo 2c547ee1fc fix(perf): disable auto_update_contacts to prevent serial blocking
auto_update_contacts=True triggers ensure_contacts() on every
ADVERTISEMENT event, fetching 324+ contacts over serial (several seconds).
This blocks the serial port and delays MESSAGES_WAITING processing,
causing 10-30s message reception delays. Contacts are synced at startup
and updated individually via NEW_CONTACT events.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:48:08 +01:00
MarekWo 63f2473933 fix(contacts): respect manual approval setting in NEW_CONTACT handler
When manual approval is enabled in settings, _on_new_contact now skips
DB upsert and emits SocketIO event for pending contacts. When auto mode
is on, contacts are added to DB immediately as before. Also enriched
approve_contact and get_pending_contacts with full contact data.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:45:44 +01:00
MarekWo 499759931c feat(analyzer): compute pkt_payload from channel secrets for Analyzer URLs
meshcore v2 doesn't provide pkt_payload in events, so compute it
lazily in the API from channel secrets + message data. Analyzer URLs
now appear for ALL messages (own and incoming), not just own.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 07:38:44 +01:00
MarekWo e37ab4243c Revert "fix(contacts): respect manual approval + fix message delay"
This reverts commit 6bb985f9c4.
2026-03-01 21:57:37 +01:00
MarekWo 6bb985f9c4 fix(contacts): respect manual approval + fix message delay
1. Manual approval: _on_new_contact now checks self_info
   manual_add_contacts flag. When enabled, new contacts stay in
   mc.pending_contacts for UI approval instead of auto-adding to DB.

2. Message delay: disable auto_update_contacts which was triggering
   full contact list refresh (270+ records over serial) on every
   ADVERTISEMENT event, blocking message reception for seconds.
   Contact names for adverts are looked up from cached mc.contacts.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:46:08 +01:00
MarekWo db5aac084c fix(adverts): fix empty names + enable auto_update_contacts
- ADVERTISEMENT events only contain public_key — look up name/type/lat/lon
  from mc.contacts instead of the empty payload
- Enable mc.auto_update_contacts so meshcore refreshes contacts after adverts
- Fix NEW_CONTACT handler to store lat/lon/last_advert (was only storing
  name and type)
- Fix type field: NEW_CONTACT uses 'type' not 'adv_type'
- Graceful handling of set_manual_add_contacts firmware incompatibility

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 21:02:49 +01:00
MarekWo 1df8fa03f9 debug: add ADVERT/NEW_CONTACT payload logging 2026-03-01 18:42:29 +01:00
MarekWo ebfe383190 feat(v2): Add SocketIO real-time push for DM page
- Add SocketIO /chat client to dm.js for real-time DM and ACK updates
- Listen for new_message (dm), ack, device_status events
- Remove 5x cascading refresh after send (replaced by SocketIO ACK)
- Reduce polling interval from 10s to 60s (fallback only)
- Add data-ack attribute to status icons for real-time ACK updates
- Enrich ACK emission with snr/rssi/route_type (device_manager.py)
- Include socket.io.min.js in dm.html template

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 17:19:54 +01:00
MarekWo 3e81eeeae7 fix(v2): Fix last_advert timestamps and DM placeholder display
- Sync last_advert from device contacts as Unix timestamp (was missing)
- Convert _on_advertisement to store Unix timestamp (was ISO string)
- Add _parse_last_advert() to handle both ISO and Unix formats in API
- Truncate full pubkey to short prefix in DM placeholder and dropdown

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 16:23:45 +01:00
MarekWo c20e7c20ad fix(v2): Fix DM contact names showing as pubkey prefix
- DM handler: don't overwrite contact name with prefix when name unknown
- Migration: upsert contact with sender name from v1 PRIV entries
- Fixes conversations showing "4e45565e" instead of "demo mc-webui"

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:58:15 +01:00
MarekWo 4b463fecfa fix(v2): Resolve DM sender pubkey prefix to full key from contacts
Incoming DM events only contain a short pubkey_prefix. Now resolves it
to the full public_key via mc.get_contact_by_key_prefix() so incoming
and outgoing messages end up in the same conversation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:46:10 +01:00
MarekWo 95dcf38d06 fix(v2): Handle bytes expected_ack from meshcore + DM prefix matching
- Convert bytes to hex string for expected_ack and pkt_payload via _to_str()
- Support pubkey prefix matching in get_dm_messages() (LIKE for short keys)
- Fixes "Object of type bytes is not JSON serializable" error on DM view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 13:36:37 +01:00
MarekWo 64860ba178 fix(v2): Parse sender name from channel message text format
Channel messages from meshcore arrive as "SenderName: message text".
The library doesn't provide sender name separately. Now parsing it
from the text (split on first colon), matching v1 parser behavior.

Also:
- Look up DM sender names from mc.contacts instead of event payload
- Fix SNR field name (uppercase 'SNR' from meshcore library)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:10:13 +01:00
MarekWo 65eb44d0ff fix(v2): Use event.payload instead of event.data throughout
The meshcore Event class has 'payload' not 'data'. All event handlers
were silently getting empty dicts, causing:
- Channel messages showing 'Unknown' sender
- Channel info not returning name/secret
- Sent message event data being lost

Also normalizes channel_name/channel_secret keys from CHANNEL_INFO
events and converts secret bytes to hex string.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 11:01:42 +01:00
MarekWo a7b9b74fa2 fix(v2): Use mc.commands for meshcore command methods
MeshCore library exposes command methods (get_channel, send_msg,
send_advert, etc.) on mc.commands, not directly on the MeshCore
instance. Updated all DeviceManager calls accordingly.

Fixes: channels not loading, message sending, advert, battery, etc.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:49:04 +01:00
MarekWo adf17d2d54 fix(v2): Add connection retry logic and self_info null guard
- Add _connect_with_retry() with exponential backoff (10 attempts)
- Guard against self_info being None after meshcore library disconnects
  due to unresponsive device
- Prevents crash when device is busy (e.g. held by orphan container)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:23:05 +01:00
MarekWo 2e95bbf9b5 fix(v2): Serial port auto-detection and channel_messages query
- Add _detect_serial_port() to DeviceManager — resolves 'auto' to
  actual device via /dev/serial/by-id with common path fallbacks
- Make channel_idx optional in get_channel_messages() so status and
  channel-updates endpoints can query across all channels

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:15:44 +01:00
MarekWo e98acf6afa feat(v2): Add pkt_payload to DMs, update watchdog for single container
- Add pkt_payload column to direct_messages table for stable packet
  hash generation and Analyzer URL linking
- Update insert_direct_message() and DeviceManager to store pkt_payload
- Add test for DM pkt_payload storage (43 tests pass)
- Update watchdog to monitor only mc-webui (meshcore-bridge removed)
- USB reset trigger now fires for mc-webui container failures

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 10:01:43 +01:00
MarekWo a8a0becb13 feat(v2): Complete DeviceManager with event handlers and commands
Event handlers: channel messages, DMs, ACKs, adverts, path updates,
new contacts, disconnection — all write to Database + emit SocketIO.
Command methods: send_channel_message, send_dm, get/delete contacts,
get/set/remove channels, send_advert, check_connection, battery,
manual_add_contacts, pending contacts approval.
Auto message fetching and initial contact sync on connect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 07:21:25 +01:00
MarekWo c9cf37e8d5 feat(v2): Add DeviceManager skeleton with connect/disconnect
Background thread runs meshcore async event loop. Supports both
serial and TCP transports. Flask routes bridge sync→async via
execute() method. Event subscriptions marked as TODO for Phase 1.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 07:01:16 +01:00