Commit Graph

11 Commits

Author SHA1 Message Date
Jakub
bf724ce692 perf(bot): lower body once and strstr instead of O(n*m) per-offset tolower
For a 140-byte channel msg with a 64-byte trigger, the old loop did
~8960 tolower() calls per inbound message; now it's 140 tolower calls
plus one strstr.

perf(buzzer): skip nRF52 STOPPED wait when PWM was not running

TASKS_STOP on a disabled PWM never fires EVENTS_STOPPED, so the wait
always timed out at 2 ms. Gating on _pwm_on removes the wait on the
first note of a melody and after pauses, where there's nothing to wait
for.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-24 19:59:21 +02:00
Jakub
b279b95b2d refactor(ui): apply code review fixes — bugs, risk, optimisations, cleanup
Fixes 7 bugs (timing UB on unsigned long, abs() no-op, XBM CRC PROGMEM
scan, CayenneLPP heap thrash ×2, UTF-8 reply prefix, lock-seq reset on
wake), 3 risk items (notif melody stop guard, bot trigger pre-lowercase,
lock-seq cleared on display wake), plus optimisations (fmtMsgAge/
getTextWidth caching, RTTTL builder consolidated to NodePrefs, HP_*
constants and homePageLabel table moved to NodePrefs, DataStore flat
lambda schema, translateUTF8Static factored out) and minor cleanup.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-23 20:03:45 +02:00
Jakub
584ef33b3e fix: channel bot respects bot_enabled flag
tryBotReplyChannel checked bot_channel_enabled but not bot_enabled,
so disabling the bot via the main Enable toggle had no effect on
channel replies. Added bot_enabled to the guard condition.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-18 09:41:56 +02:00
Jakub
5d41812784 fix: separate DM and channel bot reply cooldown timers
Single shared _bot_last_reply_ms caused a DM reply to block the
channel bot for 10s and vice versa. Split into _bot_last_dm_reply_ms
and _bot_last_ch_reply_ms so each cooldown is independent.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:26:31 +02:00
Jakub
44b2519df4 fix: with_sender buffer too small and FS_LINE_H mismatch
- with_sender[160] could hold only ~160 chars but node_name(32) +
  expanded(200) needs up to 234; snprintf would silently truncate
  the UI display entry. Increased to 240.
- FS_LINE_H was 9 but Adafruit 5x7 font line height is 8, wasting
  1px per line and showing 5 lines instead of 6.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:23:20 +02:00
Jakub
1b9dc42250 fix: bot trigger matched against message body only, not sender name
Channel messages have the format "sender_name: body". The trigger was
being searched across the whole string, so a nick containing the trigger
word would fire a reply even with an unrelated message. Now the match
skips past the ": " separator and only checks the message body.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-16 23:19:12 +02:00
Jakub
42b51935b1 feat: sensor placeholders in messages and keyboard picker
expandMsg now expands {temp}, {hum}, {pres}, {batt}, {alt}, {lux}, {dist},
{co2} from live sensor readings. The [{}] picker in the on-screen keyboard
shows only sensors currently detected by SensorManager and scrolls when
more than 3 items fit the overlay.

New SensorPlaceholders.h helper keeps sensor-to-keyboard wiring out of
UITask.cpp. MsgExpand.h handles all expansion logic centrally; MyMeshBot
and QuickMsgScreen pass &sensors and batt_volts to each call.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-14 00:12:07 +02:00
Jakub
4a4ff76f10 feat: DM chat history, per-contact unread badges, bot history, contact index fix
- Add DM_HIST phase in QuickMsgScreen: 32-entry ring buffer tracks incoming
  and outgoing DMs per contact; selecting a contact now opens history view
  before compose
- Per-contact DM unread badge in contact list (replaces hop count display)
- Bot replies (DM and channel) stored in history so they appear on-screen
- Fix contact index truncation: _sorted was uint8_t (max 255), causing
  contacts at indices 256-349 to map to wrong entries; changed to uint16_t
- Add addDMMsg() virtual to AbstractUITask; wire through MyMesh.cpp
- Incoming chat DMs call addDMMsg(); outgoing after successful send too
- msgRead(0) from companion app clears per-contact unread table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00
Jakub
71635e5e6f Bot: DM+channel modes with separate replies; buzzer auto-mute; UX fixes
- Bot redesign: DM bot active for all private messages (no pubkey filter),
  channel bot optional with separate enable flag; both can run simultaneously
- Bot: one shared trigger, separate reply texts for DM and channel
- Buzzer: add Auto mode (mutes when BT connected, unmutes on disconnect);
  per-channel force-on overrides still work as intended
- Settings: defer flash writes to menu exit (only when dirty)
- Settings: add Seconds toggle (hide clock seconds, refresh drops 1s→60s)
- Fullscreen msg preview: fix truncation (fmsg buf 79→140 chars)
- RingtoneEditor: fix melody playback cut after first note (RTTTL lib holds
  pointer — moved play buffer to member variable)
- BotScreen: remove key hint footer
- .gitattributes: protect README.md from upstream merge conflicts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00
Jakub
af7da7906a Fix: tryBotReplyChannel must check bot_target_type == 0
Without the check, a DM-mode bot (bot_target_type==1) would also reply
to channel messages whenever the trigger phrase and channel index happened
to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00
Jakub
dd2c09174f Extract bot logic from MyMesh into MyMeshBot.h
Move tryBotReplyDM() and tryBotReplyChannel() implementations to
MyMeshBot.h (included at end of MyMesh.cpp). onMessageRecv and
onChannelMessageRecv now contain only a single-line call each,
minimising the diff against upstream in those methods.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-13 21:09:47 +02:00