fix: publish offline status on clean mqtt disconnect
This commit is contained in:
@@ -50,6 +50,8 @@ Notes:
|
|||||||
- new repeater MQTT installs default `mqtt.iata` to `UNSET`
|
- new repeater MQTT installs default `mqtt.iata` to `UNSET`
|
||||||
- `letsmesh-eu` and `letsmesh-us` remain off by default unless already configured in saved prefs
|
- `letsmesh-eu` and `letsmesh-us` remain off by default unless already configured in saved prefs
|
||||||
- if `mqtt.iata` is `UNSET`, `eastmesh-au`, `letsmesh-eu`, and `letsmesh-us` will not connect even if they are toggled on
|
- if `mqtt.iata` is `UNSET`, `eastmesh-au`, `letsmesh-eu`, and `letsmesh-us` will not connect even if they are toggled on
|
||||||
|
- turning off a connected broker publishes a retained MQTT status update with `"status":"offline"` before the client disconnects
|
||||||
|
- changing `mqtt.iata` away from a configured value also publishes retained offline status to the old status topic before switching topics
|
||||||
|
|
||||||
Legacy dotted aliases are also accepted:
|
Legacy dotted aliases are also accepted:
|
||||||
|
|
||||||
|
|||||||
@@ -221,6 +221,8 @@ Notes:
|
|||||||
- while `mqtt.iata` is `UNSET`, enabled MQTT brokers do not attempt to connect
|
- while `mqtt.iata` is `UNSET`, enabled MQTT brokers do not attempt to connect
|
||||||
- the current MQTT server states are loaded when the page opens
|
- the current MQTT server states are loaded when the page opens
|
||||||
- you can toggle each MQTT server on or off from this panel
|
- you can toggle each MQTT server on or off from this panel
|
||||||
|
- turning off a connected MQTT server publishes retained offline status before the client disconnects
|
||||||
|
- changing `mqtt.iata` away from a configured value publishes retained offline status to the old status topic before the new topic is used
|
||||||
- if all three servers are enabled at once, the panel shows a warning recommending two at most
|
- if all three servers are enabled at once, the panel shows a warning recommending two at most
|
||||||
|
|
||||||
## `/stats` Overview
|
## `/stats` Overview
|
||||||
|
|||||||
@@ -557,3 +557,21 @@ releases:
|
|||||||
area: web-panel
|
area: web-panel
|
||||||
text: "Documented no-PSRAM `/stats` history behavior, stale browser-token recovery, and the lightweight `/api/session` endpoint used by the web panel."
|
text: "Documented no-PSRAM `/stats` history behavior, stale browser-token recovery, and the lightweight `/api/session` endpoint used by the web panel."
|
||||||
breaking_changes: []
|
breaking_changes: []
|
||||||
|
|
||||||
|
- track: repeater-mqtt
|
||||||
|
version: "1.3.15"
|
||||||
|
tag: "repeater-mqtt-eastmesh-v1.3.15"
|
||||||
|
date: "2026-04-30"
|
||||||
|
previous_version: "1.3.14"
|
||||||
|
summary: "Publishes retained offline status for clean MQTT broker disables and IATA topic changes so operator-driven disconnects do not leave stale online status behind."
|
||||||
|
changes:
|
||||||
|
- type: fixed
|
||||||
|
area: mqtt
|
||||||
|
text: "Published explicit retained offline status before a connected broker is toggled off, matching operator expectations without relying on last-will behavior that only fires on unclean disconnects."
|
||||||
|
- type: fixed
|
||||||
|
area: mqtt
|
||||||
|
text: "Published retained offline status to the old status topic before `mqtt.iata` changes, preventing stale online status from remaining under the previous IATA path."
|
||||||
|
- type: docs
|
||||||
|
area: mqtt
|
||||||
|
text: "Updated the CLI and web-panel docs to describe retained offline status publishing for broker toggles and IATA changes."
|
||||||
|
breaking_changes: []
|
||||||
|
|||||||
@@ -695,12 +695,12 @@ int MQTTUplink::buildRawJson(char* buffer, size_t buffer_size, const mesh::Packe
|
|||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
void MQTTUplink::publishOnlineStatus(BrokerState& broker) {
|
void MQTTUplink::publishBrokerStatus(BrokerState& broker, bool online) {
|
||||||
char* payload = allocScratchBuffer(768);
|
char* payload = allocScratchBuffer(768);
|
||||||
if (payload == nullptr) {
|
if (payload == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
int len = buildStatusJson(payload, 768, true);
|
int len = buildStatusJson(payload, 768, online);
|
||||||
if (len > 0 && static_cast<size_t>(len) < 768) {
|
if (len > 0 && static_cast<size_t>(len) < 768) {
|
||||||
queuePublish(broker, broker.status_topic, payload, true);
|
queuePublish(broker, broker.status_topic, payload, true);
|
||||||
}
|
}
|
||||||
@@ -999,7 +999,7 @@ void MQTTUplink::loop(const MQTTStatusSnapshot& snapshot) {
|
|||||||
connect_started = true;
|
connect_started = true;
|
||||||
}
|
}
|
||||||
if (broker.connected && !broker.connect_announced) {
|
if (broker.connected && !broker.connect_announced) {
|
||||||
publishOnlineStatus(broker);
|
publishBrokerStatus(broker, true);
|
||||||
broker.connect_announced = true;
|
broker.connect_announced = true;
|
||||||
_last_status_publish = millis();
|
_last_status_publish = millis();
|
||||||
} else if (!broker.connected) {
|
} else if (!broker.connected) {
|
||||||
@@ -1116,6 +1116,12 @@ bool MQTTUplink::setEndpointEnabled(uint8_t bit, bool enabled) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
for (BrokerState& broker : _brokers) {
|
||||||
|
if (broker.spec != nullptr && broker.spec->bit == bit && broker.connected && broker.client != nullptr) {
|
||||||
|
publishBrokerStatus(broker, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
next_mask &= ~bit;
|
next_mask &= ~bit;
|
||||||
}
|
}
|
||||||
_prefs.enabled_mask = next_mask;
|
_prefs.enabled_mask = next_mask;
|
||||||
@@ -1158,6 +1164,9 @@ bool MQTTUplink::setIata(const char* iata) {
|
|||||||
for (size_t i = 0; cleaned[i] != 0; ++i) {
|
for (size_t i = 0; cleaned[i] != 0; ++i) {
|
||||||
cleaned[i] = toupper(static_cast<unsigned char>(cleaned[i]));
|
cleaned[i] = toupper(static_cast<unsigned char>(cleaned[i]));
|
||||||
}
|
}
|
||||||
|
if (strcmp(cleaned, _prefs.iata) != 0 && !isUnsetIataValue(_prefs.iata)) {
|
||||||
|
publishStatus(false);
|
||||||
|
}
|
||||||
if (strcmp(cleaned, MQTT_UNSET_IATA) == 0) {
|
if (strcmp(cleaned, MQTT_UNSET_IATA) == 0) {
|
||||||
StrHelper::strncpy(_prefs.iata, MQTT_UNSET_IATA, sizeof(_prefs.iata));
|
StrHelper::strncpy(_prefs.iata, MQTT_UNSET_IATA, sizeof(_prefs.iata));
|
||||||
refreshIdentityStrings();
|
refreshIdentityStrings();
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ private:
|
|||||||
void destroyBroker(BrokerState& broker, bool reset_retry_state = true);
|
void destroyBroker(BrokerState& broker, bool reset_retry_state = true);
|
||||||
bool refreshToken(BrokerState& broker);
|
bool refreshToken(BrokerState& broker);
|
||||||
void publishStatus(bool online);
|
void publishStatus(bool online);
|
||||||
void publishOnlineStatus(BrokerState& broker);
|
void publishBrokerStatus(BrokerState& broker, bool online);
|
||||||
void queuePublish(BrokerState& broker, const char* topic, const char* payload, bool retain);
|
void queuePublish(BrokerState& broker, const char* topic, const char* payload, bool retain);
|
||||||
int buildStatusJson(char* buffer, size_t buffer_size, bool online) const;
|
int buildStatusJson(char* buffer, size_t buffer_size, bool online) const;
|
||||||
int buildPacketJson(char* buffer, size_t buffer_size, const mesh::Packet& packet, bool is_tx, int rssi, float snr,
|
int buildPacketJson(char* buffer, size_t buffer_size, const mesh::Packet& packet, bool is_tx, int rssi, float snr,
|
||||||
|
|||||||
Reference in New Issue
Block a user