feat(mqtt): add max active slots logic for MQTT connections

Implement logic to determine the maximum number of active MQTT slots
based on available memory. This change allows the system to warn users
when attempting to connect more slots than supported by the hardware,
improving user experience and preventing connection issues. The logic
is centralized in the new getMaxActiveSlots() method, ensuring
consistency across the codebase.
This commit is contained in:
agessaman
2026-07-20 16:11:11 -07:00
parent ed674fdf9d
commit 20b5b2e9c9
3 changed files with 47 additions and 9 deletions
+28
View File
@@ -405,6 +405,34 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf
} else {
sprintf(reply, "OK - slot %d preset: %s", slot + 1, preset_name);
}
// Warn when this slot won't actually connect on this hardware. The set
// is never blocked — prefs persist so the config carries over if the
// device is moved to a board with more slots — but flag it, or the
// operator waits for a connection that never comes. Mirrors the bridge
// setup loop: slots past the runtime array (RUNTIME_MQTT_SLOTS) are
// never iterated; within it, only the first getMaxActiveSlots()
// *enabled* slots connect (each WSS/TLS link costs ~40 KB heap).
if (strcmp(preset_name, MQTT_PRESET_NONE) != 0) {
size_t used = strlen(reply);
if (slot >= RUNTIME_MQTT_SLOTS) {
if (used < 158) {
snprintf(reply + used, 160 - used, " (slot inactive on this hardware)");
}
} else {
const int max_active = MQTTBridge::getMaxActiveSlots();
int rank = 0; // this slot's position among enabled slots, by index
for (int s = 0; s <= slot; s++) {
if (_mqtt_prefs.mqtt_slot_preset[s][0] != '\0' &&
strcmp(_mqtt_prefs.mqtt_slot_preset[s], MQTT_PRESET_NONE) != 0) {
rank++;
}
}
if (rank > max_active && used < 158) {
snprintf(reply + used, 160 - used,
" (won't connect: %d-slot limit on this hardware)", max_active);
}
}
}
}
} else {
strcpy(reply, "Error: unknown preset. Use 'get mqtt.presets'");
+15 -9
View File
@@ -337,6 +337,18 @@ void MQTTBridge::formatMqttStatsReply(char* buf, size_t bufsize) {
uint8_t MQTTBridge::getLastWifiDisconnectReason() { return s_wifi_disconnect_reason; }
unsigned long MQTTBridge::getLastWifiDisconnectTime() { return s_wifi_disconnect_time; }
// Each WSS/TLS connection needs ~40KB for mbedTLS buffers. Without PSRAM even 3
// concurrent connections would exhaust internal heap, so cap at 2; with PSRAM
// cap at 5 (6 configurable but 5 active max). Static so the CLI can report, at
// config time, that a slot beyond this cap won't connect.
int MQTTBridge::getMaxActiveSlots() {
#if defined(ESP_PLATFORM) && defined(BOARD_HAS_PSRAM)
return psramFound() ? 5 : 2;
#else
return 2;
#endif
}
unsigned long MQTTBridge::getSlotCurrentOutageStartMs(int slot_index) const {
if (slot_index < 0 || slot_index >= RUNTIME_MQTT_SLOTS) return 0;
return _slots[slot_index].current_outage_started_ms;
@@ -627,15 +639,9 @@ void MQTTBridge::begin() {
MQTT_DEBUG_PRINTLN("PSRAM: not configured for this board (no BOARD_HAS_PSRAM)");
#endif
// Limit active slots based on available memory.
// Each WSS/TLS connection needs ~40KB for mbedTLS buffers.
// Without PSRAM, even 3 concurrent connections would exhaust internal heap.
// With PSRAM, cap at 5 for safety (6 configurable but 5 active max).
#if defined(ESP_PLATFORM) && defined(BOARD_HAS_PSRAM)
_max_active_slots = psramFound() ? 5 : 2;
#else
_max_active_slots = 2;
#endif
// Limit active slots based on available memory (single source of truth in
// getMaxActiveSlots(), which the CLI also uses to warn about inactive slots).
_max_active_slots = getMaxActiveSlots();
MQTT_DEBUG_PRINTLN("Max active slots: %d", _max_active_slots);
// Check if WiFi credentials are configured first
+4
View File
@@ -498,6 +498,10 @@ public:
static void formatSlotDiagReply(char* buf, size_t bufsize, int slot_index);
static uint8_t getLastWifiDisconnectReason();
static unsigned long getLastWifiDisconnectTime();
/** Max slots that can be connected at once on this hardware (each WSS/TLS link
* needs ~40 KB internal heap): 5 with PSRAM, 2 without. Note this is below
* RUNTIME_MQTT_SLOTS, so more slots can be configured than will connect. */
static int getMaxActiveSlots();
#if defined(WITH_MQTT_NEIGHBORS)
void requestPublishNeighbors(const char* json, size_t len);