fix: extend MQTT JWT lifetime and suppress reconnect noise during planned refresh
This commit is contained in:
1 parent
b003cdc9d9
commit
c729a58c81
7 files changed
+45
-8
No files matched your search
@@ -229,6 +229,8 @@ The `/stats` page currently shows:
|
||||
- `Neighbours`: current neighbour table with ID, SNR, heard age, and advert age
|
||||
- `Events`: current boot/session events
|
||||
|
||||
Planned MQTT JWT rotations are shown as `mqtt_token_refreshed` events instead of a short `mqtt_disconnected` / `mqtt_connected` pair.
|
||||
|
||||
For boards that expose extra telemetry, the optional `Environment` summary card can show current values such as GPS fix state, latitude, longitude, GPS altitude, voltage, sensor temperature, humidity, barometer, pressure-derived altitude, and MCU temperature.
|
||||
|
||||
Metrics with no current value are hidden rather than showing placeholder rows, so the cards vary by board and by current sensor state.
|
||||
|
||||
@@ -1793,8 +1793,12 @@ void MyMesh::updateStatsHistory(unsigned long now_ms) {
|
||||
const bool wifi_connected = network.isWifiConnected();
|
||||
#ifdef WITH_MQTT_UPLINK
|
||||
const bool mqtt_connected = mqtt.isAnyBrokerConnected();
|
||||
const uint32_t mqtt_token_refresh_count = mqtt.getTokenRefreshCount();
|
||||
const bool mqtt_token_refreshing = mqtt.isTokenRefreshInProgress();
|
||||
#else
|
||||
const bool mqtt_connected = false;
|
||||
const uint32_t mqtt_token_refresh_count = 0;
|
||||
const bool mqtt_token_refreshing = false;
|
||||
#endif
|
||||
const bool web_panel_up = web.isPanelRunning();
|
||||
const bool archive_mounted = (_archive != nullptr) && _archive->isMounted();
|
||||
@@ -1821,11 +1825,22 @@ void MyMesh::updateStatsHistory(unsigned long now_ms) {
|
||||
_stats_state.web_panel_up = web_panel_up;
|
||||
_stats_state.archive_mounted = archive_mounted;
|
||||
_stats_state.low_memory = low_memory;
|
||||
_stats_state.mqtt_token_refresh_count = mqtt_token_refresh_count;
|
||||
_stats_state.last_low_memory_event_uptime_secs = 0;
|
||||
} else {
|
||||
if (_stats_state.mqtt_token_refresh_count != mqtt_token_refresh_count) {
|
||||
const uint32_t refresh_delta = mqtt_token_refresh_count - _stats_state.mqtt_token_refresh_count;
|
||||
recordStatsEvent(HISTORY_EVENT_MQTT_TOKEN_REFRESHED,
|
||||
static_cast<int16_t>(min<uint32_t>(refresh_delta, 32767)));
|
||||
_stats_state.mqtt_token_refresh_count = mqtt_token_refresh_count;
|
||||
}
|
||||
if (_stats_state.mqtt_connected != mqtt_connected) {
|
||||
recordStatsEvent(mqtt_connected ? HISTORY_EVENT_MQTT_CONNECTED : HISTORY_EVENT_MQTT_DISCONNECTED);
|
||||
_stats_state.mqtt_connected = mqtt_connected;
|
||||
if (_stats_state.mqtt_connected && !mqtt_connected && mqtt_token_refreshing) {
|
||||
// Planned JWT rotation briefly drops MQTT; keep the event stream focused on real outages.
|
||||
} else {
|
||||
recordStatsEvent(mqtt_connected ? HISTORY_EVENT_MQTT_CONNECTED : HISTORY_EVENT_MQTT_DISCONNECTED);
|
||||
_stats_state.mqtt_connected = mqtt_connected;
|
||||
}
|
||||
}
|
||||
if (_stats_state.web_panel_up != web_panel_up) {
|
||||
recordStatsEvent(web_panel_up ? HISTORY_EVENT_WEB_STARTED : HISTORY_EVENT_WEB_STOPPED);
|
||||
|
||||
@@ -185,6 +185,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks, public WebPanelComm
|
||||
bool web_panel_up;
|
||||
bool archive_mounted;
|
||||
bool low_memory;
|
||||
uint32_t mqtt_token_refresh_count;
|
||||
uint32_t last_low_memory_event_uptime_secs;
|
||||
} _stats_state;
|
||||
|
||||
|
||||
@@ -396,6 +396,7 @@ uint8_t eventTypeFromName(const char* name) {
|
||||
if (strcmp(name, "low_memory") == 0) return HISTORY_EVENT_LOW_MEMORY;
|
||||
if (strcmp(name, "stats_enabled") == 0) return HISTORY_EVENT_STATS_ENABLED;
|
||||
if (strcmp(name, "stats_disabled") == 0) return HISTORY_EVENT_STATS_DISABLED;
|
||||
if (strcmp(name, "mqtt_token_refreshed") == 0) return HISTORY_EVENT_MQTT_TOKEN_REFRESHED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1369,6 +1370,8 @@ const char* StatsHistory::getEventTypeName(uint8_t type) {
|
||||
return "stats_enabled";
|
||||
case HISTORY_EVENT_STATS_DISABLED:
|
||||
return "stats_disabled";
|
||||
case HISTORY_EVENT_MQTT_TOKEN_REFRESHED:
|
||||
return "mqtt_token_refreshed";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ enum HistoryEventType : uint8_t {
|
||||
HISTORY_EVENT_LOW_MEMORY = 8,
|
||||
HISTORY_EVENT_STATS_ENABLED = 9,
|
||||
HISTORY_EVENT_STATS_DISABLED = 10,
|
||||
HISTORY_EVENT_MQTT_TOKEN_REFRESHED = 11,
|
||||
};
|
||||
|
||||
class StatsHistory {
|
||||
|
||||
@@ -43,8 +43,9 @@
|
||||
namespace {
|
||||
constexpr unsigned long kBrokerRetryBaseMillis = 10000;
|
||||
constexpr unsigned long kBrokerRetryMaxMillis = 300000;
|
||||
constexpr unsigned long kTokenRefreshEventWindowMs = 2UL * 60UL * 1000UL;
|
||||
constexpr size_t kBrokerTokenSize = 640;
|
||||
constexpr time_t kTokenLifetimeSecs = 3600;
|
||||
constexpr time_t kTokenLifetimeSecs = 6UL * 60UL * 60UL;
|
||||
constexpr time_t kTokenRefreshSlackSecs = 300;
|
||||
constexpr time_t kMinSaneEpoch = 1735689600; // 2025-01-01T00:00:00Z
|
||||
|
||||
@@ -104,8 +105,8 @@ const MQTTUplink::BrokerSpec MQTTUplink::kBrokerSpecs[3] = {
|
||||
};
|
||||
|
||||
MQTTUplink::MQTTUplink(mesh::RTCClock& rtc, mesh::LocalIdentity& identity)
|
||||
: _fs(nullptr), _rtc(&rtc), _identity(&identity), _running(false), _last_status_publish(0), _last_status{},
|
||||
_node_name(nullptr), _network(nullptr)
|
||||
: _fs(nullptr), _rtc(&rtc), _identity(&identity), _running(false), _last_status_publish(0),
|
||||
_token_refresh_count(0), _token_refresh_active_until_ms(0), _last_status{}, _node_name(nullptr), _network(nullptr)
|
||||
{
|
||||
memset(_device_id, 0, sizeof(_device_id));
|
||||
MQTTPrefsStore::setDefaults(_prefs);
|
||||
@@ -124,6 +125,11 @@ bool MQTTUplink::savePrefs() {
|
||||
return MQTTPrefsStore::save(_fs, _prefs);
|
||||
}
|
||||
|
||||
bool MQTTUplink::isTokenRefreshInProgress() const {
|
||||
return _token_refresh_active_until_ms != 0 &&
|
||||
static_cast<long>(millis() - _token_refresh_active_until_ms) < 0;
|
||||
}
|
||||
|
||||
bool MQTTUplink::hasEnabledBroker() const {
|
||||
return (_prefs.enabled_mask & 0x07) != 0;
|
||||
}
|
||||
@@ -622,11 +628,15 @@ void MQTTUplink::ensureBroker(BrokerState& broker, bool allow_new_connect) {
|
||||
}
|
||||
|
||||
time_t now = time(nullptr);
|
||||
unsigned long now_ms = millis();
|
||||
if (broker.client != nullptr && broker.token_expires_at > 0 && now + kTokenRefreshSlackSecs >= broker.token_expires_at) {
|
||||
_token_refresh_count++;
|
||||
_token_refresh_active_until_ms = now_ms + kTokenRefreshEventWindowMs;
|
||||
MQTT_LOG("%s token refresh reconnect count=%lu", broker.spec->label,
|
||||
static_cast<unsigned long>(_token_refresh_count));
|
||||
destroyBroker(broker, false);
|
||||
}
|
||||
|
||||
unsigned long now_ms = millis();
|
||||
if (broker.client != nullptr) {
|
||||
if (broker.connected) {
|
||||
return;
|
||||
@@ -1000,8 +1010,8 @@ const char* MQTTUplink::getAggregateBrokerState() const {
|
||||
#else
|
||||
|
||||
MQTTUplink::MQTTUplink(mesh::RTCClock&, mesh::LocalIdentity&)
|
||||
: _fs(nullptr), _rtc(nullptr), _identity(nullptr), _running(false), _last_status_publish(0), _last_status{},
|
||||
_node_name(nullptr), _network(nullptr) {
|
||||
: _fs(nullptr), _rtc(nullptr), _identity(nullptr), _running(false), _last_status_publish(0),
|
||||
_token_refresh_count(0), _token_refresh_active_until_ms(0), _last_status{}, _node_name(nullptr), _network(nullptr) {
|
||||
MQTTPrefsStore::setDefaults(_prefs);
|
||||
}
|
||||
|
||||
@@ -1024,6 +1034,7 @@ bool MQTTUplink::setOwnerEmail(const char*) { return false; }
|
||||
bool MQTTUplink::sendStatusNow() { return false; }
|
||||
bool MQTTUplink::isAnyBrokerConnected() const { return false; }
|
||||
const char* MQTTUplink::getAggregateBrokerState() const { return "down"; }
|
||||
bool MQTTUplink::isTokenRefreshInProgress() const { return false; }
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
bool isAnyBrokerConnected() const;
|
||||
const char* getAggregateBrokerState() const;
|
||||
void setNetworkStateProvider(NetworkStateProvider* network) { _network = network; }
|
||||
uint32_t getTokenRefreshCount() const { return _token_refresh_count; }
|
||||
bool isTokenRefreshInProgress() const;
|
||||
|
||||
private:
|
||||
#if defined(ESP_PLATFORM)
|
||||
@@ -101,6 +103,8 @@ private:
|
||||
MQTTPrefs _prefs;
|
||||
bool _running;
|
||||
unsigned long _last_status_publish;
|
||||
uint32_t _token_refresh_count;
|
||||
unsigned long _token_refresh_active_until_ms;
|
||||
MQTTStatusSnapshot _last_status;
|
||||
char _device_id[65];
|
||||
const char* _node_name;
|
||||
|
||||
Reference in new issue
Block a user