12namespace improv_serial {
14static const char *
const TAG =
"improv_serial";
20#elif defined(USE_ARDUINO)
25 this->
state_ = improv::STATE_PROVISIONED;
35 ESP_LOGV(TAG,
"Timeout");
39 while (
byte.has_value()) {
49 if (this->
state_ == improv::STATE_PROVISIONING) {
52 this->connecting_sta_.get_password());
72#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
73 !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3)
79 uart_get_buffered_data_len(this->
uart_num_, &available);
81 uart_read_bytes(this->
uart_num_, &data, 1, 0);
86#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC)
88 if (esp_usb_console_available_for_read()) {
89 esp_usb_console_read_buf((
char *) &data, 1);
94#ifdef USE_LOGGER_USB_SERIAL_JTAG
96 if (usb_serial_jtag_read_bytes((
char *) &data, 1, 0)) {
105#elif defined(USE_ARDUINO)
118 const bool there_is_data = data !=
nullptr && size > 0;
120 const uint8_t header_checksum_len = there_is_data ? TX_BUFFER_SIZE - 3 : TX_BUFFER_SIZE - 2;
122 const uint8_t header_tx_len = there_is_data ? TX_BUFFER_SIZE - 3 : TX_BUFFER_SIZE;
125 for (uint8_t i = 0; i < header_checksum_len; i++) {
130 for (
size_t i = 0; i < size; i++) {
140#if !defined(USE_ESP32_VARIANT_ESP32C3) && !defined(USE_ESP32_VARIANT_ESP32C6) && \
141 !defined(USE_ESP32_VARIANT_ESP32C61) && !defined(USE_ESP32_VARIANT_ESP32S2) && !defined(USE_ESP32_VARIANT_ESP32S3)
146 uart_write_bytes(this->
uart_num_, data, size);
150#if defined(USE_LOGGER_USB_CDC) && defined(CONFIG_ESP_CONSOLE_USB_CDC)
152 esp_usb_console_write_buf((
const char *) this->
tx_header_, header_tx_len);
154 esp_usb_console_write_buf((
const char *) data, size);
155 esp_usb_console_write_buf((
const char *) &this->tx_header_[TX_CHECKSUM_IDX],
160#ifdef USE_LOGGER_USB_SERIAL_JTAG
162 usb_serial_jtag_write_bytes((
const char *) this->tx_header_, header_tx_len, 20 / portTICK_PERIOD_MS);
164 usb_serial_jtag_write_bytes((
const char *) data, size, 20 / portTICK_PERIOD_MS);
165 usb_serial_jtag_write_bytes((
const char *) &this->tx_header_[TX_CHECKSUM_IDX], 2,
166 20 / portTICK_PERIOD_MS);
173#elif defined(USE_ARDUINO)
183 std::vector<std::string> urls;
184#ifdef USE_IMPROV_SERIAL_NEXT_URL
186 char url_buffer[384];
189 urls.emplace_back(url_buffer,
len);
196 char ip_buf[network::IP_ADDRESS_BUFFER_SIZE];
199 char webserver_url[7 + network::IP_ADDRESS_BUFFER_SIZE + 1 + 5 + 1];
200 snprintf(webserver_url,
sizeof(webserver_url),
"http://%s:%u", ip_buf, USE_WEBSERVER_PORT);
201 urls.emplace_back(webserver_url);
206 std::vector<uint8_t> data = improv::build_rpc_response(command, urls,
false);
211#ifdef ESPHOME_PROJECT_NAME
212 std::vector<std::string> infos = {ESPHOME_PROJECT_NAME, ESPHOME_PROJECT_VERSION, ESPHOME_VARIANT,
App.
get_name()};
214 std::vector<std::string> infos = {
"ESPHome", ESPHOME_VERSION, ESPHOME_VARIANT,
App.
get_name()};
216 std::vector<uint8_t> data = improv::build_rpc_response(improv::GET_DEVICE_INFO, infos,
false);
223 ESP_LOGV(TAG,
"Byte: 0x%02X",
byte);
226 return improv::parse_improv_serial_byte(
228 [
this](improv::Error error) ->
void {
229 ESP_LOGW(TAG,
"Error decoding payload");
235 switch (command.command) {
236 case improv::WIFI_SETTINGS: {
239 sta.set_password(command.password);
245 ESP_LOGD(TAG,
"Received settings: SSID=%s, password=" LOG_SECRET(
"%s"), command.ssid.c_str(),
246 command.password.c_str());
249 this->
set_timeout(
"wifi-connect-timeout", 30000, f);
252 case improv::GET_CURRENT_STATE:
254 if (this->
state_ == improv::STATE_PROVISIONED) {
259 case improv::GET_DEVICE_INFO: {
264 case improv::GET_WIFI_NETWORKS: {
265 std::vector<std::string> networks;
267 for (
auto &scan : results) {
268 if (scan.get_is_hidden())
270 const std::string &ssid = scan.get_ssid();
271 if (std::find(networks.begin(), networks.end(), ssid) != networks.end())
276 std::vector<uint8_t> data =
277 improv::build_rpc_response(improv::GET_WIFI_NETWORKS, {ssid, rssi_buf, YESNO(scan.get_with_auth())},
false);
279 networks.push_back(ssid);
282 std::vector<uint8_t> data =
283 improv::build_rpc_response(improv::GET_WIFI_NETWORKS, std::vector<std::string>{},
false);
288 ESP_LOGW(TAG,
"Unknown payload");
310 this->
write_data_(response.data(), response.size());
314 this->
set_error_(improv::ERROR_UNABLE_TO_CONNECT);
316 ESP_LOGW(TAG,
"Timed out while connecting to Wi-Fi network");
const std::string & get_name() const
Get the name of this Application set by pre_setup().
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") bool cancel_timeout(const std boo cancel_timeout)(const char *name)
Cancel a timeout function.
size_t get_formatted_next_url_(char *buffer, size_t buffer_size)
Format next_url_ into buffer, replacing placeholders. Returns length written.
std::vector< uint8_t > rx_buffer_
std::vector< uint8_t > build_rpc_settings_response_(improv::Command command)
void set_state_(improv::State state)
wifi::WiFiAP connecting_sta_
void on_wifi_connect_timeout_()
void write_data_(const uint8_t *data=nullptr, size_t size=0)
void send_response_(std::vector< uint8_t > &response)
void dump_config() override
bool parse_improv_serial_byte_(uint8_t byte)
optional< uint8_t > read_byte_()
std::vector< uint8_t > build_version_info_()
uint8_t tx_header_[TX_BUFFER_SIZE]
bool parse_improv_payload_(improv::ImprovCommand &command)
void set_error_(improv::Error error)
Stream * get_hw_serial() const
uart_port_t get_uart_num() const
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)
const wifi_scan_vector_t< WiFiScanResult > & get_scan_result() const
ImprovSerialComponent * global_improv_serial_component
@ UART_SELECTION_USB_SERIAL_JTAG
WiFiComponent * global_wifi_component
Providing packet encoding functions for exchanging data with a remote host.
char * int8_to_str(char *buf, int8_t val)
Write int8 value to buffer without modulo operations.
uint32_t IRAM_ATTR HOT millis()
Application App
Global storage of Application pointer - only one Application can exist.