mirror of
https://github.com/agessaman/MeshCore.git
synced 2026-10-13 21:47:37 +00:00
Updated the fault alert functionality to include an optional region name for scoping alert floods, allowing operators to override the default scope. Introduced a list of banned channels (e.g., Public PSK, `#test`, `#bot`) to prevent spamming community channels with alerts. The implementation ensures that alerts are only sent to private PSKs or non-banned hashtags. Relevant changes were made across multiple files, including updates to the CLI for setting and retrieving the new `alert.region` preference.
110 lines
3.9 KiB
C++
110 lines
3.9 KiB
C++
#pragma once
|
|
|
|
#include <Arduino.h>
|
|
#include <Mesh.h>
|
|
#include "CommonCLI.h"
|
|
|
|
#ifdef WITH_MQTT_BRIDGE
|
|
#include "bridges/MQTTBridge.h"
|
|
#endif
|
|
|
|
/**
|
|
* Returns the label of a banned alert channel if \a secret16 matches one of
|
|
* the channels in the BANNED_ALERT_CHANNELS table (e.g. "PUBLIC", "#test",
|
|
* "#bot"), or nullptr otherwise. Centralized here so both AlertReporter and
|
|
* the CommonCLI `set alert.psk` / `set alert.hashtag` handlers can share one
|
|
* source of truth — adding a new banned channel is a one-line table edit.
|
|
*/
|
|
const char* alertReporterBannedChannelMatch(const uint8_t* secret16);
|
|
|
|
/**
|
|
* Convenience: base64-decodes \a psk_b64 and forwards to
|
|
* alertReporterBannedChannelMatch. Returns nullptr if not banned (or if
|
|
* the input doesn't decode to a 16-byte key — non-16-byte keys cannot
|
|
* match any banned entry anyway).
|
|
*/
|
|
const char* alertReporterBannedChannelMatchB64(const char* psk_b64);
|
|
|
|
/**
|
|
* \brief Send-only group-channel "fault alert" reporter for repeater/observer
|
|
* builds.
|
|
*
|
|
* Polls WiFi and per-MQTT-slot outage timers from MQTTBridge. When any timer
|
|
* exceeds its configured threshold, floods a single PAYLOAD_TYPE_GRP_TXT
|
|
* message on the configured alert channel ("WiFi down 47m — MyObserver"),
|
|
* then arms a "recovered" message for the next state transition.
|
|
*
|
|
* The alert channel must be explicitly configured to either a private base64
|
|
* PSK (`set alert.psk`) or a hashtag name (`set alert.hashtag`); the
|
|
* well-known PUBLIC group key (and a small list of other auto-responder
|
|
* channels — see BANNED_ALERT_CHANNELS in AlertReporter.cpp) are rejected on
|
|
* purpose so fault alerts never spam community channels.
|
|
*
|
|
* Edge-triggered + rate-limited via NodePrefs::alert_min_interval_min so a
|
|
* flapping link cannot spam the channel.
|
|
*
|
|
* Designed to compile and run on any repeater build:
|
|
* - The channel-send path uses only mesh::Mesh primitives that already
|
|
* exist in the Dispatcher hierarchy (createGroupDatagram + sendFlood).
|
|
* - WiFi/MQTT polling is #ifdef WITH_MQTT_BRIDGE-gated; without it, the
|
|
* reporter still supports manual `alert test` sends.
|
|
*/
|
|
class AlertReporter {
|
|
public:
|
|
AlertReporter();
|
|
|
|
/**
|
|
* Wire up the reporter. Must be called from MyMesh::begin() after prefs
|
|
* are loaded. \a callbacks is optional — when non-null the reporter uses
|
|
* it to resolve a TransportKey scope for outgoing alert floods (so the
|
|
* packet rides the repeater's default scope or an `alert.region` override).
|
|
*/
|
|
void begin(NodePrefs* prefs, mesh::Mesh* mesh, CommonCLICallbacks* callbacks = nullptr);
|
|
|
|
#ifdef WITH_MQTT_BRIDGE
|
|
/** Bridge can be (re)created lazily; pass nullptr to detach. */
|
|
void setBridge(MQTTBridge* bridge);
|
|
#endif
|
|
|
|
/**
|
|
* Re-derive the cached GroupChannel from \a alert_psk_b64. Call from the
|
|
* CLI hot-reload hook after `set alert.psk` / `set alert.hashtag` / `set alert on|off`.
|
|
*/
|
|
void onConfigChanged();
|
|
|
|
/**
|
|
* Cooperative tick. Fast: returns immediately if disabled, throttled
|
|
* internally to ~5 s checks. Safe to call every loop().
|
|
*/
|
|
void onLoop(unsigned long now_ms);
|
|
|
|
/**
|
|
* Send an arbitrary text immediately (used by `alert test` CLI). Returns
|
|
* false when disabled, PSK invalid, or the underlying flood-send fails.
|
|
* Bypasses the rate limiter and edge logic.
|
|
*/
|
|
bool sendText(const char* text);
|
|
|
|
private:
|
|
bool resolveChannel(mesh::GroupChannel& out) const;
|
|
bool sendChannel(const char* text);
|
|
void formatAge(unsigned long age_ms, char* out, size_t out_size) const;
|
|
|
|
enum FaultState { OK, FIRING };
|
|
struct Fault {
|
|
FaultState state;
|
|
unsigned long fired_at_ms; // millis() when we last sent a "down" alert
|
|
unsigned long last_outage_started_ms; // remembered so the recovered msg can quote duration
|
|
};
|
|
|
|
NodePrefs* _prefs;
|
|
mesh::Mesh* _mesh;
|
|
CommonCLICallbacks* _callbacks;
|
|
#ifdef WITH_MQTT_BRIDGE
|
|
MQTTBridge* _bridge;
|
|
Fault _wifi;
|
|
Fault _mqtt[RUNTIME_MQTT_SLOTS];
|
|
#endif
|
|
unsigned long _next_check_ms;
|
|
};
|