diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 76e0dfde..2886ceb6 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2187,6 +2187,16 @@ bool MyMesh::handleCommand(const char* command, uint32_t sender_timestamp, char* sprintf(reply, "> %s", _prefs.wifi_ssid[0] ? _prefs.wifi_ssid : WIFI_SSID); return true; } + if (memcmp(command, "set wifi.enabled ", 17) == 0) { + _prefs.wifi_enabled = atoi(&command[17]) ? 1 : 0; + savePrefs(); + sprintf(reply, "> wifi.enabled is now %d (reboot to apply)", _prefs.wifi_enabled); + return true; + } + if (strcmp(command, "get wifi.enabled") == 0) { + sprintf(reply, "> %d", _prefs.wifi_enabled); + return true; + } if (strcmp(command, "get wifi.status") == 0) { strcpy(reply, WiFi.status() == WL_CONNECTED ? "> connected" : "> disconnected"); return true; diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index c725c317..03323675 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -47,6 +47,7 @@ public: #ifdef WIFI_SSID char wifi_ssid[33] = {0}; // if empty, the compile-time WIFI_SSID is used char wifi_pwd[64] = {0}; + uint8_t wifi_enabled = 1; // 0 = never bring up WiFi (credentials may still be baked in) #endif private: @@ -171,6 +172,7 @@ private: void structure() override { def("ssid", _parent->wifi_ssid, sizeof(_parent->wifi_ssid)); def("pwd", _parent->wifi_pwd, sizeof(_parent->wifi_pwd)); + def("enabled", _parent->wifi_enabled); } public: WiFiPrefs(NodePrefs* parent) : _parent(parent) { } diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 6b6d7cf7..cf761095 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -127,6 +127,7 @@ void halt() { char wifi_ssid[33] = WIFI_SSID; // replaced by stored prefs at boot, if set char wifi_pwd[64] = WIFI_PWD; bool wifi_was_connected = false; + bool wifi_enabled = false; // set at boot from prefs; false also when the effective SSID is blank #endif void setup() { @@ -208,21 +209,6 @@ void setup() { // add wifi interface #ifdef WIFI_SSID -#if defined(ESP32) - board.setInhibitSleep(true); // prevent sleep when WiFi is active - WiFi.setAutoReconnect(true); - - WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){ - if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { - WIFI_DEBUG_PRINTLN("WiFi disconnected. Flagging for reconnect..."); - wifi_needs_reconnect = true; - } else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) { - WIFI_DEBUG_PRINTLN("WiFi connected successfully!"); - wifi_needs_reconnect = false; - } - }); -#endif - // stored credentials win over the build-time ones ('set wifi.ssid ' over USB serial). // they are taken as a pair, so 'set wifi.ssid' alone gives an empty password, not a // silent fallback to the build-time password of a different network. Copied out of prefs @@ -232,20 +218,41 @@ void setup() { strcpy(wifi_ssid, the_mesh.getNodePrefs()->wifi_ssid); strcpy(wifi_pwd, the_mesh.getNodePrefs()->wifi_pwd); } - WIFI_DEBUG_PRINTLN("connecting to %s", wifi_ssid); + // 'set wifi.enabled 0' or a build with blank credentials leaves the radio off entirely + wifi_enabled = the_mesh.getNodePrefs()->wifi_enabled && wifi_ssid[0]; + if (wifi_enabled) { +#if defined(ESP32) + board.setInhibitSleep(true); // prevent sleep when WiFi is active + WiFi.setAutoReconnect(true); + + WiFi.onEvent([](WiFiEvent_t event, WiFiEventInfo_t info){ + if (event == ARDUINO_EVENT_WIFI_STA_DISCONNECTED) { + WIFI_DEBUG_PRINTLN("WiFi disconnected. Flagging for reconnect..."); + wifi_needs_reconnect = true; + } else if (event == ARDUINO_EVENT_WIFI_STA_GOT_IP) { + WIFI_DEBUG_PRINTLN("WiFi connected successfully!"); + wifi_needs_reconnect = false; + } + }); +#endif + + WIFI_DEBUG_PRINTLN("connecting to %s", wifi_ssid); #if defined(RP2040_PLATFORM) - // ponytail: the join itself blocks inside the core (CYW43::begin busy-waits for the - // association), so every attempt stalls the mesh loop. beginNoBlock() only skips the - // extra DHCP wait. Give the first connect a full window, then bound the retries below. - // Upgrade path if the stall ever matters: run WiFi on core1. - WiFi.beginNoBlock(wifi_ssid, wifi_pwd); - last_wifi_reconnect_attempt = millis(); // let DHCP finish before the poll can retry + // ponytail: the join itself blocks inside the core (CYW43::begin busy-waits for the + // association), so every attempt stalls the mesh loop. beginNoBlock() only skips the + // extra DHCP wait. Give the first connect a full window, then bound the retries below. + // Upgrade path if the stall ever matters: run WiFi on core1. + WiFi.beginNoBlock(wifi_ssid, wifi_pwd); + last_wifi_reconnect_attempt = millis(); // let DHCP finish before the poll can retry #else - WiFi.begin(wifi_ssid, wifi_pwd); + WiFi.begin(wifi_ssid, wifi_pwd); #endif - wifi_interface.begin(TCP_PORT); - interface_manager.addInterface(InterfaceType::WiFi, &wifi_interface); + wifi_interface.begin(TCP_PORT); + interface_manager.addInterface(InterfaceType::WiFi, &wifi_interface); + } else { + WIFI_DEBUG_PRINTLN("wifi disabled"); + } #endif // add usb interface @@ -301,31 +308,33 @@ void loop() { } #ifdef WIFI_SSID - // RP2040 has no WiFi event callbacks, so poll the link state instead + if (wifi_enabled) { + // RP2040 has no WiFi event callbacks, so poll the link state instead #if defined(RP2040_PLATFORM) - wifi_needs_reconnect = (WiFi.status() != WL_CONNECTED); - if (wifi_was_connected == wifi_needs_reconnect) { // link state changed - wifi_was_connected = !wifi_needs_reconnect; - if (wifi_was_connected) { - WIFI_DEBUG_PRINTLN("connected, listening on %s:%d", WiFi.localIP().toString().c_str(), TCP_PORT); - } else { - WIFI_DEBUG_PRINTLN("link lost"); + wifi_needs_reconnect = (WiFi.status() != WL_CONNECTED); + if (wifi_was_connected == wifi_needs_reconnect) { // link state changed + wifi_was_connected = !wifi_needs_reconnect; + if (wifi_was_connected) { + WIFI_DEBUG_PRINTLN("connected, listening on %s:%d", WiFi.localIP().toString().c_str(), TCP_PORT); + } else { + WIFI_DEBUG_PRINTLN("link lost"); + } } - } #endif - // Safely attempt to reconnect if flagged. On RP2040 each attempt blocks the mesh loop - // for up to WIFI_RETRY_TIMEOUT, so retry less often and cap how long a join may stall. - if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > WIFI_RETRY_INTERVAL)) { - WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect to %s (status %d)...", wifi_ssid, WiFi.status()); + // Safely attempt to reconnect if flagged. On RP2040 each attempt blocks the mesh loop + // for up to WIFI_RETRY_TIMEOUT, so retry less often and cap how long a join may stall. + if (wifi_needs_reconnect && (millis() - last_wifi_reconnect_attempt > WIFI_RETRY_INTERVAL)) { + WIFI_DEBUG_PRINTLN("Attempting manual WiFi reconnect to %s (status %d)...", wifi_ssid, WiFi.status()); #if defined(RP2040_PLATFORM) - WiFi.setTimeout(WIFI_RETRY_TIMEOUT); - WiFi.beginNoBlock(wifi_ssid, wifi_pwd); // no reconnect() on this platform + WiFi.setTimeout(WIFI_RETRY_TIMEOUT); + WiFi.beginNoBlock(wifi_ssid, wifi_pwd); // no reconnect() on this platform #else - WiFi.disconnect(); - WiFi.reconnect(); + WiFi.disconnect(); + WiFi.reconnect(); #endif - last_wifi_reconnect_attempt = millis(); + last_wifi_reconnect_attempt = millis(); + } } #endif }