2026-05-12 14:51:19 +02:00
|
|
|
#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) {
|
2026-05-13 10:25:55 +02:00
|
|
|
if (from.type != ADV_TYPE_CHAT) return;
|
2026-05-12 20:12:54 +02:00
|
|
|
if (!(_prefs.bot_enabled && _prefs.bot_trigger[0] && _prefs.bot_reply_dm[0] &&
|
2026-05-12 14:51:19 +02:00
|
|
|
millis() - _bot_last_reply_ms > 10000UL))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
const char* tr = _prefs.bot_trigger;
|
|
|
|
|
int tlen = strlen(tr);
|
|
|
|
|
bool matched = false;
|
|
|
|
|
for (const char* t = text; *t && !matched; t++) {
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (i < tlen && tolower((uint8_t)t[i]) == tolower((uint8_t)tr[i])) i++;
|
|
|
|
|
if (i == tlen) matched = true;
|
|
|
|
|
}
|
|
|
|
|
if (!matched) return;
|
|
|
|
|
|
|
|
|
|
uint32_t ts = getRTCClock()->getCurrentTime();
|
|
|
|
|
char expanded[200];
|
2026-05-12 20:12:54 +02:00
|
|
|
expandMsg(_prefs.bot_reply_dm, expanded, sizeof(expanded),
|
2026-05-12 14:51:19 +02:00
|
|
|
sensors.node_lat, sensors.node_lon,
|
|
|
|
|
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
|
2026-05-14 00:12:07 +02:00
|
|
|
ts, _prefs.tz_offset_hours,
|
|
|
|
|
&sensors, (float)board.getBattMilliVolts() / 1000.0f);
|
2026-05-12 14:51:19 +02:00
|
|
|
uint32_t expected_ack, est_timeout;
|
2026-05-13 10:25:55 +02:00
|
|
|
if (sendMessage(from, ts, 0, expanded, expected_ack, est_timeout) != MSG_SEND_FAILED) {
|
2026-05-12 14:51:19 +02:00
|
|
|
_bot_last_reply_ms = millis();
|
2026-05-13 10:25:55 +02:00
|
|
|
#ifdef DISPLAY_CLASS
|
|
|
|
|
if (_ui) _ui->addDMMsg(from.id.pub_key, true, expanded);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2026-05-12 14:51:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void MyMesh::tryBotReplyChannel(uint8_t channel_idx, const char* text) {
|
2026-05-12 20:12:54 +02:00
|
|
|
if (!(_prefs.bot_channel_enabled && _prefs.bot_trigger[0] && _prefs.bot_reply_ch[0] &&
|
2026-05-12 14:51:19 +02:00
|
|
|
channel_idx == _prefs.bot_channel_idx &&
|
|
|
|
|
millis() - _bot_last_reply_ms > 10000UL))
|
|
|
|
|
return;
|
|
|
|
|
|
2026-05-16 23:19:12 +02:00
|
|
|
// 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;
|
|
|
|
|
|
2026-05-12 14:51:19 +02:00
|
|
|
const char* tr = _prefs.bot_trigger;
|
|
|
|
|
int tlen = strlen(tr);
|
|
|
|
|
bool matched = false;
|
2026-05-16 23:19:12 +02:00
|
|
|
for (const char* t = msg; *t && !matched; t++) {
|
2026-05-12 14:51:19 +02:00
|
|
|
int i = 0;
|
|
|
|
|
while (i < tlen && tolower((uint8_t)t[i]) == tolower((uint8_t)tr[i])) i++;
|
|
|
|
|
if (i == tlen) matched = true;
|
|
|
|
|
}
|
|
|
|
|
if (!matched) return;
|
|
|
|
|
|
|
|
|
|
ChannelDetails ch;
|
|
|
|
|
if (!getChannel(channel_idx, ch)) return;
|
|
|
|
|
|
|
|
|
|
uint32_t ts = getRTCClock()->getCurrentTime();
|
|
|
|
|
char expanded[200];
|
2026-05-12 20:12:54 +02:00
|
|
|
expandMsg(_prefs.bot_reply_ch, expanded, sizeof(expanded),
|
2026-05-12 14:51:19 +02:00
|
|
|
sensors.node_lat, sensors.node_lon,
|
|
|
|
|
sensors.node_lat != 0.0 || sensors.node_lon != 0.0,
|
2026-05-14 00:12:07 +02:00
|
|
|
ts, _prefs.tz_offset_hours,
|
|
|
|
|
&sensors, (float)board.getBattMilliVolts() / 1000.0f);
|
2026-05-12 14:51:19 +02:00
|
|
|
int rlen = strlen(expanded);
|
2026-05-13 10:25:55 +02:00
|
|
|
if (sendGroupMessage(ts, ch.channel, _prefs.node_name, expanded, rlen)) {
|
2026-05-12 14:51:19 +02:00
|
|
|
_bot_last_reply_ms = millis();
|
2026-05-13 10:25:55 +02:00
|
|
|
#ifdef DISPLAY_CLASS
|
|
|
|
|
if (_ui) {
|
|
|
|
|
char with_sender[160];
|
|
|
|
|
snprintf(with_sender, sizeof(with_sender), "%s: %s", _prefs.node_name, expanded);
|
|
|
|
|
_ui->addChannelMsg(channel_idx, with_sender);
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
}
|
2026-05-12 14:51:19 +02:00
|
|
|
}
|