mirror of
https://github.com/esphome/esphome.git
synced 2026-05-27 11:56:11 +08:00
[wifi_info] Use callbacks instead of polling (#10748)
Co-authored-by: J. Nick Koston <nick+github@koston.org>
This commit is contained in:
@@ -608,6 +608,7 @@ async def wifi_disable_to_code(config, action_id, template_arg, args):
|
|||||||
|
|
||||||
KEEP_SCAN_RESULTS_KEY = "wifi_keep_scan_results"
|
KEEP_SCAN_RESULTS_KEY = "wifi_keep_scan_results"
|
||||||
RUNTIME_POWER_SAVE_KEY = "wifi_runtime_power_save"
|
RUNTIME_POWER_SAVE_KEY = "wifi_runtime_power_save"
|
||||||
|
WIFI_CALLBACKS_KEY = "wifi_callbacks"
|
||||||
|
|
||||||
|
|
||||||
def request_wifi_scan_results():
|
def request_wifi_scan_results():
|
||||||
@@ -633,6 +634,17 @@ def enable_runtime_power_save_control():
|
|||||||
CORE.data[RUNTIME_POWER_SAVE_KEY] = True
|
CORE.data[RUNTIME_POWER_SAVE_KEY] = True
|
||||||
|
|
||||||
|
|
||||||
|
def request_wifi_callbacks() -> None:
|
||||||
|
"""Request that WiFi callbacks be compiled in.
|
||||||
|
|
||||||
|
Components that need to be notified about WiFi state changes (IP address changes,
|
||||||
|
scan results, connection state) should call this function during their code generation.
|
||||||
|
This enables the add_on_ip_state_callback(), add_on_wifi_scan_state_callback(),
|
||||||
|
and add_on_wifi_connect_state_callback() APIs.
|
||||||
|
"""
|
||||||
|
CORE.data[WIFI_CALLBACKS_KEY] = True
|
||||||
|
|
||||||
|
|
||||||
@coroutine_with_priority(CoroPriority.FINAL)
|
@coroutine_with_priority(CoroPriority.FINAL)
|
||||||
async def final_step():
|
async def final_step():
|
||||||
"""Final code generation step to configure optional WiFi features."""
|
"""Final code generation step to configure optional WiFi features."""
|
||||||
@@ -642,6 +654,8 @@ async def final_step():
|
|||||||
)
|
)
|
||||||
if CORE.data.get(RUNTIME_POWER_SAVE_KEY, False):
|
if CORE.data.get(RUNTIME_POWER_SAVE_KEY, False):
|
||||||
cg.add_define("USE_WIFI_RUNTIME_POWER_SAVE")
|
cg.add_define("USE_WIFI_RUNTIME_POWER_SAVE")
|
||||||
|
if CORE.data.get(WIFI_CALLBACKS_KEY, False):
|
||||||
|
cg.add_define("USE_WIFI_CALLBACKS")
|
||||||
|
|
||||||
|
|
||||||
@automation.register_action(
|
@automation.register_action(
|
||||||
|
|||||||
@@ -0,0 +1,116 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
#ifdef USE_WIFI
|
||||||
|
#include "wifi_component.h"
|
||||||
|
|
||||||
|
namespace esphome::wifi {
|
||||||
|
|
||||||
|
template<typename... Ts> class WiFiConnectedCondition : public Condition<Ts...> {
|
||||||
|
public:
|
||||||
|
bool check(const Ts &...x) override { return global_wifi_component->is_connected(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class WiFiEnabledCondition : public Condition<Ts...> {
|
||||||
|
public:
|
||||||
|
bool check(const Ts &...x) override { return !global_wifi_component->is_disabled(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class WiFiAPActiveCondition : public Condition<Ts...> {
|
||||||
|
public:
|
||||||
|
bool check(const Ts &...x) override { return global_wifi_component->is_ap_active(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class WiFiEnableAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
void play(const Ts &...x) override { global_wifi_component->enable(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class WiFiDisableAction : public Action<Ts...> {
|
||||||
|
public:
|
||||||
|
void play(const Ts &...x) override { global_wifi_component->disable(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename... Ts> class WiFiConfigureAction : public Action<Ts...>, public Component {
|
||||||
|
public:
|
||||||
|
TEMPLATABLE_VALUE(std::string, ssid)
|
||||||
|
TEMPLATABLE_VALUE(std::string, password)
|
||||||
|
TEMPLATABLE_VALUE(bool, save)
|
||||||
|
TEMPLATABLE_VALUE(uint32_t, connection_timeout)
|
||||||
|
|
||||||
|
void play(const Ts &...x) override {
|
||||||
|
auto ssid = this->ssid_.value(x...);
|
||||||
|
auto password = this->password_.value(x...);
|
||||||
|
// Avoid multiple calls
|
||||||
|
if (this->connecting_)
|
||||||
|
return;
|
||||||
|
// If already connected to the same AP, do nothing
|
||||||
|
if (global_wifi_component->wifi_ssid() == ssid) {
|
||||||
|
// Callback to notify the user that the connection was successful
|
||||||
|
this->connect_trigger_->trigger();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Create a new WiFiAP object with the new SSID and password
|
||||||
|
this->new_sta_.set_ssid(ssid);
|
||||||
|
this->new_sta_.set_password(password);
|
||||||
|
// Save the current STA
|
||||||
|
this->old_sta_ = global_wifi_component->get_sta();
|
||||||
|
// Disable WiFi
|
||||||
|
global_wifi_component->disable();
|
||||||
|
// Set the state to connecting
|
||||||
|
this->connecting_ = true;
|
||||||
|
// Store the new STA so once the WiFi is enabled, it will connect to it
|
||||||
|
// This is necessary because the WiFiComponent will raise an error and fallback to the saved STA
|
||||||
|
// if trying to connect to a new STA while already connected to another one
|
||||||
|
if (this->save_.value(x...)) {
|
||||||
|
global_wifi_component->save_wifi_sta(new_sta_.get_ssid(), new_sta_.get_password());
|
||||||
|
} else {
|
||||||
|
global_wifi_component->set_sta(new_sta_);
|
||||||
|
}
|
||||||
|
// Enable WiFi
|
||||||
|
global_wifi_component->enable();
|
||||||
|
// Set timeout for the connection
|
||||||
|
this->set_timeout("wifi-connect-timeout", this->connection_timeout_.value(x...), [this, x...]() {
|
||||||
|
// If the timeout is reached, stop connecting and revert to the old AP
|
||||||
|
global_wifi_component->disable();
|
||||||
|
global_wifi_component->save_wifi_sta(old_sta_.get_ssid(), old_sta_.get_password());
|
||||||
|
global_wifi_component->enable();
|
||||||
|
// Start a timeout for the fallback if the connection to the old AP fails
|
||||||
|
this->set_timeout("wifi-fallback-timeout", this->connection_timeout_.value(x...), [this]() {
|
||||||
|
this->connecting_ = false;
|
||||||
|
this->error_trigger_->trigger();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Trigger<> *get_connect_trigger() const { return this->connect_trigger_; }
|
||||||
|
Trigger<> *get_error_trigger() const { return this->error_trigger_; }
|
||||||
|
|
||||||
|
void loop() override {
|
||||||
|
if (!this->connecting_)
|
||||||
|
return;
|
||||||
|
if (global_wifi_component->is_connected()) {
|
||||||
|
// The WiFi is connected, stop the timeout and reset the connecting flag
|
||||||
|
this->cancel_timeout("wifi-connect-timeout");
|
||||||
|
this->cancel_timeout("wifi-fallback-timeout");
|
||||||
|
this->connecting_ = false;
|
||||||
|
if (global_wifi_component->wifi_ssid() == this->new_sta_.get_ssid()) {
|
||||||
|
// Callback to notify the user that the connection was successful
|
||||||
|
this->connect_trigger_->trigger();
|
||||||
|
} else {
|
||||||
|
// Callback to notify the user that the connection failed
|
||||||
|
this->error_trigger_->trigger();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool connecting_{false};
|
||||||
|
WiFiAP new_sta_;
|
||||||
|
WiFiAP old_sta_;
|
||||||
|
Trigger<> *connect_trigger_{new Trigger<>()};
|
||||||
|
Trigger<> *error_trigger_{new Trigger<>()};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace esphome::wifi
|
||||||
|
#endif
|
||||||
@@ -37,8 +37,7 @@
|
|||||||
#include "esphome/components/esp32_improv/esp32_improv_component.h"
|
#include "esphome/components/esp32_improv/esp32_improv_component.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi {
|
||||||
namespace wifi {
|
|
||||||
|
|
||||||
static const char *const TAG = "wifi";
|
static const char *const TAG = "wifi";
|
||||||
|
|
||||||
@@ -1813,6 +1812,5 @@ bool WiFiScanResult::operator==(const WiFiScanResult &rhs) const { return this->
|
|||||||
|
|
||||||
WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
} // namespace wifi
|
} // namespace esphome::wifi
|
||||||
} // namespace esphome
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -54,8 +54,7 @@ extern "C" {
|
|||||||
#include <freertos/semphr.h>
|
#include <freertos/semphr.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi {
|
||||||
namespace wifi {
|
|
||||||
|
|
||||||
/// Sentinel value for RSSI when WiFi is not connected
|
/// Sentinel value for RSSI when WiFi is not connected
|
||||||
static constexpr int8_t WIFI_RSSI_DISCONNECTED = -127;
|
static constexpr int8_t WIFI_RSSI_DISCONNECTED = -127;
|
||||||
@@ -370,6 +369,27 @@ class WiFiComponent : public Component {
|
|||||||
|
|
||||||
int32_t get_wifi_channel();
|
int32_t get_wifi_channel();
|
||||||
|
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
/// Add a callback that will be called on configuration changes (IP change, SSID change, etc.)
|
||||||
|
/// @param callback The callback to be called; template arguments are:
|
||||||
|
/// - IP addresses
|
||||||
|
/// - DNS address 1
|
||||||
|
/// - DNS address 2
|
||||||
|
void add_on_ip_state_callback(
|
||||||
|
std::function<void(network::IPAddresses, network::IPAddress, network::IPAddress)> &&callback) {
|
||||||
|
this->ip_state_callback_.add(std::move(callback));
|
||||||
|
}
|
||||||
|
/// - Wi-Fi scan results
|
||||||
|
void add_on_wifi_scan_state_callback(std::function<void(wifi_scan_vector_t<WiFiScanResult> &)> &&callback) {
|
||||||
|
this->wifi_scan_state_callback_.add(std::move(callback));
|
||||||
|
}
|
||||||
|
/// - Wi-Fi SSID
|
||||||
|
/// - Wi-Fi BSSID
|
||||||
|
void add_on_wifi_connect_state_callback(std::function<void(std::string, wifi::bssid_t)> &&callback) {
|
||||||
|
this->wifi_connect_state_callback_.add(std::move(callback));
|
||||||
|
}
|
||||||
|
#endif // USE_WIFI_CALLBACKS
|
||||||
|
|
||||||
#ifdef USE_WIFI_RUNTIME_POWER_SAVE
|
#ifdef USE_WIFI_RUNTIME_POWER_SAVE
|
||||||
/** Request high-performance mode (no power saving) for improved WiFi latency.
|
/** Request high-performance mode (no power saving) for improved WiFi latency.
|
||||||
*
|
*
|
||||||
@@ -526,6 +546,11 @@ class WiFiComponent : public Component {
|
|||||||
WiFiAP ap_;
|
WiFiAP ap_;
|
||||||
#endif
|
#endif
|
||||||
optional<float> output_power_;
|
optional<float> output_power_;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
CallbackManager<void(network::IPAddresses, network::IPAddress, network::IPAddress)> ip_state_callback_;
|
||||||
|
CallbackManager<void(wifi_scan_vector_t<WiFiScanResult> &)> wifi_scan_state_callback_;
|
||||||
|
CallbackManager<void(std::string, wifi::bssid_t)> wifi_connect_state_callback_;
|
||||||
|
#endif // USE_WIFI_CALLBACKS
|
||||||
ESPPreferenceObject pref_;
|
ESPPreferenceObject pref_;
|
||||||
#ifdef USE_WIFI_FAST_CONNECT
|
#ifdef USE_WIFI_FAST_CONNECT
|
||||||
ESPPreferenceObject fast_connect_pref_;
|
ESPPreferenceObject fast_connect_pref_;
|
||||||
@@ -590,112 +615,5 @@ class WiFiComponent : public Component {
|
|||||||
|
|
||||||
extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
extern WiFiComponent *global_wifi_component; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
template<typename... Ts> class WiFiConnectedCondition : public Condition<Ts...> {
|
} // namespace esphome::wifi
|
||||||
public:
|
|
||||||
bool check(const Ts &...x) override { return global_wifi_component->is_connected(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Ts> class WiFiEnabledCondition : public Condition<Ts...> {
|
|
||||||
public:
|
|
||||||
bool check(const Ts &...x) override { return !global_wifi_component->is_disabled(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Ts> class WiFiAPActiveCondition : public Condition<Ts...> {
|
|
||||||
public:
|
|
||||||
bool check(const Ts &...x) override { return global_wifi_component->is_ap_active(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Ts> class WiFiEnableAction : public Action<Ts...> {
|
|
||||||
public:
|
|
||||||
void play(const Ts &...x) override { global_wifi_component->enable(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Ts> class WiFiDisableAction : public Action<Ts...> {
|
|
||||||
public:
|
|
||||||
void play(const Ts &...x) override { global_wifi_component->disable(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename... Ts> class WiFiConfigureAction : public Action<Ts...>, public Component {
|
|
||||||
public:
|
|
||||||
TEMPLATABLE_VALUE(std::string, ssid)
|
|
||||||
TEMPLATABLE_VALUE(std::string, password)
|
|
||||||
TEMPLATABLE_VALUE(bool, save)
|
|
||||||
TEMPLATABLE_VALUE(uint32_t, connection_timeout)
|
|
||||||
|
|
||||||
void play(const Ts &...x) override {
|
|
||||||
auto ssid = this->ssid_.value(x...);
|
|
||||||
auto password = this->password_.value(x...);
|
|
||||||
// Avoid multiple calls
|
|
||||||
if (this->connecting_)
|
|
||||||
return;
|
|
||||||
// If already connected to the same AP, do nothing
|
|
||||||
if (global_wifi_component->wifi_ssid() == ssid) {
|
|
||||||
// Callback to notify the user that the connection was successful
|
|
||||||
this->connect_trigger_->trigger();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// Create a new WiFiAP object with the new SSID and password
|
|
||||||
this->new_sta_.set_ssid(ssid);
|
|
||||||
this->new_sta_.set_password(password);
|
|
||||||
// Save the current STA
|
|
||||||
this->old_sta_ = global_wifi_component->get_sta();
|
|
||||||
// Disable WiFi
|
|
||||||
global_wifi_component->disable();
|
|
||||||
// Set the state to connecting
|
|
||||||
this->connecting_ = true;
|
|
||||||
// Store the new STA so once the WiFi is enabled, it will connect to it
|
|
||||||
// This is necessary because the WiFiComponent will raise an error and fallback to the saved STA
|
|
||||||
// if trying to connect to a new STA while already connected to another one
|
|
||||||
if (this->save_.value(x...)) {
|
|
||||||
global_wifi_component->save_wifi_sta(new_sta_.get_ssid(), new_sta_.get_password());
|
|
||||||
} else {
|
|
||||||
global_wifi_component->set_sta(new_sta_);
|
|
||||||
}
|
|
||||||
// Enable WiFi
|
|
||||||
global_wifi_component->enable();
|
|
||||||
// Set timeout for the connection
|
|
||||||
this->set_timeout("wifi-connect-timeout", this->connection_timeout_.value(x...), [this, x...]() {
|
|
||||||
// If the timeout is reached, stop connecting and revert to the old AP
|
|
||||||
global_wifi_component->disable();
|
|
||||||
global_wifi_component->save_wifi_sta(old_sta_.get_ssid(), old_sta_.get_password());
|
|
||||||
global_wifi_component->enable();
|
|
||||||
// Start a timeout for the fallback if the connection to the old AP fails
|
|
||||||
this->set_timeout("wifi-fallback-timeout", this->connection_timeout_.value(x...), [this]() {
|
|
||||||
this->connecting_ = false;
|
|
||||||
this->error_trigger_->trigger();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
Trigger<> *get_connect_trigger() const { return this->connect_trigger_; }
|
|
||||||
Trigger<> *get_error_trigger() const { return this->error_trigger_; }
|
|
||||||
|
|
||||||
void loop() override {
|
|
||||||
if (!this->connecting_)
|
|
||||||
return;
|
|
||||||
if (global_wifi_component->is_connected()) {
|
|
||||||
// The WiFi is connected, stop the timeout and reset the connecting flag
|
|
||||||
this->cancel_timeout("wifi-connect-timeout");
|
|
||||||
this->cancel_timeout("wifi-fallback-timeout");
|
|
||||||
this->connecting_ = false;
|
|
||||||
if (global_wifi_component->wifi_ssid() == this->new_sta_.get_ssid()) {
|
|
||||||
// Callback to notify the user that the connection was successful
|
|
||||||
this->connect_trigger_->trigger();
|
|
||||||
} else {
|
|
||||||
// Callback to notify the user that the connection failed
|
|
||||||
this->error_trigger_->trigger();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool connecting_{false};
|
|
||||||
WiFiAP new_sta_;
|
|
||||||
WiFiAP old_sta_;
|
|
||||||
Trigger<> *connect_trigger_{new Trigger<>()};
|
|
||||||
Trigger<> *error_trigger_{new Trigger<>()};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace wifi
|
|
||||||
} // namespace esphome
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -38,8 +38,7 @@ extern "C" {
|
|||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/util.h"
|
#include "esphome/core/util.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi {
|
||||||
namespace wifi {
|
|
||||||
|
|
||||||
static const char *const TAG = "wifi_esp8266";
|
static const char *const TAG = "wifi_esp8266";
|
||||||
|
|
||||||
@@ -514,6 +513,10 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
|||||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=%s channel=%u", buf, format_mac_address_pretty(it.bssid).c_str(),
|
ESP_LOGV(TAG, "Connected ssid='%s' bssid=%s channel=%u", buf, format_mac_address_pretty(it.bssid).c_str(),
|
||||||
it.channel);
|
it.channel);
|
||||||
s_sta_connected = true;
|
s_sta_connected = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
global_wifi_component->wifi_connect_state_callback_.call(global_wifi_component->wifi_ssid(),
|
||||||
|
global_wifi_component->wifi_bssid());
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_STAMODE_DISCONNECTED: {
|
case EVENT_STAMODE_DISCONNECTED: {
|
||||||
@@ -533,6 +536,9 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
|||||||
}
|
}
|
||||||
s_sta_connected = false;
|
s_sta_connected = false;
|
||||||
s_sta_connecting = false;
|
s_sta_connecting = false;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
global_wifi_component->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0}));
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_STAMODE_AUTHMODE_CHANGE: {
|
case EVENT_STAMODE_AUTHMODE_CHANGE: {
|
||||||
@@ -555,6 +561,11 @@ void WiFiComponent::wifi_event_callback(System_Event_t *event) {
|
|||||||
ESP_LOGV(TAG, "static_ip=%s gateway=%s netmask=%s", format_ip_addr(it.ip).c_str(), format_ip_addr(it.gw).c_str(),
|
ESP_LOGV(TAG, "static_ip=%s gateway=%s netmask=%s", format_ip_addr(it.ip).c_str(), format_ip_addr(it.gw).c_str(),
|
||||||
format_ip_addr(it.mask).c_str());
|
format_ip_addr(it.mask).c_str());
|
||||||
s_sta_got_ip = true;
|
s_sta_got_ip = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
global_wifi_component->ip_state_callback_.call(global_wifi_component->wifi_sta_ip_addresses(),
|
||||||
|
global_wifi_component->get_dns_address(0),
|
||||||
|
global_wifi_component->get_dns_address(1));
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EVENT_STAMODE_DHCP_TIMEOUT: {
|
case EVENT_STAMODE_DHCP_TIMEOUT: {
|
||||||
@@ -729,6 +740,9 @@ void WiFiComponent::wifi_scan_done_callback_(void *arg, STATUS status) {
|
|||||||
it->is_hidden != 0);
|
it->is_hidden != 0);
|
||||||
}
|
}
|
||||||
this->scan_done_ = true;
|
this->scan_done_ = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
global_wifi_component->wifi_scan_state_callback_.call(global_wifi_component->scan_result_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_WIFI_AP
|
#ifdef USE_WIFI_AP
|
||||||
@@ -885,8 +899,6 @@ network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {(const ip_addr_t
|
|||||||
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {(const ip_addr_t *) WiFi.dnsIP(num)}; }
|
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {(const ip_addr_t *) WiFi.dnsIP(num)}; }
|
||||||
void WiFiComponent::wifi_loop_() {}
|
void WiFiComponent::wifi_loop_() {}
|
||||||
|
|
||||||
} // namespace wifi
|
} // namespace esphome::wifi
|
||||||
} // namespace esphome
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -41,8 +41,7 @@
|
|||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/util.h"
|
#include "esphome/core/util.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi {
|
||||||
namespace wifi {
|
|
||||||
|
|
||||||
static const char *const TAG = "wifi_esp32";
|
static const char *const TAG = "wifi_esp32";
|
||||||
|
|
||||||
@@ -728,6 +727,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||||
s_sta_connected = true;
|
s_sta_connected = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_connect_state_callback_.call(this->wifi_ssid(), this->wifi_bssid());
|
||||||
|
#endif
|
||||||
|
|
||||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||||
const auto &it = data->data.sta_disconnected;
|
const auto &it = data->data.sta_disconnected;
|
||||||
@@ -751,6 +753,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
s_sta_connected = false;
|
s_sta_connected = false;
|
||||||
s_sta_connecting = false;
|
s_sta_connecting = false;
|
||||||
error_from_callback_ = true;
|
error_from_callback_ = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0}));
|
||||||
|
#endif
|
||||||
|
|
||||||
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) {
|
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_GOT_IP) {
|
||||||
const auto &it = data->data.ip_got_ip;
|
const auto &it = data->data.ip_got_ip;
|
||||||
@@ -759,12 +764,18 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
#endif /* USE_NETWORK_IPV6 */
|
#endif /* USE_NETWORK_IPV6 */
|
||||||
ESP_LOGV(TAG, "static_ip=" IPSTR " gateway=" IPSTR, IP2STR(&it.ip_info.ip), IP2STR(&it.ip_info.gw));
|
ESP_LOGV(TAG, "static_ip=" IPSTR " gateway=" IPSTR, IP2STR(&it.ip_info.ip), IP2STR(&it.ip_info.gw));
|
||||||
this->got_ipv4_address_ = true;
|
this->got_ipv4_address_ = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1));
|
||||||
|
#endif
|
||||||
|
|
||||||
#if USE_NETWORK_IPV6
|
#if USE_NETWORK_IPV6
|
||||||
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_GOT_IP6) {
|
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_GOT_IP6) {
|
||||||
const auto &it = data->data.ip_got_ip6;
|
const auto &it = data->data.ip_got_ip6;
|
||||||
ESP_LOGV(TAG, "IPv6 address=" IPV6STR, IPV62STR(it.ip6_info.ip));
|
ESP_LOGV(TAG, "IPv6 address=" IPV6STR, IPV62STR(it.ip6_info.ip));
|
||||||
this->num_ipv6_addresses_++;
|
this->num_ipv6_addresses_++;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1));
|
||||||
|
#endif
|
||||||
#endif /* USE_NETWORK_IPV6 */
|
#endif /* USE_NETWORK_IPV6 */
|
||||||
|
|
||||||
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_LOST_IP) {
|
} else if (data->event_base == IP_EVENT && data->event_id == IP_EVENT_STA_LOST_IP) {
|
||||||
@@ -804,6 +815,9 @@ void WiFiComponent::wifi_process_event_(IDFWiFiEvent *data) {
|
|||||||
scan_result_.emplace_back(bssid, ssid, record.primary, record.rssi, record.authmode != WIFI_AUTH_OPEN,
|
scan_result_.emplace_back(bssid, ssid, record.primary, record.rssi, record.authmode != WIFI_AUTH_OPEN,
|
||||||
ssid.empty());
|
ssid.empty());
|
||||||
}
|
}
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_scan_state_callback_.call(this->scan_result_);
|
||||||
|
#endif
|
||||||
|
|
||||||
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_START) {
|
} else if (data->event_base == WIFI_EVENT && data->event_id == WIFI_EVENT_AP_START) {
|
||||||
ESP_LOGV(TAG, "AP start");
|
ESP_LOGV(TAG, "AP start");
|
||||||
@@ -1088,8 +1102,6 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) {
|
|||||||
return network::IPAddress(dns_ip);
|
return network::IPAddress(dns_ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wifi
|
} // namespace esphome::wifi
|
||||||
} // namespace esphome
|
|
||||||
|
|
||||||
#endif // USE_ESP32
|
#endif // USE_ESP32
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,8 +15,7 @@
|
|||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/util.h"
|
#include "esphome/core/util.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi {
|
||||||
namespace wifi {
|
|
||||||
|
|
||||||
static const char *const TAG = "wifi_lt";
|
static const char *const TAG = "wifi_lt";
|
||||||
|
|
||||||
@@ -288,7 +287,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
|||||||
buf[it.ssid_len] = '\0';
|
buf[it.ssid_len] = '\0';
|
||||||
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
ESP_LOGV(TAG, "Connected ssid='%s' bssid=" LOG_SECRET("%s") " channel=%u, authmode=%s", buf,
|
||||||
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
format_mac_address_pretty(it.bssid).c_str(), it.channel, get_auth_mode_str(it.authmode));
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_connect_state_callback_.call(this->wifi_ssid(), this->wifi_bssid());
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: {
|
case ESPHOME_EVENT_ID_WIFI_STA_DISCONNECTED: {
|
||||||
@@ -314,6 +315,9 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
|||||||
}
|
}
|
||||||
|
|
||||||
s_sta_connecting = false;
|
s_sta_connecting = false;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0}));
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE: {
|
case ESPHOME_EVENT_ID_WIFI_STA_AUTHMODE_CHANGE: {
|
||||||
@@ -335,11 +339,17 @@ void WiFiComponent::wifi_event_callback_(esphome_wifi_event_id_t event, esphome_
|
|||||||
ESP_LOGV(TAG, "static_ip=%s gateway=%s", format_ip4_addr(WiFi.localIP()).c_str(),
|
ESP_LOGV(TAG, "static_ip=%s gateway=%s", format_ip4_addr(WiFi.localIP()).c_str(),
|
||||||
format_ip4_addr(WiFi.gatewayIP()).c_str());
|
format_ip4_addr(WiFi.gatewayIP()).c_str());
|
||||||
s_sta_connecting = false;
|
s_sta_connecting = false;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1));
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: {
|
case ESPHOME_EVENT_ID_WIFI_STA_GOT_IP6: {
|
||||||
// auto it = info.got_ip.ip_info;
|
// auto it = info.got_ip.ip_info;
|
||||||
ESP_LOGV(TAG, "Got IPv6");
|
ESP_LOGV(TAG, "Got IPv6");
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1));
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: {
|
case ESPHOME_EVENT_ID_WIFI_STA_LOST_IP: {
|
||||||
@@ -433,6 +443,9 @@ void WiFiComponent::wifi_scan_done_callback_() {
|
|||||||
}
|
}
|
||||||
WiFi.scanDelete();
|
WiFi.scanDelete();
|
||||||
this->scan_done_ = true;
|
this->scan_done_ = true;
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_scan_state_callback_.call(this->scan_result_);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef USE_WIFI_AP
|
#ifdef USE_WIFI_AP
|
||||||
@@ -493,8 +506,6 @@ network::IPAddress WiFiComponent::wifi_gateway_ip_() { return {WiFi.gatewayIP()}
|
|||||||
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; }
|
network::IPAddress WiFiComponent::wifi_dns_ip_(int num) { return {WiFi.dnsIP(num)}; }
|
||||||
void WiFiComponent::wifi_loop_() {}
|
void WiFiComponent::wifi_loop_() {}
|
||||||
|
|
||||||
} // namespace wifi
|
} // namespace esphome::wifi
|
||||||
} // namespace esphome
|
|
||||||
|
|
||||||
#endif // USE_LIBRETINY
|
#endif // USE_LIBRETINY
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
#include "wifi_component.h"
|
#include "wifi_component.h"
|
||||||
|
|
||||||
#ifdef USE_WIFI
|
#ifdef USE_WIFI
|
||||||
@@ -15,11 +14,14 @@
|
|||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
#include "esphome/core/util.h"
|
#include "esphome/core/util.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi {
|
||||||
namespace wifi {
|
|
||||||
|
|
||||||
static const char *const TAG = "wifi_pico_w";
|
static const char *const TAG = "wifi_pico_w";
|
||||||
|
|
||||||
|
// Track previous state for detecting changes
|
||||||
|
static bool s_sta_was_connected = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
static bool s_sta_had_ip = false; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
|
bool WiFiComponent::wifi_mode_(optional<bool> sta, optional<bool> ap) {
|
||||||
if (sta.has_value()) {
|
if (sta.has_value()) {
|
||||||
if (sta.value()) {
|
if (sta.value()) {
|
||||||
@@ -51,7 +53,7 @@ bool WiFiComponent::wifi_apply_power_save_() {
|
|||||||
return ret == 0;
|
return ret == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: The driver doesnt seem to have an API for this
|
// TODO: The driver doesn't seem to have an API for this
|
||||||
bool WiFiComponent::wifi_apply_output_power_(float output_power) { return true; }
|
bool WiFiComponent::wifi_apply_output_power_(float output_power) { return true; }
|
||||||
|
|
||||||
bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
|
bool WiFiComponent::wifi_sta_connect_(const WiFiAP &ap) {
|
||||||
@@ -219,16 +221,61 @@ network::IPAddress WiFiComponent::wifi_dns_ip_(int num) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WiFiComponent::wifi_loop_() {
|
void WiFiComponent::wifi_loop_() {
|
||||||
|
// Handle scan completion
|
||||||
if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) {
|
if (this->state_ == WIFI_COMPONENT_STATE_STA_SCANNING && !cyw43_wifi_scan_active(&cyw43_state)) {
|
||||||
this->scan_done_ = true;
|
this->scan_done_ = true;
|
||||||
ESP_LOGV(TAG, "Scan done");
|
ESP_LOGV(TAG, "Scan done");
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_scan_state_callback_.call(this->scan_result_);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Poll for connection state changes
|
||||||
|
// The arduino-pico WiFi library doesn't have event callbacks like ESP8266/ESP32,
|
||||||
|
// so we need to poll the link status to detect state changes
|
||||||
|
auto status = cyw43_tcpip_link_status(&cyw43_state, CYW43_ITF_STA);
|
||||||
|
bool is_connected = (status == CYW43_LINK_UP);
|
||||||
|
|
||||||
|
// Detect connection state change
|
||||||
|
if (is_connected && !s_sta_was_connected) {
|
||||||
|
// Just connected
|
||||||
|
s_sta_was_connected = true;
|
||||||
|
ESP_LOGV(TAG, "Connected");
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_connect_state_callback_.call(this->wifi_ssid(), this->wifi_bssid());
|
||||||
|
#endif
|
||||||
|
} else if (!is_connected && s_sta_was_connected) {
|
||||||
|
// Just disconnected
|
||||||
|
s_sta_was_connected = false;
|
||||||
|
s_sta_had_ip = false;
|
||||||
|
ESP_LOGV(TAG, "Disconnected");
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->wifi_connect_state_callback_.call("", bssid_t({0, 0, 0, 0, 0, 0}));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect IP address changes (only when connected)
|
||||||
|
if (is_connected) {
|
||||||
|
bool has_ip = false;
|
||||||
|
// Check for any IP address (IPv4 or IPv6)
|
||||||
|
for (auto addr : addrList) {
|
||||||
|
has_ip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_ip && !s_sta_had_ip) {
|
||||||
|
// Just got IP address
|
||||||
|
s_sta_had_ip = true;
|
||||||
|
ESP_LOGV(TAG, "Got IP address");
|
||||||
|
#ifdef USE_WIFI_CALLBACKS
|
||||||
|
this->ip_state_callback_.call(this->wifi_sta_ip_addresses(), this->get_dns_address(0), this->get_dns_address(1));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiFiComponent::wifi_pre_setup_() {}
|
void WiFiComponent::wifi_pre_setup_() {}
|
||||||
|
|
||||||
} // namespace wifi
|
} // namespace esphome::wifi
|
||||||
} // namespace esphome
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -15,31 +15,27 @@ DEPENDENCIES = ["wifi"]
|
|||||||
|
|
||||||
wifi_info_ns = cg.esphome_ns.namespace("wifi_info")
|
wifi_info_ns = cg.esphome_ns.namespace("wifi_info")
|
||||||
IPAddressWiFiInfo = wifi_info_ns.class_(
|
IPAddressWiFiInfo = wifi_info_ns.class_(
|
||||||
"IPAddressWiFiInfo", text_sensor.TextSensor, cg.PollingComponent
|
"IPAddressWiFiInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
ScanResultsWiFiInfo = wifi_info_ns.class_(
|
ScanResultsWiFiInfo = wifi_info_ns.class_(
|
||||||
"ScanResultsWiFiInfo", text_sensor.TextSensor, cg.PollingComponent
|
"ScanResultsWiFiInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
|
||||||
SSIDWiFiInfo = wifi_info_ns.class_(
|
|
||||||
"SSIDWiFiInfo", text_sensor.TextSensor, cg.PollingComponent
|
|
||||||
)
|
)
|
||||||
|
SSIDWiFiInfo = wifi_info_ns.class_("SSIDWiFiInfo", text_sensor.TextSensor, cg.Component)
|
||||||
BSSIDWiFiInfo = wifi_info_ns.class_(
|
BSSIDWiFiInfo = wifi_info_ns.class_(
|
||||||
"BSSIDWiFiInfo", text_sensor.TextSensor, cg.PollingComponent
|
"BSSIDWiFiInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
MacAddressWifiInfo = wifi_info_ns.class_(
|
MacAddressWifiInfo = wifi_info_ns.class_(
|
||||||
"MacAddressWifiInfo", text_sensor.TextSensor, cg.Component
|
"MacAddressWifiInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
DNSAddressWifiInfo = wifi_info_ns.class_(
|
DNSAddressWifiInfo = wifi_info_ns.class_(
|
||||||
"DNSAddressWifiInfo", text_sensor.TextSensor, cg.PollingComponent
|
"DNSAddressWifiInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema(
|
||||||
IPAddressWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
IPAddressWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
)
|
).extend(
|
||||||
.extend(cv.polling_component_schema("1s"))
|
|
||||||
.extend(
|
|
||||||
{
|
{
|
||||||
cv.Optional(f"address_{x}"): text_sensor.text_sensor_schema(
|
cv.Optional(f"address_{x}"): text_sensor.text_sensor_schema(
|
||||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
@@ -49,22 +45,31 @@ CONFIG_SCHEMA = cv.Schema(
|
|||||||
),
|
),
|
||||||
cv.Optional(CONF_SCAN_RESULTS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_SCAN_RESULTS): text_sensor.text_sensor_schema(
|
||||||
ScanResultsWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
ScanResultsWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
).extend(cv.polling_component_schema("60s")),
|
),
|
||||||
cv.Optional(CONF_SSID): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_SSID): text_sensor.text_sensor_schema(
|
||||||
SSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
SSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
).extend(cv.polling_component_schema("1s")),
|
),
|
||||||
cv.Optional(CONF_BSSID): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_BSSID): text_sensor.text_sensor_schema(
|
||||||
BSSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
BSSIDWiFiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
).extend(cv.polling_component_schema("1s")),
|
),
|
||||||
cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema(
|
||||||
MacAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
MacAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
),
|
),
|
||||||
cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema(
|
||||||
DNSAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
DNSAddressWifiInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
).extend(cv.polling_component_schema("1s")),
|
),
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Keys that require WiFi callbacks
|
||||||
|
_NETWORK_INFO_KEYS = {
|
||||||
|
CONF_SSID,
|
||||||
|
CONF_BSSID,
|
||||||
|
CONF_IP_ADDRESS,
|
||||||
|
CONF_DNS_ADDRESS,
|
||||||
|
CONF_SCAN_RESULTS,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async def setup_conf(config, key):
|
async def setup_conf(config, key):
|
||||||
if key in config:
|
if key in config:
|
||||||
@@ -74,6 +79,10 @@ async def setup_conf(config, key):
|
|||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
|
# Request WiFi callbacks for any sensor that needs them
|
||||||
|
if _NETWORK_INFO_KEYS.intersection(config):
|
||||||
|
wifi.request_wifi_callbacks()
|
||||||
|
|
||||||
await setup_conf(config, CONF_SSID)
|
await setup_conf(config, CONF_SSID)
|
||||||
await setup_conf(config, CONF_BSSID)
|
await setup_conf(config, CONF_BSSID)
|
||||||
await setup_conf(config, CONF_MAC_ADDRESS)
|
await setup_conf(config, CONF_MAC_ADDRESS)
|
||||||
|
|||||||
@@ -2,18 +2,121 @@
|
|||||||
#ifdef USE_WIFI
|
#ifdef USE_WIFI
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi_info {
|
||||||
namespace wifi_info {
|
|
||||||
|
|
||||||
static const char *const TAG = "wifi_info";
|
static const char *const TAG = "wifi_info";
|
||||||
|
|
||||||
|
static constexpr size_t MAX_STATE_LENGTH = 255;
|
||||||
|
|
||||||
|
/********************
|
||||||
|
* IPAddressWiFiInfo
|
||||||
|
*******************/
|
||||||
|
|
||||||
|
void IPAddressWiFiInfo::setup() {
|
||||||
|
wifi::global_wifi_component->add_on_ip_state_callback(
|
||||||
|
[this](const network::IPAddresses &ips, const network::IPAddress &dns1_ip, const network::IPAddress &dns2_ip) {
|
||||||
|
this->state_callback_(ips);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void IPAddressWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "IP Address", this); }
|
void IPAddressWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "IP Address", this); }
|
||||||
void ScanResultsWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "Scan Results", this); }
|
|
||||||
void SSIDWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "SSID", this); }
|
void IPAddressWiFiInfo::state_callback_(const network::IPAddresses &ips) {
|
||||||
void BSSIDWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "BSSID", this); }
|
this->publish_state(ips[0].str());
|
||||||
void MacAddressWifiInfo::dump_config() { LOG_TEXT_SENSOR("", "MAC Address", this); }
|
uint8_t sensor = 0;
|
||||||
|
for (const auto &ip : ips) {
|
||||||
|
if (ip.is_set()) {
|
||||||
|
if (this->ip_sensors_[sensor] != nullptr) {
|
||||||
|
this->ip_sensors_[sensor]->publish_state(ip.str());
|
||||||
|
}
|
||||||
|
sensor++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************
|
||||||
|
* DNSAddressWifiInfo
|
||||||
|
********************/
|
||||||
|
|
||||||
|
void DNSAddressWifiInfo::setup() {
|
||||||
|
wifi::global_wifi_component->add_on_ip_state_callback(
|
||||||
|
[this](const network::IPAddresses &ips, const network::IPAddress &dns1_ip, const network::IPAddress &dns2_ip) {
|
||||||
|
this->state_callback_(dns1_ip, dns2_ip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void DNSAddressWifiInfo::dump_config() { LOG_TEXT_SENSOR("", "DNS Address", this); }
|
void DNSAddressWifiInfo::dump_config() { LOG_TEXT_SENSOR("", "DNS Address", this); }
|
||||||
|
|
||||||
} // namespace wifi_info
|
void DNSAddressWifiInfo::state_callback_(const network::IPAddress &dns1_ip, const network::IPAddress &dns2_ip) {
|
||||||
} // namespace esphome
|
std::string dns_results = dns1_ip.str() + " " + dns2_ip.str();
|
||||||
|
this->publish_state(dns_results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**********************
|
||||||
|
* ScanResultsWiFiInfo
|
||||||
|
*********************/
|
||||||
|
|
||||||
|
void ScanResultsWiFiInfo::setup() {
|
||||||
|
wifi::global_wifi_component->add_on_wifi_scan_state_callback(
|
||||||
|
[this](const wifi::wifi_scan_vector_t<wifi::WiFiScanResult> &results) { this->state_callback_(results); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScanResultsWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "Scan Results", this); }
|
||||||
|
|
||||||
|
void ScanResultsWiFiInfo::state_callback_(const wifi::wifi_scan_vector_t<wifi::WiFiScanResult> &results) {
|
||||||
|
std::string scan_results;
|
||||||
|
for (const auto &scan : results) {
|
||||||
|
if (scan.get_is_hidden())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
scan_results += scan.get_ssid();
|
||||||
|
scan_results += ": ";
|
||||||
|
scan_results += esphome::to_string(scan.get_rssi());
|
||||||
|
scan_results += "dB\n";
|
||||||
|
}
|
||||||
|
// There's a limit of 255 characters per state; longer states just don't get sent so we truncate it
|
||||||
|
if (scan_results.length() > MAX_STATE_LENGTH) {
|
||||||
|
scan_results.resize(MAX_STATE_LENGTH);
|
||||||
|
}
|
||||||
|
this->publish_state(scan_results);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************
|
||||||
|
* SSIDWiFiInfo
|
||||||
|
**************/
|
||||||
|
|
||||||
|
void SSIDWiFiInfo::setup() {
|
||||||
|
wifi::global_wifi_component->add_on_wifi_connect_state_callback(
|
||||||
|
[this](const std::string &ssid, const wifi::bssid_t &bssid) { this->state_callback_(ssid); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void SSIDWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "SSID", this); }
|
||||||
|
|
||||||
|
void SSIDWiFiInfo::state_callback_(const std::string &ssid) { this->publish_state(ssid); }
|
||||||
|
|
||||||
|
/****************
|
||||||
|
* BSSIDWiFiInfo
|
||||||
|
***************/
|
||||||
|
|
||||||
|
void BSSIDWiFiInfo::setup() {
|
||||||
|
wifi::global_wifi_component->add_on_wifi_connect_state_callback(
|
||||||
|
[this](const std::string &ssid, const wifi::bssid_t &bssid) { this->state_callback_(bssid); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void BSSIDWiFiInfo::dump_config() { LOG_TEXT_SENSOR("", "BSSID", this); }
|
||||||
|
|
||||||
|
void BSSIDWiFiInfo::state_callback_(const wifi::bssid_t &bssid) {
|
||||||
|
char buf[18] = "unknown";
|
||||||
|
if (mac_address_is_valid(bssid.data())) {
|
||||||
|
format_mac_addr_upper(bssid.data(), buf);
|
||||||
|
}
|
||||||
|
this->publish_state(buf);
|
||||||
|
}
|
||||||
|
/*********************
|
||||||
|
* MacAddressWifiInfo
|
||||||
|
********************/
|
||||||
|
|
||||||
|
void MacAddressWifiInfo::dump_config() { LOG_TEXT_SENSOR("", "MAC Address", this); }
|
||||||
|
|
||||||
|
} // namespace esphome::wifi_info
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -7,121 +7,54 @@
|
|||||||
#ifdef USE_WIFI
|
#ifdef USE_WIFI
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome::wifi_info {
|
||||||
namespace wifi_info {
|
|
||||||
|
|
||||||
static constexpr size_t MAX_STATE_LENGTH = 255;
|
class IPAddressWiFiInfo : public Component, public text_sensor::TextSensor {
|
||||||
|
|
||||||
class IPAddressWiFiInfo : public PollingComponent, public text_sensor::TextSensor {
|
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
auto ips = wifi::global_wifi_component->wifi_sta_ip_addresses();
|
|
||||||
if (ips != this->last_ips_) {
|
|
||||||
this->last_ips_ = ips;
|
|
||||||
this->publish_state(ips[0].str());
|
|
||||||
uint8_t sensor = 0;
|
|
||||||
for (auto &ip : ips) {
|
|
||||||
if (ip.is_set()) {
|
|
||||||
if (this->ip_sensors_[sensor] != nullptr) {
|
|
||||||
this->ip_sensors_[sensor]->publish_state(ip.str());
|
|
||||||
}
|
|
||||||
sensor++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
|
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
network::IPAddresses last_ips_;
|
void state_callback_(const network::IPAddresses &ips);
|
||||||
std::array<text_sensor::TextSensor *, 5> ip_sensors_;
|
std::array<text_sensor::TextSensor *, 5> ip_sensors_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DNSAddressWifiInfo : public PollingComponent, public text_sensor::TextSensor {
|
class DNSAddressWifiInfo : public Component, public text_sensor::TextSensor {
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
auto dns_one = wifi::global_wifi_component->get_dns_address(0);
|
|
||||||
auto dns_two = wifi::global_wifi_component->get_dns_address(1);
|
|
||||||
|
|
||||||
std::string dns_results = dns_one.str() + " " + dns_two.str();
|
|
||||||
|
|
||||||
if (dns_results != this->last_results_) {
|
|
||||||
this->last_results_ = dns_results;
|
|
||||||
this->publish_state(dns_results);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string last_results_;
|
void state_callback_(const network::IPAddress &dns1_ip, const network::IPAddress &dns2_ip);
|
||||||
};
|
};
|
||||||
|
|
||||||
class ScanResultsWiFiInfo : public PollingComponent, public text_sensor::TextSensor {
|
class ScanResultsWiFiInfo : public Component, public text_sensor::TextSensor {
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
std::string scan_results;
|
|
||||||
for (auto &scan : wifi::global_wifi_component->get_scan_result()) {
|
|
||||||
if (scan.get_is_hidden())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
scan_results += scan.get_ssid();
|
|
||||||
scan_results += ": ";
|
|
||||||
scan_results += esphome::to_string(scan.get_rssi());
|
|
||||||
scan_results += "dB\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's a limit of 255 characters per state.
|
|
||||||
// Longer states just don't get sent so we truncate it.
|
|
||||||
if (scan_results.length() > MAX_STATE_LENGTH) {
|
|
||||||
scan_results.resize(MAX_STATE_LENGTH);
|
|
||||||
}
|
|
||||||
if (this->last_scan_results_ != scan_results) {
|
|
||||||
this->last_scan_results_ = scan_results;
|
|
||||||
this->publish_state(scan_results);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string last_scan_results_;
|
void state_callback_(const wifi::wifi_scan_vector_t<wifi::WiFiScanResult> &results);
|
||||||
};
|
};
|
||||||
|
|
||||||
class SSIDWiFiInfo : public PollingComponent, public text_sensor::TextSensor {
|
class SSIDWiFiInfo : public Component, public text_sensor::TextSensor {
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
std::string ssid = wifi::global_wifi_component->wifi_ssid();
|
|
||||||
if (this->last_ssid_ != ssid) {
|
|
||||||
this->last_ssid_ = ssid;
|
|
||||||
this->publish_state(this->last_ssid_);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string last_ssid_;
|
void state_callback_(const std::string &ssid);
|
||||||
};
|
};
|
||||||
|
|
||||||
class BSSIDWiFiInfo : public PollingComponent, public text_sensor::TextSensor {
|
class BSSIDWiFiInfo : public Component, public text_sensor::TextSensor {
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
wifi::bssid_t bssid = wifi::global_wifi_component->wifi_bssid();
|
|
||||||
if (memcmp(bssid.data(), last_bssid_.data(), 6) != 0) {
|
|
||||||
std::copy(bssid.begin(), bssid.end(), last_bssid_.begin());
|
|
||||||
char buf[18];
|
|
||||||
format_mac_addr_upper(bssid.data(), buf);
|
|
||||||
this->publish_state(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::AFTER_WIFI; }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
wifi::bssid_t last_bssid_;
|
void state_callback_(const wifi::bssid_t &bssid);
|
||||||
};
|
};
|
||||||
|
|
||||||
class MacAddressWifiInfo : public Component, public text_sensor::TextSensor {
|
class MacAddressWifiInfo : public Component, public text_sensor::TextSensor {
|
||||||
@@ -133,6 +66,5 @@ class MacAddressWifiInfo : public Component, public text_sensor::TextSensor {
|
|||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace wifi_info
|
} // namespace esphome::wifi_info
|
||||||
} // namespace esphome
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -210,6 +210,7 @@
|
|||||||
#define USE_WEBSERVER_SORTING
|
#define USE_WEBSERVER_SORTING
|
||||||
#define USE_WIFI_11KV_SUPPORT
|
#define USE_WIFI_11KV_SUPPORT
|
||||||
#define USE_WIFI_FAST_CONNECT
|
#define USE_WIFI_FAST_CONNECT
|
||||||
|
#define USE_WIFI_CALLBACKS
|
||||||
#define USE_WIFI_RUNTIME_POWER_SAVE
|
#define USE_WIFI_RUNTIME_POWER_SAVE
|
||||||
#define USB_HOST_MAX_REQUESTS 16
|
#define USB_HOST_MAX_REQUESTS 16
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user