Expose Companion WiFi and radio power controls

This commit is contained in:
mikecarper committed 2026-08-18 16:51:59 -07:00
1 parent 818f610ba3
commit 0c4619bcc3
27 files changed
+1840 -1349

No files matched your search

+3 -1
View File
@@ -7,6 +7,7 @@
#include "MQTTPrefs.h"
#include "MQTTPacketFilter.h"
#include "MQTTPresets.h"
#include "WiFiPowerSave.h"
// Compile-time defaults for fresh /mqtt_prefs (override via platformio build_flags).
// Example:
@@ -14,6 +15,7 @@
// -D MQTT_DEFAULT_IATA='"YYZ"'
// -D MQTT_DEFAULT_TIMEZONE='"America/Toronto"'
// -D MQTT_DEFAULT_TIMEZONE_OFFSET=-5
// -D DEFAULT_WIFI_POWER_SAVE_MODE=0 // min; 1=none, 2=max
#ifndef MQTT_DEFAULT_SLOT1_PRESET
#define MQTT_DEFAULT_SLOT1_PRESET "analyzer-us"
@@ -69,7 +71,7 @@ static inline void applyMQTTDefaults(MQTTPrefs* prefs) {
prefs->mqtt_tx_enabled = 2;
prefs->mqtt_rx_enabled = 1;
prefs->mqtt_status_interval = 300000;
prefs->wifi_power_save = 1;
prefs->wifi_power_save = mesh::wifi::kDefaultPowerSave;
mqttDefaultSlotPreset(prefs->mqtt_slot_preset[0], sizeof(prefs->mqtt_slot_preset[0]),
MQTT_DEFAULT_SLOT1_PRESET);
+21 -5
View File
@@ -2,16 +2,32 @@
#include <stdint.h>
// Stored WiFi power-save values are 0=min, 1=none, and 2=max. Build profiles
// may override the fresh-install default without changing the persisted wire /
// file representation. Existing saved settings always take precedence.
#ifndef DEFAULT_WIFI_POWER_SAVE_MODE
#define DEFAULT_WIFI_POWER_SAVE_MODE 1
#endif
#if DEFAULT_WIFI_POWER_SAVE_MODE < 0 || DEFAULT_WIFI_POWER_SAVE_MODE > 2
#error "DEFAULT_WIFI_POWER_SAVE_MODE must be 0 (min), 1 (none), or 2 (max)"
#endif
namespace mesh {
namespace wifi {
// MeshCore stores WiFi power save as: 0=min, 1=none, 2=max. ESP32 WiFi and
// Bluetooth coexistence requires modem sleep, so "none" must fall back to the
// minimum sleep policy whenever Bluetooth is active.
static constexpr uint8_t kPowerSaveMin = 0;
static constexpr uint8_t kPowerSaveNone = 1;
static constexpr uint8_t kPowerSaveMax = 2;
static constexpr uint8_t kDefaultPowerSave = DEFAULT_WIFI_POWER_SAVE_MODE;
// ESP32 WiFi and Bluetooth coexistence requires modem sleep, so "none" must
// fall back to the minimum sleep policy whenever Bluetooth is active.
inline uint8_t effectivePowerSave(uint8_t configured,
bool bluetooth_active) {
if (configured > 2) configured = 1;
return bluetooth_active && configured == 1 ? 0 : configured;
if (configured > kPowerSaveMax) configured = kDefaultPowerSave;
return bluetooth_active && configured == kPowerSaveNone
? kPowerSaveMin : configured;
}
} // namespace wifi
+1
View File
@@ -49,6 +49,7 @@ public:
* Radio interface.
*/
virtual bool setRxBoostedGainMode(bool) { return false; }
virtual bool supportsRxBoostedGainMode() const { return false; }
virtual bool getRxBoostedGainMode() const { return false; }
// ESP-NOW has no LoRa RX power-saving watchdog or noise-floor calibration.
File diff suppressed because it is too large. Load diff
+19 -15
View File
@@ -205,7 +205,8 @@ WebConfigServer::WebConfigServer(Callbacks* callbacks, void* mqtt_prefs, bool ow
if (obs) {
strncpy(_wifi_ssid, obs->wifi_ssid, sizeof(_wifi_ssid) - 1);
strncpy(_wifi_password, obs->wifi_password, sizeof(_wifi_password) - 1);
_wifi_power_save = obs->wifi_power_save <= 2 ? obs->wifi_power_save : 1;
_wifi_power_save = obs->wifi_power_save <= mesh::wifi::kPowerSaveMax
? obs->wifi_power_save : mesh::wifi::kDefaultPowerSave;
// Companion builds keep their canonical connection credentials in the
// shared mesh-wifi namespace. A fresh MQTT configuration can therefore
// have an empty MQTTPrefs WiFi field even while the companion is already
@@ -270,7 +271,8 @@ bool WebConfigServer::loadStandaloneWiFi(char* ssid, size_t ssid_len,
if (!nvs.begin("mesh-wifi", true)) return false;
String stored_ssid = nvs.getString("ssid", "");
String stored_password = nvs.getString("password", "");
uint8_t stored_ps = nvs.getUChar("powersave", 1);
uint8_t stored_ps = nvs.getUChar(
"powersave", mesh::wifi::kDefaultPowerSave);
nvs.end();
if (stored_ssid.length() >= ssid_len
|| stored_password.length() >= password_len) {
@@ -288,7 +290,8 @@ bool WebConfigServer::saveStandaloneWiFi(const char* ssid, const char* password,
uint8_t power_save) {
power_save = effectiveWiFiPowerSave(power_save);
if (!ssid || !ssid[0] || strlen(ssid) >= 32
|| (password && strlen(password) >= 64) || power_save > 2) {
|| (password && strlen(password) >= 64)
|| power_save > mesh::wifi::kPowerSaveMax) {
return false;
}
Preferences nvs;
@@ -347,7 +350,7 @@ bool WebConfigServer::setStandaloneWiFiPassword(const char* value, char* reply,
bool WebConfigServer::setStandaloneWiFiPowerSave(const char* value, char* reply,
size_t reply_len) {
if (!reply || reply_len == 0) return false;
uint8_t power_save = 1;
uint8_t power_save = mesh::wifi::kDefaultPowerSave;
if (!mesh::cli::parseStandaloneWiFiPowerSave(value, power_save)) {
snprintf(reply, reply_len, "Error: power save must be none, min, or max");
return false;
@@ -374,9 +377,9 @@ bool WebConfigServer::setStandaloneWiFiPowerSave(const char* value, char* reply,
esp_err_t apply_result = ESP_OK;
if (WiFi.getMode() != WIFI_OFF) {
const wifi_ps_type_t ps_mode =
power_save == 1 ? WIFI_PS_NONE
: power_save == 2 ? WIFI_PS_MAX_MODEM
: WIFI_PS_MIN_MODEM;
power_save == mesh::wifi::kPowerSaveNone ? WIFI_PS_NONE
: power_save == mesh::wifi::kPowerSaveMax ? WIFI_PS_MAX_MODEM
: WIFI_PS_MIN_MODEM;
apply_result = esp_wifi_set_ps(ps_mode);
}
if (apply_result == ESP_OK) {
@@ -419,7 +422,7 @@ bool WebConfigServer::formatWiFiSSID(char* reply, size_t reply_len) {
char ssid[32] = "";
char password[64] = "";
uint8_t power_save = 1;
uint8_t power_save = mesh::wifi::kDefaultPowerSave;
bool configured = loadStandaloneWiFi(
ssid, sizeof(ssid), password, sizeof(password), &power_save);
if (_active && _active->_wifi_ssid[0]) {
@@ -435,7 +438,7 @@ bool WebConfigServer::formatWiFiSSID(char* reply, size_t reply_len) {
bool WebConfigServer::formatWiFiPowerSave(char* reply, size_t reply_len) {
if (!reply || reply_len == 0) return false;
uint8_t power_save = 1;
uint8_t power_save = mesh::wifi::kDefaultPowerSave;
if (_active) {
power_save = _active->_wifi_power_save;
} else {
@@ -446,9 +449,9 @@ bool WebConfigServer::formatWiFiPowerSave(char* reply, size_t reply_len) {
}
const char* name = "none";
if (power_save == 0) {
if (power_save == mesh::wifi::kPowerSaveMin) {
name = "min";
} else if (power_save == 2) {
} else if (power_save == mesh::wifi::kPowerSaveMax) {
name = "max";
}
snprintf(reply, reply_len, "> %s", name);
@@ -477,7 +480,7 @@ bool WebConfigServer::formatWiFiStatus(char* reply, size_t reply_len) {
char ssid[32] = "";
char password[64] = "";
uint8_t power_save = 1;
uint8_t power_save = mesh::wifi::kDefaultPowerSave;
bool configured = loadStandaloneWiFi(
ssid, sizeof(ssid), password, sizeof(password), &power_save);
WebConfigServer* active = _active;
@@ -678,9 +681,10 @@ bool WebConfigServer::startAutoMode(char reply[]) {
_wifi_reconnect_tracker.noteDisconnected(millis());
WiFi.begin(_wifi_ssid, _wifi_password);
_wifi_power_save = effectiveWiFiPowerSave(_wifi_power_save);
wifi_ps_type_t ps_mode = _wifi_power_save == 1 ? WIFI_PS_NONE
: _wifi_power_save == 2 ? WIFI_PS_MAX_MODEM
: WIFI_PS_MIN_MODEM;
wifi_ps_type_t ps_mode =
_wifi_power_save == mesh::wifi::kPowerSaveNone ? WIFI_PS_NONE
: _wifi_power_save == mesh::wifi::kPowerSaveMax ? WIFI_PS_MAX_MODEM
: WIFI_PS_MIN_MODEM;
esp_wifi_set_ps(ps_mode);
_mode = MODE_CONNECTING;
_connect_deadline = millis() + 15000;
+2 -1
View File
@@ -28,6 +28,7 @@
#include <freertos/FreeRTOS.h>
#include <freertos/semphr.h>
#include <helpers/WebConfigBatch.h>
#include <helpers/WiFiPowerSave.h>
#include <helpers/WiFiReconnectPolicy.h>
class AsyncWebServer;
@@ -229,7 +230,7 @@ private:
uint32_t _connect_deadline = 0;
char _wifi_ssid[32] = {0};
char _wifi_password[64] = {0};
uint8_t _wifi_power_save = 1;
uint8_t _wifi_power_save = mesh::wifi::kDefaultPowerSave;
bool _cli_enabled = true;
// A `password` command has succeeded this session. Lets the CLI satisfy the
// initial-setup invariant across separate submissions; the form batch always
@@ -55,6 +55,7 @@ protected:
return ((CustomLLCC68 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
}
public:
bool supportsRxBoostedGainMode() const override { return true; }
bool getRxBoostedGainMode() const override {
return ((CustomLLCC68 *)_radio)->getRxBoostedGainMode();
}
@@ -134,6 +134,7 @@ protected:
return ((CustomLR1110 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
}
public:
bool supportsRxBoostedGainMode() const override { return true; }
bool getRxBoostedGainMode() const override {
return ((CustomLR1110 *)_radio)->getRxBoostedGainMode();
}
@@ -178,6 +178,7 @@ public:
void doResetAGC() override { }
bool supportsRxBoostedGainMode() const override { return true; }
bool getRxBoostedGainMode() const override {
return ((CustomLR2021 *)_radio)->getRxBoostedGainMode();
}
@@ -160,6 +160,7 @@ protected:
return ((CustomSX1262 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
}
public:
bool supportsRxBoostedGainMode() const override { return true; }
bool getRxBoostedGainMode() const override {
return ((CustomSX1262 *)_radio)->getRxBoostedGainMode();
}
@@ -57,6 +57,7 @@ protected:
return ((CustomSX1268 *)_radio)->setRxBoostedGainMode(en) == RADIOLIB_ERR_NONE;
}
public:
bool supportsRxBoostedGainMode() const override { return true; }
bool getRxBoostedGainMode() const override {
return ((CustomSX1268 *)_radio)->getRxBoostedGainMode();
}
+1
View File
@@ -210,6 +210,7 @@ public:
float packetScore(float snr, int packet_len) override { return packetScoreInt(snr, 10, packet_len); } // assume sf=10
bool setRxBoostedGainMode(bool enabled);
virtual bool supportsRxBoostedGainMode() const { return false; }
virtual bool getRxBoostedGainMode() const { return false; }
virtual bool configSideDetectors(const uint8_t sideDetSFs[], uint8_t num, float bw) { return false; }
+1
View File
@@ -81,6 +81,7 @@ public:
uint32_t getPacketsSent() const { return n_sent; }
void resetStats() { n_recv = n_sent = n_recv_errors = 0; }
bool setRxBoostedGainMode(bool /*enabled*/) { return false; }
bool supportsRxBoostedGainMode() const { return false; }
bool getRxBoostedGainMode() const { return false; }
uint32_t getRxPsWatchdogSoftCount() const { return 0; }
uint32_t getRxPsWatchdogHardCount() const { return 0; }