mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-05-02 20:16:59 +00:00
refactor network code
This commit is contained in:
@@ -4,110 +4,17 @@
|
||||
|
||||
APSettingsService::APSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(APSettings::read, APSettings::update, this, server, AP_SETTINGS_SERVICE_PATH, securityManager)
|
||||
, _fsPersistence(APSettings::read, APSettings::update, this, fs, AP_SETTINGS_FILE)
|
||||
, _dnsServer(nullptr)
|
||||
, _lastManaged(0)
|
||||
, _reconfigureAp(false)
|
||||
, _connected(0) {
|
||||
addUpdateHandler([this] { reconfigureAP(); }, false);
|
||||
, _fsPersistence(APSettings::read, APSettings::update, this, fs, AP_SETTINGS_FILE) {
|
||||
}
|
||||
|
||||
void APSettingsService::begin() {
|
||||
_fsPersistence.readFromFS();
|
||||
// disabled for delayed start, first try station mode
|
||||
// reconfigureAP();
|
||||
}
|
||||
|
||||
void APSettingsService::reconfigureAP() {
|
||||
_lastManaged = uuid::get_uptime() - MANAGE_NETWORK_DELAY;
|
||||
_reconfigureAp = true;
|
||||
}
|
||||
|
||||
void APSettingsService::loop() {
|
||||
const uint8_t was_connected = _connected;
|
||||
if (WiFi.isConnected()) {
|
||||
_connected |= 1U;
|
||||
} else {
|
||||
_connected &= ~1U;
|
||||
}
|
||||
if (ETH.connected()) {
|
||||
_connected |= 2U;
|
||||
} else {
|
||||
_connected &= ~2U;
|
||||
}
|
||||
// wait 10 sec before starting AP
|
||||
if (was_connected && !_connected) {
|
||||
_lastManaged = uuid::get_uptime();
|
||||
}
|
||||
const unsigned long currentMillis = uuid::get_uptime();
|
||||
if ((currentMillis - _lastManaged) >= MANAGE_NETWORK_DELAY) {
|
||||
_lastManaged = currentMillis;
|
||||
manageAP();
|
||||
}
|
||||
|
||||
if (_dnsServer) {
|
||||
handleDNS();
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::manageAP() {
|
||||
const WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
if (_state.provisionMode == AP_MODE_ALWAYS || (_state.provisionMode == AP_MODE_DISCONNECTED && !_connected)) {
|
||||
if (_reconfigureAp || currentWiFiMode == WIFI_OFF || currentWiFiMode == WIFI_STA) {
|
||||
startAP();
|
||||
}
|
||||
} else if ((currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA) && _connected && (_reconfigureAp || !WiFi.softAPgetStationNum())) {
|
||||
stopAP();
|
||||
}
|
||||
_reconfigureAp = false;
|
||||
}
|
||||
|
||||
void APSettingsService::startAP() {
|
||||
WiFi.softAPenableIPv6(); // force IPV6, same as for WiFi - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
|
||||
WiFi.softAPConfig(_state.localIP, _state.gatewayIP, _state.subnetMask);
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
|
||||
WiFi.softAP(_state.ssid.c_str(), _state.password.c_str(), _state.channel, _state.ssidHidden, _state.maxClients);
|
||||
#if CONFIG_IDF_TARGET_ESP32C3
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm); // https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
#endif
|
||||
if (!_dnsServer) {
|
||||
const IPAddress apIp = WiFi.softAPIP();
|
||||
char ipStr[16];
|
||||
snprintf(ipStr, sizeof(ipStr), "%u.%u.%u.%u", apIp[0], apIp[1], apIp[2], apIp[3]);
|
||||
emsesp::EMSESP::logger().info("Starting Access Point with captive portal on %s", ipStr);
|
||||
_dnsServer = new DNSServer;
|
||||
_dnsServer->start(DNS_PORT, "*", apIp);
|
||||
}
|
||||
}
|
||||
|
||||
void APSettingsService::stopAP() {
|
||||
if (_dnsServer) {
|
||||
emsesp::EMSESP::logger().info("Stopping Access Point");
|
||||
_dnsServer->stop();
|
||||
delete _dnsServer;
|
||||
_dnsServer = nullptr;
|
||||
}
|
||||
WiFi.softAPdisconnect(true);
|
||||
}
|
||||
|
||||
void APSettingsService::handleDNS() {
|
||||
if (_dnsServer) {
|
||||
_dnsServer->processNextRequest();
|
||||
}
|
||||
}
|
||||
|
||||
APNetworkStatus APSettingsService::getAPNetworkStatus() {
|
||||
const WiFiMode_t currentWiFiMode = WiFi.getMode();
|
||||
const bool apActive = (currentWiFiMode == WIFI_AP || currentWiFiMode == WIFI_AP_STA);
|
||||
|
||||
if (apActive && _state.provisionMode != AP_MODE_ALWAYS && WiFi.status() == WL_CONNECTED) {
|
||||
return APNetworkStatus::LINGERING;
|
||||
}
|
||||
|
||||
return apActive ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE;
|
||||
return emsesp::EMSESP::network_.ap_connected() ? APNetworkStatus::ACTIVE : APNetworkStatus::INACTIVE;
|
||||
}
|
||||
|
||||
|
||||
void APSettings::read(const APSettings & settings, JsonObject root) {
|
||||
root["provision_mode"] = settings.provisionMode;
|
||||
root["ssid"] = settings.ssid;
|
||||
@@ -125,12 +32,11 @@ StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||
newSettings.provisionMode = static_cast<uint8_t>(root["provision_mode"] | FACTORY_AP_PROVISION_MODE);
|
||||
|
||||
switch (settings.provisionMode) {
|
||||
case AP_MODE_ALWAYS:
|
||||
case AP_MODE_DISCONNECTED:
|
||||
case AP_MODE_NEVER:
|
||||
break;
|
||||
default:
|
||||
newSettings.provisionMode = AP_MODE_ALWAYS;
|
||||
newSettings.provisionMode = AP_MODE_DISCONNECTED;
|
||||
}
|
||||
|
||||
newSettings.ssid = root["ssid"] | FACTORY_AP_SSID;
|
||||
@@ -148,5 +54,10 @@ StateUpdateResult APSettings::update(JsonObject root, APSettings & settings) {
|
||||
}
|
||||
|
||||
settings = newSettings;
|
||||
|
||||
// if the AP mode has changed, force a disconnect and reconnect
|
||||
if (settings.provisionMode != newSettings.provisionMode) {
|
||||
emsesp::EMSESP::network_.reconnect();
|
||||
}
|
||||
return StateUpdateResult::CHANGED;
|
||||
}
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
#include "FSPersistence.h"
|
||||
#include "JsonUtils.h"
|
||||
|
||||
#include <DNSServer.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#ifndef FACTORY_AP_PROVISION_MODE
|
||||
#define FACTORY_AP_PROVISION_MODE AP_MODE_DISCONNECTED
|
||||
#endif
|
||||
@@ -47,14 +44,10 @@
|
||||
#define AP_SETTINGS_FILE "/config/apSettings.json"
|
||||
#define AP_SETTINGS_SERVICE_PATH "/rest/apSettings"
|
||||
|
||||
#define AP_MODE_ALWAYS 0
|
||||
#define AP_MODE_DISCONNECTED 1
|
||||
#define AP_MODE_NEVER 2
|
||||
|
||||
#define MANAGE_NETWORK_DELAY 10000
|
||||
#define DNS_PORT 53
|
||||
|
||||
enum APNetworkStatus { ACTIVE = 0, INACTIVE, LINGERING };
|
||||
enum APNetworkStatus { ACTIVE = 0, INACTIVE };
|
||||
|
||||
class APSettings {
|
||||
public:
|
||||
@@ -84,26 +77,11 @@ class APSettingsService : public StatefulService<APSettings> {
|
||||
APSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||
|
||||
void begin();
|
||||
void loop();
|
||||
APNetworkStatus getAPNetworkStatus();
|
||||
|
||||
private:
|
||||
HttpEndpoint<APSettings> _httpEndpoint;
|
||||
FSPersistence<APSettings> _fsPersistence;
|
||||
|
||||
// for the captive portal
|
||||
DNSServer * _dnsServer;
|
||||
|
||||
// for the management delay loop
|
||||
volatile unsigned long _lastManaged;
|
||||
volatile bool _reconfigureAp;
|
||||
volatile uint8_t _connected;
|
||||
|
||||
void reconfigureAP();
|
||||
void manageAP();
|
||||
void startAP();
|
||||
void stopAP();
|
||||
void handleDNS();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "APStatus.h"
|
||||
|
||||
#include <emsesp.h>
|
||||
|
||||
APStatus::APStatus(AsyncWebServer * server, SecurityManager * securityManager, APSettingsService * apSettingsService)
|
||||
: _apSettingsService(apSettingsService) {
|
||||
securityManager->addEndpoint(server, AP_STATUS_SERVICE_PATH, AuthenticationPredicates::IS_AUTHENTICATED, [this](AsyncWebServerRequest * request) {
|
||||
@@ -12,9 +14,9 @@ void APStatus::apStatus(AsyncWebServerRequest * request) {
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
root["status"] = _apSettingsService->getAPNetworkStatus();
|
||||
root["ip_address"] = WiFi.softAPIP().toString();
|
||||
root["mac_address"] = WiFi.softAPmacAddress();
|
||||
root["station_num"] = WiFi.softAPgetStationNum();
|
||||
root["ip_address"] = emsesp::EMSESP::network_.getLocalIP();
|
||||
root["mac_address"] = emsesp::EMSESP::network_.getMacAddress();
|
||||
root["station_num"] = emsesp::EMSESP::network_.getStationNum();
|
||||
|
||||
response->setLength();
|
||||
request->send(response);
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
#ifndef APStatus_h
|
||||
#define APStatus_h
|
||||
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
|
||||
#include <ArduinoJson.h>
|
||||
#include <ESPAsyncWebServer.h>
|
||||
#include <IPAddress.h>
|
||||
|
||||
#include "SecurityManager.h"
|
||||
#include "APSettingsService.h"
|
||||
|
||||
@@ -101,8 +101,6 @@ void ESP32React::begin() {
|
||||
}
|
||||
|
||||
void ESP32React::loop() {
|
||||
_networkSettingsService.loop();
|
||||
_apSettingsService.loop();
|
||||
_mqttSettingsService.loop();
|
||||
_ntpSettingsService.loop();
|
||||
}
|
||||
|
||||
@@ -54,19 +54,6 @@ class ESP32React {
|
||||
return _mqttSettingsService.getMqttClient();
|
||||
}
|
||||
|
||||
//
|
||||
// special functions needed outside scope
|
||||
//
|
||||
|
||||
// true if AP is active
|
||||
bool apStatus() {
|
||||
return _apSettingsService.getAPNetworkStatus() == APNetworkStatus::ACTIVE;
|
||||
}
|
||||
|
||||
uint16_t getWifiReconnects() {
|
||||
return _networkSettingsService.getWifiReconnects();
|
||||
}
|
||||
|
||||
private:
|
||||
AsyncWebServer * _server;
|
||||
SecuritySettingsService _securitySettingsService;
|
||||
|
||||
@@ -79,7 +79,7 @@ void MqttSettingsService::startClient() {
|
||||
}
|
||||
|
||||
void MqttSettingsService::loop() {
|
||||
if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::system_.network_connected()) {
|
||||
if (_state.enabled && _mqttClient && _mqttClient->connected() && !emsesp::EMSESP::network_.network_connected()) {
|
||||
// emsesp::EMSESP::logger().info("Network connection dropped, stopping MQTT client");
|
||||
_mqttClient->disconnect(true);
|
||||
}
|
||||
@@ -154,7 +154,7 @@ bool MqttSettingsService::configureMqtt() {
|
||||
}
|
||||
|
||||
// only connect if WiFi is connected and MQTT is enabled
|
||||
if (_state.enabled && emsesp::EMSESP::system_.network_connected() && !_state.host.isEmpty()) {
|
||||
if (_state.enabled && emsesp::EMSESP::network_.network_connected() && !_state.host.isEmpty()) {
|
||||
// create the Last Will Testament topic (LWT) with the base prefixed. It has to be static because the client destroys the reference
|
||||
static char will_topic[FACTORY_MQTT_MAX_TOPIC_LENGTH];
|
||||
if (_state.base.isEmpty()) {
|
||||
|
||||
@@ -19,8 +19,8 @@ void NTPSettingsService::begin() {
|
||||
}
|
||||
|
||||
void NTPSettingsService::loop() {
|
||||
if (_connected != emsesp::EMSESP::system_.network_connected()) {
|
||||
_connected = emsesp::EMSESP::system_.network_connected();
|
||||
if (_connected != emsesp::EMSESP::network_.network_connected()) {
|
||||
_connected = emsesp::EMSESP::network_.network_connected();
|
||||
configureNTP();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,484 +4,13 @@
|
||||
|
||||
NetworkSettingsService::NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager)
|
||||
: _httpEndpoint(NetworkSettings::read, NetworkSettings::update, this, server, NETWORK_SETTINGS_SERVICE_PATH, securityManager)
|
||||
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE)
|
||||
, _lastConnectionAttempt(0)
|
||||
, _stopping(false) {
|
||||
addUpdateHandler([this] { reconfigureWiFiConnection(); }, false);
|
||||
// Eth is also bound to the WifiGeneric event handler
|
||||
// Network.onEvent([this](arduino_event_id_t event, arduino_event_info_t info) { WiFiEvent(event, info); });
|
||||
}
|
||||
|
||||
static bool formatBssid(const String & bssid, uint8_t (&mac)[6]) {
|
||||
uint tmp[6];
|
||||
if (bssid.isEmpty() || sscanf(bssid.c_str(), "%X:%X:%X:%X:%X:%X", &tmp[0], &tmp[1], &tmp[2], &tmp[3], &tmp[4], &tmp[5]) != 6) {
|
||||
return false;
|
||||
}
|
||||
for (uint8_t i = 0; i < 6; i++) {
|
||||
mac[i] = static_cast<uint8_t>(tmp[i]);
|
||||
}
|
||||
return true;
|
||||
, _fsPersistence(NetworkSettings::read, NetworkSettings::update, this, fs, NETWORK_SETTINGS_FILE) {
|
||||
}
|
||||
|
||||
void NetworkSettingsService::begin() {
|
||||
// We want the device to come up in opmode=0 (WIFI_OFF), when erasing the flash this is not the default.
|
||||
// If needed, we save opmode=0 before disabling persistence so the device boots with WiFi disabled in the future.
|
||||
if (WiFi.getMode() != WIFI_OFF) {
|
||||
WiFi.mode(WIFI_OFF);
|
||||
}
|
||||
|
||||
// Disable WiFi config persistance and auto reconnect
|
||||
WiFi.persistent(false);
|
||||
WiFi.setAutoReconnect(false);
|
||||
|
||||
WiFi.mode(WIFI_STA);
|
||||
WiFi.mode(WIFI_OFF);
|
||||
|
||||
// scan settings give connect issues since arduino 2.0.14 and arduino 3.x.x with some wifi systems
|
||||
// WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN); // default is FAST_SCAN
|
||||
// WiFi.setSortMethod(WIFI_CONNECT_AP_BY_SIGNAL); // is default, no need to set
|
||||
|
||||
_fsPersistence.readFromFS();
|
||||
}
|
||||
|
||||
void NetworkSettingsService::reconfigureWiFiConnection() {
|
||||
// do not disconnect for switching to eth, restart is needed
|
||||
if (WiFi.isConnected() && _state.ssid.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// disconnect and de-configure wifi
|
||||
if (WiFi.disconnect(true)) {
|
||||
_stopping = true;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkSettingsService::loop() {
|
||||
unsigned long currentMillis = millis();
|
||||
if (!_lastConnectionAttempt || static_cast<uint32_t>(currentMillis - _lastConnectionAttempt) >= WIFI_RECONNECTION_DELAY) {
|
||||
_lastConnectionAttempt = currentMillis;
|
||||
manageSTA();
|
||||
}
|
||||
static uint8_t connect = 0;
|
||||
enum uint8_t {
|
||||
CONNECT_IDLE = 0,
|
||||
CONNECT_WAIT_ETH,
|
||||
CONNECT_WAIT_IP4,
|
||||
CONNECT_WAIT_ETH_IP4,
|
||||
CONNECT_WAIT_IP6,
|
||||
CONNECT_WAIT_ETH_IP6,
|
||||
CONNECT_ETH_ACTIVE,
|
||||
CONNECT_WIFI_ACTIVE
|
||||
};
|
||||
switch (connect) {
|
||||
default:
|
||||
connect = CONNECT_IDLE;
|
||||
break;
|
||||
case CONNECT_IDLE:
|
||||
if (ETH.started() && _state.ssid.length() == 0) {
|
||||
emsesp::EMSESP::logger().info("ETH started");
|
||||
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
|
||||
ETH.enableIPv6(true);
|
||||
if (_state.staticIPConfig) {
|
||||
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
|
||||
}
|
||||
connect = CONNECT_WAIT_ETH;
|
||||
}
|
||||
if (WiFi.isConnected()) {
|
||||
emsesp::EMSESP::logger().info("Wifi connected");
|
||||
if (_state.tx_power == 0) {
|
||||
setWiFiPowerOnRSSI();
|
||||
}
|
||||
mDNS_start();
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_WAIT_IP4;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_ETH:
|
||||
if (ETH.connected()) {
|
||||
emsesp::EMSESP::logger().info("ETH connected");
|
||||
emsesp::EMSESP::system_.ethernet_connected(true);
|
||||
mDNS_start();
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_WAIT_ETH_IP4;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_ETH_IP4:
|
||||
if (ETH.hasIP()) {
|
||||
emsesp::EMSESP::logger().info("ETH IPv4: %s", ETH.localIP().toString().c_str());
|
||||
connect = CONNECT_WAIT_ETH_IP6;
|
||||
}
|
||||
if (!ETH.connected()) {
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_ETH_IP6:
|
||||
if (ETH.hasLinkLocalIPv6() && ETH.hasGlobalIPv6()) {
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
if (!ETH.connected()) {
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_ETH_ACTIVE:
|
||||
if (!ETH.connected()) {
|
||||
emsesp::EMSESP::logger().info("ETH disconnected");
|
||||
emsesp::EMSESP::system_.ethernet_connected(false);
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
connect = CONNECT_IDLE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_IP4:
|
||||
if (!WiFi.localIP().toString().isEmpty()) {
|
||||
emsesp::EMSESP::logger().info("Wifi IPv4: %s", WiFi.localIP().toString().c_str());
|
||||
connect = CONNECT_WAIT_IP6;
|
||||
}
|
||||
if (!WiFi.isConnected()) {
|
||||
connect = CONNECT_ETH_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WAIT_IP6:
|
||||
if (WiFi.linkLocalIPv6().toString() != "::" && WiFi.globalIPv6().toString() != "::") {
|
||||
emsesp::EMSESP::logger().info("Wifi IPv6: %s, %s", WiFi.linkLocalIPv6().toString().c_str(), WiFi.globalIPv6().toString().c_str());
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
connect = CONNECT_WIFI_ACTIVE;
|
||||
}
|
||||
if (!WiFi.isConnected()) {
|
||||
connect = CONNECT_WIFI_ACTIVE;
|
||||
}
|
||||
break;
|
||||
case CONNECT_WIFI_ACTIVE:
|
||||
if (!WiFi.isConnected()) {
|
||||
emsesp::EMSESP::logger().info("WiFi disconnected");
|
||||
if (_stopping) {
|
||||
_lastConnectionAttempt = 0;
|
||||
_stopping = false;
|
||||
}
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
connect = CONNECT_IDLE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkSettingsService::manageSTA() {
|
||||
// Abort if already connected, or if we have no SSID
|
||||
if (WiFi.isConnected() || _state.ssid.length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect or reconnect as required
|
||||
if ((WiFi.getMode() & WIFI_STA) == 0) {
|
||||
WiFi.setHostname(_state.hostname.c_str()); // updates shared default_hostname buffer
|
||||
WiFi.enableSTA(true); // creates the STA netif
|
||||
WiFi.STA.setHostname(_state.hostname.c_str()); // pushes to esp_netif_set_hostname
|
||||
WiFi.enableIPv6(true);
|
||||
if (_state.staticIPConfig) {
|
||||
WiFi.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2); // configure for static IP
|
||||
}
|
||||
|
||||
// www.esp32.com/viewtopic.php?t=12055
|
||||
if (_state.bandwidth20) {
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_STA), WIFI_BW_HT20);
|
||||
} else {
|
||||
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_STA), WIFI_BW_HT40);
|
||||
}
|
||||
if (_state.nosleep) {
|
||||
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
|
||||
}
|
||||
|
||||
// attempt to connect to the network
|
||||
uint8_t bssid[6];
|
||||
if (formatBssid(_state.bssid, bssid)) {
|
||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str(), 0, bssid);
|
||||
} else {
|
||||
WiFi.begin(_state.ssid.c_str(), _state.password.c_str());
|
||||
}
|
||||
|
||||
#ifdef BOARD_C3_MINI_V1
|
||||
// always hardcode Tx power for Wemos CS Mini v1
|
||||
// v1 needs this value, see https://github.com/emsesp/EMS-ESP32/pull/620#discussion_r993173979
|
||||
// https://www.wemos.cc/en/latest/c3/c3_mini_1_0_0.html#about-wifi
|
||||
WiFi.setTxPower(WIFI_POWER_8_5dBm);
|
||||
#else
|
||||
if (_state.tx_power != 0) {
|
||||
// if not set to Auto (0) set the Tx power now
|
||||
if (!WiFi.setTxPower(static_cast<wifi_power_t>(_state.tx_power))) {
|
||||
emsesp::EMSESP::logger().warning("Failed to set WiFi Tx Power");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else { // not connected but STA-mode active => disconnect
|
||||
reconfigureWiFiConnection();
|
||||
}
|
||||
}
|
||||
|
||||
// set the TxPower based on the RSSI (signal strength), picking the lowest value
|
||||
// code is based of RSSI (signal strength) and copied from Tasmota's WiFiSetTXpowerBasedOnRssi() which is copied ESPEasy's ESPEasyWifi.SetWiFiTXpower() function
|
||||
void NetworkSettingsService::setWiFiPowerOnRSSI() {
|
||||
// Range ESP32 : 2dBm - 20dBm
|
||||
// 802.11b - wifi1
|
||||
// 802.11a - wifi2
|
||||
// 802.11g - wifi3
|
||||
// 802.11n - wifi4
|
||||
// 802.11ac - wifi5
|
||||
// 802.11ax - wifi6
|
||||
|
||||
int max_tx_pwr = MAX_TX_PWR_DBM_n; // assume wifi4
|
||||
int threshold = WIFI_SENSITIVITY_n + 120; // Margin in dBm * 10 on top of threshold
|
||||
|
||||
// Assume AP sends with max set by ETSI standard.
|
||||
// 2.4 GHz: 100 mWatt (20 dBm)
|
||||
// US and some other countries allow 1000 mW (30 dBm)
|
||||
int rssi = WiFi.RSSI() * 10;
|
||||
int newrssi = rssi - 200; // We cannot send with over 20 dBm, thus it makes no sense to force higher TX power all the time.
|
||||
|
||||
int min_tx_pwr = 0;
|
||||
if (newrssi < threshold) {
|
||||
min_tx_pwr = threshold - newrssi;
|
||||
}
|
||||
if (min_tx_pwr > max_tx_pwr) {
|
||||
min_tx_pwr = max_tx_pwr;
|
||||
}
|
||||
|
||||
// from WiFIGeneric.h use:
|
||||
// WIFI_POWER_19_5dBm = 78,// 19.5dBm
|
||||
// WIFI_POWER_19dBm = 76,// 19dBm
|
||||
// WIFI_POWER_18_5dBm = 74,// 18.5dBm
|
||||
// WIFI_POWER_17dBm = 68,// 17dBm
|
||||
// WIFI_POWER_15dBm = 60,// 15dBm
|
||||
// WIFI_POWER_13dBm = 52,// 13dBm
|
||||
// WIFI_POWER_11dBm = 44,// 11dBm
|
||||
// WIFI_POWER_8_5dBm = 34,// 8.5dBm
|
||||
// WIFI_POWER_7dBm = 28,// 7dBm
|
||||
// WIFI_POWER_5dBm = 20,// 5dBm
|
||||
// WIFI_POWER_2dBm = 8,// 2dBm
|
||||
// WIFI_POWER_MINUS_1dBm = -4// -1dBm
|
||||
wifi_power_t p = WIFI_POWER_2dBm;
|
||||
if (min_tx_pwr > 185)
|
||||
p = WIFI_POWER_19_5dBm;
|
||||
else if (min_tx_pwr > 170)
|
||||
p = WIFI_POWER_18_5dBm;
|
||||
else if (min_tx_pwr > 150)
|
||||
p = WIFI_POWER_17dBm;
|
||||
else if (min_tx_pwr > 130)
|
||||
p = WIFI_POWER_15dBm;
|
||||
else if (min_tx_pwr > 110)
|
||||
p = WIFI_POWER_13dBm;
|
||||
else if (min_tx_pwr > 85)
|
||||
p = WIFI_POWER_11dBm;
|
||||
else if (min_tx_pwr > 70)
|
||||
p = WIFI_POWER_8_5dBm;
|
||||
else if (min_tx_pwr > 50)
|
||||
p = WIFI_POWER_7dBm;
|
||||
else if (min_tx_pwr > 20)
|
||||
p = WIFI_POWER_5dBm;
|
||||
|
||||
#if defined(EMSESP_DEBUG)
|
||||
// emsesp::EMSESP::logger().debug("Recommended WiFi Tx Power (set_power %d, new power %d, rssi %d, threshold %d)", min_tx_pwr / 10, p, rssi, threshold);
|
||||
#endif
|
||||
|
||||
if (!WiFi.setTxPower(p)) {
|
||||
emsesp::EMSESP::logger().warning("Failed to set WiFi Tx Power");
|
||||
}
|
||||
}
|
||||
|
||||
// start the multicast UDP service so EMS-ESP is discoverable via .local
|
||||
void NetworkSettingsService::mDNS_start() const {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
MDNS.end();
|
||||
|
||||
if (_state.enableMDNS) {
|
||||
if (!MDNS.begin(emsesp::EMSESP::system_.hostname().c_str())) {
|
||||
emsesp::EMSESP::logger().warning("Failed to start mDNS Responder service");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string address_s = emsesp::EMSESP::system_.hostname() + ".local";
|
||||
|
||||
MDNS.addService("http", "tcp", 80); // add our web server and rest API
|
||||
MDNS.addService("telnet", "tcp", 23); // add our telnet console
|
||||
|
||||
// MDNS.addServiceTxt("http", "tcp", "version", EMSESP_APP_VERSION);
|
||||
MDNS.addServiceTxt("http", "tcp", "address", address_s.c_str());
|
||||
|
||||
emsesp::EMSESP::logger().info("Starting mDNS Responder service");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
const char * NetworkSettingsService::disconnectReason(uint8_t code) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
switch (code) {
|
||||
case WIFI_REASON_UNSPECIFIED: // = 1,
|
||||
return "unspecified";
|
||||
case WIFI_REASON_AUTH_EXPIRE: // = 2,
|
||||
return "auth expire";
|
||||
case WIFI_REASON_AUTH_LEAVE: // = 3,
|
||||
return "auth leave";
|
||||
case WIFI_REASON_ASSOC_EXPIRE: // = 4,
|
||||
return "assoc expired";
|
||||
case WIFI_REASON_ASSOC_TOOMANY: // = 5,
|
||||
return "assoc too many";
|
||||
case WIFI_REASON_NOT_AUTHED: // = 6,
|
||||
return "not authenticated";
|
||||
case WIFI_REASON_NOT_ASSOCED: // = 7,
|
||||
return "not assoc";
|
||||
case WIFI_REASON_ASSOC_LEAVE: // = 8,
|
||||
return "assoc leave";
|
||||
case WIFI_REASON_ASSOC_NOT_AUTHED: // = 9,
|
||||
return "assoc not authed";
|
||||
case WIFI_REASON_DISASSOC_PWRCAP_BAD: // = 10,
|
||||
return "disassoc powerCAP bad";
|
||||
case WIFI_REASON_DISASSOC_SUPCHAN_BAD: // = 11,
|
||||
return "disassoc supchan bad";
|
||||
case WIFI_REASON_IE_INVALID: // = 13,
|
||||
return "IE invalid";
|
||||
case WIFI_REASON_MIC_FAILURE: // = 14,
|
||||
return "MIC failure";
|
||||
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT: // = 15,
|
||||
return "4way handshake timeout";
|
||||
case WIFI_REASON_GROUP_KEY_UPDATE_TIMEOUT: // = 16,
|
||||
return "group key-update timeout";
|
||||
case WIFI_REASON_IE_IN_4WAY_DIFFERS: // = 17,
|
||||
return "IE in 4way differs";
|
||||
case WIFI_REASON_GROUP_CIPHER_INVALID: // = 18,
|
||||
return "group cipher invalid";
|
||||
case WIFI_REASON_PAIRWISE_CIPHER_INVALID: // = 19,
|
||||
return "pairwise cipher invalid";
|
||||
case WIFI_REASON_AKMP_INVALID: // = 20,
|
||||
return "AKMP invalid";
|
||||
case WIFI_REASON_UNSUPP_RSN_IE_VERSION: // = 21,
|
||||
return "unsupported RSN_IE version";
|
||||
case WIFI_REASON_INVALID_RSN_IE_CAP: // = 22,
|
||||
return "invalid RSN_IE_CAP";
|
||||
case WIFI_REASON_802_1X_AUTH_FAILED: // = 23,
|
||||
return "802 X1 auth failed";
|
||||
case WIFI_REASON_CIPHER_SUITE_REJECTED: // = 24,
|
||||
return "cipher suite rejected";
|
||||
case WIFI_REASON_BEACON_TIMEOUT: // = 200,
|
||||
return "beacon timeout";
|
||||
case WIFI_REASON_NO_AP_FOUND: // = 201,
|
||||
return "no AP found";
|
||||
case WIFI_REASON_AUTH_FAIL: // = 202,
|
||||
return "auth fail";
|
||||
case WIFI_REASON_ASSOC_FAIL: // = 203,
|
||||
return "assoc fail";
|
||||
case WIFI_REASON_HANDSHAKE_TIMEOUT: // = 204,
|
||||
return "handshake timeout";
|
||||
case WIFI_REASON_CONNECTION_FAIL: // 205,
|
||||
return "connection fail";
|
||||
case WIFI_REASON_AP_TSF_RESET: // 206,
|
||||
return "AP tsf reset";
|
||||
case WIFI_REASON_ROAMING: // 207,
|
||||
return "roaming";
|
||||
case WIFI_REASON_ASSOC_COMEBACK_TIME_TOO_LONG: // 208,
|
||||
return "assoc comeback time too long";
|
||||
case WIFI_REASON_SA_QUERY_TIMEOUT: // 209,
|
||||
return "sa query timeout";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
#endif
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// handles both WiFI and Ethernet
|
||||
void NetworkSettingsService::WiFiEvent(arduino_event_id_t event, arduino_event_info_t info) {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
|
||||
switch (event) {
|
||||
case ARDUINO_EVENT_WIFI_STA_STOP:
|
||||
if (_stopping) {
|
||||
_lastConnectionAttempt = 0;
|
||||
_stopping = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_DISCONNECTED:
|
||||
connectcount_ = connectcount_ + 1; // count the number of WiFi reconnects
|
||||
emsesp::EMSESP::logger().warning("WiFi disconnected (#%d). Reason: %s (%d)",
|
||||
connectcount_,
|
||||
disconnectReason(info.wifi_sta_disconnected.reason),
|
||||
info.wifi_sta_disconnected.reason); // IDF 4.0
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
|
||||
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP:
|
||||
char result[10];
|
||||
emsesp::EMSESP::logger().info("WiFi connected (Local IP=%s, hostname=%s, TxPower=%s dBm)",
|
||||
WiFi.localIP().toString().c_str(),
|
||||
WiFi.getHostname(),
|
||||
emsesp::Helpers::render_value(result, ((double)(WiFi.getTxPower()) / 4), 1));
|
||||
mDNS_start();
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_START:
|
||||
// apply hostname FIRST so DHCP DISCOVER carries the correct name
|
||||
ETH.setHostname(emsesp::EMSESP::system_.hostname().c_str());
|
||||
if (_state.staticIPConfig) {
|
||||
ETH.config(_state.localIP, _state.gatewayIP, _state.subnetMask, _state.dnsIP1, _state.dnsIP2);
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||
// prevent double calls to mDNS
|
||||
if (!emsesp::EMSESP::system_.ethernet_connected()) {
|
||||
emsesp::EMSESP::logger().info("Ethernet connected (Local IP=%s, speed %d Mbps)", ETH.localIP().toString().c_str(), ETH.linkSpeed());
|
||||
emsesp::EMSESP::system_.ethernet_connected(true);
|
||||
mDNS_start();
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||
emsesp::EMSESP::logger().warning("Ethernet disconnected. Reason: %s (%d)",
|
||||
disconnectReason(info.wifi_sta_disconnected.reason),
|
||||
info.wifi_sta_disconnected.reason);
|
||||
emsesp::EMSESP::system_.ethernet_connected(false);
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_STOP:
|
||||
emsesp::EMSESP::logger().info("Ethernet stopped");
|
||||
emsesp::EMSESP::system_.ethernet_connected(false);
|
||||
emsesp::EMSESP::system_.has_ipv6(false);
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_WIFI_STA_CONNECTED:
|
||||
// Set the TxPower after the connection is established, if we're using TxPower = 0 (Auto)
|
||||
if (_state.tx_power == 0) {
|
||||
setWiFiPowerOnRSSI();
|
||||
}
|
||||
break;
|
||||
|
||||
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||
break;
|
||||
|
||||
// IPv6 specific - WiFi/Eth
|
||||
case ARDUINO_EVENT_WIFI_STA_GOT_IP6:
|
||||
case ARDUINO_EVENT_ETH_GOT_IP6: {
|
||||
auto ip6 = IPAddress(IPv6, (uint8_t *)info.got_ip6.ip6_info.ip.addr, 0).toString();
|
||||
const char * link = event == ARDUINO_EVENT_ETH_GOT_IP6 ? "Eth" : "WiFi";
|
||||
if (ip6.startsWith("fe80")) {
|
||||
emsesp::EMSESP::logger().info("IPv6 (%s) local: %s", link, ip6.c_str());
|
||||
} else if (ip6.startsWith("fd") || ip6.startsWith("fc")) {
|
||||
emsesp::EMSESP::logger().info("IPv6 (%s) ULA: %s", link, ip6.c_str());
|
||||
} else {
|
||||
emsesp::EMSESP::logger().info("IPv6 (%s) global: %s", link, ip6.c_str());
|
||||
}
|
||||
emsesp::EMSESP::system_.has_ipv6(true);
|
||||
} break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void NetworkSettings::read(NetworkSettings & settings, JsonObject root) {
|
||||
// connection settings
|
||||
root["ssid"] = settings.ssid;
|
||||
@@ -544,6 +73,7 @@ StateUpdateResult NetworkSettings::update(JsonObject root, NetworkSettings & set
|
||||
}
|
||||
|
||||
// see if we need to inform the user of a restart
|
||||
// if tx power, enableCORS, CORSOrigin, ssid changes, we need to restart
|
||||
if (tx_power != settings.tx_power || enableCORS != settings.enableCORS || CORSOrigin != settings.CORSOrigin
|
||||
|| (ssid != settings.ssid && settings.ssid.isEmpty())) {
|
||||
return StateUpdateResult::CHANGED_RESTART; // tell WebUI that a restart is needed
|
||||
|
||||
@@ -8,15 +8,10 @@
|
||||
|
||||
#ifndef EMSESP_STANDALONE
|
||||
#include <esp_wifi.h>
|
||||
#include <ETH.h>
|
||||
#include <WiFi.h>
|
||||
#include <AsyncTCP.h>
|
||||
#include <ESPmDNS.h>
|
||||
#endif
|
||||
|
||||
#define NETWORK_SETTINGS_FILE "/config/networkSettings.json"
|
||||
#define NETWORK_SETTINGS_SERVICE_PATH "/rest/networkSettings"
|
||||
#define WIFI_RECONNECTION_DELAY (1000 * 3)
|
||||
|
||||
#ifndef FACTORY_WIFI_SSID
|
||||
#define FACTORY_WIFI_SSID ""
|
||||
@@ -30,37 +25,6 @@
|
||||
#define FACTORY_WIFI_HOSTNAME ""
|
||||
#endif
|
||||
|
||||
// copied from Tasmota
|
||||
#if CONFIG_IDF_TARGET_ESP32S2
|
||||
#define MAX_TX_PWR_DBM_11b 195
|
||||
#define MAX_TX_PWR_DBM_54g 150
|
||||
#define MAX_TX_PWR_DBM_n 130
|
||||
#define WIFI_SENSITIVITY_11b -880
|
||||
#define WIFI_SENSITIVITY_54g -750
|
||||
#define WIFI_SENSITIVITY_n -720
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#define MAX_TX_PWR_DBM_11b 210
|
||||
#define MAX_TX_PWR_DBM_54g 190
|
||||
#define MAX_TX_PWR_DBM_n 185
|
||||
#define WIFI_SENSITIVITY_11b -880
|
||||
#define WIFI_SENSITIVITY_54g -760
|
||||
#define WIFI_SENSITIVITY_n -720
|
||||
#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3
|
||||
#define MAX_TX_PWR_DBM_11b 210
|
||||
#define MAX_TX_PWR_DBM_54g 190
|
||||
#define MAX_TX_PWR_DBM_n 185
|
||||
#define WIFI_SENSITIVITY_11b -880
|
||||
#define WIFI_SENSITIVITY_54g -760
|
||||
#define WIFI_SENSITIVITY_n -730
|
||||
#else
|
||||
#define MAX_TX_PWR_DBM_11b 195
|
||||
#define MAX_TX_PWR_DBM_54g 160
|
||||
#define MAX_TX_PWR_DBM_n 140
|
||||
#define WIFI_SENSITIVITY_11b -880
|
||||
#define WIFI_SENSITIVITY_54g -750
|
||||
#define WIFI_SENSITIVITY_n -700
|
||||
#endif
|
||||
|
||||
class NetworkSettings {
|
||||
public:
|
||||
// core wifi configuration
|
||||
@@ -92,27 +56,10 @@ class NetworkSettingsService : public StatefulService<NetworkSettings> {
|
||||
NetworkSettingsService(AsyncWebServer * server, FS * fs, SecurityManager * securityManager);
|
||||
|
||||
void begin();
|
||||
void loop();
|
||||
|
||||
uint16_t getWifiReconnects() const {
|
||||
return connectcount_;
|
||||
}
|
||||
|
||||
private:
|
||||
HttpEndpoint<NetworkSettings> _httpEndpoint;
|
||||
FSPersistence<NetworkSettings> _fsPersistence;
|
||||
|
||||
volatile unsigned long _lastConnectionAttempt;
|
||||
volatile bool _stopping;
|
||||
|
||||
volatile uint16_t connectcount_ = 0; // number of wifi reconnects
|
||||
|
||||
void WiFiEvent(arduino_event_id_t event, arduino_event_info_t info);
|
||||
void mDNS_start() const;
|
||||
const char * disconnectReason(uint8_t code);
|
||||
void reconfigureWiFiConnection();
|
||||
void manageSTA();
|
||||
void setWiFiPowerOnRSSI();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -16,11 +16,10 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
auto * response = new AsyncJsonResponse(false);
|
||||
JsonObject root = response->getRoot();
|
||||
|
||||
bool ethernet_connected = emsesp::EMSESP::system_.ethernet_connected();
|
||||
wl_status_t wifi_status = WiFi.status();
|
||||
wl_status_t wifi_status = WiFi.status();
|
||||
|
||||
// see if Ethernet is connected
|
||||
if (ethernet_connected) {
|
||||
if (emsesp::EMSESP::network_.ethernet_connected()) {
|
||||
root["status"] = 10; // custom code #10 - ETHERNET_STATUS_CONNECTED
|
||||
root["hostname"] = ETH.getHostname();
|
||||
} else {
|
||||
@@ -29,7 +28,7 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
}
|
||||
|
||||
// for both connections show ethernet
|
||||
if (ethernet_connected) {
|
||||
if (emsesp::EMSESP::network_.ethernet_connected()) {
|
||||
// Ethernet
|
||||
root["local_ip"] = ETH.localIP().toString();
|
||||
root["local_ipv6"] = ETH.linkLocalIPv6().toString();
|
||||
@@ -52,7 +51,7 @@ void NetworkStatus::networkStatus(AsyncWebServerRequest * request) {
|
||||
root["ssid"] = WiFi.SSID();
|
||||
root["bssid"] = WiFi.BSSIDstr();
|
||||
root["channel"] = WiFi.channel();
|
||||
root["reconnect_count"] = emsesp::EMSESP::esp32React.getWifiReconnects();
|
||||
root["reconnect_count"] = emsesp::EMSESP::network_.getWifiReconnects();
|
||||
root["subnet_mask"] = WiFi.subnetMask().toString();
|
||||
|
||||
if (WiFi.gatewayIP() != INADDR_NONE) {
|
||||
|
||||
Reference in New Issue
Block a user