refactor network code

This commit is contained in:
proddy
2026-05-01 08:07:05 +02:00
parent 0e08334132
commit 751c540cb3
38 changed files with 999 additions and 852 deletions

View File

@@ -202,7 +202,7 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
commands->add_command(ShellContext::MAIN,
CommandFlags::ADMIN,
string_vector{F_(wifi), F_(reconnect)},
[](Shell & shell, const std::vector<std::string> & arguments) { EMSESP::system_.wifi_reconnect(); });
[](Shell & shell, const std::vector<std::string> & arguments) { EMSESP::network_.reconnect(); });
//
// SET commands
@@ -250,12 +250,12 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
shell.enter_password(F_(new_password_prompt2), [password1](Shell & shell, bool completed, const std::string & password2) {
if (completed) {
if (password1 == password2) {
EMSESP::esp32React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) {
EMSESP::esp32React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
networkSettings.password = password2.c_str();
return StateUpdateResult::CHANGED;
});
shell.println("WiFi password updated. Reconnecting...");
EMSESP::system_.wifi_reconnect();
EMSESP::network_.reconnect();
} else {
shell.println("Passwords do not match");
}
@@ -277,6 +277,7 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
networkSettings.hostname = arguments.front().c_str();
return StateUpdateResult::CHANGED;
});
EMSESP::network_.reconnect();
});
commands->add_command(ShellContext::MAIN,
@@ -284,12 +285,14 @@ static void setup_commands(std::shared_ptr<Commands> const & commands) {
string_vector{F_(set), F_(wifi), F_(ssid)},
{F_(name_mandatory)},
[](Shell & shell, const std::vector<std::string> & arguments) {
EMSESP::esp32React.getNetworkSettingsService()->updateWithoutPropagation([&](NetworkSettings & networkSettings) {
shell.println("The network connection will be reset...");
Shell::loop_all();
delay(1000); // wait a second
EMSESP::esp32React.getNetworkSettingsService()->update([&](NetworkSettings & networkSettings) {
networkSettings.ssid = arguments.front().c_str();
return StateUpdateResult::CHANGED;
});
shell.println("WiFi ssid updated. Reconnecting...");
EMSESP::system_.wifi_reconnect();
EMSESP::network_.reconnect();
});

View File

@@ -86,6 +86,7 @@ TxService EMSESP::txservice_; // outgoing Telegram Tx handler
Mqtt EMSESP::mqtt_; // mqtt handler
Modbus * EMSESP::modbus_ = nullptr; // modbus handler
System EMSESP::system_; // core system services
Network EMSESP::network_; // network services
TemperatureSensor EMSESP::temperaturesensor_; // Temperature sensors
AnalogSensor EMSESP::analogsensor_; // Analog sensors
Shower EMSESP::shower_; // Shower logic
@@ -1721,13 +1722,13 @@ void EMSESP::start() {
// start web log service. now we can start capturing logs to the web log
webLogService.begin();
// loads core system services settings (network, mqtt, ap, ntp etc)
// loads core system services settings (mqtt, ap, ntp etc)
esp32React.begin();
#ifndef EMSESP_STANDALONE
if (factory_settings) {
LOG_WARNING("No settings found on filesystem. Using factory settings.");
// make sure OTAdata is updated with core3 format
// make sure OTAdata is updated with core3 (v3.9.0) format
esp_ota_set_boot_partition(esp_ota_get_running_partition());
}
#endif
@@ -1777,6 +1778,9 @@ void EMSESP::start() {
webSettingsService.begin(); // load EMS-ESP Application settings
// start network services. This will initialise WiFi or Ethernet depending on the settings.
network_.begin();
// perform any system upgrades
if (!factory_settings) {
if (system_.check_upgrade()) {
@@ -1847,6 +1851,9 @@ void EMSESP::shell_prompt() {
void EMSESP::loop() {
uuid::loop(); // store system uptime
// handle network
network_.loop();
// handles LED and checks system health, and syslog service
if (system_.loop()) {
return; // LED flashing is active, skip the rest of the loop

View File

@@ -63,6 +63,7 @@
#include "mqtt.h"
#include "modbus.h"
#include "system.h"
#include "network.h"
#include "temperaturesensor.h"
#include "analogsensor.h"
#include "console.h"
@@ -228,6 +229,7 @@ class EMSESP {
static Mqtt mqtt_;
static Modbus * modbus_;
static System system_;
static Network network_;
static TemperatureSensor temperaturesensor_;
static AnalogSensor analogsensor_;
static Shower shower_;

View File

@@ -60,6 +60,7 @@ MAKE_WORD(mqtt)
MAKE_WORD(gpio)
MAKE_WORD(modbus)
MAKE_WORD(emsesp)
MAKE_WORD(network)
MAKE_WORD(connected)
MAKE_WORD(disconnected)
MAKE_WORD(passwd)

View File

@@ -563,7 +563,7 @@ void Mqtt::ha_status() {
// create the HA sensors - must match the MQTT payload keys in the heartbeat topic
// Note we don't use camelCase as it would change the HA entity_id and impact historic data
#ifndef EMSESP_STANDALONE
if (!EMSESP::system_.ethernet_connected() || WiFi.isConnected()) {
if (EMSESP::network_.wifi_connected()) {
publish_system_ha_sensor_config(DeviceValueType::INT8, "RSSI", "rssi", DeviceValueUOM::DBM);
publish_system_ha_sensor_config(DeviceValueType::INT8, "Signal", "wifistrength", DeviceValueUOM::PERCENT);
}
@@ -585,7 +585,7 @@ void Mqtt::ha_status() {
publish_system_ha_sensor_config(DeviceValueType::INT8, "CPU temperature", "temperature", DeviceValueUOM::DEGREES);
#endif
if (!EMSESP::system_.ethernet_connected()) {
if (!EMSESP::network_.ethernet_connected()) {
publish_system_ha_sensor_config(DeviceValueType::INT16, "WiFi reconnects", "wifireconnects", DeviceValueUOM::NONE);
}
// This one comes from the info MQTT topic - and handled in the publish_ha_sensor_config function

673
src/core/network.cpp Normal file
View File

@@ -0,0 +1,673 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "network.h"
#include "emsesp.h"
namespace emsesp {
uuid::log::Logger Network::logger_{F_(network), uuid::log::Facility::KERN};
void Network::begin() {
#ifndef EMSESP_STANDALONE
// pull Network settings and store locally on stack
EMSESP::esp32React.getNetworkSettingsService()->read([&](auto & settings) {
enableMDNS_ = settings.enableMDNS;
staticIPConfig_ = settings.staticIPConfig;
localIP_ = settings.localIP;
gatewayIP_ = settings.gatewayIP;
subnetMask_ = settings.subnetMask;
dnsIP1_ = settings.dnsIP1;
dnsIP2_ = settings.dnsIP2;
hostname_ = settings.hostname;
ssid_ = settings.ssid;
password_ = settings.password;
bandwidth20_ = settings.bandwidth20;
nosleep_ = settings.nosleep;
tx_power_ = settings.tx_power;
bssid_ = settings.bssid;
});
// read Ethernet settings
EMSESP::webSettingsService.read([&](WebSettings & settings) {
phy_type_ = settings.phy_type;
eth_power_ = settings.eth_power;
eth_phy_addr_ = settings.eth_phy_addr;
eth_clock_mode_ = settings.eth_clock_mode;
});
// get Access Point settings
EMSESP::esp32React.getAPSettingsService()->read([&](APSettings & settings) {
ap_provisionMode_ = settings.provisionMode;
ap_ssid_ = settings.ssid;
ap_password_ = settings.password;
ap_channel_ = settings.channel;
ap_ssid_hidden_ = settings.ssidHidden;
ap_max_clients_ = settings.maxClients;
ap_localIP_ = settings.localIP;
ap_gatewayIP_ = settings.gatewayIP;
ap_subnetMask_ = settings.subnetMask;
});
// Initialise WiFi - we only do this once, when the network service is started
// 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
// capture the WIFI_REASON_* code on every STA disconnect event so check_connection() can
// log a meaningful reason when its periodic poll notices we're no longer associated
WiFi.onEvent([this](WiFiEvent_t /*event*/, WiFiEventInfo_t info) { last_disconnect_reason_ = info.wifi_sta_disconnected.reason; },
ARDUINO_EVENT_WIFI_STA_DISCONNECTED);
// clear the saved reason on a fresh STA association so we don't log a stale code on the next disconnect
WiFi.onEvent([this](WiFiEvent_t /*event*/, WiFiEventInfo_t /*info*/) { last_disconnect_reason_ = 0; }, ARDUINO_EVENT_WIFI_STA_GOT_IP);
#endif
}
// format the BSSID (MAC address) of the network interface
bool Network::formatBSSID(const String & bssid, uint8_t (&mac)[6]) {
#ifndef EMSESP_STANDALONE
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]);
}
#endif
return true;
}
// get the local IP address of the network interface
std::string Network::getLocalIP() const {
switch (network_iface_) {
#ifndef EMSESP_STANDALONE
case NetIface::AP:
return WiFi.softAPIP().toString().c_str();
case NetIface::WIFI:
return WiFi.localIP().toString().c_str();
case NetIface::ETHERNET:
return ETH.localIP().toString().c_str();
case NetIface::NONE:
#endif
default:
return "";
}
}
// get the MAC address of the network interface
std::string Network::getMacAddress() const {
switch (network_iface_) {
#ifndef EMSESP_STANDALONE
case NetIface::AP:
return WiFi.softAPmacAddress().c_str();
case NetIface::WIFI:
return WiFi.macAddress().c_str();
case NetIface::ETHERNET:
return ETH.macAddress().c_str();
case NetIface::NONE:
#endif
default:
return "";
}
}
// get the number of stations connected to the AP
uint8_t Network::getStationNum() const {
#ifndef EMSESP_STANDALONE
return network_iface_ == NetIface::AP ? WiFi.softAPgetStationNum() : 0;
#else
return 0;
#endif
}
// disconnect all WiFi, Eth and AP
// so we can starts searching again to reconnect
void Network::reconnect() {
LOG_DEBUG("Disconnecting all networks");
#ifndef EMSESP_STANDALONE
// disconnect WiFi
if (wifi_connected()) {
WiFi.disconnect(true);
}
// disconnect AP
if (WiFi.getMode() & WIFI_AP) {
stopAP();
}
#endif
// reset network state
network_ip_ = 0;
network_iface_ = NetIface::NONE;
has_ipv6_ = false;
juststopped_ = true;
// reload the network settings
begin();
}
// network loop, looking for new and disconnecting networks
void Network::loop() {
#ifndef EMSESP_STANDALONE
// if we already have a Wifi or Ethernet connection then re-check every NETWORK_RECONNECTION_DELAY_LONG, otherwise NETWORK_RECONNECTION_DELAY_SHORT
const unsigned long currentMillis = millis();
const uint32_t reconnectDelay =
(network_iface_ == NetIface::WIFI || network_iface_ == NetIface::ETHERNET) ? NETWORK_RECONNECTION_DELAY_LONG : NETWORK_RECONNECTION_DELAY_SHORT;
if (!lastConnectionAttempt_ || static_cast<uint32_t>(currentMillis - lastConnectionAttempt_) >= reconnectDelay) {
lastConnectionAttempt_ = currentMillis;
// manage network interfaces
startAP(); // Captive Portal (AP)
startWIFI(); // WiFi
startEthernet(); // Ethernet
if (network_ip_ != 0) {
checkConnection(); // already have a connection: verify it's still alive
}
findNetworks(); // detect new connections
}
// process DNS requests for the captive portal while the soft-AP is up
if (ap_dnsServer_) {
ap_dnsServer_->processNextRequest();
}
#endif
}
// Re-validate the currently active connection
// if a netif is no longer up or has lost its IP (cable unplugged, AP gone, DHCP lease lost, ...) we drop our state so
// find_networks() can pick up a new one
void Network::checkConnection() {
#ifndef EMSESP_STANDALONE
bool still_up = false;
for (esp_netif_t * netif = esp_netif_next_unsafe(NULL); netif != NULL; netif = esp_netif_next_unsafe(netif)) {
if (iface_from_desc(esp_netif_get_desc(netif)) != network_iface_) {
continue;
}
esp_netif_ip_info_t ip_info = {};
if (esp_netif_is_netif_up(netif) && esp_netif_get_ip_info(netif, &ip_info) == ESP_OK && ip_info.ip.addr == network_ip_) {
still_up = true;
}
break; // only one active netif per kind in our world (sta / eth / ap)
}
if (!still_up) {
if (network_iface_ == NetIface::WIFI) {
uint8_t reason = last_disconnect_reason_;
if (reason == 0) {
reason = WIFI_REASON_UNSPECIFIED; // event hasn't fired yet (or was cleared); avoid logging "0"
}
LOG_INFO("WiFi connection lost (reason %u: %s)", reason, disconnectReason(reason));
} else {
LOG_INFO("Ethernet connection lost");
}
reconnect();
}
#endif
}
// set the WiFi 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
// Range ESP32 : 2dBm - 20dBm
// 802.11b - wifi1
// 802.11a - wifi2
// 802.11g - wifi3
// 802.11n - wifi4
// 802.11ac - wifi5
// 802.11ax - wifi6
// tx_power is the Tx power to set, 0 for auto
void Network::setWiFiPower(uint8_t tx_power) {
#ifndef EMSESP_STANDALONE
if (tx_power != 0) {
if (!WiFi.setTxPower(static_cast<wifi_power_t>(tx_power))) {
emsesp::EMSESP::logger().warning("Failed to set WiFi Tx Power");
}
return;
}
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_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");
}
#endif
}
// start the multicast UDP service so EMS-ESP is discoverable via .local
void Network::startmDNS() const {
#ifndef EMSESP_STANDALONE
MDNS.end();
if (!enableMDNS_) {
return;
}
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", "address", address_s.c_str());
emsesp::EMSESP::logger().info("Starting mDNS Responder service");
#endif
}
// WiFi disconnect reason code to string
const char * Network::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 "";
}
// WiFi management
void Network::startWIFI() {
#ifndef EMSESP_STANDALONE
// Abort if already connected, or if we have no SSID
if (WiFi.isConnected() || ssid_.length() == 0) {
return;
}
LOG_DEBUG("Managing WiFi"); // TODO remove
WiFi.setHostname(hostname_.c_str()); // updates shared default_hostname buffer
WiFi.enableSTA(true); // creates the STA netif
WiFi.STA.setHostname(hostname_.c_str()); // pushes to esp_netif_set_hostname
WiFi.enableIPv6(true);
if (staticIPConfig_) {
WiFi.config(localIP_, gatewayIP_, subnetMask_, dnsIP1_, dnsIP2_); // configure for static IP
}
// www.esp32.com/viewtopic.php?t=12055
if (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 (nosleep_) {
WiFi.setSleep(false); // turn off sleep - WIFI_PS_NONE
}
// attempt to connect to the network
uint8_t bssid[6];
wl_status_t status;
if (formatBSSID(bssid_, bssid)) {
status = WiFi.begin(ssid_.c_str(), password_.c_str(), 0, bssid);
} else {
LOG_DEBUG("Connecting to WiFi SSID %s with password %s, hostname %s", ssid_.c_str(), password_.c_str(), hostname_.c_str()); // TODO remove
status = WiFi.begin(ssid_.c_str(), password_.c_str());
}
if (status == WL_CONNECT_FAILED) {
LOG_ERROR("WiFi connection failed (code %d)", status);
}
#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
setWiFiPower(tx_power_);
#endif
#endif
}
// Ethernet management
// Brings up the ETH driver / netif exactly once. After ETH.begin() returns true the driver
// continues to run autonomously (link negotiation, DHCP, etc); the loop must NOT call ETH.begin()
// again on every iteration because that thrashes the netif and can prevent DHCP from completing
void Network::startEthernet() {
#if CONFIG_IDF_TARGET_ESP32
// already up and running, nothing to do
if (eth_started_) {
return;
}
#ifndef EMSESP_STANDALONE
// no ethernet present or wifi takes precedence
if (phy_type_ == PHY_type::PHY_TYPE_NONE || (ssid_.length() > 0)) {
return;
}
LOG_DEBUG("Managing Ethernet"); // TODO remove
// configure Ethernet
int mdc = 23; // Pin# of the I²C clock signal for the Ethernet PHY - hardcoded
int mdio = 18; // Pin# of the I²C IO signal for the Ethernet PHY - hardcoded
uint8_t phy_addr = eth_phy_addr_; // I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
int8_t power = eth_power_; // Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
eth_phy_type_t type = (phy_type_ == PHY_type::PHY_TYPE_LAN8720) ? ETH_PHY_LAN8720
: (phy_type_ == PHY_type::PHY_TYPE_TLK110) ? ETH_PHY_TLK110
: ETH_PHY_RTL8201; // Type of the Ethernet PHY (LAN8720 or TLK110)
// clock mode:
// ETH_CLOCK_GPIO0_IN = 0 RMII clock input to GPIO0
// ETH_CLOCK_GPIO0_OUT = 1 RMII clock output from GPIO0
// ETH_CLOCK_GPIO16_OUT = 2 RMII clock output from GPIO16
// ETH_CLOCK_GPIO17_OUT = 3 RMII clock output from GPIO17, for 50hz inverted clock
auto clock_mode = (eth_clock_mode_t)eth_clock_mode_;
// reset power and add a delay as ETH doesn't not always start up correctly after a warm boot
if (eth_power_ != -1) {
pinMode(eth_power_, OUTPUT);
digitalWrite(eth_power_, LOW);
delay(500);
digitalWrite(eth_power_, HIGH);
}
if (ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode)) {
eth_started_ = true; // mark up; do not re-enter this block until reboot / explicit teardown
ETH.setHostname(hostname_.c_str()); // Push hostname to the ETH netif immediately after it's created
ETH.enableIPv6(true);
if (staticIPConfig_) {
ETH.config(localIP_, gatewayIP_, subnetMask_, dnsIP1_, dnsIP2_);
}
} else {
LOG_ERROR("Failed to start Ethernet");
}
#endif
#endif
}
// check if the network is connected and set network_ip_ / network_iface_ / has_ipv6_
// Iterates over every esp-netif that exists, prioritizing Ethernet > WiFi > AP
bool Network::findNetworks() {
#ifndef EMSESP_STANDALONE
// exit if already have a connection, unless in AP mode
// when in AP mode, it will always try and connect to the WiFi
if (network_ip_ != 0 && !(WiFi.getMode() & WIFI_AP)) {
// const esp_ip4_addr_t ip4 = {.addr = network_ip_};
// LOG_DEBUG("Network already connected via IPv4: " IPSTR, IP2STR(&ip4));
return true;
}
struct NetInfo {
esp_ip4_addr_t ip;
esp_ip6_addr_t ip6;
char desc[8];
bool has_ipv6;
} info = {};
// Preference order: ETHERNET > WIFI (STA) > AP
auto iface_priority = [](NetIface iface) -> uint8_t {
switch (iface) {
case NetIface::ETHERNET:
return 3;
case NetIface::WIFI:
return 2;
case NetIface::AP:
return 1;
case NetIface::NONE:
default:
return 0;
}
};
NetIface best_iface = NetIface::NONE;
for (esp_netif_t * netif = esp_netif_next_unsafe(NULL); netif != NULL; netif = esp_netif_next_unsafe(netif)) {
const char * desc = esp_netif_get_desc(netif);
bool is_up = esp_netif_is_netif_up(netif);
esp_netif_ip_info_t ip_info = {};
esp_err_t err = esp_netif_get_ip_info(netif, &ip_info);
if (!is_up || err != ESP_OK || ip_info.ip.addr == 0) {
continue;
}
const NetIface candidate = iface_from_desc(desc);
if (iface_priority(candidate) <= iface_priority(best_iface)) {
continue; // already have something at least as good
}
info.ip = ip_info.ip;
if (desc) {
strlcpy(info.desc, desc, sizeof(info.desc));
}
info.has_ipv6 = (esp_netif_get_ip6_linklocal(netif, &info.ip6) == ESP_OK);
best_iface = candidate;
if (best_iface == NetIface::ETHERNET) {
break; // top priority, can't be beaten by anything later in the list
}
}
auto previous_iface = NetIface::NONE;
// LOG_DEBUG("best_iface: %d, previous_iface: %d, network_iface_: %d", best_iface, previous_iface, network_iface_); // TODO remove
// if we have a connection and it's a new one, set it up
if (best_iface != NetIface::NONE && best_iface != previous_iface) {
previous_iface = network_iface_; // save the previous interface for comparison next time
network_ip_ = info.ip.addr;
network_iface_ = iface_from_desc(info.desc); // "sta"/"ap"/"eth*"
has_ipv6_ = info.has_ipv6;
connnect_retry_ = 0;
LOG_INFO("Network connected via %s (IP: " IPSTR ")",
network_iface_ == NetIface::ETHERNET ? "Ethernet"
: network_iface_ == NetIface::WIFI ? "WiFi"
: network_iface_ == NetIface::AP ? "AP"
: "unknown",
IP2STR(&info.ip));
// if we have a Eth or Wifi connection and the AP is running, stop it
if (network_iface_ != NetIface::AP && WiFi.getMode() & WIFI_AP) {
stopAP();
}
// count the number of restarts (for Wifi and Eth)
if (juststopped_) {
juststopped_ = false;
connectcount_++;
LOG_DEBUG("Network re-connection count %d", connectcount_);
}
// start mDNS for any real network interface (skip the SoftAP since the captive portal handles its own DNS)
if (enableMDNS_ && network_iface_ != NetIface::AP && network_iface_ != NetIface::NONE) {
startmDNS();
}
return true; // we have a network connection
}
// fallback
network_ip_ = 0;
network_iface_ = NetIface::NONE;
has_ipv6_ = false;
connnect_retry_++;
LOG_DEBUG("No active network interfaces found yet, re-connection count %d", connnect_retry_);
#endif
return false; // no connection found yet
}
// access point (soft-AP) and the captive portal
void Network::startAP() {
#ifndef EMSESP_STANDALONE
// Only start AP as a fallback if the Network has failed
if (connnect_retry_ < MAX_NETWORK_RECONNECTION_ATTEMPTS) {
return;
}
// don't start the soft-AP if it is disabled, or Ethernet has taken over or we have a real WiFi connection or it's already running
if (ap_provisionMode_ == AP_MODE_NEVER || network_connected() || WiFi.getMode() & WIFI_AP) {
return;
}
WiFi.softAPenableIPv6(); // force IPv6, same as for STA - fixes https://github.com/emsesp/EMS-ESP32/issues/1922
WiFi.softAPConfig(ap_localIP_, ap_gatewayIP_, ap_subnetMask_);
esp_wifi_set_bandwidth(static_cast<wifi_interface_t>(ESP_IF_WIFI_AP), WIFI_BW_HT20);
WiFi.softAP(ap_ssid_.c_str(), ap_password_.c_str(), ap_channel_, ap_ssid_hidden_, ap_max_clients_);
#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
const IPAddress apIp = WiFi.softAPIP();
LOG_INFO("Starting Access Point with captive portal on %u.%u.%u.%u", apIp[0], apIp[1], apIp[2], apIp[3]);
// start DNS server for Captive Portal
ap_dnsServer_ = new DNSServer;
ap_dnsServer_->start(DNS_PORT, "*", apIp);
#endif
}
// stop AP
void Network::stopAP() {
LOG_INFO("Stopping Access Point");
#ifndef EMSESP_STANDALONE
WiFi.softAPdisconnect(true);
if (ap_dnsServer_) {
ap_dnsServer_->stop();
delete ap_dnsServer_;
ap_dnsServer_ = nullptr;
}
#endif
}
} // namespace emsesp

215
src/core/network.h Normal file
View File

@@ -0,0 +1,215 @@
/*
* EMS-ESP - https://github.com/emsesp/EMS-ESP
* Copyright 2020-2025 emsesp.org
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef EMSESP_NETWORK_H_
#define EMSESP_NETWORK_H_
#ifndef EMSESP_STANDALONE
#include <esp_wifi.h>
#include <ETH.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include <ESPmDNS.h>
#include <DNSServer.h>
#endif
#include <cstring>
#include <esp32-psram.h>
#include <uuid/log.h>
namespace emsesp {
#define NETWORK_RECONNECTION_DELAY_SHORT 2000 // 2 seconds
#define NETWORK_RECONNECTION_DELAY_LONG 60000 // 60 seconds
#define MAX_NETWORK_RECONNECTION_ATTEMPTS 3 // maximum number of network reconnection attempts
#define DNS_PORT 53
// 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
// which physical interface we are currently using for the active network connection.
// Mapped from the esp-netif description string returned by esp_netif_get_desc(): "sta" -> WIFI,
// "ap" -> AP, "eth"/"eth1"/"eth2"/... (arduino-esp32 v3.x suffixes ETH netifs because it supports
// multiple ETH instances) -> ETHERNET. Anything else stays as NONE.
enum class NetIface : uint8_t {
NONE = 0,
WIFI,
ETHERNET,
AP,
};
class Network {
public:
void begin();
void loop();
uint16_t getWifiReconnects() const {
return connectcount_;
}
uint32_t network_ip() const {
return network_ip_;
}
NetIface network_iface() const {
return network_iface_;
}
bool ethernet_connected() const {
return network_iface_ == NetIface::ETHERNET && network_ip_ != 0;
}
bool wifi_connected() const {
return network_iface_ == NetIface::WIFI && network_ip_ != 0;
}
bool ap_connected() const {
return network_iface_ == NetIface::AP && network_ip_ != 0;
}
bool network_connected() const {
return ethernet_connected() || wifi_connected(); // don't include AP here
}
bool has_ipv6() const {
return has_ipv6_ && (network_iface_ == NetIface::WIFI || network_iface_ == NetIface::ETHERNET);
}
uint16_t getWifiReconnects() {
return connectcount_;
}
std::string getLocalIP() const;
std::string getMacAddress() const;
uint8_t getStationNum() const;
void reconnect();
// map a netif description string (from esp_netif_get_desc) to a NetIface
static NetIface iface_from_desc(const char * desc) {
if (!desc) {
return NetIface::NONE;
}
if (strcmp(desc, "sta") == 0) {
return NetIface::WIFI;
}
if (strcmp(desc, "ap") == 0) {
return NetIface::AP;
}
// any "eth*" (eth, eth0, eth1, ...) is treated as Ethernet
if (strncmp(desc, "eth", 3) == 0) {
return NetIface::ETHERNET;
}
return NetIface::NONE;
}
private:
static uuid::log::Logger logger_;
bool findNetworks();
void checkConnection();
void startmDNS() const;
bool formatBSSID(const String & bssid, uint8_t (&mac)[6]);
void startAP();
void startWIFI();
void startEthernet();
void setWiFiPower(uint8_t tx_power);
const char * disconnectReason(uint8_t code);
void stopAP();
unsigned long lastConnectionAttempt_ = 0;
uint16_t connectcount_ = 0; // number of network reconnects
uint32_t network_ip_ = 0;
NetIface network_iface_ = NetIface::NONE;
bool has_ipv6_ = false;
bool juststopped_ = false;
bool eth_started_ = false; // true after ETH.begin() has succeeded once; prevents repeated re-init while DHCP is still running
volatile uint8_t last_disconnect_reason_ = 0;
uint16_t connnect_retry_ = 0; // number of network re-connection attempts
// Network and AP settings
bool enableMDNS_;
bool staticIPConfig_;
IPAddress localIP_;
IPAddress gatewayIP_;
IPAddress subnetMask_;
IPAddress dnsIP1_;
IPAddress dnsIP2_;
String hostname_;
String ssid_;
String password_;
bool bandwidth20_;
bool nosleep_;
uint8_t tx_power_;
String bssid_;
uint8_t phy_type_;
int8_t eth_power_;
uint8_t eth_phy_addr_;
uint8_t eth_clock_mode_;
// AP settings
uint8_t ap_provisionMode_;
String ap_ssid_;
String ap_password_;
uint8_t ap_channel_;
bool ap_ssid_hidden_;
uint8_t ap_max_clients_;
IPAddress ap_localIP_;
IPAddress ap_gatewayIP_;
IPAddress ap_subnetMask_;
// for the captive portal in AP mode
#ifndef EMSESP_STANDALONE
DNSServer * ap_dnsServer_;
#endif
};
} // namespace emsesp
#endif

View File

@@ -17,6 +17,7 @@
*/
#include "system.h"
#include "network.h"
#include "emsesp.h" // for send_raw_telegram() command
#ifndef EMSESP_STANDALONE
@@ -485,7 +486,7 @@ void System::set_partition_install_date() {
snprintf(c, sizeof(c), "d_%s", current_partition);
time_t d = EMSESP::nvs_.getULong(c, 0);
if (d < 1500000000L) {
LOG_DEBUG("Setting the install date in partition %s", current_partition);
LOG_DEBUG("Setting the NTP install date in partition %s", current_partition);
auto t = time(nullptr) - uuid::get_uptime_sec();
EMSESP::nvs_.putULong(c, t);
}
@@ -586,15 +587,6 @@ void System::system_restart(const char * partitionname) {
#endif
}
// saves all settings
void System::wifi_reconnect() {
EMSESP::esp32React.getNetworkSettingsService()->read(
[](NetworkSettings & networkSettings) { LOG_INFO("WiFi reconnecting to SSID '%s'...", networkSettings.ssid.c_str()); });
delay(500); // wait
EMSESP::webSettingsService.save(); // save local settings
EMSESP::esp32React.getNetworkSettingsService()->callUpdateHandlers(); // in case we've changed ssid or password
}
void System::syslog_init() {
EMSESP::webSettingsService.read([&](WebSettings & settings) {
syslog_enabled_ = settings.syslog_enabled;
@@ -673,14 +665,9 @@ void System::store_settings(WebSettings & settings) {
bool_dashboard_ = settings.bool_dashboard;
enum_format_ = settings.enum_format;
readonly_mode_ = settings.readonly_mode;
phy_type_ = settings.phy_type;
eth_power_ = settings.eth_power;
eth_phy_addr_ = settings.eth_phy_addr;
eth_clock_mode_ = settings.eth_clock_mode;
locale_ = settings.locale;
developer_mode_ = settings.developer_mode;
// start services
if (settings.modbus_enabled) {
if (EMSESP::modbus_ == nullptr) {
@@ -736,9 +723,10 @@ void System::start() {
commands_init(); // console & api commands
led_init(); // init LED
button_init(); // button
network_init(); // network
uart_init(); // start UART
syslog_init(); // start syslog
last_system_check_ = 0; // force the LED to go from fast flash to pulse
uart_init(); // start UART
syslog_init(); // start syslog
}
// button single click
@@ -756,9 +744,10 @@ void System::button_OnClick(PButton & b) {
// button double click
void System::button_OnDblClick(PButton & b) {
LOG_NOTICE("Button pressed - double click - wifi reconnect to AP");
#ifndef EMSESP_STANDALONE
// set AP mode to always so will join AP if wifi ssid fails to connect
EMSESP::esp32React.getAPSettingsService()->update([&](APSettings & apSettings) {
apSettings.provisionMode = AP_MODE_ALWAYS;
apSettings.provisionMode = AP_MODE_DISCONNECTED;
return StateUpdateResult::CHANGED;
});
// remove SSID from network settings
@@ -766,7 +755,8 @@ void System::button_OnDblClick(PButton & b) {
networkSettings.ssid = "";
return StateUpdateResult::CHANGED;
});
EMSESP::esp32React.getNetworkSettingsService()->callUpdateHandlers(); // in case we've changed ssid or password
EMSESP::network_.reconnect(); // reconnect to the network
#endif
}
// LED flash every 100ms
@@ -904,7 +894,8 @@ bool System::loop() {
// this is only done once when the connection is established
void System::send_info_mqtt() {
static uint8_t _connection = 0;
uint8_t connection = (ethernet_connected() ? 1 : 0) + ((WiFi.status() == WL_CONNECTED) ? 2 : 0) + (ntp_connected_ ? 4 : 0) + (has_ipv6_ ? 8 : 0);
uint8_t connection = (EMSESP::network_.ethernet_connected() ? 1 : 0) + (EMSESP::network_.wifi_connected() ? 2 : 0) + (ntp_connected_ ? 4 : 0)
+ (EMSESP::network_.has_ipv6() ? 8 : 0);
// check if connection status has changed
if (!Mqtt::connected() || connection == _connection) {
return;
@@ -924,7 +915,7 @@ void System::send_info_mqtt() {
}
#ifndef EMSESP_STANDALONE
if (EMSESP::system_.ethernet_connected()) {
if (EMSESP::network_.ethernet_connected()) {
doc["network"] = "ethernet";
doc["hostname"] = ETH.getHostname();
/*
@@ -1003,11 +994,11 @@ void System::heartbeat_json(JsonObject output) {
#endif
#ifndef EMSESP_STANDALONE
if (!ethernet_connected_) {
if (!EMSESP::network_.ethernet_connected()) {
int8_t rssi = WiFi.RSSI();
output["rssi"] = rssi;
output["wifistrength"] = wifi_quality(rssi);
output["wifireconnects"] = EMSESP::esp32React.getWifiReconnects();
output["wifireconnects"] = EMSESP::network_.getWifiReconnects();
}
#endif
}
@@ -1023,49 +1014,6 @@ void System::send_heartbeat() {
Mqtt::queue_publish(F_(heartbeat), json); // send to MQTT with retain off. This will add to MQTT queue.
}
// initializes network
void System::network_init() {
last_system_check_ = 0; // force the LED to go from fast flash to pulse
#if CONFIG_IDF_TARGET_ESP32
bool disableEth;
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & settings) { disableEth = settings.ssid.length() > 0; });
// no ethernet present or disabled
if (phy_type_ == PHY_type::PHY_TYPE_NONE || disableEth) {
return;
} // no ethernet present
// configure Ethernet
int mdc = 23; // Pin# of the I²C clock signal for the Ethernet PHY - hardcoded
int mdio = 18; // Pin# of the I²C IO signal for the Ethernet PHY - hardcoded
uint8_t phy_addr = eth_phy_addr_; // I²C-address of Ethernet PHY (0 or 1 for LAN8720, 31 for TLK110)
int8_t power = eth_power_; // Pin# of the enable signal for the external crystal oscillator (-1 to disable for internal APLL source)
eth_phy_type_t type = (phy_type_ == PHY_type::PHY_TYPE_LAN8720) ? ETH_PHY_LAN8720
: (phy_type_ == PHY_type::PHY_TYPE_TLK110) ? ETH_PHY_TLK110
: ETH_PHY_RTL8201; // Type of the Ethernet PHY (LAN8720 or TLK110)
// clock mode:
// ETH_CLOCK_GPIO0_IN = 0 RMII clock input to GPIO0
// ETH_CLOCK_GPIO0_OUT = 1 RMII clock output from GPIO0
// ETH_CLOCK_GPIO16_OUT = 2 RMII clock output from GPIO16
// ETH_CLOCK_GPIO17_OUT = 3 RMII clock output from GPIO17, for 50hz inverted clock
auto clock_mode = (eth_clock_mode_t)eth_clock_mode_;
// reset power and add a delay as ETH doesn't not always start up correctly after a warm boot
if (eth_power_ != -1) {
pinMode(eth_power_, OUTPUT);
digitalWrite(eth_power_, LOW);
delay(500);
digitalWrite(eth_power_, HIGH);
}
eth_present_ = ETH.begin(type, phy_addr, mdc, mdio, power, clock_mode);
if (eth_present_) {
// Push hostname to the ETH netif immediately after it's created
ETH.setHostname(hostname_.c_str());
}
#endif
}
// check health of system, done every 5 seconds
void System::system_check() {
uint32_t current_uptime = uuid::get_uptime();
@@ -1084,7 +1032,7 @@ void System::system_check() {
#endif
// check if we have a valid network connection
if (!ethernet_connected() && (WiFi.status() != WL_CONNECTED)) {
if (!EMSESP::network_.network_connected()) {
healthcheck_ |= HEALTHCHECK_NO_NETWORK;
} else {
healthcheck_ &= ~HEALTHCHECK_NO_NETWORK;
@@ -1402,7 +1350,7 @@ void System::show_system(uuid::console::Shell & shell) {
}
// show Ethernet if connected
if (ethernet_connected_) {
if (EMSESP::network_.ethernet_connected()) {
shell.println();
shell.printfln(" Ethernet Status: connected");
shell.printfln(" Ethernet MAC address: %s", ETH.macAddress().c_str());
@@ -1694,6 +1642,7 @@ bool System::check_upgrade() {
}
return changed;
});
EMSESP::network_.reconnect();
}
// changes to application settings
@@ -2348,7 +2297,6 @@ std::string System::get_metrics_prometheus() {
}
result += info_metric;
// TODO fix, as local_info_labels is always empty here
if (!local_info_labels.empty()) {
result += "{";
bool first = true;
@@ -2379,14 +2327,14 @@ String System::get_ip_or_hostname() {
#ifndef EMSESP_STANDALONE
EMSESP::esp32React.getNetworkSettingsService()->read([&](NetworkSettings & settings) {
if (settings.enableMDNS) {
if (EMSESP::system_.ethernet_connected()) {
if (EMSESP::network_.ethernet_connected()) {
result = ETH.getHostname();
} else if (WiFi.status() == WL_CONNECTED) {
result = WiFi.getHostname();
}
} else {
// no DNS, use the IP
if (EMSESP::system_.ethernet_connected()) {
if (EMSESP::network_.ethernet_connected()) {
result = ETH.localIP().toString();
} else if (WiFi.status() == WL_CONNECTED) {
result = WiFi.localIP().toString();
@@ -2470,7 +2418,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
// Network Status
node = output["network"].to<JsonObject>();
#ifndef EMSESP_STANDALONE
if (EMSESP::system_.ethernet_connected()) {
if (EMSESP::network_.ethernet_connected()) {
node["network"] = "Ethernet";
node["hostname"] = ETH.getHostname();
// node["MAC"] = ETH.macAddress();
@@ -2484,7 +2432,7 @@ bool System::command_info(const char * value, const int8_t id, JsonObject output
node["network"] = "WiFi";
node["hostname"] = WiFi.getHostname();
node["RSSI"] = WiFi.RSSI();
node["WIFIReconnects"] = EMSESP::esp32React.getWifiReconnects();
node["WIFIReconnects"] = EMSESP::network_.getWifiReconnects();
// node["MAC"] = WiFi.macAddress();
// node["IPv4 address"] = uuid::printable_to_string(WiFi.localIP()) + "/" + uuid::printable_to_string(WiFi.subnetMask());
// node["IPv4 gateway"] = uuid::printable_to_string(WiFi.gatewayIP());

View File

@@ -141,7 +141,6 @@ class System {
static bool uploadFirmwareURL(const char * url = nullptr);
void led_init();
void network_init();
void button_init();
void commands_init();
void uart_init();
@@ -260,33 +259,9 @@ class System {
hostname_ = hostname;
}
bool ethernet_connected() {
return ethernet_connected_;
}
void ethernet_connected(bool b) {
ethernet_connected_ = b;
}
void has_ipv6(bool b) {
has_ipv6_ = b;
}
bool has_ipv6() {
return has_ipv6_;
}
void ntp_connected(bool b);
bool ntp_connected();
bool network_connected() {
#ifndef EMSESP_STANDALONE
return (ethernet_connected() || WiFi.isConnected());
#else
return true;
#endif
}
void fahrenheit(bool b) {
fahrenheit_ = b;
}
@@ -312,8 +287,6 @@ class System {
void show_system(uuid::console::Shell & shell);
void show_users(uuid::console::Shell & shell);
void wifi_reconnect();
static std::string languages_string();
uint32_t FStotal() {
@@ -442,15 +415,11 @@ class System {
uint8_t healthcheck_ = HEALTHCHECK_NO_NETWORK | HEALTHCHECK_NO_BUS; // start with all flags set, no wifi and no ems bus connection
uint32_t last_system_check_ = 0;
bool upload_isrunning_ = false; // true if we're in the middle of a OTA firmware upload
bool ethernet_connected_ = false;
bool has_ipv6_ = false;
bool upload_isrunning_ = false; // true if we're in the middle of a OTA firmware upload
bool ntp_connected_ = false;
uint32_t ntp_last_check_ = 0;
bool eth_present_ = false;
// EMS-ESP settings
std::string hostname_;
String locale_;
@@ -482,17 +451,10 @@ class System {
uint8_t modbus_max_clients_;
uint32_t modbus_timeout_;
bool developer_mode_;
// ethernet
uint8_t phy_type_;
int8_t eth_power_;
uint8_t eth_phy_addr_;
uint8_t eth_clock_mode_;
uint32_t fstotal_;
uint32_t psram_;
uint32_t appused_;
uint32_t appfree_;
uint32_t fstotal_;
uint32_t psram_;
uint32_t appused_;
uint32_t appfree_;
#if CONFIG_IDF_TARGET_ESP32S3 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S2
temperature_sensor_handle_t temperature_handle_ = NULL;