| @@ -0,0 +1,7 @@ | |||||
| build | |||||
| main/wifi_cfg.hpp | |||||
| CMakeFiles | |||||
| CMakeCache.txt | |||||
| sdkconfig | |||||
| sdkconfig.old | |||||
| main/broker.pem | |||||
| @@ -0,0 +1,8 @@ | |||||
| # The following lines of boilerplate have to be in your project's | |||||
| # CMakeLists in this exact order for cmake to work correctly | |||||
| cmake_minimum_required(VERSION 3.16) | |||||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | |||||
| project(blinky) | |||||
| target_add_binary_data(blinky.elf "main/broker.pem" TEXT) | |||||
| @@ -0,0 +1,29 @@ | |||||
| idf_component_register( | |||||
| SRCS | |||||
| "main.cpp" | |||||
| "wifi.cpp" | |||||
| "http_serv.cpp" | |||||
| "ota.cpp" | |||||
| "mqtt.cpp" | |||||
| INCLUDE_DIRS "." | |||||
| ) | |||||
| # Build static library, do not build test executables | |||||
| option(BUILD_SHARED_LIBS OFF) | |||||
| option(BUILD_TESTING OFF) | |||||
| # Unfortunately the library performs install and export. Would | |||||
| # have been nice if devs made that an option like BUILD_SHARED_LIBS | |||||
| # and BUILD_TESTING. Override install() and export() to do nothing | |||||
| # instead. | |||||
| function(install) | |||||
| endfunction() | |||||
| function(export) | |||||
| endfunction() | |||||
| # Import tinyxml2 targets | |||||
| #add_subdirectory(lib/tinyxml2) | |||||
| # Link tinyxml2 to main component | |||||
| #target_link_libraries(${COMPONENT_LIB} PUBLIC tinyxml2) | |||||
| @@ -0,0 +1,20 @@ | |||||
| menu "* Project: MQTT Broker Configuration" | |||||
| config BROKER_URI | |||||
| string "Broker URL" | |||||
| default "mqtts://mqtt.eclipseprojects.io:8883" | |||||
| help | |||||
| URL of an mqtt broker which this client connects to. | |||||
| config BROKER_USER | |||||
| string "Broker user" | |||||
| default "blinky" | |||||
| help | |||||
| Username for the mqtt broker. | |||||
| config BROKER_PASSWORD | |||||
| string "Broker password" | |||||
| help | |||||
| Password for the mqtt broker. | |||||
| endmenu | |||||
| @@ -0,0 +1,24 @@ | |||||
| static const char *TAG = "http_serv"; | |||||
| #include "esp_log.h" | |||||
| #include "http_serv.hpp" | |||||
| httpd_handle_t start_webserver(void) { | |||||
| ESP_LOGI(TAG, "Starting HTTP server"); | |||||
| // Default configuration, EXCEPT for the wildcard URI match | |||||
| httpd_config_t config = HTTPD_DEFAULT_CONFIG(); | |||||
| config.stack_size = 4096 * 4; | |||||
| config.uri_match_fn = httpd_uri_match_wildcard; | |||||
| // Start the httpd server | |||||
| httpd_handle_t server = NULL; | |||||
| ESP_ERROR_CHECK(httpd_start(&server, &config)); | |||||
| return server; | |||||
| } | |||||
| void stop_webserver(httpd_handle_t server) { | |||||
| if (server) httpd_stop(server); | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| #pragma once | |||||
| #include <esp_http_server.h> | |||||
| httpd_handle_t start_webserver(void); | |||||
| void stop_webserver(httpd_handle_t server); | |||||
| @@ -0,0 +1,115 @@ | |||||
| static const char *TAG = "blinky"; | |||||
| #include <esp_log.h> | |||||
| #include <freertos/FreeRTOS.h> | |||||
| #include <freertos/task.h> | |||||
| #include <esp_spiffs.h> | |||||
| #include <nvs_flash.h> | |||||
| #include "wifi.hpp" | |||||
| #include "http_serv.hpp" | |||||
| #include "ota.hpp" | |||||
| #include "mqtt.hpp" | |||||
| // mDNS / NetBIOS | |||||
| #include <mdns.h> | |||||
| #include <lwip/apps/netbiosns.h> | |||||
| static void start_mdns_service(const char *hostname) { | |||||
| // Initialize mDNS service | |||||
| ESP_ERROR_CHECK(mdns_init()); | |||||
| // Set hostname | |||||
| mdns_hostname_set(hostname); | |||||
| // Set default instance | |||||
| mdns_instance_name_set("Blinky Lights"); | |||||
| // NetBIOS too | |||||
| netbiosns_init(); | |||||
| netbiosns_set_name(hostname); | |||||
| } | |||||
| // Dummy FS | |||||
| static void start_filesystem() { | |||||
| ESP_LOGI(TAG, "Initializing filesystem"); | |||||
| esp_vfs_spiffs_conf_t conf = { | |||||
| .base_path = "/spiffs", | |||||
| .partition_label = NULL, | |||||
| .max_files = 5, | |||||
| .format_if_mount_failed = true | |||||
| }; | |||||
| // Use settings defined above to initialize and mount SPIFFS filesystem. | |||||
| // Note: esp_vfs_spiffs_register is an all-in-one convenience function. | |||||
| ESP_ERROR_CHECK(esp_vfs_spiffs_register(&conf)); | |||||
| } | |||||
| #include <string> | |||||
| #include <dirent.h> | |||||
| #include <sys/stat.h> | |||||
| #include <errno.h> | |||||
| static void log_dir(const std::string &path) { | |||||
| struct stat st; | |||||
| int err = stat(path.c_str(), &st); | |||||
| if (err < 0) { | |||||
| ESP_LOGE(TAG, "%s %d", path.c_str(), errno); | |||||
| } else { | |||||
| ESP_LOGI(TAG, "%s %d", path.c_str(), st.st_size); | |||||
| } | |||||
| DIR *dir; | |||||
| if ((dir = opendir(path.c_str())) == NULL) { | |||||
| //ESP_LOGE(TAG, "Failed to open %s", path.c_str()); | |||||
| return; | |||||
| } | |||||
| struct dirent *de; | |||||
| while ((de = readdir(dir)) != NULL) { | |||||
| log_dir(path + "/" + de->d_name); | |||||
| } | |||||
| closedir(dir); | |||||
| } | |||||
| // Entry Point | |||||
| extern "C" void app_main(void) { | |||||
| // Initialize NVS for WiFi Data | |||||
| esp_err_t ret = nvs_flash_init(); | |||||
| if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) { | |||||
| ESP_ERROR_CHECK(nvs_flash_erase()); | |||||
| ret = nvs_flash_init(); | |||||
| } | |||||
| ESP_ERROR_CHECK(ret); | |||||
| // WiFi | |||||
| config_wifi(); | |||||
| // mDNS | |||||
| start_mdns_service("blinky-jr"); | |||||
| // HTTP Server | |||||
| httpd_handle_t server = start_webserver(); | |||||
| // OTA Server | |||||
| start_ota_serv(server); | |||||
| // Dummy Filesystem | |||||
| start_filesystem(); | |||||
| log_dir("/spiffs"); | |||||
| // TODO: Something useful | |||||
| esp_mqtt_client_handle_t client = start_mqtt_client(NULL, NULL, NULL); | |||||
| esp_mqtt_client_subscribe(client, "#", 0); | |||||
| // Spin | |||||
| } | |||||
| @@ -0,0 +1,108 @@ | |||||
| static const char *TAG = "mqtt"; | |||||
| #include <esp_log.h> | |||||
| #include "mqtt.hpp" | |||||
| extern const uint8_t broker_pem_start[] asm("_binary_broker_pem_start"); | |||||
| typedef struct { | |||||
| mqtt_connect_handler connect; | |||||
| mqtt_message_handler message; | |||||
| void* data; | |||||
| } mqtt_client_data; | |||||
| static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) { | |||||
| mqtt_client_data *client_data = (mqtt_client_data*)handler_args; | |||||
| ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id); | |||||
| esp_mqtt_event_handle_t event = (esp_mqtt_event_handle_t)event_data; | |||||
| esp_mqtt_client_handle_t client = event->client; | |||||
| int msg_id; | |||||
| switch ((esp_mqtt_event_id_t)event_id) { | |||||
| case MQTT_EVENT_CONNECTED: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED"); | |||||
| if (client_data && client_data->connect) { | |||||
| client_data->connect(client, client_data->data); | |||||
| } | |||||
| break; | |||||
| case MQTT_EVENT_DISCONNECTED: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED"); | |||||
| break; | |||||
| case MQTT_EVENT_SUBSCRIBED: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id); | |||||
| break; | |||||
| case MQTT_EVENT_UNSUBSCRIBED: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id); | |||||
| break; | |||||
| case MQTT_EVENT_PUBLISHED: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id); | |||||
| break; | |||||
| case MQTT_EVENT_DATA: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_DATA"); | |||||
| printf("TOPIC=%.*s\r\n", event->topic_len, event->topic); | |||||
| printf("DATA=%.*s\r\n", event->data_len, event->data); | |||||
| if (client_data && client_data->message) { | |||||
| client_data->message(client, event, client_data->data); | |||||
| } | |||||
| break; | |||||
| case MQTT_EVENT_ERROR: | |||||
| ESP_LOGI(TAG, "MQTT_EVENT_ERROR"); | |||||
| if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) { | |||||
| ESP_LOGI(TAG, "Last error code reported from esp-tls: 0x%x", event->error_handle->esp_tls_last_esp_err); | |||||
| ESP_LOGI(TAG, "Last tls stack error number: 0x%x", event->error_handle->esp_tls_stack_err); | |||||
| ESP_LOGI(TAG, "Last captured errno : %d (%s)", event->error_handle->esp_transport_sock_errno, | |||||
| strerror(event->error_handle->esp_transport_sock_errno)); | |||||
| } else if (event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) { | |||||
| ESP_LOGI(TAG, "Connection refused error: 0x%x", event->error_handle->connect_return_code); | |||||
| } else { | |||||
| ESP_LOGW(TAG, "Unknown error type: 0x%x", event->error_handle->error_type); | |||||
| } | |||||
| break; | |||||
| /* | |||||
| case MQTT_USER_EVENT: | |||||
| event->data = (char*)handler_args; | |||||
| break; | |||||
| */ | |||||
| default: | |||||
| ESP_LOGI(TAG, "Other event id:%d", event->event_id); | |||||
| break; | |||||
| } | |||||
| } | |||||
| esp_mqtt_client_handle_t start_mqtt_client( | |||||
| mqtt_connect_handler connect, | |||||
| mqtt_message_handler message, | |||||
| void* data | |||||
| ) { | |||||
| ESP_LOGI(TAG, "Starting MQTT client"); | |||||
| mqtt_client_data* client_data = (mqtt_client_data*)malloc(sizeof(*client_data)); | |||||
| client_data->connect = connect; | |||||
| client_data->message = message; | |||||
| client_data->data = data; | |||||
| const esp_mqtt_client_config_t mqtt_cfg = { | |||||
| .uri = CONFIG_BROKER_URI, | |||||
| .cert_pem = (const char *)broker_pem_start, | |||||
| .username = CONFIG_BROKER_USER, | |||||
| .password = CONFIG_BROKER_PASSWORD, | |||||
| }; | |||||
| esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt_cfg); | |||||
| esp_mqtt_client_register_event(client, MQTT_EVENT_ANY, mqtt_event_handler, client_data); | |||||
| esp_mqtt_client_start(client); | |||||
| return client; | |||||
| } | |||||
| void stop_mqtt_client(esp_mqtt_client_handle_t client) { | |||||
| /* | |||||
| // Hijack the user event to grab the client data on the heap | |||||
| esp_mqtt_event_t event; | |||||
| esp_mqtt_dispatch_custom_event(client, &event); | |||||
| esp_mqtt_client_stop(client); | |||||
| free((mqtt_client_data*)event->data) | |||||
| */ | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| #pragma once | |||||
| #include <mqtt_client.h> | |||||
| typedef void (*mqtt_connect_handler)( | |||||
| esp_mqtt_client_handle_t, void* | |||||
| ); | |||||
| typedef void (*mqtt_message_handler)( | |||||
| esp_mqtt_client_handle_t, esp_mqtt_event_handle_t, void* | |||||
| ); | |||||
| esp_mqtt_client_handle_t start_mqtt_client( | |||||
| mqtt_connect_handler, mqtt_message_handler, void* | |||||
| ); | |||||
| void stop_mqtt_client(esp_mqtt_client_handle_t); | |||||
| @@ -0,0 +1,163 @@ | |||||
| static const char *TAG = "ota"; | |||||
| #include <esp_log.h> | |||||
| #include <mdns.h> | |||||
| #include <esp_ota_ops.h> | |||||
| #include <freertos/FreeRTOS.h> | |||||
| #include <freertos/task.h> | |||||
| #include "ota.hpp" | |||||
| // The real version probably lives somewhere else. Too lazy to find it | |||||
| template <class T> static inline T MIN(T a, T b) { return a < b ? a : b; } | |||||
| // TODO: Stick this somewhere useful? | |||||
| static void reboot_soon_task(void*) { | |||||
| int delay_s = 1; | |||||
| ESP_LOGI(TAG, "Rebooting in %d second%s", | |||||
| delay_s, delay_s == 1 ? "" : "s"); | |||||
| vTaskDelay(pdMS_TO_TICKS(delay_s * 1000)); | |||||
| esp_restart(); | |||||
| } | |||||
| static void reboot_soon() { | |||||
| xTaskCreate( | |||||
| reboot_soon_task, "reboot_task", | |||||
| configMINIMAL_STACK_SIZE * 2, // TODO: Choose the best size | |||||
| NULL, 1, NULL | |||||
| ); | |||||
| } | |||||
| // HTTP Server Helpers. | |||||
| // TODO: Share these? | |||||
| static inline esp_err_t serv_err(httpd_req_t *req, const char *msg) { | |||||
| ESP_LOGE(TAG, "%s", msg); | |||||
| return httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, msg); | |||||
| } | |||||
| static inline esp_err_t serv_progress(httpd_req_t *req, int progress) { | |||||
| ESP_LOGI(TAG, "%d%% complete", progress); | |||||
| /* | |||||
| char msg[100]; | |||||
| snprintf(msg, sizeof(msg), "%d%% complete\n", progress); | |||||
| httpd_resp_set_status(req, "102 Processing"); | |||||
| httpd_resp_set_type(req, HTTPD_TYPE_TEXT); | |||||
| return httpd_resp_send(req, msg, HTTPD_RESP_USE_STRLEN); | |||||
| */ | |||||
| return ESP_OK; | |||||
| } | |||||
| // OTA POST | |||||
| static esp_err_t ota_post_handler(httpd_req_t *req) | |||||
| { | |||||
| esp_err_t err; | |||||
| const esp_partition_t *part = esp_ota_get_next_update_partition(NULL); | |||||
| if (!part) return serv_err(req, "Could not find update partition"); | |||||
| int remaining = req->content_len; | |||||
| ESP_LOGI(TAG, "Starting OTA: %d bytes", remaining); | |||||
| esp_ota_handle_t ota; | |||||
| err = esp_ota_begin(part, remaining, &ota); | |||||
| if (err != ESP_OK) { | |||||
| ESP_LOGE(TAG, "esp_ota_begin: %d", err); | |||||
| return serv_err(req, "Could not start OTA"); | |||||
| } | |||||
| constexpr int progress_step = 10; | |||||
| int next_progress = 0; | |||||
| constexpr size_t CHUNK_MAX = 4096; | |||||
| char *chunk_buf = new char[CHUNK_MAX]; | |||||
| while (remaining > 0) { | |||||
| int chunk_size = MIN((unsigned int)remaining, CHUNK_MAX); | |||||
| int nread = httpd_req_recv(req, chunk_buf, chunk_size); | |||||
| if (nread <= 0) { /* 0 return value indicates connection closed */ | |||||
| ESP_LOGE(TAG, "httpd_req_recv(%d): %d", chunk_size, nread); | |||||
| esp_ota_abort(ota); | |||||
| delete[] chunk_buf; | |||||
| /* Check if timeout occurred */ | |||||
| if (nread == HTTPD_SOCK_ERR_TIMEOUT) { | |||||
| /* In case of timeout one can choose to retry calling | |||||
| * httpd_req_recv(), but to keep it simple, here we | |||||
| * respond with an HTTP 408 (Request Timeout) error */ | |||||
| httpd_resp_send_408(req); | |||||
| } | |||||
| /* In case of error, returning ESP_FAIL will | |||||
| * ensure that the underlying socket is closed */ | |||||
| return ESP_FAIL; | |||||
| } | |||||
| err = esp_ota_write(ota, chunk_buf, nread); | |||||
| if (err != ESP_OK) { | |||||
| ESP_LOGE(TAG, "esp_ota_write(%d): %d", nread, err); | |||||
| esp_ota_abort(ota); | |||||
| delete[] chunk_buf; | |||||
| return serv_err(req, "Failed to write OTA chunk"); | |||||
| } | |||||
| remaining -= nread; | |||||
| int progress = 100 * (req->content_len - remaining) / req->content_len; | |||||
| if (progress >= next_progress) { | |||||
| serv_progress(req, progress); | |||||
| next_progress += progress_step; | |||||
| } | |||||
| } | |||||
| delete[] chunk_buf; | |||||
| ESP_LOGI(TAG, "Finalizing OTA"); | |||||
| err = esp_ota_end(ota); | |||||
| if (err != ESP_OK) { | |||||
| ESP_LOGE(TAG, "esp_ota_end: %d", err); | |||||
| esp_ota_abort(ota); | |||||
| return serv_err(req, "Failed to finalize OTA"); | |||||
| } | |||||
| ESP_LOGI(TAG, "Setting new boot partition"); | |||||
| err = esp_ota_set_boot_partition(part); | |||||
| if (err != ESP_OK) { | |||||
| ESP_LOGE(TAG, "esp_ota_set_boot_partition: %d", err); | |||||
| return serv_err(req, "Failed to set partition"); | |||||
| } | |||||
| ESP_LOGI(TAG, "OTA Successful"); | |||||
| httpd_resp_sendstr(req, "OTA Successful\n"); | |||||
| reboot_soon(); | |||||
| return ESP_FAIL; | |||||
| } | |||||
| int start_ota_serv(httpd_handle_t server) { | |||||
| ESP_LOGI(TAG, "Starting OTA server"); | |||||
| // Register handlers (move these to components) | |||||
| httpd_uri_t uri_ota_post = { | |||||
| .uri = "/ota", | |||||
| .method = HTTP_POST, | |||||
| .handler = ota_post_handler, | |||||
| .user_ctx = NULL | |||||
| }; | |||||
| ESP_ERROR_CHECK(httpd_register_uri_handler(server, &uri_ota_post)); | |||||
| // mDNS Entry | |||||
| mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0); | |||||
| mdns_service_instance_name_set("_http", "_tcp", "ESP32S2 OTA"); | |||||
| return 0; | |||||
| } | |||||
| int stop_ota_serv() { | |||||
| // TODO | |||||
| return -1; | |||||
| } | |||||
| @@ -0,0 +1,7 @@ | |||||
| #pragma once | |||||
| #include <esp_http_server.h> | |||||
| int start_ota_serv(httpd_handle_t); | |||||
| int stop_ota_serv(); | |||||
| @@ -0,0 +1,107 @@ | |||||
| static const char *TAG = "WiFi"; | |||||
| #include "esp_log.h" | |||||
| #include "wifi.hpp" | |||||
| // Defines SSID and PASS | |||||
| #include "wifi_cfg.hpp" | |||||
| static const int CONFIG_ESP_MAXIMUM_RETRY = 3; | |||||
| #include "esp_wifi.h" | |||||
| #include "freertos/event_groups.h" | |||||
| static EventGroupHandle_t s_wifi_event_group; | |||||
| #define WIFI_CONNECTED_BIT BIT0 | |||||
| #define WIFI_FAIL_BIT BIT1 | |||||
| static void event_handler(void* arg, esp_event_base_t event_base, | |||||
| int32_t event_id, void* event_data) { | |||||
| static int s_retry_num = 0; | |||||
| if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { | |||||
| esp_wifi_connect(); | |||||
| } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { | |||||
| ESP_LOGI(TAG, "Disconnected, retrying connection to AP"); | |||||
| esp_wifi_connect(); | |||||
| } else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) { | |||||
| ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data; | |||||
| ESP_LOGI(TAG, "Got IP address: " IPSTR, IP2STR(&event->ip_info.ip)); | |||||
| s_retry_num = 0; | |||||
| xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); | |||||
| } | |||||
| } | |||||
| int config_wifi() { | |||||
| ESP_LOGI(TAG, "Connecting to %s", SSID); | |||||
| s_wifi_event_group = xEventGroupCreate(); | |||||
| ESP_ERROR_CHECK(esp_netif_init()); | |||||
| ESP_ERROR_CHECK(esp_event_loop_create_default()); | |||||
| esp_netif_create_default_wifi_sta(); | |||||
| wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); | |||||
| ESP_ERROR_CHECK(esp_wifi_init(&cfg)); | |||||
| esp_event_handler_instance_t instance_any_id; | |||||
| esp_event_handler_instance_t instance_got_ip; | |||||
| ESP_ERROR_CHECK(esp_event_handler_instance_register( | |||||
| WIFI_EVENT, | |||||
| ESP_EVENT_ANY_ID, | |||||
| &event_handler, | |||||
| NULL, | |||||
| &instance_any_id | |||||
| )); | |||||
| ESP_ERROR_CHECK(esp_event_handler_instance_register( | |||||
| IP_EVENT, | |||||
| IP_EVENT_STA_GOT_IP, | |||||
| &event_handler, | |||||
| NULL, | |||||
| &instance_got_ip | |||||
| )); | |||||
| wifi_config_t wifi_config = { | |||||
| .sta = { | |||||
| .ssid = SSID, | |||||
| .password = PASS, | |||||
| }, | |||||
| }; | |||||
| ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); | |||||
| ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); | |||||
| ESP_ERROR_CHECK( esp_wifi_start() ); | |||||
| /* | |||||
| // Waiting until either the connection is established (WIFI_CONNECTED_BIT) | |||||
| // or connection failed for the maximum number of re-tries (WIFI_FAIL_BIT). | |||||
| // The bits are set by event_handler() (see above) | |||||
| EventBits_t bits = xEventGroupWaitBits( | |||||
| s_wifi_event_group, | |||||
| WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, | |||||
| pdFALSE, | |||||
| pdFALSE, | |||||
| portMAX_DELAY | |||||
| ); | |||||
| // xEventGroupWaitBits() returns the bits before the call returned, hence we | |||||
| // can test which event actually happened. | |||||
| if (bits & WIFI_CONNECTED_BIT) { | |||||
| ESP_LOGI(TAG, "Connected to AP: %s", SSID); | |||||
| return 0; | |||||
| } else if (bits & WIFI_FAIL_BIT) { | |||||
| ESP_LOGE(TAG, "Failed to connect to SSID %s", SSID); | |||||
| } else { | |||||
| ESP_LOGE(TAG, "UNEXPECTED EVENT"); | |||||
| } | |||||
| */ | |||||
| return 0; | |||||
| } | |||||
| @@ -0,0 +1,3 @@ | |||||
| #pragma once | |||||
| int config_wifi(); | |||||
| @@ -0,0 +1,8 @@ | |||||
| # Name, Type, SubType, Offset, Size, Flags | |||||
| nvs, data, nvs, 0x9000, 0x4000 | |||||
| otadata, data, ota, , 0x2000 | |||||
| phy_init, data, phy, , 0x1000 | |||||
| factory, app, factory, , 1M | |||||
| ota_0, app, ota_0, , 1M | |||||
| ota_1, app, ota_1, , 1M | |||||
| storage, data, spiffs, , 0xF0000 | |||||