mirror of
https://github.com/emsesp/EMS-ESP32.git
synced 2026-09-13 05:34:34 +00:00
power save - Reduce EMS-ESP energy consumption #3213
This commit is contained in:
@@ -129,6 +129,7 @@
|
||||
"eth_power": 15,
|
||||
"eth_phy_addr": 0,
|
||||
"eth_clock_mode": 1,
|
||||
"eth_10mbit": false,
|
||||
"modbus_enabled": false,
|
||||
"modbus_port": 502,
|
||||
"modbus_max_clients": 10,
|
||||
|
||||
@@ -39,6 +39,7 @@ export interface Settings {
|
||||
eth_power: number;
|
||||
eth_phy_addr: number;
|
||||
eth_clock_mode: number;
|
||||
eth_10mbit: boolean;
|
||||
platform: string;
|
||||
modbus_enabled: boolean;
|
||||
modbus_port: number;
|
||||
|
||||
@@ -820,6 +820,18 @@ const ApplicationSettings = () => {
|
||||
</Grid>
|
||||
</Grid>
|
||||
)}
|
||||
{data.phy_type !== 0 && (
|
||||
<BlockFormControlLabel
|
||||
control={
|
||||
<Checkbox
|
||||
checked={data.eth_10mbit}
|
||||
onChange={updateFormValue}
|
||||
name="eth_10mbit"
|
||||
/>
|
||||
}
|
||||
label="Force 10Mbit half-duplex"
|
||||
/>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
<Grid container spacing={2} rowSpacing={0}>
|
||||
|
||||
@@ -58,6 +58,7 @@ let settings = {
|
||||
eth_power: 15,
|
||||
eth_phy_addr: 0,
|
||||
eth_clock_mode: 1,
|
||||
eth_10mbit: false,
|
||||
led_type: 0,
|
||||
platform: 'ESP32',
|
||||
modbus_enabled: false,
|
||||
|
||||
+3
-1
@@ -1345,4 +1345,6 @@ Sumr
|
||||
eraseap
|
||||
roomtempoffset
|
||||
dhcpc
|
||||
wifioff
|
||||
wifioff
|
||||
autonegotiation
|
||||
Mbit
|
||||
@@ -28,4 +28,7 @@ void setup() {
|
||||
|
||||
void loop() {
|
||||
application.loop();
|
||||
#ifndef EMSESP_STANDALONE
|
||||
delay(1); // block for a tick so the idle task gets to run and the core can clock-gate
|
||||
#endif
|
||||
}
|
||||
|
||||
+95
-31
@@ -57,6 +57,7 @@ void Network::begin() {
|
||||
eth_power_ = settings.eth_power;
|
||||
eth_phy_addr_ = settings.eth_phy_addr;
|
||||
eth_clock_mode_ = settings.eth_clock_mode;
|
||||
eth_10mbit_ = settings.eth_10mbit;
|
||||
});
|
||||
|
||||
// get Access Point settings
|
||||
@@ -78,39 +79,16 @@ void Network::begin() {
|
||||
|
||||
phase_ = initialPhase();
|
||||
|
||||
// Initialise WiFi once when the Network service starts.
|
||||
// persistent(false) keeps credentials in RAM so we don't auto-join leftover NVS config.
|
||||
WiFi.persistent(false);
|
||||
WiFi.setAutoReconnect(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
startWiFiRadio();
|
||||
|
||||
// Keep the radio up. disconnect(wifioff=true) maps to STA.end() -> esp_wifi_stop()
|
||||
if (WiFi.STA.started()) {
|
||||
WiFi.disconnect(false, true); // drop leftover association, wipe RAM config
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
// Ethernet is switched off but the board still has a PHY wired up. Hold its power/oscillator
|
||||
// enable low so an unused LAN8720 isn't left clocked and burning current for the whole uptime.
|
||||
if (phy_type_ == PHY_type::PHY_TYPE_NONE && eth_power_ != -1) {
|
||||
pinMode(eth_power_, OUTPUT);
|
||||
digitalWrite(eth_power_, LOW);
|
||||
}
|
||||
|
||||
WiFi.setScanMethod(WIFI_ALL_CHANNEL_SCAN);
|
||||
WiFi.setHostname(hostname_.c_str()); // updates shared default_hostname buffer
|
||||
WiFi.enableSTA(true); // no-op if already STA; recreates netif after a full off
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
#endif
|
||||
|
||||
// avoid duplicate registration, so register the lambdas only once across the lifetime of this Network instance
|
||||
if (!wifi_events_registered_) {
|
||||
@@ -326,6 +304,10 @@ void Network::checkConnection() {
|
||||
network_iface_ = NetIface::NONE;
|
||||
if (lost_iface == NetIface::ETHERNET) {
|
||||
LOG_WARNING("Ethernet connection lost");
|
||||
// restore the radio now so the WiFi and AP fallbacks have something to work with
|
||||
if (wifi_radio_off_) {
|
||||
startWiFiRadio();
|
||||
}
|
||||
return;
|
||||
}
|
||||
begin();
|
||||
@@ -502,6 +484,59 @@ const char * Network::disconnectReason([[maybe_unused]] uint8_t code) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Bring up the STA interface and apply all the radio-level settings to it
|
||||
// Safe to call repeatedly - enableSTA() is a no-op when the STA is already running, and recreates the netif after stopWiFiRadio() has torn it down
|
||||
void Network::startWiFiRadio() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
WiFi.persistent(false); // keep credentials in RAM so we don't auto-join leftover NVS config
|
||||
WiFi.setAutoReconnect(false);
|
||||
WiFi.mode(WIFI_STA);
|
||||
|
||||
// Keep the radio up. disconnect(wifioff=true) maps to STA.end() -> esp_wifi_stop()
|
||||
if (WiFi.STA.started()) {
|
||||
WiFi.disconnect(false, true); // drop leftover association, wipe RAM config
|
||||
}
|
||||
|
||||
// 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.setHostname(hostname_.c_str()); // updates shared default_hostname buffer
|
||||
WiFi.enableSTA(true); // no-op if already STA; recreates netif after a full off
|
||||
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
|
||||
} else {
|
||||
WiFi.setSleep(true); // WIFI_PS_MIN_MODEM
|
||||
}
|
||||
|
||||
wifi_radio_off_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Power down the WiFi radio completely (esp_wifi_stop), used when Ethernet is carrying the traffic.
|
||||
// An idle STA still keeps the receiver powered, which on an Ethernet gateway is a pure waste of heat.
|
||||
void Network::stopWiFiRadio() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
if (wifi_radio_off_) {
|
||||
return;
|
||||
}
|
||||
WiFi.mode(WIFI_OFF);
|
||||
wifi_radio_off_ = true;
|
||||
wifi_connect_pending_ = false;
|
||||
LOG_INFO("Powering down WiFi radio, Ethernet is active");
|
||||
#endif
|
||||
}
|
||||
|
||||
// WiFi management
|
||||
void Network::startWIFI() {
|
||||
#ifndef EMSESP_STANDALONE
|
||||
@@ -510,6 +545,11 @@ void Network::startWIFI() {
|
||||
return;
|
||||
}
|
||||
|
||||
// the radio was powered down while Ethernet was up, so bring it back before trying to associate
|
||||
if (wifi_radio_off_) {
|
||||
startWiFiRadio();
|
||||
}
|
||||
|
||||
// exit if WiFi or Ethernet is already connected, or if we have no SSID or another Wifi.begin() is already in progress
|
||||
if (WiFi.isConnected() || ssid_.isEmpty() || ethernet_connected() || wifi_connect_pending_) {
|
||||
return;
|
||||
@@ -610,6 +650,17 @@ void Network::startEthernet() {
|
||||
eth_hostname_handler_registered_ = true;
|
||||
}
|
||||
|
||||
// Forcing 10BASE-T roughly halves the PHY's power draw, which on these boards is usually the
|
||||
// hottest component. All three must be set before ETH.begin(), and in this order - the speed
|
||||
// and duplex setters are ignored while autonegotiation is still on. Half duplex is deliberate:
|
||||
// a switch port that can't negotiate falls back to parallel detection, which is always half,
|
||||
// so forcing full here would be a duplex mismatch. Opt-in only for that reason.
|
||||
if (eth_10mbit_) {
|
||||
ETH.setAutoNegotiation(false);
|
||||
ETH.setLinkSpeed(10);
|
||||
ETH.setFullDuplex(false);
|
||||
}
|
||||
|
||||
if (ETH.begin(type, eth_phy_addr_, 23, 18, eth_power_, (eth_clock_mode_t)eth_clock_mode_)) {
|
||||
// LOG_DEBUG("Ethernet module found - initialising");
|
||||
ethernet_started_ = true;
|
||||
@@ -739,6 +790,14 @@ void Network::findNetworks() {
|
||||
stopAP();
|
||||
}
|
||||
|
||||
// Ethernet is carrying the traffic so the STA is dead weight - shut the radio down.
|
||||
// It is brought back by checkConnection() when the link drops, or by startWIFI() if we
|
||||
// fall through to the WiFi phase. Do this before startmDNS() so we don't register on a
|
||||
// netif we are about to destroy.
|
||||
if (network_iface_ == NetIface::ETHERNET) {
|
||||
stopWiFiRadio();
|
||||
}
|
||||
|
||||
// count the number of restarts (for Wifi and Eth)
|
||||
if (juststopped_) {
|
||||
juststopped_ = false;
|
||||
@@ -823,6 +882,11 @@ void Network::startAP() {
|
||||
return;
|
||||
}
|
||||
|
||||
// the AP needs the radio, which may have been powered down while Ethernet was up
|
||||
if (wifi_radio_off_) {
|
||||
startWiFiRadio();
|
||||
}
|
||||
|
||||
if (!WiFi.softAPConfig(ap_localIP_, ap_gatewayIP_, ap_subnetMask_)) {
|
||||
LOG_DEBUG("softAPConfig failed");
|
||||
return;
|
||||
|
||||
@@ -186,6 +186,8 @@ class Network {
|
||||
void startAP();
|
||||
void startWIFI();
|
||||
void startEthernet();
|
||||
void startWiFiRadio();
|
||||
void stopWiFiRadio();
|
||||
void setWiFiPower(uint8_t tx_power);
|
||||
const char * disconnectReason(uint8_t code);
|
||||
void stopAP();
|
||||
@@ -216,6 +218,7 @@ class Network {
|
||||
bool ethernet_started_ = false; // ETH.begin() succeeded; the driver runs for the lifetime of the boot
|
||||
bool wifi_ever_connected_ = false; // set true once we've successfully obtained an IP
|
||||
bool ethernet_ever_connected_ = false; // set true once we've successfully obtained an IP
|
||||
bool wifi_radio_off_ = false; // STA powered down because Ethernet is carrying the traffic
|
||||
|
||||
// Network and AP settings
|
||||
bool enableMDNS_;
|
||||
@@ -236,6 +239,7 @@ class Network {
|
||||
int8_t eth_power_;
|
||||
uint8_t eth_phy_addr_;
|
||||
uint8_t eth_clock_mode_;
|
||||
bool eth_10mbit_;
|
||||
|
||||
// AP settings
|
||||
uint8_t ap_provisionMode_;
|
||||
|
||||
@@ -79,6 +79,7 @@ void WebSettings::read(WebSettings & settings, JsonObject root) {
|
||||
root["eth_power"] = settings.eth_power;
|
||||
root["eth_phy_addr"] = settings.eth_phy_addr;
|
||||
root["eth_clock_mode"] = settings.eth_clock_mode;
|
||||
root["eth_10mbit"] = settings.eth_10mbit;
|
||||
root["modbus_enabled"] = settings.modbus_enabled;
|
||||
root["modbus_port"] = settings.modbus_port;
|
||||
root["modbus_max_clients"] = settings.modbus_max_clients;
|
||||
@@ -120,6 +121,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
settings.eth_power = root["eth_power"];
|
||||
settings.eth_phy_addr = root["eth_phy_addr"];
|
||||
settings.eth_clock_mode = root["eth_clock_mode"];
|
||||
settings.eth_10mbit = root["eth_10mbit"];
|
||||
settings.led_type = root["led_type"]; // 1 = RGB-LED
|
||||
|
||||
reset_flags();
|
||||
@@ -145,6 +147,7 @@ StateUpdateResult WebSettings::update(JsonObject root, WebSettings & settings) {
|
||||
if (settings.phy_type != PHY_type::PHY_TYPE_NONE) {
|
||||
check_flag(original_settings.eth_power, settings.eth_power, ChangeFlags::RESTART);
|
||||
check_flag(original_settings.eth_clock_mode, settings.eth_clock_mode, ChangeFlags::RESTART);
|
||||
check_flag(original_settings.eth_10mbit, settings.eth_10mbit, ChangeFlags::RESTART);
|
||||
if (settings.eth_power != -1) { // Ethernet Power -1 means disabled
|
||||
EMSESP::system_.remove_gpio(settings.eth_power, true);
|
||||
}
|
||||
|
||||
@@ -119,6 +119,7 @@ class WebSettings {
|
||||
int8_t eth_power; // -1 means disabled
|
||||
uint8_t eth_phy_addr;
|
||||
uint8_t eth_clock_mode;
|
||||
bool eth_10mbit; // force 10BASE-T half-duplex, no auto-negotiation
|
||||
|
||||
bool developer_mode; // developer mode
|
||||
bool disable_reset; // disable reset
|
||||
|
||||
Reference in New Issue
Block a user