Files
MeshCore-Solo/examples/companion_radio/MyMeshBot.h
MarekZegare4 2766a098a5 fix(bot): preserve trigger case, lowercase only at match time
Trigger is now stored as typed (e.g. "Ping" stays "Ping").
Case-insensitive matching is preserved by lowercasing both
the trigger and incoming message at comparison time.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 09:53:09 +02:00

83 lines
3.3 KiB
C

#pragma once
// Bot logic — not part of upstream MyMesh.cpp.
// Included at the bottom of MyMesh.cpp after all class definitions.
void MyMesh::tryBotReplyDM(const ContactInfo& from, const char* text) {
if (from.type != ADV_TYPE_CHAT) return;
if (!(_prefs.bot_enabled && _prefs.bot_trigger[0] && _prefs.bot_reply_dm[0] &&
millis() - _bot_last_dm_reply_ms > 10000UL))
return;
// Lower-case both body and trigger for case-insensitive matching.
char low[200];
size_t n = strlen(text);
if (n >= sizeof(low)) n = sizeof(low) - 1;
for (size_t i = 0; i < n; i++) low[i] = (char)tolower((uint8_t)text[i]);
low[n] = '\0';
char low_trigger[sizeof(_prefs.bot_trigger)];
size_t tlen = strnlen(_prefs.bot_trigger, sizeof(low_trigger) - 1);
for (size_t i = 0; i < tlen; i++) low_trigger[i] = (char)tolower((uint8_t)_prefs.bot_trigger[i]);
low_trigger[tlen] = '\0';
if (!strstr(low, low_trigger)) return;
uint32_t ts = getRTCClock()->getCurrentTime();
char expanded[200];
expandMsg(_prefs.bot_reply_dm, expanded, sizeof(expanded),
sensors.node_lat, sensors.node_lon,
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
ts, _prefs.tz_offset_hours,
&sensors, (float)board.getBattMilliVolts() / 1000.0f);
uint32_t expected_ack, est_timeout;
if (sendMessage(from, ts, 0, expanded, expected_ack, est_timeout) != MSG_SEND_FAILED) {
_bot_last_dm_reply_ms = millis();
#ifdef DISPLAY_CLASS
if (_ui) _ui->addDMMsg(from.id.pub_key, true, expanded);
#endif
}
}
void MyMesh::tryBotReplyChannel(uint8_t channel_idx, const char* text) {
if (!(_prefs.bot_enabled && _prefs.bot_channel_enabled && _prefs.bot_trigger[0] && _prefs.bot_reply_ch[0] &&
channel_idx == _prefs.bot_channel_idx &&
millis() - _bot_last_ch_reply_ms > 10000UL))
return;
// Skip "sender_name: " prefix so the trigger is only matched against the message body.
const char* msg = text;
const char* sep = strstr(text, ": ");
if (sep) msg = sep + 2;
char low[200];
size_t n = strlen(msg);
if (n >= sizeof(low)) n = sizeof(low) - 1;
for (size_t i = 0; i < n; i++) low[i] = (char)tolower((uint8_t)msg[i]);
low[n] = '\0';
char low_trigger[sizeof(_prefs.bot_trigger)];
size_t tlen = strnlen(_prefs.bot_trigger, sizeof(low_trigger) - 1);
for (size_t i = 0; i < tlen; i++) low_trigger[i] = (char)tolower((uint8_t)_prefs.bot_trigger[i]);
low_trigger[tlen] = '\0';
if (!strstr(low, low_trigger)) return;
ChannelDetails ch;
if (!getChannel(channel_idx, ch)) return;
uint32_t ts = getRTCClock()->getCurrentTime();
char expanded[200];
expandMsg(_prefs.bot_reply_ch, expanded, sizeof(expanded),
sensors.node_lat, sensors.node_lon,
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
ts, _prefs.tz_offset_hours,
&sensors, (float)board.getBattMilliVolts() / 1000.0f);
int rlen = strlen(expanded);
if (sendGroupMessage(ts, ch.channel, _prefs.node_name, expanded, rlen)) {
_bot_last_ch_reply_ms = millis();
#ifdef DISPLAY_CLASS
if (_ui) {
char with_sender[240]; // node_name(32) + ": "(2) + expanded(200) + margin
snprintf(with_sender, sizeof(with_sender), "%s: %s", _prefs.node_name, expanded);
_ui->addChannelMsg(channel_idx, with_sender);
}
#endif
}
}