/* Taken from Wi-Fi Provisioning Manager Example of ESP-IDF 4.3 */ #include #include #include #include #include #include #include #include #include #include #include #include static const char *TAG = "nm"; /* Signal Wi-Fi events on this event-group */ const int WIFI_CONNECTED_EVENT = BIT0; static EventGroupHandle_t wifi_event_group; /* Event handler for catching system events */ static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { if (event_base == WIFI_PROV_EVENT) { switch (event_id) { case WIFI_PROV_START: ESP_LOGI(TAG, "Provisioning started"); break; case WIFI_PROV_CRED_RECV: { wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data; ESP_LOGI(TAG, "Received Wi-Fi credentials" "\n\tSSID : %s\n\tPassword : %s", (const char *) wifi_sta_cfg->ssid, (const char *) wifi_sta_cfg->password); break; } case WIFI_PROV_CRED_FAIL: { wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data; ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s" "\n\tPlease reset to factory and retry provisioning", (*reason == WIFI_PROV_STA_AUTH_ERROR) ? "Wi-Fi station authentication failed" : "Wi-Fi access-point not found"); break; } case WIFI_PROV_CRED_SUCCESS: ESP_LOGI(TAG, "Provisioning successful"); break; case WIFI_PROV_END: /* De-initialize manager once provisioning is finished */ wifi_prov_mgr_deinit(); break; default: break; } } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) { 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, "Connected with IP Address:" IPSTR, IP2STR(&event->ip_info.ip)); /* Signal main application to continue execution */ xEventGroupSetBits(wifi_event_group, WIFI_CONNECTED_EVENT); } else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) { ESP_LOGI(TAG, "Disconnected. Connecting to the AP again..."); esp_wifi_connect(); } } static void wifi_init_sta(void) { /* Start Wi-Fi in station mode */ ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); ESP_ERROR_CHECK(esp_wifi_start()); } static void get_device_service_name(char *service_name, size_t max) { uint8_t eth_mac[6]; const char *ssid_prefix = "PROV_"; esp_wifi_get_mac(WIFI_IF_STA, eth_mac); snprintf(service_name, max, "%s%02X%02X%02X", ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]); } /* Handler for the optional provisioning endpoint registered by the application. * The data format can be chosen by applications. Here, we are using plain ascii text. * Applications can choose to use other formats like protobuf, JSON, XML, etc. */ esp_err_t custom_prov_data_handler(uint32_t session_id, const uint8_t *inbuf, ssize_t inlen, uint8_t **outbuf, ssize_t *outlen, void *priv_data) { if (inbuf) { ESP_LOGI(TAG, "Received data: %.*s", inlen, (char *)inbuf); } char response[] = "SUCCESS"; *outbuf = (uint8_t *)strdup(response); if (*outbuf == NULL) { ESP_LOGE(TAG, "System out of memory"); return ESP_ERR_NO_MEM; } *outlen = strlen(response) + 1; /* +1 for NULL terminating byte */ return ESP_OK; } void networkInit(bool forceProv) { ESP_LOGI(TAG, "forceProv: %d", forceProv); /* Initialize TCP/IP */ ESP_ERROR_CHECK(esp_netif_init()); /* Initialize the event loop */ ESP_ERROR_CHECK(esp_event_loop_create_default()); wifi_event_group = xEventGroupCreate(); /* Register our event handler for Wi-Fi, IP and Provisioning related events */ ESP_ERROR_CHECK(esp_event_handler_register(WIFI_PROV_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL)); ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &event_handler, NULL)); /* Initialize Wi-Fi including netif with default config */ esp_netif_create_default_wifi_sta(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_wifi_init(&cfg)); /* Configuration for the provisioning manager */ wifi_prov_mgr_config_t config = { /* What is the Provisioning Scheme that we want ? * wifi_prov_scheme_softap or wifi_prov_scheme_ble */ .scheme = wifi_prov_scheme_ble, /* Any default scheme specific event handler that you would * like to choose. Since our example application requires * neither BT nor BLE, we can choose to release the associated * memory once provisioning is complete, or not needed * (in case when device is already provisioned). Choosing * appropriate scheme specific event handler allows the manager * to take care of this automatically. This can be set to * WIFI_PROV_EVENT_HANDLER_NONE when using wifi_prov_scheme_softap*/ .scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM }; /* Initialize provisioning manager with the * configuration parameters set above */ ESP_ERROR_CHECK(wifi_prov_mgr_init(config)); bool provisioned = false; /* Let's find out if the device is provisioned */ ESP_ERROR_CHECK(wifi_prov_mgr_is_provisioned(&provisioned)); /* If device is not yet provisioned start provisioning service */ if (forceProv || !provisioned) { ESP_LOGI(TAG, "Starting provisioning"); /* What is the Device Service Name that we want * This translates to : * - Wi-Fi SSID when scheme is wifi_prov_scheme_softap * - device name when scheme is wifi_prov_scheme_ble */ char service_name[12]; get_device_service_name(service_name, sizeof(service_name)); /* What is the security level that we want (0 or 1): * - WIFI_PROV_SECURITY_0 is simply plain text communication. * - WIFI_PROV_SECURITY_1 is secure communication which consists of secure handshake * using X25519 key exchange and proof of possession (pop) and AES-CTR * for encryption/decryption of messages. */ wifi_prov_security_t security = WIFI_PROV_SECURITY_1; /* Do we want a proof-of-possession (ignored if Security 0 is selected): * - this should be a string with length > 0 * - NULL if not used */ const char *pop = "abcd1234"; /* What is the service key (could be NULL) * This translates to : * - Wi-Fi password when scheme is wifi_prov_scheme_softap * - simply ignored when scheme is wifi_prov_scheme_ble */ const char *service_key = NULL; /* This step is only useful when scheme is wifi_prov_scheme_ble. This will * set a custom 128 bit UUID which will be included in the BLE advertisement * and will correspond to the primary GATT service that provides provisioning * endpoints as GATT characteristics. Each GATT characteristic will be * formed using the primary service UUID as base, with different auto assigned * 12th and 13th bytes (assume counting starts from 0th byte). The client side * applications must identify the endpoints by reading the User Characteristic * Description descriptor (0x2901) for each characteristic, which contains the * endpoint name of the characteristic */ uint8_t custom_service_uuid[] = { /* LSB <--------------------------------------- * ---------------------------------------> MSB */ 0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf, 0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02, }; wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid); /* An optional endpoint that applications can create if they expect to * get some additional custom data during provisioning workflow. * The endpoint name can be anything of your choice. * This call must be made before starting the provisioning. */ wifi_prov_mgr_endpoint_create("custom-data"); /* Start provisioning service */ ESP_ERROR_CHECK(wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key)); /* The handler for the optional endpoint created above. * This call must be made after starting the provisioning, and only if the endpoint * has already been created above. */ wifi_prov_mgr_endpoint_register("custom-data", custom_prov_data_handler, NULL); /* Uncomment the following to wait for the provisioning to finish and then release * the resources of the manager. Since in this case de-initialization is triggered * by the default event loop handler, we don't need to call the following */ // wifi_prov_mgr_wait(); // wifi_prov_mgr_deinit(); } else { ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA"); /* We don't need the manager as device is already provisioned, * so let's release it's resources */ wifi_prov_mgr_deinit(); /* Start Wi-Fi station */ wifi_init_sta(); } /* Wait for Wi-Fi connection */ xEventGroupWaitBits(wifi_event_group, WIFI_CONNECTED_EVENT, false, true, portMAX_DELAY); }