Compare commits
8
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d5bddf5111 | ||
|
|
1c41163bc1 | ||
|
|
f86eccd51b | ||
|
|
4687db8283 | ||
|
|
25d55285ca | ||
|
|
8c414262db | ||
|
|
e9dafd810d | ||
|
|
349833d5d3 |
@@ -23,6 +23,9 @@
|
||||
#include "mesh/RadioLibInterface.h"
|
||||
#include "modules/AdminModule.h"
|
||||
#include "modules/CannedMessageModule.h"
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
#include "mqtt/MQTT.h"
|
||||
#endif
|
||||
#include "modules/ExternalNotificationModule.h"
|
||||
#include "modules/KeyVerificationModule.h"
|
||||
#include "modules/TraceRouteModule.h"
|
||||
@@ -259,6 +262,11 @@ void menuHandler::LoraRegionPicker(uint32_t duration)
|
||||
// Default broker is in use, so subscribe to the appropriate MQTT root topic for this region
|
||||
sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name);
|
||||
changes |= SEGMENT_MODULECONFIG;
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
if (mqtt) {
|
||||
mqtt->reinitTopics();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
service->reloadConfig(changes);
|
||||
|
||||
@@ -830,6 +830,11 @@ void AdminModule::handleSetConfig(const meshtastic_Config &c, bool fromOthers)
|
||||
if (strncmp(moduleConfig.mqtt.root, default_mqtt_root, strlen(default_mqtt_root)) == 0) {
|
||||
// Default root is in use, so subscribe to the appropriate MQTT topic for this region
|
||||
sprintf(moduleConfig.mqtt.root, "%s/%s", default_mqtt_root, myRegion->name);
|
||||
#if !MESHTASTIC_EXCLUDE_MQTT
|
||||
if (mqtt) {
|
||||
mqtt->reinitTopics();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
changes = SEGMENT_CONFIG | SEGMENT_MODULECONFIG;
|
||||
} else {
|
||||
|
||||
+25
-9
@@ -303,6 +303,30 @@ void mqttInit()
|
||||
new MQTT();
|
||||
}
|
||||
|
||||
void MQTT::reinitTopics()
|
||||
{
|
||||
cryptTopic = "/2/e/";
|
||||
mapTopic = "/2/map/";
|
||||
|
||||
if (*moduleConfig.mqtt.root) {
|
||||
cryptTopic = moduleConfig.mqtt.root + cryptTopic;
|
||||
mapTopic = moduleConfig.mqtt.root + mapTopic;
|
||||
isConfiguredForDefaultRootTopic = isDefaultRootTopic(moduleConfig.mqtt.root);
|
||||
} else {
|
||||
cryptTopic = "msh" + cryptTopic;
|
||||
mapTopic = "msh" + mapTopic;
|
||||
isConfiguredForDefaultRootTopic = true;
|
||||
}
|
||||
|
||||
#if HAS_NETWORKING
|
||||
// Force a broker reconnect so subscriptions are refreshed with the new topic prefix
|
||||
if (pubSub.connected()) {
|
||||
pubSub.disconnect();
|
||||
}
|
||||
isConnected = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_NETWORKING
|
||||
MQTT::MQTT() : MQTT(std::unique_ptr<MQTTClient>(new MQTTClient())) {}
|
||||
MQTT::MQTT(std::unique_ptr<MQTTClient> _mqttClient)
|
||||
@@ -317,15 +341,7 @@ MQTT::MQTT() : concurrency::OSThread("mqtt"), mqttQueue(MAX_MQTT_QUEUE)
|
||||
assert(!mqtt);
|
||||
mqtt = this;
|
||||
|
||||
if (*moduleConfig.mqtt.root) {
|
||||
cryptTopic = moduleConfig.mqtt.root + cryptTopic;
|
||||
mapTopic = moduleConfig.mqtt.root + mapTopic;
|
||||
isConfiguredForDefaultRootTopic = isDefaultRootTopic(moduleConfig.mqtt.root);
|
||||
} else {
|
||||
cryptTopic = "msh" + cryptTopic;
|
||||
mapTopic = "msh" + mapTopic;
|
||||
isConfiguredForDefaultRootTopic = true;
|
||||
}
|
||||
reinitTopics();
|
||||
|
||||
if (moduleConfig.mqtt.map_reporting_enabled && moduleConfig.mqtt.has_map_report_settings) {
|
||||
map_position_precision = Default::getConfiguredOrDefault(moduleConfig.mqtt.map_report_settings.position_precision,
|
||||
|
||||
@@ -58,6 +58,12 @@ class MQTT : private concurrency::OSThread
|
||||
bool isUsingDefaultServer() { return isConfiguredForDefaultServer; }
|
||||
bool isUsingDefaultRootTopic() { return isConfiguredForDefaultRootTopic; }
|
||||
|
||||
/** Re-read moduleConfig.mqtt.root and rebuild the topic strings.
|
||||
* Call this after changing the MQTT root (e.g. on LoRa region change).
|
||||
* Also forces a broker reconnect so subscriptions are refreshed.
|
||||
*/
|
||||
void reinitTopics();
|
||||
|
||||
/// Validate the meshtastic_ModuleConfig_MQTTConfig.
|
||||
static bool isValidConfig(const meshtastic_ModuleConfig_MQTTConfig &config) { return isValidConfig(config, nullptr); }
|
||||
|
||||
|
||||
@@ -815,6 +815,35 @@ void test_customMqttRoot(void)
|
||||
[] { return pubsub->subscriptions_.count("custom/2/e/test/+") && pubsub->subscriptions_.count("custom/2/e/PKI/+"); }));
|
||||
}
|
||||
|
||||
// After a LoRa region change, reinitTopics() updates the publish topic and forces
|
||||
// the broker to reconnect with updated subscriptions.
|
||||
void test_reinitTopicsUpdatesOnRegionChange(void)
|
||||
{
|
||||
// Start MQTT with a US region root.
|
||||
strcpy(moduleConfig.mqtt.root, "msh/US");
|
||||
MQTTUnitTest::restart();
|
||||
|
||||
TEST_ASSERT_TRUE(loopUntil(
|
||||
[] { return pubsub->subscriptions_.count("msh/US/2/e/test/+") && pubsub->subscriptions_.count("msh/US/2/e/PKI/+"); }));
|
||||
|
||||
// Simulate region change: update the root and call reinitTopics().
|
||||
strcpy(moduleConfig.mqtt.root, "msh/EU_868");
|
||||
pubsub->subscriptions_.clear();
|
||||
pubsub->published_.clear();
|
||||
mqtt->reinitTopics();
|
||||
|
||||
// Verify that subscriptions are refreshed with the new region prefix.
|
||||
TEST_ASSERT_TRUE(loopUntil([] {
|
||||
return pubsub->subscriptions_.count("msh/EU_868/2/e/test/+") && pubsub->subscriptions_.count("msh/EU_868/2/e/PKI/+");
|
||||
}));
|
||||
|
||||
// Verify that publish also uses the new topic prefix.
|
||||
mqtt->onSend(encrypted, decoded, 0);
|
||||
TEST_ASSERT_EQUAL(1, pubsub->published_.size());
|
||||
const auto &[topic, payload] = pubsub->published_.front();
|
||||
TEST_ASSERT_EQUAL_STRING("msh/EU_868/2/e/test/!12345678", topic.c_str());
|
||||
}
|
||||
|
||||
// Empty configuration is valid.
|
||||
void test_configEmptyIsValid(void)
|
||||
{
|
||||
@@ -919,6 +948,7 @@ void setup()
|
||||
RUN_TEST(test_disabled);
|
||||
RUN_TEST(test_mqttInitSkipsAllocationWhenDisabled);
|
||||
RUN_TEST(test_customMqttRoot);
|
||||
RUN_TEST(test_reinitTopicsUpdatesOnRegionChange);
|
||||
RUN_TEST(test_configEmptyIsValid);
|
||||
RUN_TEST(test_configEnabledEmptyIsValid);
|
||||
RUN_TEST(test_configWithDefaultServer);
|
||||
|
||||
Reference in New Issue
Block a user