fix(bot,ui): defer bot actions past throttle, fix CardKB lock bypass, add !gps fix timeout arg

- Bot Actions (!buzz/!gps/!advert/!gpio1-4) ran their side effect
  immediately during botScanCommands(), before quiet-hours/cooldown/
  per-contact throttle were checked -- those gates only suppressed the
  reply text, not the actual buzz/GPS toggle/advert/pin write. botCommandReply()
  now only records what was requested; applyPendingBotActions() runs the
  deferred effects once a wrapper's throttle checks pass and the ack sent,
  mirroring the existing _locfix_requested pattern. resetPendingBotActions()
  clears everything on every throttled/aborted path.

- CardKB's Fn+<letter> accent-popup shortcut bypassed the locked-input gate
  (it called into KeyboardWidget directly instead of through the
  enqueueKey()/dequeue path every other key uses, so it wasn't discarded
  while _locked). Now checks _locked itself.

- Since a locked device now correctly ignores CardKB entirely, Fn+Esc
  (single press) is added as CardKB's own lock/unlock gesture -- otherwise
  a CardKB-only setup had no way to unlock. Esc rather than the adjacent
  Fn+Backspace, to avoid an accidental press.

- botScanCommands() now parses up to two arguments per command instead of
  one. Used by "!gps fix [seconds]" to override the default 90s timeout
  (clamped 15-300s) for a poor sky view where 90s isn't always enough to
  reach isLocFixReady()'s HDOP/satellite bar.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Jakub
2026-07-24 23:51:31 +02:00
parent 7b6ae8e2cb
commit 0a61b7ef15
7 changed files with 173 additions and 41 deletions

View File

@@ -16,15 +16,17 @@ Screen lock prevents accidental keypresses. While locked the display turns off a
**Hold Back** and press **Enter** three times within 3 seconds. The sequence works in both directions — the same combination locks and unlocks.
If the display is off when the sequence begins, it turns on automatically so the hint is visible. Each press in the sequence extends the display-on timer by 5 seconds.
On boards with an optional CardKB (I2C keyboard) attached, a single **Fn+Esc** does the same thing, in either direction — no repetition needed, since Fn+Esc is already a deliberate two-key combo. Esc rather than the adjacent Backspace, since Fn and Backspace sit right next to each other on CardKB's layout and would be too easy to hit by accident.
The hint popup at the bottom of the lock screen guides through the sequence:
If the display is off when the sequence begins, it turns on automatically so the hint is visible. Each press in the physical sequence extends the display-on timer by 5 seconds.
| Step | Hint |
| -------------- | --------------------- |
| Not started | _Hold Back + 3×Enter_ |
| 1 press done | _Enter ×2 more…_ |
| 2 presses done | _Enter ×1 more…_ |
The hint popup at the bottom of the lock screen guides through the physical sequence:
| Step | Hint |
| -------------- | ------------------------------------------------------------ |
| Not started | _Hold Back + 3×Enter_ (_Back+3xEnter/Fn+Esc_ with CardKB attached) |
| 1 press done | _Enter ×2 more…_ |
| 2 presses done | _Enter ×1 more…_ |
If no press is made for 3 seconds, the counter resets.

View File

@@ -451,7 +451,7 @@ A separate **Actions** toggle, nested under Commands (Commands must be ON for Ac
| ----------------- | -------------------------------------------------------------------- |
| `!buzz [seconds]` | Sounds the buzzer as a find-me signal — default 5s, capped at 30s. Sounds even if the buzzer is muted in Settings (that's the point of a find-me signal). |
| `!gps on` / `!gps off` | Enables/disables GPS, same effect as the Home page's GPS toggle. |
| `!gps fix` | Single-shot location: turns GPS on if it wasn't already, waits for a stabilised fix (HDOP ≤ 2.0, or ≥8 satellites on GPS hardware that doesn't report HDOP, averaged over 10s), sends the position, then restores GPS to whatever state it was in before. Replies in two parts — an immediate `GPS: acquiring fix...` ack, then the position (or `GPS: no fix (timeout)` / a partial fix) as a follow-up message up to 90s later. Only one `!gps fix` can be in flight at a time; a second one gets `GPS: fix already pending`. |
| `!gps fix [seconds]` | Single-shot location: turns GPS on if it wasn't already, waits for a stabilised fix (HDOP ≤ 2.0, or ≥8 satellites on GPS hardware that doesn't report HDOP, averaged over 10s), sends the position, then restores GPS to whatever state it was in before. Replies in two parts — an immediate `GPS: acquiring fix...` ack, then the position (or `GPS: no fix (timeout)` / a partial fix) as a follow-up message up to `seconds` later (default 90s, clamped to 15-300s) — raise it under poor sky view, where 90s isn't always enough to reach the HDOP/satellite bar. Only one `!gps fix` can be in flight at a time; a second one gets `GPS: fix already pending`. |
| `!advert` | Sends an advert immediately, same as the Home page's manual advert action. |
Actions combine with Commands and each other in one message the same way — `!batt !gps on` answers with `4.10V | GPS: on` in a single reply. With Actions OFF for a target, `!buzz`/`!gps`/`!gps fix`/`!advert` are silently ignored (no reply, no effect) exactly like any other unrecognised command, and `!help`'s reply doesn't mention them.