mirror of
https://github.com/esphome/esphome.git
synced 2026-10-02 01:10:22 +00:00
End the web_server captive DNS when the provisioning window closes and report a DNS start failure
This commit is contained in:
@@ -444,9 +444,12 @@ void WebServer::start_captive() {
|
||||
if (this->dns_.is_running())
|
||||
return;
|
||||
network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip();
|
||||
this->dns_.start(ip);
|
||||
this->enable_loop();
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
if (!this->dns_.start(ip)) {
|
||||
ESP_LOGW(TAG, "AP mode: captive DNS failed to start; open http://%s/ manually", ip.str_to(ip_buf));
|
||||
return;
|
||||
}
|
||||
this->enable_loop();
|
||||
ESP_LOGI(TAG, "AP mode: serving the web interface as captive portal at http://%s/", ip.str_to(ip_buf));
|
||||
}
|
||||
|
||||
|
||||
@@ -20,16 +20,21 @@ namespace esphome::web_server_base {
|
||||
// The server object only exists while running, so an idle owner (AP not up) pays one pointer.
|
||||
class CaptiveDNS {
|
||||
public:
|
||||
void start(const network::IPAddress &ip) {
|
||||
/// Returns false when the DNS server could not start; nothing is kept, so a later start retries.
|
||||
bool start(const network::IPAddress &ip) {
|
||||
if (this->dns_server_ != nullptr)
|
||||
return;
|
||||
this->dns_server_ = make_unique<DNSServer>();
|
||||
return true;
|
||||
auto server = make_unique<DNSServer>();
|
||||
#if defined(USE_ESP32)
|
||||
this->dns_server_->start(ip);
|
||||
const bool started = server->start(ip);
|
||||
#elif defined(USE_ARDUINO)
|
||||
this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError);
|
||||
this->dns_server_->start(53, ESPHOME_F("*"), ip);
|
||||
server->setErrorReplyCode(DNSReplyCode::NoError);
|
||||
const bool started = server->start(53, ESPHOME_F("*"), ip);
|
||||
#endif
|
||||
if (!started)
|
||||
return false;
|
||||
this->dns_server_ = std::move(server);
|
||||
return true;
|
||||
}
|
||||
void stop() {
|
||||
if (this->dns_server_ == nullptr)
|
||||
|
||||
@@ -46,7 +46,7 @@ struct DNSAnswer {
|
||||
uint32_t ip_addr;
|
||||
} __attribute__((packed));
|
||||
|
||||
void DNSServer::start(const network::IPAddress &ip) {
|
||||
bool DNSServer::start(const network::IPAddress &ip) {
|
||||
this->server_ip_ = ip;
|
||||
#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_VERBOSE
|
||||
char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||
@@ -57,7 +57,7 @@ void DNSServer::start(const network::IPAddress &ip) {
|
||||
this->socket_ = socket::socket_ip_loop_monitored(SOCK_DGRAM, IPPROTO_UDP).release();
|
||||
if (this->socket_ == nullptr) {
|
||||
ESP_LOGE(TAG, "Socket create failed");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set socket options
|
||||
@@ -72,9 +72,10 @@ void DNSServer::start(const network::IPAddress &ip) {
|
||||
if (err != 0) {
|
||||
ESP_LOGE(TAG, "Bind failed: %d", errno);
|
||||
this->destroy_socket_();
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
ESP_LOGV(TAG, "Bound to port %d", DNS_PORT);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DNSServer::stop() {
|
||||
|
||||
@@ -13,7 +13,8 @@ namespace esphome::web_server_base {
|
||||
|
||||
class DNSServer {
|
||||
public:
|
||||
void start(const network::IPAddress &ip);
|
||||
/// Returns false when the socket could not be created or bound.
|
||||
bool start(const network::IPAddress &ip);
|
||||
void stop();
|
||||
void process_next_request();
|
||||
|
||||
|
||||
@@ -638,13 +638,14 @@ void WiFiComponent::setup() {
|
||||
|
||||
#if defined(USE_PROVISIONING) && defined(USE_WIFI_AP)
|
||||
// The access point is a provisioning surface: once the provisioning window has
|
||||
// closed, shut it down (mirrors the teardown done on a successful connection).
|
||||
// The captive portal registers its own closed-callback, and the fallback block
|
||||
// in loop() is gated so neither is started again afterwards.
|
||||
// closed, end both portals and shut it down (mirrors the teardown done on a
|
||||
// successful connection). The fallback block in loop() is gated so none of them
|
||||
// is started again afterwards.
|
||||
if (provisioning::global_provisioning_manager != nullptr) {
|
||||
provisioning::global_provisioning_manager->add_on_closed_callback([this]() {
|
||||
if (this->ap_setup_) {
|
||||
ESP_LOGD(TAG, "Provisioning window closed; disabling AP");
|
||||
this->end_ap_portal_();
|
||||
this->wifi_mode_({}, false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
# STA with AP fallback plus local: true opts the fallback into captive AP mode; exercises
|
||||
# the runtime start (fallback branch in wifi loop) and end (on STA connect) paths.
|
||||
# the runtime start (fallback branch in wifi loop) and end (on STA connect, and when the
|
||||
# provisioning window closes) paths.
|
||||
provisioning:
|
||||
timeout: 1min
|
||||
|
||||
api:
|
||||
encryption:
|
||||
|
||||
wifi:
|
||||
ssid: MySSID
|
||||
password: password1
|
||||
|
||||
Reference in New Issue
Block a user