mirror of
https://github.com/esphome/esphome.git
synced 2025-11-15 14:25:45 +00:00
123 lines
4.2 KiB
C++
123 lines
4.2 KiB
C++
#include "captive_portal.h"
|
|
#ifdef USE_CAPTIVE_PORTAL
|
|
#include "esphome/core/log.h"
|
|
#include "esphome/core/application.h"
|
|
#include "esphome/components/wifi/wifi_component.h"
|
|
#include "captive_index.h"
|
|
|
|
namespace esphome {
|
|
namespace captive_portal {
|
|
|
|
static const char *const TAG = "captive_portal";
|
|
|
|
void CaptivePortal::handle_config(AsyncWebServerRequest *request) {
|
|
AsyncResponseStream *stream = request->beginResponseStream(ESPHOME_F("application/json"));
|
|
stream->addHeader(ESPHOME_F("cache-control"), ESPHOME_F("public, max-age=0, must-revalidate"));
|
|
#ifdef USE_ESP8266
|
|
stream->print(ESPHOME_F("{\"mac\":\""));
|
|
stream->print(get_mac_address_pretty().c_str());
|
|
stream->print(ESPHOME_F("\",\"name\":\""));
|
|
stream->print(App.get_name().c_str());
|
|
stream->print(ESPHOME_F("\",\"aps\":[{}"));
|
|
#else
|
|
stream->printf(R"({"mac":"%s","name":"%s","aps":[{})", get_mac_address_pretty().c_str(), App.get_name().c_str());
|
|
#endif
|
|
|
|
for (auto &scan : wifi::global_wifi_component->get_scan_result()) {
|
|
if (scan.get_is_hidden())
|
|
continue;
|
|
|
|
// Assumes no " in ssid, possible unicode isses?
|
|
#ifdef USE_ESP8266
|
|
stream->print(ESPHOME_F(",{\"ssid\":\""));
|
|
stream->print(scan.get_ssid().c_str());
|
|
stream->print(ESPHOME_F("\",\"rssi\":"));
|
|
stream->print(scan.get_rssi());
|
|
stream->print(ESPHOME_F(",\"lock\":"));
|
|
stream->print(scan.get_with_auth());
|
|
stream->print(ESPHOME_F("}"));
|
|
#else
|
|
stream->printf(R"(,{"ssid":"%s","rssi":%d,"lock":%d})", scan.get_ssid().c_str(), scan.get_rssi(),
|
|
scan.get_with_auth());
|
|
#endif
|
|
}
|
|
stream->print(ESPHOME_F("]}"));
|
|
request->send(stream);
|
|
}
|
|
void CaptivePortal::handle_wifisave(AsyncWebServerRequest *request) {
|
|
std::string ssid = request->arg("ssid").c_str(); // NOLINT(readability-redundant-string-cstr)
|
|
std::string psk = request->arg("psk").c_str(); // NOLINT(readability-redundant-string-cstr)
|
|
ESP_LOGI(TAG, "Requested WiFi Settings Change:");
|
|
ESP_LOGI(TAG, " SSID='%s'", ssid.c_str());
|
|
ESP_LOGI(TAG, " Password=" LOG_SECRET("'%s'"), psk.c_str());
|
|
wifi::global_wifi_component->save_wifi_sta(ssid, psk);
|
|
wifi::global_wifi_component->start_scanning();
|
|
request->redirect(ESPHOME_F("/?save"));
|
|
}
|
|
|
|
void CaptivePortal::setup() {
|
|
// Disable loop by default - will be enabled when captive portal starts
|
|
this->disable_loop();
|
|
}
|
|
void CaptivePortal::start() {
|
|
this->base_->init();
|
|
if (!this->initialized_) {
|
|
this->base_->add_handler(this);
|
|
}
|
|
|
|
network::IPAddress ip = wifi::global_wifi_component->wifi_soft_ap_ip();
|
|
|
|
#ifdef USE_ESP_IDF
|
|
// Create DNS server instance for ESP-IDF
|
|
this->dns_server_ = make_unique<DNSServer>();
|
|
this->dns_server_->start(ip);
|
|
#endif
|
|
#ifdef USE_ARDUINO
|
|
this->dns_server_ = make_unique<DNSServer>();
|
|
this->dns_server_->setErrorReplyCode(DNSReplyCode::NoError);
|
|
this->dns_server_->start(53, ESPHOME_F("*"), ip);
|
|
#endif
|
|
|
|
this->initialized_ = true;
|
|
this->active_ = true;
|
|
|
|
// Enable loop() now that captive portal is active
|
|
this->enable_loop();
|
|
|
|
ESP_LOGV(TAG, "Captive portal started");
|
|
}
|
|
|
|
void CaptivePortal::handleRequest(AsyncWebServerRequest *req) {
|
|
if (req->url() == ESPHOME_F("/config.json")) {
|
|
this->handle_config(req);
|
|
return;
|
|
} else if (req->url() == ESPHOME_F("/wifisave")) {
|
|
this->handle_wifisave(req);
|
|
return;
|
|
}
|
|
|
|
// All other requests get the captive portal page
|
|
// This includes OS captive portal detection endpoints which will trigger
|
|
// the captive portal when they don't receive their expected responses
|
|
#ifndef USE_ESP8266
|
|
auto *response = req->beginResponse(200, ESPHOME_F("text/html"), INDEX_GZ, sizeof(INDEX_GZ));
|
|
#else
|
|
auto *response = req->beginResponse_P(200, ESPHOME_F("text/html"), INDEX_GZ, sizeof(INDEX_GZ));
|
|
#endif
|
|
response->addHeader(ESPHOME_F("Content-Encoding"), ESPHOME_F("gzip"));
|
|
req->send(response);
|
|
}
|
|
|
|
CaptivePortal::CaptivePortal(web_server_base::WebServerBase *base) : base_(base) { global_captive_portal = this; }
|
|
float CaptivePortal::get_setup_priority() const {
|
|
// Before WiFi
|
|
return setup_priority::WIFI + 1.0f;
|
|
}
|
|
void CaptivePortal::dump_config() { ESP_LOGCONFIG(TAG, "Captive Portal:"); }
|
|
|
|
CaptivePortal *global_captive_portal = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
|
|
|
} // namespace captive_portal
|
|
} // namespace esphome
|
|
#endif
|