add a power save mode listener and use it for the text sensor

This commit is contained in:
Kevin Ahrendt
2025-12-02 15:01:39 -05:00
parent 85d8a26d51
commit 2a27a3a95a
10 changed files with 97 additions and 66 deletions

View File

@@ -273,6 +273,16 @@ class WiFiConnectStateListener {
virtual void on_wifi_connect_state(const std::string &ssid, const bssid_t &bssid) = 0;
};
/** Listener interface for WiFi power save mode changes.
*
* Components can implement this interface to receive power save mode updates
* without the overhead of std::function callbacks.
*/
class WiFiPowerSaveListener {
public:
virtual void on_wifi_power_save(WiFiPowerSaveMode mode) = 0;
};
/// This component is responsible for managing the ESP WiFi interface.
class WiFiComponent : public Component {
public:
@@ -419,6 +429,10 @@ class WiFiComponent : public Component {
void add_connect_state_listener(WiFiConnectStateListener *listener) {
this->connect_state_listeners_.push_back(listener);
}
/** Add a listener for WiFi power save mode changes.
* Listener receives: WiFiPowerSaveMode
*/
void add_power_save_listener(WiFiPowerSaveListener *listener) { this->power_save_listeners_.push_back(listener); }
#endif // USE_WIFI_LISTENERS
#ifdef USE_WIFI_RUNTIME_POWER_SAVE
@@ -581,6 +595,7 @@ class WiFiComponent : public Component {
std::vector<WiFiIPStateListener *> ip_state_listeners_;
std::vector<WiFiScanResultsListener *> scan_results_listeners_;
std::vector<WiFiConnectStateListener *> connect_state_listeners_;
std::vector<WiFiPowerSaveListener *> power_save_listeners_;
#endif // USE_WIFI_LISTENERS
ESPPreferenceObject pref_;
#ifdef USE_WIFI_FAST_CONNECT

View File

@@ -104,7 +104,15 @@ bool WiFiComponent::wifi_apply_power_save_() {
break;
}
wifi_fpm_auto_sleep_set_in_null_mode(1);
return wifi_set_sleep_type(power_save);
bool success = wifi_set_sleep_type(power_save);
if (success) {
#ifdef USE_WIFI_LISTENERS
for (auto *listener : this->power_save_listeners_) {
listener->on_wifi_power_save(this->power_save_);
}
#endif
}
return success;
}
#if LWIP_VERSION_MAJOR != 1

View File

@@ -280,7 +280,15 @@ bool WiFiComponent::wifi_apply_power_save_() {
power_save = WIFI_PS_NONE;
break;
}
return esp_wifi_set_ps(power_save) == ESP_OK;
bool success = esp_wifi_set_ps(power_save) == ESP_OK;
if (success) {
#ifdef USE_WIFI_LISTENERS
for (auto *listener : this->power_save_listeners_) {
listener->on_wifi_power_save(this->power_save_);
}
#endif
}
return success;
}
bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {

View File

@@ -69,7 +69,17 @@ bool WiFiComponent::wifi_sta_pre_setup_() {
delay(10);
return true;
}
bool WiFiComponent::wifi_apply_power_save_() { return WiFi.setSleep(this->power_save_ != WIFI_POWER_SAVE_NONE); }
bool WiFiComponent::wifi_apply_power_save_() {
bool success = WiFi.setSleep(this->power_save_ != WIFI_POWER_SAVE_NONE);
if (success) {
#ifdef USE_WIFI_LISTENERS
for (auto *listener : this->power_save_listeners_) {
listener->on_wifi_power_save(this->power_save_);
}
#endif
}
return success;
}
bool WiFiComponent::wifi_sta_ip_config_(const optional<ManualIP> &manual_ip) {
// enable STA
if (!this->wifi_mode_(true, {}))

View File

@@ -54,7 +54,15 @@ bool WiFiComponent::wifi_apply_power_save_() {
break;
}
int ret = cyw43_wifi_pm(&cyw43_state, pm);
return ret == 0;
bool success = ret == 0;
if (success) {
#ifdef USE_WIFI_LISTENERS
for (auto *listener : this->power_save_listeners_) {
listener->on_wifi_power_save(this->power_save_);
}
#endif
}
return success;
}
// TODO: The driver doesn't seem to have an API for this

View File

@@ -32,7 +32,7 @@ DNSAddressWifiInfo = wifi_info_ns.class_(
"DNSAddressWifiInfo", text_sensor.TextSensor, cg.Component
)
PowerSaveModeWiFiInfo = wifi_info_ns.class_(
"PowerSaveModeWiFiInfo", text_sensor.TextSensor, cg.PollingComponent
"PowerSaveModeWiFiInfo", text_sensor.TextSensor, cg.Component
)
CONFIG_SCHEMA = cv.Schema(
@@ -62,12 +62,9 @@ CONFIG_SCHEMA = cv.Schema(
cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema(
DNSAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
),
cv.Optional(CONF_POWER_SAVE_MODE): cv.All(
text_sensor.text_sensor_schema(
PowerSaveModeWiFiInfo,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
).extend(cv.polling_component_schema("60s")),
cv.only_on(["esp32"]),
cv.Optional(CONF_POWER_SAVE_MODE): text_sensor.text_sensor_schema(
PowerSaveModeWiFiInfo,
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
),
}
)
@@ -79,6 +76,7 @@ _NETWORK_INFO_KEYS = {
CONF_IP_ADDRESS,
CONF_DNS_ADDRESS,
CONF_SCAN_RESULTS,
CONF_POWER_SAVE_MODE,
}

View File

@@ -6,29 +6,6 @@ namespace esphome::wifi_info {
static const char *const TAG = "wifi_info";
#ifdef USE_ESP32
/// @brief Helper function to convert ESP32 WiFi power save mode to string
/// @param ps_mode WiFi power save mode from esp_wifi_get_ps()
/// @return const char pointer to the readable power save mode
///
/// Maps ESP32 WiFi power save modes to user-friendly strings:
/// - WIFI_PS_NONE (no power saving) -> "NONE"
/// - WIFI_PS_MIN_MODEM (minimal modem sleep) -> "LIGHT"
/// - WIFI_PS_MAX_MODEM (maximum modem sleep) -> "HIGH"
static const char *wifi_ps_mode_to_string(wifi_ps_type_t ps_mode) {
switch (ps_mode) {
case WIFI_PS_NONE:
return "NONE";
case WIFI_PS_MIN_MODEM:
return "LIGHT";
case WIFI_PS_MAX_MODEM:
return "HIGH";
default:
return "UNKNOWN";
}
}
#endif // USE_ESP32
#ifdef USE_WIFI_LISTENERS
static constexpr size_t MAX_STATE_LENGTH = 255;
@@ -123,6 +100,32 @@ void BSSIDWiFiInfo::on_wifi_connect_state(const std::string &ssid, const wifi::b
this->publish_state(buf);
}
/************************
* PowerSaveModeWiFiInfo
***********************/
void PowerSaveModeWiFiInfo::setup() { wifi::global_wifi_component->add_power_save_listener(this); }
void PowerSaveModeWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "WiFi Power Save Mode", this); }
void PowerSaveModeWiFiInfo::on_wifi_power_save(wifi::WiFiPowerSaveMode mode) {
const char *mode_str;
switch (mode) {
case wifi::WIFI_POWER_SAVE_NONE:
mode_str = "NONE";
break;
case wifi::WIFI_POWER_SAVE_LIGHT:
mode_str = "LIGHT";
break;
case wifi::WIFI_POWER_SAVE_HIGH:
mode_str = "HIGH";
break;
default:
mode_str = "UNKNOWN";
break;
}
this->publish_state(mode_str);
}
#endif
/*********************
@@ -131,20 +134,5 @@ void BSSIDWiFiInfo::on_wifi_connect_state(const std::string &ssid, const wifi::b
void MacAddressWifiInfo::dump_config() { LOG_TEXT_SENSOR("", "MAC Address", this); }
#ifdef USE_ESP32
void PowerSaveModeWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "WiFi Power Save Mode", this); }
void PowerSaveModeWiFiInfo::update() {
wifi_ps_type_t power_save_mode;
if (esp_wifi_get_ps(&power_save_mode) == ESP_OK) {
// Publish if the state has changed or if this is the first read
if (this->last_power_save_mode_ != power_save_mode || !this->has_state()) {
this->publish_state(wifi_ps_mode_to_string(power_save_mode));
this->last_power_save_mode_ = power_save_mode;
}
}
}
#endif // USE_ESP32
} // namespace esphome::wifi_info
#endif

View File

@@ -66,6 +66,17 @@ class BSSIDWiFiInfo final : public Component, public text_sensor::TextSensor, pu
// WiFiConnectStateListener interface
void on_wifi_connect_state(const std::string &ssid, const wifi::bssid_t &bssid) override;
};
class PowerSaveModeWiFiInfo final : public Component,
public text_sensor::TextSensor,
public wifi::WiFiPowerSaveListener {
public:
void setup() override;
void dump_config() override;
// WiFiPowerSaveListener interface
void on_wifi_power_save(wifi::WiFiPowerSaveMode mode) override;
};
#endif
class MacAddressWifiInfo final : public Component, public text_sensor::TextSensor {
@@ -77,17 +88,5 @@ class MacAddressWifiInfo final : public Component, public text_sensor::TextSenso
void dump_config() override;
};
#ifdef USE_ESP32
class PowerSaveModeWiFiInfo : public PollingComponent, public text_sensor::TextSensor {
public:
void update() override;
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
void dump_config() override;
protected:
wifi_ps_type_t last_power_save_mode_{};
};
#endif // USE_ESP32
} // namespace esphome::wifi_info
#endif

View File

@@ -16,3 +16,5 @@ text_sensor:
name: MAC Address
dns_address:
name: DNS ADdress
power_save_mode:
name: "WiFi Power Save Mode"

View File

@@ -2,8 +2,3 @@ packages:
i2c: !include ../../test_build_components/common/i2c/esp32-idf.yaml
<<: !include common.yaml
text_sensor:
- platform: wifi_info
power_save_mode:
name: "WiFi Power Save Mode"