12namespace esp32_improv {
14using namespace bytebuffer;
16static const char *
const TAG =
"esp32_improv.component";
17static const char *
const ESPHOME_MY_LINK =
"https://my.home-assistant.io/redirect/config_flow_start?domain=esphome";
18static constexpr uint16_t STOP_ADVERTISING_DELAY =
24#ifdef USE_BINARY_SENSOR
35 [
this](uint16_t conn_id) { this->
set_error_(improv::ERROR_NONE); });
54 BLECharacteristicEvt::VectorEvt::ON_WRITE, [
this](
const std::vector<uint8_t> &data, uint16_t
id) {
71 uint8_t capabilities = 0x00;
74 capabilities |= improv::CAPABILITY_IDENTIFY;
82 if (this->
state_ != improv::STATE_STOPPED) {
83 this->
state_ = improv::STATE_STOPPED;
84#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
93 ESP_LOGD(TAG,
"Creating Improv service");
103 case improv::STATE_STOPPED:
112 this->
set_state_(improv::STATE_AWAITING_AUTHORIZATION);
114 ESP_LOGD(TAG,
"Service started!");
118 case improv::STATE_AWAITING_AUTHORIZATION: {
119#ifdef USE_BINARY_SENSOR
125 { this->
set_state_(improv::STATE_AUTHORIZED); }
133 case improv::STATE_AUTHORIZED: {
134#ifdef USE_BINARY_SENSOR
137 ESP_LOGD(TAG,
"Authorization timeout");
138 this->
set_state_(improv::STATE_AWAITING_AUTHORIZATION);
148 case improv::STATE_PROVISIONING: {
152 this->connecting_sta_.get_password());
157 std::vector<std::string> urls = {ESPHOME_MY_LINK};
161 std::string webserver_url =
"http://" + ip.str() +
":" + to_string(USE_WEBSERVER_PORT);
162 urls.push_back(webserver_url);
167 std::vector<uint8_t> data = improv::build_rpc_response(improv::WIFI_SETTINGS, urls);
173 case improv::STATE_PROVISIONED: {
198#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
201 case improv::STATE_STOPPED:
203 case improv::STATE_AWAITING_AUTHORIZATION:
204 return "AWAITING_AUTHORIZATION";
205 case improv::STATE_AUTHORIZED:
207 case improv::STATE_PROVISIONING:
208 return "PROVISIONING";
209 case improv::STATE_PROVISIONED:
210 return "PROVISIONED";
223 uint32_t time = now % 1000;
230#if ESPHOME_LOG_LEVEL >= ESPHOME_LOG_LEVEL_DEBUG
231 if (this->
state_ != state) {
239 if (
state != improv::STATE_STOPPED)
246 if (state != improv::STATE_STOPPED) {
247 std::vector<uint8_t> service_data(8, 0);
248 service_data[0] = 0x77;
249 service_data[1] = 0x46;
250 service_data[2] =
static_cast<uint8_t
>(
state);
252 uint8_t capabilities = 0x00;
255 capabilities |= improv::CAPABILITY_IDENTIFY;
258 service_data[3] = capabilities;
259 service_data[4] = 0x00;
260 service_data[5] = 0x00;
261 service_data[6] = 0x00;
262 service_data[7] = 0x00;
266#ifdef USE_ESP32_IMPROV_STATE_CALLBACK
272 if (error != improv::ERROR_NONE) {
273 ESP_LOGE(TAG,
"Error: %d", error);
280 if (this->
error_ !=
nullptr && (this->
error_->
get_value().empty() || this->error_->get_value()[0] != error)) {
282 if (this->
state_ != improv::STATE_STOPPED)
289 if (this->
state_ != improv::STATE_STOPPED)
297 ESP_LOGD(TAG,
"Setting Improv to start");
307 this->
set_timeout(
"end-service", STOP_ADVERTISING_DELAY, [
this] {
308 if (this->
state_ == improv::STATE_STOPPED || this->
service_ ==
nullptr)
318 ESP_LOGCONFIG(TAG,
"ESP32 Improv:");
319#ifdef USE_BINARY_SENSOR
320 LOG_BINARY_SENSOR(
" ",
"Authorizer", this->
authorizer_);
323 ESP_LOGCONFIG(TAG,
" Status Indicator: '%s'", YESNO(this->
status_indicator_ !=
nullptr));
333 improv::ImprovCommand command = improv::parse_improv_data(this->
incoming_data_);
334 switch (command.command) {
335 case improv::BAD_CHECKSUM:
336 ESP_LOGW(TAG,
"Error decoding Improv payload");
340 case improv::WIFI_SETTINGS: {
341 if (this->
state_ != improv::STATE_AUTHORIZED) {
342 ESP_LOGW(TAG,
"Settings received, but not authorized");
343 this->
set_error_(improv::ERROR_NOT_AUTHORIZED);
349 sta.set_password(command.password);
355 ESP_LOGD(TAG,
"Received Improv Wi-Fi settings ssid=%s, password=" LOG_SECRET(
"%s"), command.ssid.c_str(),
356 command.password.c_str());
359 this->
set_timeout(
"wifi-connect-timeout", 30000, f);
363 case improv::IDENTIFY:
368 ESP_LOGW(TAG,
"Unknown Improv payload");
373 ESP_LOGV(TAG,
"Too much data received or data malformed; resetting buffer");
376 ESP_LOGV(TAG,
"Waiting for split data packets");
381 this->
set_error_(improv::ERROR_UNABLE_TO_CONNECT);
383#ifdef USE_BINARY_SENSOR
387 ESP_LOGW(TAG,
"Timed out while connecting to Wi-Fi network");
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
bool cancel_timeout(const std::string &name)
Cancel a timeout function.
void enable_loop()
Enable this component's loop.
void disable_loop()
Disable this component's loop.
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
void add_on_state_callback(std::function< void(T)> &&callback)
static ByteBuffer wrap(T value, Endian endianness=LITTLE)
void advertising_set_service_data(const std::vector< uint8_t > &data)
static ESPBTUUID from_raw(const uint8_t *data)
void set_value(ByteBuffer buffer)
static const uint32_t PROPERTY_NOTIFY
static const uint32_t PROPERTY_WRITE
void add_descriptor(BLEDescriptor *descriptor)
static const uint32_t PROPERTY_READ
std::vector< uint8_t > & get_value()
BLEService * create_service(ESPBTUUID uuid, bool advertise=false, uint16_t num_handles=15)
BLECharacteristic * create_characteristic(const std::string &uuid, esp_gatt_char_prop_t properties)
void on_wifi_connect_timeout_()
void send_response_(std::vector< uint8_t > &response)
binary_sensor::BinarySensor * authorizer_
bool status_indicator_state_
improv::Error error_state_
BLECharacteristic * status_
uint32_t authorized_duration_
void set_state_(improv::State state)
float get_setup_priority() const override
void set_status_indicator_state_(bool state)
uint32_t identify_duration_
uint32_t authorized_start_
CallbackManager< void(improv::State, improv::Error)> state_callback_
void dump_config() override
std::vector< uint8_t > incoming_data_
void set_error_(improv::Error error)
BLECharacteristic * rpc_response_
void process_incoming_data_()
void setup_characteristics()
BLECharacteristic * capabilities_
BLECharacteristic * error_
wifi::WiFiAP connecting_sta_
output::BinaryOutput * status_indicator_
const char * state_to_string_(improv::State state)
EventEmitterListenerID on(EvtType event, std::function< void(Args...)> listener)
virtual void turn_off()
Disable this binary output.
virtual void turn_on()
Enable this binary output.
const std::string & get_ssid() const
void set_ssid(const std::string &ssid)
void set_sta(const WiFiAP &ap)
void save_wifi_sta(const std::string &ssid, const std::string &password)
void start_connecting(const WiFiAP &ap, bool two)
BLEServer * global_ble_server
ESP32ImprovComponent * global_improv_component
const float AFTER_BLUETOOTH
WiFiComponent * global_wifi_component
Providing packet encoding functions for exchanging data with a remote host.
std::string format_hex_pretty(const uint8_t *data, size_t length, char separator, bool show_length)
Format a byte array in pretty-printed, human-readable hex format.
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.