From e43c58405e741699cd09ac17a5e818205ec58e1e Mon Sep 17 00:00:00 2001 From: Janez T Date: Wed, 1 Apr 2026 09:57:02 +0200 Subject: [PATCH] feat: Add companion WiFi CLI --- examples/companion_radio/DataStore.cpp | 8 ++- examples/companion_radio/MyMesh.cpp | 99 ++++++++++++++++++++++++++ examples/companion_radio/MyMesh.h | 3 + examples/companion_radio/NodePrefs.h | 4 +- examples/companion_radio/main.cpp | 10 ++- 5 files changed, 120 insertions(+), 4 deletions(-) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 40f1ceeb61..d0fd050278 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -230,7 +230,9 @@ void DataStore::loadPrefsInt(const char *filename, NodePrefs& _prefs, double& no file.read((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86 file.read((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87 file.read((uint8_t *)&_prefs.autoadd_max_hops, sizeof(_prefs.autoadd_max_hops)); // 88 - file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 + file.read((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 + file.read((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 90 + file.read((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 123 file.close(); } @@ -268,7 +270,9 @@ void DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_ file.write((uint8_t *)&_prefs.gps_interval, sizeof(_prefs.gps_interval)); // 86 file.write((uint8_t *)&_prefs.autoadd_config, sizeof(_prefs.autoadd_config)); // 87 file.write((uint8_t *)&_prefs.autoadd_max_hops, sizeof(_prefs.autoadd_max_hops)); // 88 - file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 + file.write((uint8_t *)&_prefs.rx_boosted_gain, sizeof(_prefs.rx_boosted_gain)); // 89 + file.write((uint8_t *)_prefs.wifi_ssid, sizeof(_prefs.wifi_ssid)); // 90 + file.write((uint8_t *)_prefs.wifi_pwd, sizeof(_prefs.wifi_pwd)); // 123 file.close(); } diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 60a5a75fec..800665cac8 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -2,6 +2,9 @@ #include // needed for PlatformIO #include +#ifdef WIFI_SSID + #include +#endif #define CMD_APP_START 1 #define CMD_SEND_TXT_MSG 2 @@ -141,6 +144,25 @@ #define AUTO_ADD_ROOM_SERVER (1 << 3) // 0x08 - auto-add Room Server (ADV_TYPE_ROOM) #define AUTO_ADD_SENSOR (1 << 4) // 0x10 - auto-add Sensor (ADV_TYPE_SENSOR) +#ifdef WIFI_SSID +static void restartWifiClient(const NodePrefs& prefs) { + const char* ssid = prefs.wifi_ssid; + const char* pwd = prefs.wifi_pwd; + + if (ssid[0] == 0) { + WiFi.disconnect(); + return; + } + + WiFi.disconnect(); + if (pwd[0] == 0) { + WiFi.begin(ssid); + } else { + WiFi.begin(ssid, pwd); + } +} +#endif + void MyMesh::writeOKFrame() { uint8_t buf[1]; buf[0] = RESP_CODE_OK; @@ -895,6 +917,15 @@ void MyMesh::begin(bool has_display) { // load persisted prefs _store->loadPrefs(_prefs, sensors.node_lat, sensors.node_lon); + _prefs.wifi_ssid[sizeof(_prefs.wifi_ssid) - 1] = 0; + _prefs.wifi_pwd[sizeof(_prefs.wifi_pwd) - 1] = 0; +#ifdef WIFI_SSID + if (_prefs.wifi_ssid[0] == 0 && _prefs.wifi_pwd[0] == 0) { + StrHelper::strncpy(_prefs.wifi_ssid, WIFI_SSID, sizeof(_prefs.wifi_ssid)); + StrHelper::strncpy(_prefs.wifi_pwd, WIFI_PWD, sizeof(_prefs.wifi_pwd)); + savePrefs(); + } +#endif // sanitise bad pref values _prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f); @@ -1911,6 +1942,70 @@ void MyMesh::enterCLIRescue() { Serial.println("========= CLI Rescue ========="); } +bool MyMesh::handleWifiGetConfig(const char* config) { +#ifdef WIFI_SSID + if (memcmp(config, "wifi.ssid", 9) == 0) { + Serial.printf(" > %s\n", _prefs.wifi_ssid); + return true; + } else if (memcmp(config, "wifi.pwd", 8) == 0) { + Serial.printf(" > %s\n", _prefs.wifi_pwd); + return true; + } +#else + (void)config; +#endif + return false; +} + +bool MyMesh::handleWifiSetConfig(const char* config) { +#ifdef WIFI_SSID + if (memcmp(config, "wifi.ssid ", 10) == 0) { + StrHelper::strncpy(_prefs.wifi_ssid, &config[10], sizeof(_prefs.wifi_ssid)); + savePrefs(); + restartWifiClient(_prefs); + Serial.println(" OK"); + return true; + } else if (memcmp(config, "wifi.pwd ", 9) == 0) { + StrHelper::strncpy(_prefs.wifi_pwd, &config[9], sizeof(_prefs.wifi_pwd)); + savePrefs(); + restartWifiClient(_prefs); + Serial.println(" OK"); + return true; + } +#else + (void)config; +#endif + return false; +} + +void MyMesh::checkWifiConfigSerial() { +#ifdef WIFI_SSID + int len = strlen(cli_command); + while (Serial.available() && len < sizeof(cli_command)-1) { + char c = Serial.read(); + if (c != '\n') { + cli_command[len++] = c; + cli_command[len] = 0; + } + Serial.print(c); + } + if (len == sizeof(cli_command)-1) { + cli_command[sizeof(cli_command)-1] = '\r'; + } + if (len > 0 && cli_command[len - 1] == '\r') { + cli_command[len - 1] = 0; + if (memcmp(cli_command, "get ", 4) == 0) { + const char* config = &cli_command[4]; + handleWifiGetConfig(config); + } else if (memcmp(cli_command, "set ", 4) == 0) { + const char* config = &cli_command[4]; + handleWifiSetConfig(config); + } + cli_command[0] = 0; + } +#endif +} + void MyMesh::checkCLIRescueCmd() { int len = strlen(cli_command); while (Serial.available() && len < sizeof(cli_command)-1) { @@ -2115,6 +2210,10 @@ void MyMesh::loop() { if (_cli_rescue) { checkCLIRescueCmd(); +#ifdef WIFI_SSID + } else if (Serial.available()) { + checkWifiConfigSerial(); +#endif } else { checkSerialInterface(); } diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 3b02f5f69d..ddae825044 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -191,6 +191,9 @@ class MyMesh : public BaseChatMesh, public DataStoreHost { return _store->putBlobByKey(key, key_len, src_buf, len); } + bool handleWifiGetConfig(const char* config); + bool handleWifiSetConfig(const char* config); + void checkWifiConfigSerial(); void checkCLIRescueCmd(); void checkSerialInterface(); bool isValidClientRepeatFreq(uint32_t f) const; diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 557be306c0..439f7c0ce7 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -32,4 +32,6 @@ struct NodePrefs { // persisted to file uint8_t client_repeat; uint8_t path_hash_mode; // which path mode to use when sending uint8_t autoadd_max_hops; // 0 = no limit, 1 = direct (0 hops), N = up to N-1 hops (max 64) -}; \ No newline at end of file + char wifi_ssid[33]; + char wifi_pwd[65]; +}; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 876dc9c33c..efabac9700 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -195,7 +195,15 @@ void setup() { #ifdef WIFI_SSID board.setInhibitSleep(true); // prevent sleep when WiFi is active - WiFi.begin(WIFI_SSID, WIFI_PWD); + const char* wifi_ssid = the_mesh.getNodePrefs()->wifi_ssid; + const char* wifi_pwd = the_mesh.getNodePrefs()->wifi_pwd; + if (wifi_ssid[0] != 0) { + if (wifi_pwd[0] == 0) { + WiFi.begin(wifi_ssid); + } else { + WiFi.begin(wifi_ssid, wifi_pwd); + } + } serial_interface.begin(TCP_PORT); #elif defined(BLE_PIN_CODE) serial_interface.begin(BLE_NAME_PREFIX, the_mesh.getNodePrefs()->node_name, the_mesh.getBLEPin());