Commit Graph
7 Commits
Author SHA1 Message Date
pe1hvh 4abcb97fbc fix(worker): run repeater poll as cancellable background task WHAT Run _poll_repeaters() as an asyncio.Task instead of awaiting it in _main_loop(). The task is cancelled as soon as has_pending_commands() reports queued work, and a new poll is only started when the queue is empty. RepeaterPoller.poll_due() catches the CancelledError, resets the repeater's _next_due to now and re-raises, so a cancelled poll writes no archive record and is retried on the next tick. Adds SharedData.has_pending_commands() with its SharedDataWriter protocol entry, and REPEATER_POLL_CANCEL_TIMEOUT (default 5.0) to bound the logout cleanup of a cancelled poll. Corrects the comment on REPEATER_POLL_MAX_ATTEMPTS, which still claimed a poll blocks the loop. WHY _main_loop() awaited the poll in the same iteration as process_all(), so a repeater poll blocked command dispatch for its full duration.
fix(worker): run repeater poll as cancellable background task

WHAT
Run _poll_repeaters() as an asyncio.Task instead of awaiting it in
_main_loop(). The task is cancelled as soon as has_pending_commands()
reports queued work, and a new poll is only started when the queue is
empty. RepeaterPoller.poll_due() catches the CancelledError, resets the
repeater's _next_due to now and re-raises, so a cancelled poll writes no
archive record and is retried on the next tick.

Adds SharedData.has_pending_commands() with its SharedDataWriter protocol
entry, and REPEATER_POLL_CANCEL_TIMEOUT (default 5.0) to bound the logout
cleanup of a cancelled poll. Corrects the comment on
REPEATER_POLL_MAX_ATTEMPTS, which still claimed a poll blocks the loop.

WHY
_main_loop() awaited the poll in the same iteration as process_all(), so
a repeater poll blocked command dispatch for its full duration. With the
1.24.2 defaults an unreachable repeater occupies 5 x 30 s login timeout
plus 4 x 5 s retry delay, roughly 190 s. A bot reply queued in that
window was only transmitted once the poll gave up, and a restart within
the window discarded it because the command queue lives in memory.
Confirmed in journal meshcore-gui-ttyUSB1.service of 2026-09-06: replies
queued at 09:33:46 and 09:35:23 were both sent at 09:36:25, the second
the poll ran out of attempts.

Statistics collection has no deadline; a bot reply does. Shortening the
retry budget would only shorten the window, not remove it.

NOTES
No breaking changes. has_pending_commands() is additive. Archive schema
unchanged, but no record is written for a cancelled poll, so the number
of polls per day can be lower than the interval suggests. A repeater on a
busy channel may go longer without a measurement — the intended trade-off.

Bumps version to 1.24.3.
2026-09-06 10:09:19 +02:00
pe1hvh af74caf766 fix(route): default reply channel to message channel, add date to timestamps
WHAT
- route_page: _default_reply_channel() derives the reply select default
  from msg.channel instead of the first entry in the channel list
- models: new Message.date field, now_date() and display_timestamp();
  format_line() and incoming()/outgoing() use them
- message_archive: persist "date" alongside "time" and "timestamp_utc"
- room_server_panel + route_page info header use display_timestamp()
- VERSION 1.22.2 -> 1.22.3

WHY
The route page exists to show one specific message, so that message —
not the ordering of the channel list — is the correct source for the
reply default. The date could not be fixed at the render site because
Message had no date at all: now_timestamp() yields HH:MM:SS and the
date lived only as timestamp_utc inside the archive layer, unread by
from_dict(). A first-class field plus a single formatting helper fixes
the cause and keeps the format in one place.

NOTES
No breaking changes. The archive schema gains one additive field;
pre-1.22.3 entries have their date derived from timestamp_utc
(converted to local time) and fall back to time-only when absent.
Message.incoming() gained an optional keyword-only date parameter.
Message display lines are ~11 characters wider.
2026-08-16 08:32:24 +02:00
pe1hvh 8080bcc203 fix: Multibyte path hash support
### FIXED
- **Multibyte path hash support** (`ble/events.py`, `core/shared_data.py`):
  corrected docstrings in both `_resolve_path_names` methods that incorrectly
  described path hashes as "2-char hex strings". The actual contact lookup
  uses `startswith` matching, which is hash-size agnostic and correctly
  handles 1-byte (2 hex chars), 2-byte (4 hex chars) and 3-byte (6 hex chars)
  path hashes as introduced in MeshCore firmware v1.14.0. No functional code
  was changed — only the documentation was incorrect.
- **MariaDB schema** (`meshcore_schema.sql`): `meshcore_messages.path_hashes`
  column widened from `VARCHAR(128)` to `VARCHAR(255)`. The old limit caused
  silent truncation for paths longer than ~40 hops in 1-byte mode or ~25 hops
  in 2-byte mode. Migration is backward-compatible; existing data is unchanged.

### CHANGED
- `config.py`: version bump `1.17.0 → 1.17.1`.

### RATIONALE
- MeshCore firmware v1.14.0 (2026-03-06) introduced configurable path hash
  sizes (1-, 2- or 3-byte per repeater). Verification confirmed that
  `meshcoredecoder 0.3.2` already returns correctly sized hex strings via
  `_decode_path_len_byte`. The GUI path-resolution logic was already
  forward-compatible; only the docstrings and the MariaDB column width required
  correction.

### IMPACT
- No BLE handler, GUI panel, service or API endpoint modified.
- `meshcoredecoder` library unchanged; no pip update required.
- MariaDB migration: single `ALTER TABLE` statement, no downtime, no data loss.
2026-04-04 22:59:44 +02:00
pe1hvh 3e7b44f8ad HotFix5 2026-03-12 21:30:44 +01:00
pe1hvh a8e148f1a6 HotFix3 2026-03-12 21:19:40 +01:00
pe1hvh 8774f6c036 Update shared_data.py 2026-03-12 20:24:48 +01:00
pe1hvh d8a7947c6b Initial clean code 2026-03-09 17:53:29 +01:00