mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-23 12:12:24 +00:00
Split MQTT and ESP-NOW controls in Full ESP32 builds
This commit is contained in:
1 parent
9a149eaea1
commit
30067cb5cd
14 files changed
+337
-108
No files matched your search
@@ -1154,9 +1154,9 @@
|
||||
], "Separate from device sleep and LoRa RXPS. Bluetooth coexistence can constrain the effective mode.");
|
||||
}
|
||||
if (info.mqtt) {
|
||||
toggle(info.espnowBridge ? "MQTT + ESP-NOW bridge" : "MQTT broker connections", "set mqtt.enabled", "get mqtt.enabled",
|
||||
toggle("MQTT broker connections", "set mqtt.enabled", "get mqtt.enabled",
|
||||
info.espnowBridge
|
||||
? "This Full image has one shared bridge switch: On starts WiFi/MQTT and then ESP-NOW after WiFi associates; Off stops both. Configure WiFi and broker slots first, and set bridge.channel to your access point's fixed 2.4 GHz channel."
|
||||
? "Independent of the ESP-NOW bridge below. Configure WiFi and broker slots first. Use MQTT alone, ESP-NOW alone, or enable both; get mqtt.running checks the MQTT runtime."
|
||||
: "Configure WiFi and broker slots first, using WebConfig or set mqtt1.preset/settings. Off keeps those settings. get mqtt.running checks the runtime; get mqtt.status shows connections.");
|
||||
["status", "packets", "raw", "rx"].forEach(function (name) {
|
||||
toggle("MQTT " + (name === "rx" ? "receive capture" : name + " publication"), "set mqtt." + name, "get mqtt." + name,
|
||||
@@ -1183,11 +1183,14 @@
|
||||
}), "Use the UART and pin map for this exact board. Canonical GPS-enabled RAK4631 uses UART2; select it with set bridge.uart 2 while the bridge is stopped. UART1 needs a compatible GPS-free image.");
|
||||
}
|
||||
if (info.espnowBridge && infrastructure) {
|
||||
if (!info.mqtt) toggle("ESP-NOW bridge", "set bridge.enabled", "get bridge.running");
|
||||
toggle("ESP-NOW bridge", "set bridge.enabled", "get bridge.enabled",
|
||||
info.mqtt
|
||||
? "Independent of MQTT in this Full image. set espnow.enabled is an alias. get bridge.running (or get espnow.running) checks its live state."
|
||||
: "set bridge.enabled controls the ESP-NOW bridge; get bridge.running checks its live state.");
|
||||
section("ESP-NOW bridge framing", ["wrapped", "raw"].map(function (mode) {
|
||||
return { label: mode, commands: ["set bridge.format " + mode] };
|
||||
}), info.mqtt
|
||||
? "This Full image shares one 2.4 GHz radio between WiFi/MQTT and ESP-NOW. ESP-NOW begins after WiFi connects and only when bridge.channel matches that access point's fixed channel. Primary ESP-NOW mesh uses set espnow.channel instead."
|
||||
? "This Full image shares one 2.4 GHz radio between WiFi/MQTT and ESP-NOW. When both are enabled, ESP-NOW begins after WiFi connects and only when bridge.channel matches that access point's fixed channel. ESP-NOW-only mode does not need WiFi credentials. Primary ESP-NOW mesh uses set espnow.channel instead."
|
||||
: "Set bridge.channel to the bridge channel. Primary ESP-NOW mesh uses set espnow.channel instead; see the board guide before changing channels.");
|
||||
}
|
||||
if (full && /sensecapindicator/i.test(profile.target)) section("Indicator wireless transport", [
|
||||
|
||||
@@ -180,8 +180,12 @@ For commands and option explanations, follow the
|
||||
|
||||
An ESP-NOW bridge target keeps LoRa as its primary mesh radio. Expanded ESP32
|
||||
Full repeater and room-server images combine ESP-NOW with WiFi MQTT in the
|
||||
same firmware. Both use one 2.4 GHz radio, so the ESP-NOW bridge channel must
|
||||
match the connected WiFi access point's fixed channel. Its runtime
|
||||
same firmware. MQTT and ESP-NOW are independent runtime transports: use
|
||||
`set mqtt.enabled on|off` for MQTT and `set bridge.enabled on|off` (or
|
||||
`set espnow.enabled on|off`) for ESP-NOW, so either or both can run. Both use
|
||||
one 2.4 GHz radio, so when both are enabled the ESP-NOW bridge channel must
|
||||
match the connected WiFi access point's fixed channel. ESP-NOW-only mode does
|
||||
not require WiFi credentials. Its runtime
|
||||
`bridge.format` setting chooses the peer protocol: `wrapped` (the
|
||||
backward-compatible bridge-to-bridge default using `bridge.secret`) or `raw`
|
||||
(direct MeshCore ESP-NOW LR frames for `Generic_ESPNOW`,
|
||||
|
||||
@@ -26,10 +26,10 @@ public:
|
||||
if (the_mesh.isWebConfigActive()) mask |= mesh::wireless::WiFi;
|
||||
#endif
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
if (the_mesh.isBridgeRunning()) mask |= mesh::wireless::WiFi;
|
||||
if (the_mesh.isMqttBridgeRunning()) mask |= mesh::wireless::WiFi;
|
||||
#endif
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
if (the_mesh.isBridgeRunning()) mask |= mesh::wireless::EspNow;
|
||||
if (the_mesh.isEspNowBridgeRunning()) mask |= mesh::wireless::EspNow;
|
||||
#endif
|
||||
#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW
|
||||
if (radio_driver.isEnabled()) mask |= mesh::wireless::EspNow;
|
||||
@@ -61,12 +61,12 @@ public:
|
||||
resume_web_ = the_mesh.isWebConfigActive();
|
||||
#endif
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
resume_mqtt_ = the_mesh.isBridgeRunning();
|
||||
resume_mqtt_ = the_mesh.isMqttBridgeRunning();
|
||||
#endif
|
||||
wifi_saved_ = true;
|
||||
}
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
if (!the_mesh.setBridgeState(false)) return Result::Failed;
|
||||
if (!the_mesh.setMqttBridgeState(false)) return Result::Failed;
|
||||
#endif
|
||||
#ifdef WITH_WEBCONFIG
|
||||
if (the_mesh.isWebConfigActive()) {
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
|| !(enabled() & mesh::wireless::WiFi)
|
||||
#endif
|
||||
) {
|
||||
if (!the_mesh.setBridgeState(true)) return Result::Failed;
|
||||
if (!the_mesh.setMqttBridgeState(true)) return Result::Failed;
|
||||
}
|
||||
#endif
|
||||
wifi_saved_ = resume_web_ = resume_mqtt_ = false;
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
#endif
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
if (service == mesh::wireless::EspNow)
|
||||
return the_mesh.setBridgeState(on) ? Result::Done : Result::Failed;
|
||||
return the_mesh.setEspNowBridgeState(on) ? Result::Done : Result::Failed;
|
||||
#endif
|
||||
#if defined(MESH_PRIMARY_ESPNOW) && MESH_PRIMARY_ESPNOW
|
||||
if (service == mesh::wireless::EspNow) {
|
||||
|
||||
@@ -1146,7 +1146,7 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
|
||||
#endif
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
// MQTT bridge: always feed RX packets - bridge decides based on mqtt.rx setting
|
||||
if (mqtt_bridge) mqtt_bridge->onPacketReceived(pkt);
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning()) mqtt_bridge->onPacketReceived(pkt);
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
// ESP-NOW follows bridge.source, independently of MQTT's mqtt.rx policy.
|
||||
ESPNowBridge* espnow = &espnow_bridge;
|
||||
@@ -1198,7 +1198,7 @@ void MyMesh::logTx(mesh::Packet *pkt, int len) {
|
||||
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
// MQTT bridge: always feed TX packets - bridge decides based on mqtt.tx setting
|
||||
if (mqtt_bridge) mqtt_bridge->sendPacket(pkt);
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning()) mqtt_bridge->sendPacket(pkt);
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
ESPNowBridge* espnow = &espnow_bridge;
|
||||
if (_prefs.bridge_pkt_src == 0 && espnow && espnow->isRunning()) {
|
||||
@@ -3595,6 +3595,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
#else
|
||||
_prefs.bridge_enabled = 1; // enabled
|
||||
#endif
|
||||
_prefs.espnow_bridge_enabled = 1; // preserves the Full image's former combined default
|
||||
_prefs.bridge_delay = 500; // milliseconds
|
||||
_prefs.bridge_pkt_src = 1; // logRx (RX packets)
|
||||
_prefs.bridge_baud = 115200; // baud rate
|
||||
@@ -3792,6 +3793,10 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
if (_prefs.espnow_bridge_enabled) setEspNowBridgeState(true);
|
||||
#endif
|
||||
|
||||
// Wire fault-alert reporter. begin() is safe regardless of bridge state.
|
||||
// Passing `this` as the callbacks lets the reporter resolve a TransportKey
|
||||
// scope (alert.region override, falling back to default_scope) so alert
|
||||
@@ -3806,7 +3811,8 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
// Preserve the MQTT observer's first-boot setup experience even though the
|
||||
// persistent WebUI master switch defaults off on infrastructure roles.
|
||||
start_webui = start_webui || _cli.getObserverPrefs()->wifi_ssid[0] == 0;
|
||||
start_webui = start_webui || (_prefs.bridge_enabled
|
||||
&& _cli.getObserverPrefs()->wifi_ssid[0] == 0);
|
||||
if (start_webui && _cli.getObserverPrefs()->wifi_ssid[0] == 0) {
|
||||
#if defined(WITH_ESPNOW_BRIDGE)
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
@@ -10814,7 +10820,7 @@ void MyMesh::onConfigBatchEnd() {
|
||||
if (_wc_restart_pending) {
|
||||
_wc_restart_pending = false;
|
||||
_wc_slot_restart_mask = 0;
|
||||
if (_prefs.bridge_enabled) restartBridge();
|
||||
if (_prefs.bridge_enabled) restartMqttBridge();
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -604,7 +604,8 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks
|
||||
// up a second WiFi owner before the AP selects the shared channel.
|
||||
bool startSharedEspNowBridgeIfReady() {
|
||||
if (espnow_bridge.isRunning()) return true;
|
||||
if (!mqtt_bridge || !mqtt_bridge->isRunning() || !WiFi.isConnected()) return false;
|
||||
if (!_prefs.espnow_bridge_enabled) return false;
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning() && !WiFi.isConnected()) return false;
|
||||
if (!millisHasNowPassed(shared_espnow_retry_at)) return false;
|
||||
shared_espnow_retry_at = millis() + 5000;
|
||||
configureBridgeFilter(&espnow_bridge);
|
||||
@@ -1246,12 +1247,22 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
bool setBridgeState(bool enable) override {
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
// The combined Full bridge is intentionally one saved switch. ESP-NOW is
|
||||
// started only after MQTT has brought WiFi up, so it can validate and share
|
||||
// the access point channel instead of retuning the station interface.
|
||||
if (!enable && !mqtt_bridge && !espnow_bridge.isRunning()) return true;
|
||||
bool isEspNowBridgeRunning() override {
|
||||
return espnow_bridge.isRunning();
|
||||
}
|
||||
|
||||
bool setMqttBridgeState(bool enable) override {
|
||||
if (!enable) {
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning()) mqtt_bridge->end();
|
||||
_alerter.setBridge(nullptr);
|
||||
return !mqtt_bridge || !mqtt_bridge->isRunning();
|
||||
}
|
||||
// Give the WiFi station to MQTT while it associates. ESP-NOW is restarted
|
||||
// after the AP channel is known, which avoids a raw ESP-NOW-only session
|
||||
// pinning the station to a different channel.
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
shared_espnow_retry_at = 0;
|
||||
if (!mqtt_bridge) {
|
||||
MQTTNodeInfo node_info;
|
||||
node_info.node_name = _prefs.node_name;
|
||||
@@ -1265,32 +1276,71 @@ public:
|
||||
getRTCClock(), &self_id);
|
||||
if (!mqtt_bridge) return false;
|
||||
}
|
||||
if (enable) {
|
||||
if (!mqtt_bridge->isRunning()) {
|
||||
char device_id[65];
|
||||
mesh::LocalIdentity self_id = getSelfId();
|
||||
mesh::Utils::toHex(device_id, self_id.pub_key, PUB_KEY_SIZE);
|
||||
mqtt_bridge->setDeviceID(device_id);
|
||||
mqtt_bridge->setFirmwareVersion(getFirmwareVer());
|
||||
mqtt_bridge->setBoardModel(_cli.getBoard()->getManufacturerName());
|
||||
mqtt_bridge->setBuildDate(getBuildDate());
|
||||
mqtt_bridge->setStatsSources(this, _radio, _cli.getBoard(), _ms);
|
||||
configureBridgeFilter(mqtt_bridge);
|
||||
mqtt_bridge->begin();
|
||||
_alerter.setBridge(mqtt_bridge);
|
||||
}
|
||||
if (!mqtt_bridge->isRunning()) return false;
|
||||
if (!mqtt_bridge->isRunning()) {
|
||||
char device_id[65];
|
||||
mesh::LocalIdentity self_id = getSelfId();
|
||||
mesh::Utils::toHex(device_id, self_id.pub_key, PUB_KEY_SIZE);
|
||||
mqtt_bridge->setDeviceID(device_id);
|
||||
mqtt_bridge->setFirmwareVersion(getFirmwareVer());
|
||||
mqtt_bridge->setBoardModel(_cli.getBoard()->getManufacturerName());
|
||||
mqtt_bridge->setBuildDate(getBuildDate());
|
||||
mqtt_bridge->setStatsSources(this, _radio, _cli.getBoard(), _ms);
|
||||
configureBridgeFilter(mqtt_bridge);
|
||||
mqtt_bridge->begin();
|
||||
_alerter.setBridge(mqtt_bridge);
|
||||
}
|
||||
if (_prefs.espnow_bridge_enabled) startSharedEspNowBridgeIfReady();
|
||||
return mqtt_bridge->isRunning();
|
||||
}
|
||||
|
||||
bool setEspNowBridgeState(bool enable) override {
|
||||
if (!enable) {
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
shared_espnow_retry_at = 0;
|
||||
return !espnow_bridge.isRunning();
|
||||
}
|
||||
if (espnow_bridge.isRunning()) return true;
|
||||
shared_espnow_retry_at = 0;
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning()) {
|
||||
// Association is asynchronous; servicePostMeshLoop retries once the
|
||||
// MQTT station has joined the access point on its fixed channel.
|
||||
startSharedEspNowBridgeIfReady();
|
||||
// MQTT has started successfully; ESP-NOW joins after its WiFi station
|
||||
// associates and validates the configured shared channel.
|
||||
return true;
|
||||
}
|
||||
configureBridgeFilter(&espnow_bridge);
|
||||
espnow_bridge.begin();
|
||||
return espnow_bridge.isRunning();
|
||||
}
|
||||
|
||||
bool restartMqttBridge() override {
|
||||
#ifdef WITH_WEBCONFIG
|
||||
if (_wc_batch_active) {
|
||||
_wc_restart_pending = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
if (mqtt_bridge->isRunning()) mqtt_bridge->end();
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning()) mqtt_bridge->end();
|
||||
shared_espnow_retry_at = 0;
|
||||
_alerter.setBridge(nullptr);
|
||||
return !mqtt_bridge->isRunning() && !espnow_bridge.isRunning();
|
||||
return !_prefs.bridge_enabled || setMqttBridgeState(true);
|
||||
}
|
||||
|
||||
bool restartEspNowBridge() override {
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
shared_espnow_retry_at = 0;
|
||||
return !_prefs.espnow_bridge_enabled || setEspNowBridgeState(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
bool setBridgeState(bool enable) override {
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
if (!enable) return setEspNowBridgeState(false) && setMqttBridgeState(false);
|
||||
const bool mqtt_ok = _prefs.bridge_enabled
|
||||
? setMqttBridgeState(true) : setMqttBridgeState(false);
|
||||
const bool espnow_ok = _prefs.espnow_bridge_enabled
|
||||
? setEspNowBridgeState(true) : setEspNowBridgeState(false);
|
||||
return mqtt_ok && espnow_ok;
|
||||
#else
|
||||
// Disabling an already-absent heap-backed bridge is successful and must
|
||||
// not allocate an instance merely to stop it. The embedded ESP-NOW bridge
|
||||
@@ -1381,11 +1431,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
if (mqtt_bridge && mqtt_bridge->isRunning()) mqtt_bridge->end();
|
||||
shared_espnow_retry_at = 0;
|
||||
_alerter.setBridge(nullptr);
|
||||
return setBridgeState(true);
|
||||
return restartEspNowBridge() && restartMqttBridge();
|
||||
#else
|
||||
#ifdef WITH_RS232_BRIDGE
|
||||
// RS-232 changes must be applied synchronously so the CLI can commit or
|
||||
|
||||
@@ -331,7 +331,7 @@ void MyMesh::logRx(mesh::Packet *pkt, int len, float score) {
|
||||
#endif
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
// MQTT bridge: always feed RX packets - bridge decides based on mqtt.rx setting
|
||||
if (_prefs.bridge_enabled && bridge) bridge->onPacketReceived(pkt);
|
||||
if (_prefs.bridge_enabled && bridge && bridge->isRunning()) bridge->onPacketReceived(pkt);
|
||||
#endif
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
if (_prefs.bridge_pkt_src == 1 && espnow_bridge.isRunning()) {
|
||||
@@ -373,7 +373,7 @@ void MyMesh::logTx(mesh::Packet *pkt, int len) {
|
||||
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
// MQTT bridge: always feed TX packets - bridge decides based on mqtt.tx setting
|
||||
if (_prefs.bridge_enabled && bridge) bridge->sendPacket(pkt);
|
||||
if (_prefs.bridge_enabled && bridge && bridge->isRunning()) bridge->sendPacket(pkt);
|
||||
#endif
|
||||
#ifdef WITH_ESPNOW_BRIDGE
|
||||
if (_prefs.bridge_pkt_src == 0 && espnow_bridge.isRunning()) {
|
||||
@@ -1321,6 +1321,7 @@ MyMesh::MyMesh(mesh::MainBoard &board, mesh::Radio &radio, mesh::MillisecondCloc
|
||||
|
||||
// bridge defaults (same as repeater)
|
||||
_prefs.bridge_enabled = 1; // enabled
|
||||
_prefs.espnow_bridge_enabled = 1; // preserves the Full image's former combined default
|
||||
_prefs.bridge_delay = 500; // milliseconds
|
||||
_prefs.bridge_pkt_src = 1; // logRx (RX packets)
|
||||
_prefs.bridge_baud = 115200; // baud rate
|
||||
@@ -1458,6 +1459,10 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
if (_prefs.espnow_bridge_enabled) setEspNowBridgeState(true);
|
||||
#endif
|
||||
|
||||
// Wire fault-alert reporter. begin() is safe regardless of bridge state.
|
||||
// Passing `this` as the callbacks lets the reporter resolve a TransportKey
|
||||
// scope (alert.region override, falling back to default_scope) so alert
|
||||
@@ -1470,7 +1475,8 @@ void MyMesh::begin(FILESYSTEM *fs) {
|
||||
#if defined(WITH_WEBCONFIG) && !defined(WEBCONFIG_NO_AUTO_AP)
|
||||
bool start_webui = WebConfigServer::loadEnabled(false);
|
||||
#ifdef WITH_MQTT_BRIDGE
|
||||
start_webui = start_webui || _cli.getObserverPrefs()->wifi_ssid[0] == 0;
|
||||
start_webui = start_webui || (_prefs.bridge_enabled
|
||||
&& _cli.getObserverPrefs()->wifi_ssid[0] == 0);
|
||||
if (start_webui && _cli.getObserverPrefs()->wifi_ssid[0] == 0) {
|
||||
#if defined(WITH_ESPNOW_BRIDGE)
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
@@ -2008,7 +2014,7 @@ void MyMesh::onConfigBatchEnd() {
|
||||
if (_wc_restart_pending) {
|
||||
_wc_restart_pending = false;
|
||||
_wc_slot_restart_mask = 0;
|
||||
if (_prefs.bridge_enabled) restartBridge();
|
||||
if (_prefs.bridge_enabled) restartMqttBridge();
|
||||
return;
|
||||
}
|
||||
const uint8_t mask = _wc_slot_restart_mask;
|
||||
|
||||
@@ -564,7 +564,8 @@ public:
|
||||
// station interface so it can share the AP-selected channel safely.
|
||||
bool startSharedEspNowBridgeIfReady() {
|
||||
if (espnow_bridge.isRunning()) return true;
|
||||
if (!bridge || !bridge->isRunning() || !WiFi.isConnected()) return false;
|
||||
if (!_prefs.espnow_bridge_enabled) return false;
|
||||
if (bridge && bridge->isRunning() && !WiFi.isConnected()) return false;
|
||||
if (!millisHasNowPassed(shared_espnow_retry_at)) return false;
|
||||
shared_espnow_retry_at = millis() + 5000;
|
||||
configureBridgeFilter(&espnow_bridge);
|
||||
@@ -581,20 +582,22 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void configureBridgeFilter(AbstractBridge* active_bridge) {
|
||||
#if MESH_ENABLE_ROOM_FLOOD_RULE_ENGINE
|
||||
active_bridge->setPacketFilter([](void* context, const mesh::Packet* packet) {
|
||||
return static_cast<MyMesh*>(context)->allowTransportPacket(packet, 2); // RULE_MODE_BRIDGE
|
||||
}, this);
|
||||
#else
|
||||
(void)active_bridge;
|
||||
#endif
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
bool isEspNowBridgeRunning() override {
|
||||
return espnow_bridge.isRunning();
|
||||
}
|
||||
|
||||
bool setBridgeState(bool enable) override {
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
if (!enable && !bridge && !espnow_bridge.isRunning()) return true;
|
||||
bool setMqttBridgeState(bool enable) override {
|
||||
if (!enable) {
|
||||
if (bridge && bridge->isRunning()) bridge->end();
|
||||
_alerter.setBridge(nullptr);
|
||||
return !bridge || !bridge->isRunning();
|
||||
}
|
||||
// Give the WiFi station to MQTT while it associates. ESP-NOW is restarted
|
||||
// after the AP channel is known, which avoids a raw ESP-NOW-only session
|
||||
// pinning the station to a different channel.
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
shared_espnow_retry_at = 0;
|
||||
if (!bridge) {
|
||||
MQTTNodeInfo node_info;
|
||||
node_info.node_name = _prefs.node_name;
|
||||
@@ -608,39 +611,87 @@ public:
|
||||
getRTCClock(), &self_id);
|
||||
if (!bridge) return false;
|
||||
}
|
||||
if (enable) {
|
||||
if (!bridge->isRunning()) {
|
||||
char device_id[65];
|
||||
mesh::LocalIdentity self_id = getSelfId();
|
||||
mesh::Utils::toHex(device_id, self_id.pub_key, PUB_KEY_SIZE);
|
||||
bridge->setDeviceID(device_id);
|
||||
bridge->setFirmwareVersion(getFirmwareVer());
|
||||
bridge->setBoardModel(_cli.getBoard()->getManufacturerName());
|
||||
bridge->setBuildDate(getBuildDate());
|
||||
bridge->setStatsSources(this, _radio, _cli.getBoard(), _ms);
|
||||
if (!bridge->isRunning()) {
|
||||
char device_id[65];
|
||||
mesh::LocalIdentity self_id = getSelfId();
|
||||
mesh::Utils::toHex(device_id, self_id.pub_key, PUB_KEY_SIZE);
|
||||
bridge->setDeviceID(device_id);
|
||||
bridge->setFirmwareVersion(getFirmwareVer());
|
||||
bridge->setBoardModel(_cli.getBoard()->getManufacturerName());
|
||||
bridge->setBuildDate(getBuildDate());
|
||||
bridge->setStatsSources(this, _radio, _cli.getBoard(), _ms);
|
||||
#ifdef WITH_SNMP
|
||||
if (_cli.getObserverPrefs()->snmp_enabled) {
|
||||
_snmp_agent.setNodeName(_prefs.node_name);
|
||||
_snmp_agent.setFirmwareVersion(getFirmwareVer());
|
||||
bridge->setSNMPAgent(&_snmp_agent);
|
||||
}
|
||||
#endif
|
||||
configureBridgeFilter(bridge);
|
||||
bridge->begin();
|
||||
_alerter.setBridge(bridge);
|
||||
if (_cli.getObserverPrefs()->snmp_enabled) {
|
||||
_snmp_agent.setNodeName(_prefs.node_name);
|
||||
_snmp_agent.setFirmwareVersion(getFirmwareVer());
|
||||
bridge->setSNMPAgent(&_snmp_agent);
|
||||
}
|
||||
if (!bridge->isRunning()) return false;
|
||||
#endif
|
||||
configureBridgeFilter(bridge);
|
||||
bridge->begin();
|
||||
_alerter.setBridge(bridge);
|
||||
}
|
||||
if (_prefs.espnow_bridge_enabled) startSharedEspNowBridgeIfReady();
|
||||
return bridge->isRunning();
|
||||
}
|
||||
|
||||
bool setEspNowBridgeState(bool enable) override {
|
||||
if (!enable) {
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
shared_espnow_retry_at = 0;
|
||||
return !espnow_bridge.isRunning();
|
||||
}
|
||||
if (espnow_bridge.isRunning()) return true;
|
||||
shared_espnow_retry_at = 0;
|
||||
if (bridge && bridge->isRunning()) {
|
||||
startSharedEspNowBridgeIfReady();
|
||||
// The MQTT task owns association. ESP-NOW starts after it sees the
|
||||
// active AP channel and accepts the configured bridge channel.
|
||||
return true;
|
||||
}
|
||||
configureBridgeFilter(&espnow_bridge);
|
||||
espnow_bridge.begin();
|
||||
return espnow_bridge.isRunning();
|
||||
}
|
||||
|
||||
bool restartMqttBridge() override {
|
||||
#ifdef WITH_WEBCONFIG
|
||||
if (_wc_batch_active) {
|
||||
_wc_restart_pending = true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
if (bridge->isRunning()) bridge->end();
|
||||
if (bridge && bridge->isRunning()) bridge->end();
|
||||
shared_espnow_retry_at = 0;
|
||||
_alerter.setBridge(nullptr);
|
||||
return !bridge->isRunning() && !espnow_bridge.isRunning();
|
||||
return !_prefs.bridge_enabled || setMqttBridgeState(true);
|
||||
}
|
||||
|
||||
bool restartEspNowBridge() override {
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
shared_espnow_retry_at = 0;
|
||||
return !_prefs.espnow_bridge_enabled || setEspNowBridgeState(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void configureBridgeFilter(AbstractBridge* active_bridge) {
|
||||
#if MESH_ENABLE_ROOM_FLOOD_RULE_ENGINE
|
||||
active_bridge->setPacketFilter([](void* context, const mesh::Packet* packet) {
|
||||
return static_cast<MyMesh*>(context)->allowTransportPacket(packet, 2); // RULE_MODE_BRIDGE
|
||||
}, this);
|
||||
#else
|
||||
(void)active_bridge;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool setBridgeState(bool enable) override {
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
if (!enable) return setEspNowBridgeState(false) && setMqttBridgeState(false);
|
||||
const bool mqtt_ok = _prefs.bridge_enabled
|
||||
? setMqttBridgeState(true) : setMqttBridgeState(false);
|
||||
const bool espnow_ok = _prefs.espnow_bridge_enabled
|
||||
? setEspNowBridgeState(true) : setEspNowBridgeState(false);
|
||||
return mqtt_ok && espnow_ok;
|
||||
#else
|
||||
// An absent MQTT bridge is already stopped. Do not allocate one solely to
|
||||
// satisfy an idempotent disable request.
|
||||
@@ -705,11 +756,7 @@ public:
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
if (espnow_bridge.isRunning()) espnow_bridge.end();
|
||||
if (bridge && bridge->isRunning()) bridge->end();
|
||||
shared_espnow_retry_at = 0;
|
||||
_alerter.setBridge(nullptr);
|
||||
return setBridgeState(true);
|
||||
return restartEspNowBridge() && restartMqttBridge();
|
||||
#else
|
||||
if (!bridge) return false;
|
||||
#ifdef WITH_WEBCONFIG
|
||||
|
||||
@@ -1286,6 +1286,10 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
&& preamble <= mesh::RadioProfiles::MaxPreamble))) {
|
||||
_prefs->primary_radio_preamble = preamble;
|
||||
}
|
||||
if (file.available() >= (int)sizeof(_prefs->espnow_bridge_enabled)) {
|
||||
file.read((uint8_t *)&_prefs->espnow_bridge_enabled,
|
||||
sizeof(_prefs->espnow_bridge_enabled));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1359,6 +1363,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
|
||||
}
|
||||
#endif
|
||||
_prefs->bridge_enabled = constrain(_prefs->bridge_enabled, 0, 1);
|
||||
_prefs->espnow_bridge_enabled = constrain(_prefs->espnow_bridge_enabled, 0, 1);
|
||||
_prefs->bridge_delay = constrain(_prefs->bridge_delay, 0, 10000);
|
||||
_prefs->bridge_pkt_src = constrain(_prefs->bridge_pkt_src, 0, 1);
|
||||
_prefs->bridge_baud = constrain(_prefs->bridge_baud, 9600, BRIDGE_MAX_BAUD);
|
||||
@@ -1607,6 +1612,7 @@ static bool writeCommonPrefsImage(Writer& writer, NodePrefs* prefs) {
|
||||
WRITE_COMMON_PREFS(&prefs->bridge_uart); // 862
|
||||
WRITE_COMMON_PREFS(&prefs->bridge_format); // 863
|
||||
WRITE_COMMON_PREFS(&prefs->primary_radio_preamble); // appended primary tuple field
|
||||
WRITE_COMMON_PREFS(&prefs->espnow_bridge_enabled); // appended Full ESP-NOW intent
|
||||
|
||||
#undef WRITE_COMMON_PREFS_BYTES
|
||||
#undef WRITE_COMMON_PREFS
|
||||
@@ -1764,6 +1770,7 @@ void CommonCLI::savePrefs(FILESYSTEM* fs, PrefsSaveRouting::Scope scope) {
|
||||
file.write((uint8_t *)&_prefs->bridge_uart, sizeof(_prefs->bridge_uart)); // 862
|
||||
file.write((uint8_t *)&_prefs->bridge_format, sizeof(_prefs->bridge_format)); // 863
|
||||
file.write((uint8_t *)&_prefs->primary_radio_preamble, sizeof(_prefs->primary_radio_preamble)); // appended
|
||||
file.write((uint8_t *)&_prefs->espnow_bridge_enabled, sizeof(_prefs->espnow_bridge_enabled)); // appended
|
||||
|
||||
_common_save_succeeded = file.commit();
|
||||
if (!_common_save_succeeded) {
|
||||
@@ -3343,7 +3350,7 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
_prefs->usb_logging_enabled = usb_enabled ? 1 : 0;
|
||||
_prefs->bridge_enabled = wifi_enabled ? 1 : 0;
|
||||
mesh::setUsbLoggingEnabled(usb_enabled);
|
||||
_callbacks->setBridgeState(wifi_enabled);
|
||||
_callbacks->setMqttBridgeState(wifi_enabled);
|
||||
savePrefs();
|
||||
snprintf(reply, 160, "OK - logging.output %s (saved)", value);
|
||||
return;
|
||||
@@ -3392,6 +3399,19 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
#endif
|
||||
// Observer/MQTT/WiFi/timezone/alert/SNMP commands live in CommonCLI_Observer.cpp.
|
||||
if (handleObserverSetCmd(sender_timestamp, config, reply)) return;
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
if (memcmp(config, "espnow.enabled ", 15) == 0) {
|
||||
const char* value = config + 15;
|
||||
if (strcmp(value, "on") != 0 && strcmp(value, "off") != 0) {
|
||||
strcpy(reply, "Error: use set espnow.enabled on|off");
|
||||
} else {
|
||||
char canonical[28];
|
||||
snprintf(canonical, sizeof(canonical), "set bridge.enabled %s", value);
|
||||
handleSetCmd(sender_timestamp, canonical, reply);
|
||||
}
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
#if defined(NRF52_PLATFORM) && defined(OTA_SD_STORE)
|
||||
if (handleSdCardSetCmd(config, reply)) return;
|
||||
#endif
|
||||
@@ -4246,6 +4266,15 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
if (!parseOnOffStrict(&config[15], enable)) {
|
||||
strcpy(reply, "Error: usage set bridge.enabled on|off");
|
||||
} else {
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
// In a combined Full image bridge.enabled retains its ESP-NOW meaning;
|
||||
// mqtt.enabled is the independent MQTT switch.
|
||||
_prefs->espnow_bridge_enabled = enable;
|
||||
const bool applied = _callbacks->setEspNowBridgeState(enable);
|
||||
savePrefs();
|
||||
strcpy(reply, applied ? "OK"
|
||||
: "Error: ESP-NOW runtime change failed; setting saved");
|
||||
#else
|
||||
#ifdef WITH_RS232_BRIDGE
|
||||
if (enable
|
||||
&& _sensors->gpsSerialTransportMayConflict(_prefs->bridge_uart)
|
||||
@@ -4290,6 +4319,7 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
savePrefs();
|
||||
strcpy(reply, applied ? "OK"
|
||||
: "Error: bridge runtime change failed; setting saved");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
} else if (memcmp(config, "bridge.delay ", 13) == 0) {
|
||||
@@ -4331,7 +4361,12 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
const uint32_t previous_baud = _prefs->bridge_baud;
|
||||
const bool previous_running = _callbacks->isBridgeRunning();
|
||||
_prefs->bridge_baud = baud;
|
||||
const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
const bool applied =
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
!_prefs->espnow_bridge_enabled || _callbacks->restartEspNowBridge();
|
||||
#else
|
||||
!_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
#endif
|
||||
if (applied) {
|
||||
savePrefs();
|
||||
strcpy(reply, "OK");
|
||||
@@ -4374,7 +4409,12 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
const uint8_t previous_uart = _prefs->bridge_uart;
|
||||
const bool previous_running = _callbacks->isBridgeRunning();
|
||||
_prefs->bridge_uart = (uint8_t)uart;
|
||||
const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
const bool applied =
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
!_prefs->espnow_bridge_enabled || _callbacks->restartEspNowBridge();
|
||||
#else
|
||||
!_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
#endif
|
||||
if (!applied) {
|
||||
_prefs->bridge_uart = previous_uart;
|
||||
const bool restored = previous_running
|
||||
@@ -4401,7 +4441,12 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
if (mesh::bridge::parseEspNowBridgeChannel(
|
||||
&config[15], _prefs->bridge_format, channel)) {
|
||||
_prefs->bridge_channel = channel;
|
||||
const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
const bool applied =
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
!_prefs->espnow_bridge_enabled || _callbacks->restartEspNowBridge();
|
||||
#else
|
||||
!_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
#endif
|
||||
savePrefs();
|
||||
strcpy(reply, applied ? "OK"
|
||||
: "Error: setting saved; bridge failed to restart");
|
||||
@@ -4416,7 +4461,12 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
sprintf(reply, "Error: secret must be 1-%u characters", (unsigned)(sizeof(_prefs->bridge_secret) - 1));
|
||||
} else {
|
||||
StrHelper::strncpy(_prefs->bridge_secret, secret, sizeof(_prefs->bridge_secret));
|
||||
const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
const bool applied =
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
!_prefs->espnow_bridge_enabled || _callbacks->restartEspNowBridge();
|
||||
#else
|
||||
!_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
#endif
|
||||
savePrefs();
|
||||
strcpy(reply, applied ? "OK"
|
||||
: "Error: setting saved; bridge failed to restart");
|
||||
@@ -4430,7 +4480,12 @@ void CommonCLI::handleSetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
strcpy(reply, "Error: set bridge.channel to 1-13 before changing format");
|
||||
} else {
|
||||
_prefs->bridge_format = format;
|
||||
const bool applied = !_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
const bool applied =
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
!_prefs->espnow_bridge_enabled || _callbacks->restartEspNowBridge();
|
||||
#else
|
||||
!_prefs->bridge_enabled || _callbacks->restartBridge();
|
||||
#endif
|
||||
savePrefs();
|
||||
if (!applied) {
|
||||
strcpy(reply, "Error: setting saved; bridge failed to restart");
|
||||
@@ -4839,7 +4894,9 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
sprintf(reply, "> %s", _callbacks->getRole());
|
||||
} else if (configKeyEquals(config, "bridge.type")) {
|
||||
sprintf(reply, "> %s",
|
||||
#ifdef WITH_RS232_BRIDGE
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
"mqtt+espnow"
|
||||
#elif defined(WITH_RS232_BRIDGE)
|
||||
"rs232"
|
||||
#elif WITH_ESPNOW_BRIDGE
|
||||
"espnow"
|
||||
@@ -4851,9 +4908,25 @@ void CommonCLI::handleGetCmd(uint32_t sender_timestamp, char* command, char* rep
|
||||
);
|
||||
#ifdef WITH_BRIDGE
|
||||
} else if (configKeyEquals(config, "bridge.enabled")) {
|
||||
sprintf(reply, "> %s", _prefs->bridge_enabled ? "on" : "off");
|
||||
sprintf(reply, "> %s",
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
_prefs->espnow_bridge_enabled ? "on" : "off");
|
||||
#else
|
||||
_prefs->bridge_enabled ? "on" : "off");
|
||||
#endif
|
||||
} else if (configKeyEquals(config, "bridge.running")) {
|
||||
sprintf(reply, "> %s", _callbacks->isBridgeRunning() ? "on" : "off");
|
||||
sprintf(reply, "> %s",
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
_callbacks->isEspNowBridgeRunning() ? "on" : "off");
|
||||
#else
|
||||
_callbacks->isBridgeRunning() ? "on" : "off");
|
||||
#endif
|
||||
#if defined(WITH_MQTT_BRIDGE) && defined(WITH_ESPNOW_BRIDGE)
|
||||
} else if (configKeyEquals(config, "espnow.enabled")) {
|
||||
sprintf(reply, "> %s", _prefs->espnow_bridge_enabled ? "on" : "off");
|
||||
} else if (configKeyEquals(config, "espnow.running")) {
|
||||
sprintf(reply, "> %s", _callbacks->isEspNowBridgeRunning() ? "on" : "off");
|
||||
#endif
|
||||
} else if (configKeyEquals(config, "bridge.delay")) {
|
||||
sprintf(reply, "> %d", (uint32_t)_prefs->bridge_delay);
|
||||
} else if (configKeyEquals(config, "bridge.source")) {
|
||||
|
||||
@@ -191,6 +191,11 @@ public:
|
||||
// Appended after the existing /com_prefs tail. Keep the preamble in the same
|
||||
// transaction as frequency/modulation; old images adopt /radio_profiles.
|
||||
uint16_t primary_radio_preamble = 0;
|
||||
// Full ESP32 images can carry MQTT and ESP-NOW simultaneously. Keep the
|
||||
// ESP-NOW intent separately so either transport can be selected at runtime.
|
||||
// Old preference images did not have this byte; they default to enabled to
|
||||
// retain the previous combined-Full behavior after an upgrade.
|
||||
uint8_t espnow_bridge_enabled = 1;
|
||||
uint8_t retry_preset = 0;
|
||||
uint8_t direct_retry_attempts = 0;
|
||||
uint16_t direct_retry_base_ms = 0;
|
||||
@@ -574,6 +579,15 @@ public:
|
||||
|
||||
virtual bool isBridgeRunning() const { return false; }
|
||||
|
||||
// Most roles have one bridge, so the transport-specific methods retain the
|
||||
// legacy bridge behavior by default. Combined MQTT + ESP-NOW roles override
|
||||
// them to let each transport be started, stopped, and queried independently.
|
||||
virtual bool setMqttBridgeState(bool enable) { return setBridgeState(enable); }
|
||||
virtual bool setEspNowBridgeState(bool enable) { return setBridgeState(enable); }
|
||||
virtual bool restartMqttBridge() { return restartBridge(); }
|
||||
virtual bool restartEspNowBridge() { return restartBridge(); }
|
||||
virtual bool isEspNowBridgeRunning() { return isBridgeRunning(); }
|
||||
|
||||
virtual void restartBridgeSlot(int slot) {
|
||||
// Default: fall back to full restart
|
||||
restartBridge();
|
||||
|
||||
@@ -187,16 +187,19 @@ bool CommonCLI::handleObserverSetCmd(uint32_t sender_timestamp, const char* conf
|
||||
if (strcmp(value, "on") != 0 && strcmp(value, "off") != 0) {
|
||||
strcpy(reply, "Error: use set mqtt.enabled on|off");
|
||||
} else {
|
||||
char canonical[24];
|
||||
snprintf(canonical, sizeof(canonical), "set bridge.enabled %s", value);
|
||||
handleSetCmd(sender_timestamp, canonical, reply);
|
||||
const bool enable = strcmp(value, "on") == 0;
|
||||
_prefs->bridge_enabled = enable ? 1 : 0;
|
||||
const bool applied = _callbacks->setMqttBridgeState(enable);
|
||||
savePrefs();
|
||||
strcpy(reply, applied ? "OK"
|
||||
: "Error: MQTT runtime change failed; setting saved");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
const auto restart_observer_bridge = [this]() {
|
||||
return mesh::cli::restartBridgeIfEnabled(
|
||||
_prefs->bridge_enabled != 0,
|
||||
[this]() { return _callbacks->restartBridge(); });
|
||||
[this]() { return _callbacks->restartMqttBridge(); });
|
||||
};
|
||||
if (memcmp(config, "snmp.community ", 15) == 0) {
|
||||
if (valueTooLong(&config[15], sizeof(_mqtt_prefs.snmp_community), reply, "snmp.community")) return true;
|
||||
@@ -887,7 +890,7 @@ bool CommonCLI::handleObserverGetCmd(uint32_t sender_timestamp, const char* conf
|
||||
return true;
|
||||
}
|
||||
if (strcmp(config, "mqtt.running") == 0) {
|
||||
snprintf(reply, 160, "> %s", _callbacks->isBridgeRunning() ? "on" : "off");
|
||||
snprintf(reply, 160, "> %s", _callbacks->isMqttBridgeRunning() ? "on" : "off");
|
||||
return true;
|
||||
}
|
||||
if (memcmp(config, "snmp.community", 14) == 0) {
|
||||
|
||||
@@ -48,6 +48,7 @@ def full_command_keys(text):
|
||||
COMMON_QUERY_EXCEPTIONS = {
|
||||
'bootloader.ver': 'Installed bootloader identity',
|
||||
'bridge.running': 'Live bridge state; set bridge.enabled controls intent',
|
||||
'espnow.running': 'Live ESP-NOW bridge state; set espnow.enabled controls intent',
|
||||
'bridge.type': 'Build-selected bridge transport',
|
||||
'password': 'Written by the password command, not set password',
|
||||
'public.key': 'Derived from identity; written through set prv.key',
|
||||
@@ -80,6 +81,8 @@ class CLISettingsContractTest(unittest.TestCase):
|
||||
'esp32_web': ['ESP_PLATFORM', 'ESP32_PLATFORM', 'ADMIN_PASSWORD', 'MESH_USB_LOGGING_AVAILABLE'],
|
||||
'esp32_mqtt': ['ESP_PLATFORM', 'ESP32_PLATFORM', 'WITH_MQTT_BRIDGE', 'WITH_BRIDGE',
|
||||
'WITH_MQTT_NEIGHBORS', 'MESH_USB_LOGGING_AVAILABLE'],
|
||||
'esp32_mqtt_espnow': ['ESP_PLATFORM', 'ESP32_PLATFORM', 'WITH_MQTT_BRIDGE',
|
||||
'WITH_ESPNOW_BRIDGE', 'WITH_BRIDGE'],
|
||||
'rs232_gps': ['WITH_BRIDGE', 'WITH_RS232_BRIDGE', 'ENV_INCLUDE_GPS'],
|
||||
'espnow': ['ESP_PLATFORM', 'ESP32_PLATFORM', 'WITH_BRIDGE', 'WITH_ESPNOW_BRIDGE', 'MESH_PRIMARY_ESPNOW'],
|
||||
'lr2021': ['USE_LR2021'],
|
||||
|
||||
@@ -113,6 +113,25 @@ int main(){
|
||||
'''
|
||||
|
||||
class EspNowLifecycleTests(unittest.TestCase):
|
||||
def test_combined_full_transport_controls_are_independent(self):
|
||||
common = (ROOT/'src/helpers/CommonCLI.cpp').read_text()
|
||||
observer = (ROOT/'src/helpers/CommonCLI_Observer.cpp').read_text()
|
||||
prefs = (ROOT/'src/helpers/CommonCLI.h').read_text()
|
||||
self.assertIn('uint8_t espnow_bridge_enabled = 1;', prefs)
|
||||
self.assertIn('setEspNowBridgeState(enable)', common)
|
||||
self.assertIn('_prefs->espnow_bridge_enabled', common)
|
||||
self.assertIn('setMqttBridgeState(enable)', observer)
|
||||
self.assertIn('isMqttBridgeRunning()', observer)
|
||||
for role in ('simple_repeater', 'simple_room_server'):
|
||||
header = (ROOT/f'examples/{role}/MyMesh.h').read_text()
|
||||
combined = method(header, 'bool setBridgeState(bool enable) override')
|
||||
self.assertIn('setMqttBridgeState(true)', combined)
|
||||
self.assertIn('setEspNowBridgeState(true)', combined)
|
||||
mqtt = method(header, 'bool setMqttBridgeState(bool enable) override')
|
||||
espnow = method(header, 'bool setEspNowBridgeState(bool enable) override')
|
||||
self.assertIn('if (espnow_bridge.isRunning()) espnow_bridge.end();', mqtt)
|
||||
self.assertIn('if (mqtt_bridge' if role == 'simple_repeater' else 'if (bridge', espnow)
|
||||
|
||||
def test_sdk_failures_stop_and_restart(self):
|
||||
header=(ROOT/'src/helpers/esp32/ESPNOWRadio.h').read_text()
|
||||
source=(ROOT/'src/helpers/esp32/ESPNOWRadio.cpp').read_text()
|
||||
|
||||
@@ -1012,9 +1012,10 @@ const combinedObserver = combinedCatalog.profiles.find(profile => profile.target
|
||||
assert.deepStrictEqual(picker.profileFieldValues(combinedObserver, 'mode'), ['standard', 'espnow']);
|
||||
assert(picker.profileMatches(combinedObserver, {mode: 'espnow'}, ['mode']));
|
||||
const combinedDirections = picker.runtimeDirections(combinedObserver, {logging: 'usb'});
|
||||
assert(combinedDirections.some(section => section.title === 'MQTT + ESP-NOW bridge'));
|
||||
assert(!combinedDirections.some(section => section.title === 'ESP-NOW bridge'));
|
||||
assert(combinedDirections.some(section => section.title === 'MQTT broker connections'));
|
||||
assert(combinedDirections.some(section => section.title === 'ESP-NOW bridge'));
|
||||
assert.strictEqual(commands(combinedDirections).filter(command => command === 'set mqtt.enabled on').length, 1);
|
||||
assert.strictEqual(commands(combinedDirections).filter(command => command === 'set bridge.enabled on').length, 1);
|
||||
console.log('current release metadata and capacity directions tests passed');
|
||||
|
||||
assert.strictEqual(nrf.chipFamily, 'nrf52');
|
||||
|
||||
@@ -338,6 +338,10 @@ struct {
|
||||
bool hasWirelessNetworkClient(){return network;}
|
||||
bool isBridgeRunning(){return bridge;}
|
||||
bool setBridgeState(bool on){bridge=on;return true;}
|
||||
bool isMqttBridgeRunning(){return bridge;}
|
||||
bool isEspNowBridgeRunning(){return bridge;}
|
||||
bool setMqttBridgeState(bool on){bridge=on;return true;}
|
||||
bool setEspNowBridgeState(bool on){bridge=on;return true;}
|
||||
bool stopWebConfig(char*){web=false;stopping=true;return true;}
|
||||
bool startWebConfig(bool,char*){web=true;return true;}
|
||||
} the_mesh;
|
||||
|
||||
Reference in new issue
Block a user