mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-07-02 23:10:08 +08:00
feat(provisioning): Modify component and example for ESP8266
This commit is contained in:
@ -1,28 +1,23 @@
|
||||
if(CONFIG_ENABLE_UNIFIED_PROVISIONING)
|
||||
set(srcs "src/wifi_config.c"
|
||||
"src/wifi_scan.c"
|
||||
"src/manager.c"
|
||||
"src/handlers.c"
|
||||
"src/scheme_softap.c"
|
||||
"src/scheme_console.c"
|
||||
"proto-c/wifi_config.pb-c.c"
|
||||
"proto-c/wifi_scan.pb-c.c"
|
||||
"proto-c/wifi_constants.pb-c.c")
|
||||
|
||||
if(CONFIG_BT_ENABLED)
|
||||
if(CONFIG_BT_BLUEDROID_ENABLED OR CONFIG_BT_NIMBLE_ENABLED)
|
||||
list(APPEND srcs
|
||||
"src/scheme_ble.c")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
idf_component_register(SRCS "${srcs}"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS src proto-c ../protocomm/proto-c
|
||||
REQUIRES lwip protocomm
|
||||
PRIV_REQUIRES protobuf-c bt mdns json esp_timer)
|
||||
PRIV_REQUIRES protobuf-c mdns json)
|
||||
|
||||
# To avoid warning for strncpy
|
||||
set_source_files_properties(src/handlers.c src/scheme_softap.c
|
||||
PROPERTIES COMPILE_FLAGS
|
||||
-Wno-stringop-truncation
|
||||
)
|
||||
|
||||
|
@ -1,9 +1,17 @@
|
||||
menu "Wi-Fi Provisioning Manager"
|
||||
|
||||
config ENABLE_UNIFIED_PROVISIONING
|
||||
bool "Enable Unified Provisioning"
|
||||
default n
|
||||
select ENABLE_MDNS
|
||||
help
|
||||
This enables Unified Provisioning feature along with required components like Wifi-Provisioning, Protocomm and their mbedtls dependencies.
|
||||
|
||||
config WIFI_PROV_SCAN_MAX_ENTRIES
|
||||
int "Max Wi-Fi Scan Result Entries"
|
||||
default 16
|
||||
range 1 255
|
||||
depends on ENABLE_UNIFIED_PROVISIONING
|
||||
help
|
||||
This sets the maximum number of entries of Wi-Fi scan results that will be kept by the provisioning manager
|
||||
|
||||
@ -11,6 +19,7 @@ menu "Wi-Fi Provisioning Manager"
|
||||
int "Provisioning auto-stop timeout"
|
||||
default 30
|
||||
range 5 600
|
||||
depends on ENABLE_UNIFIED_PROVISIONING
|
||||
help
|
||||
Time (in seconds) after which the Wi-Fi provisioning manager will auto-stop after connecting to
|
||||
a Wi-Fi network successfully.
|
||||
|
@ -1,13 +1,11 @@
|
||||
COMPONENT_SRCDIRS :=
|
||||
COMPONENT_ADD_INCLUDEDIRS :=
|
||||
|
||||
ifdef CONFIG_ENABLE_UNIFIED_PROVISIONING
|
||||
COMPONENT_SRCDIRS := src proto-c
|
||||
COMPONENT_ADD_INCLUDEDIRS := include
|
||||
COMPONENT_PRIV_INCLUDEDIRS := src proto-c ../protocomm/proto-c/
|
||||
|
||||
# To avoid warning for strncpy in "handlers.c" and "scheme_softap.c"
|
||||
CPPFLAGS += -Wno-stringop-truncation
|
||||
|
||||
ifndef CONFIG_BT_BLUEDROID_ENABLED
|
||||
ifndef CONFIG_BT_NIMBLE_ENABLED
|
||||
COMPONENT_OBJEXCLUDE := src/scheme_ble.o
|
||||
endif
|
||||
endif
|
||||
|
||||
|
@ -1,82 +0,0 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_ble.h>
|
||||
|
||||
#include "wifi_provisioning/manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Scheme that can be used by manager for provisioning
|
||||
* over BLE transport with GATT server
|
||||
*/
|
||||
extern const wifi_prov_scheme_t wifi_prov_scheme_ble;
|
||||
|
||||
/* This scheme specific event handler is to be used when application
|
||||
* doesn't require BT and BLE after provisioning has finished */
|
||||
#define WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM { \
|
||||
.event_cb = wifi_prov_scheme_ble_event_cb_free_btdm, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
/* This scheme specific event handler is to be used when application
|
||||
* doesn't require BLE to be active after provisioning has finished */
|
||||
#define WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE { \
|
||||
.event_cb = wifi_prov_scheme_ble_event_cb_free_ble, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
/* This scheme specific event handler is to be used when application
|
||||
* doesn't require BT to be active after provisioning has finished */
|
||||
#define WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT { \
|
||||
.event_cb = wifi_prov_scheme_ble_event_cb_free_bt, \
|
||||
.user_data = NULL \
|
||||
}
|
||||
|
||||
void wifi_prov_scheme_ble_event_cb_free_btdm(void *user_data, wifi_prov_cb_event_t event, void *event_data);
|
||||
void wifi_prov_scheme_ble_event_cb_free_ble (void *user_data, wifi_prov_cb_event_t event, void *event_data);
|
||||
void wifi_prov_scheme_ble_event_cb_free_bt (void *user_data, wifi_prov_cb_event_t event, void *event_data);
|
||||
|
||||
/**
|
||||
* @brief Set the 128 bit GATT service UUID used for provisioning
|
||||
*
|
||||
* This API is used to override the default 128 bit provisioning
|
||||
* service UUID, which is 0000ffff-0000-1000-8000-00805f9b34fb.
|
||||
*
|
||||
* This must be called before starting provisioning, i.e. before
|
||||
* making a call to wifi_prov_mgr_start_provisioning(), otherwise
|
||||
* the default UUID will be used.
|
||||
*
|
||||
* @note The data being pointed to by the argument must be valid
|
||||
* atleast till provisioning is started. Upon start, the
|
||||
* manager will store an internal copy of this UUID, and
|
||||
* this data can be freed or invalidated afterwords.
|
||||
*
|
||||
* @param[in] uuid128 A custom 128 bit UUID
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Success
|
||||
* - ESP_ERR_INVALID_ARG : Null argument
|
||||
*/
|
||||
esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -1,34 +0,0 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_console.h>
|
||||
|
||||
#include "wifi_provisioning/manager.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Scheme that can be used by manager for provisioning
|
||||
* over console (Serial UART)
|
||||
*/
|
||||
extern const wifi_prov_scheme_t wifi_prov_scheme_console;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
@ -64,10 +64,10 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi
|
||||
ESP_LOGD(TAG, "Got state : connected");
|
||||
|
||||
/* IP Addr assigned to STA */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
|
||||
|
||||
tcpip_adapter_ip_info_t ip_info;
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
|
||||
char *ip_addr = ip4addr_ntoa(&ip_info.ip);
|
||||
strcpy(resp_data->conn_info.ip_addr, ip_addr);
|
||||
|
||||
/* AP information to which STA is connected */
|
||||
wifi_ap_record_t ap_info;
|
||||
|
@ -880,6 +880,10 @@ static void wifi_prov_mgr_event_handler_internal(
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
prov_ctx->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
if (disconnected->reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||
}
|
||||
esp_wifi_connect();
|
||||
}
|
||||
|
||||
|
@ -1,232 +0,0 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_bt.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_ble.h>
|
||||
|
||||
#include "wifi_provisioning/scheme_ble.h"
|
||||
#include "wifi_provisioning_priv.h"
|
||||
|
||||
static const char *TAG = "wifi_prov_scheme_ble";
|
||||
|
||||
extern const wifi_prov_scheme_t wifi_prov_scheme_ble;
|
||||
|
||||
static uint8_t *custom_service_uuid;
|
||||
|
||||
static esp_err_t prov_start(protocomm_t *pc, void *config)
|
||||
{
|
||||
if (!pc) {
|
||||
ESP_LOGE(TAG, "Protocomm handle cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot start with null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
|
||||
/* Start protocomm as BLE service */
|
||||
if (protocomm_ble_start(pc, ble_config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start protocomm BLE service");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t wifi_prov_scheme_ble_set_service_uuid(uint8_t *uuid128)
|
||||
{
|
||||
if (!uuid128) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
custom_service_uuid = uuid128;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void *new_config(void)
|
||||
{
|
||||
protocomm_ble_config_t *ble_config = calloc(1, sizeof(protocomm_ble_config_t));
|
||||
if (!ble_config) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for new configuration");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* The default provisioning service UUID */
|
||||
const uint8_t service_uuid[16] = {
|
||||
/* LSB <---------------------------------------
|
||||
* ---------------------------------------> MSB */
|
||||
0x07, 0xed, 0x9b, 0x2d, 0x0f, 0x06, 0x7c, 0x87,
|
||||
0x9b, 0x43, 0x43, 0x6b, 0x4d, 0x24, 0x75, 0x17,
|
||||
};
|
||||
|
||||
memcpy(ble_config->service_uuid, service_uuid, sizeof(ble_config->service_uuid));
|
||||
return ble_config;
|
||||
}
|
||||
|
||||
static void delete_config(void *config)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot delete null configuration");
|
||||
return;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
for (unsigned int i = 0; i < ble_config->nu_lookup_count; i++) {
|
||||
free((void *)ble_config->nu_lookup[i].name);
|
||||
}
|
||||
free(ble_config->nu_lookup);
|
||||
free(ble_config);
|
||||
}
|
||||
|
||||
static esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot set null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!service_name) {
|
||||
ESP_LOGE(TAG, "Service name cannot be NULL");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
strlcpy(ble_config->device_name, service_name, sizeof(ble_config->device_name));
|
||||
|
||||
/* If a custom service UUID has been provided, override the default one */
|
||||
if (custom_service_uuid) {
|
||||
memcpy(ble_config->service_uuid, custom_service_uuid, sizeof(ble_config->service_uuid));
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot set null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!endpoint_name) {
|
||||
ESP_LOGE(TAG, "EP name cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_ble_config_t *ble_config = (protocomm_ble_config_t *) config;
|
||||
|
||||
char *copy_ep_name = strdup(endpoint_name);
|
||||
if (!copy_ep_name) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for EP name");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
protocomm_ble_name_uuid_t *lookup_table = (
|
||||
realloc(ble_config->nu_lookup, (ble_config->nu_lookup_count + 1) * sizeof(protocomm_ble_name_uuid_t)));
|
||||
if (!lookup_table) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for EP-UUID lookup table");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
lookup_table[ble_config->nu_lookup_count].name = copy_ep_name;
|
||||
lookup_table[ble_config->nu_lookup_count].uuid = uuid;
|
||||
ble_config->nu_lookup = lookup_table;
|
||||
ble_config->nu_lookup_count += 1;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
/* Used when both BT and BLE are not needed by application */
|
||||
void wifi_prov_scheme_ble_event_cb_free_btdm(void *user_data, wifi_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
esp_err_t err;
|
||||
switch (event) {
|
||||
case WIFI_PROV_INIT:
|
||||
/* Release BT memory, as we need only BLE */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of classic BT failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BT memory released");
|
||||
}
|
||||
break;
|
||||
|
||||
case WIFI_PROV_DEINIT:
|
||||
/* Release memory used by BLE and Bluedroid host stack */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_BTDM);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of BTDM failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BTDM memory released");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Used when BT is not needed by application */
|
||||
void wifi_prov_scheme_ble_event_cb_free_bt(void *user_data, wifi_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
esp_err_t err;
|
||||
switch (event) {
|
||||
case WIFI_PROV_INIT:
|
||||
/* Release BT memory, as we need only BLE */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of classic BT failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BT memory released");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Used when BLE is not needed by application */
|
||||
void wifi_prov_scheme_ble_event_cb_free_ble(void *user_data, wifi_prov_cb_event_t event, void *event_data)
|
||||
{
|
||||
esp_err_t err;
|
||||
switch (event) {
|
||||
case WIFI_PROV_DEINIT:
|
||||
/* Release memory used by BLE stack */
|
||||
err = esp_bt_mem_release(ESP_BT_MODE_BLE);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "bt_mem_release of BLE failed %d", err);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "BLE memory released");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const wifi_prov_scheme_t wifi_prov_scheme_ble = {
|
||||
.prov_start = prov_start,
|
||||
.prov_stop = protocomm_ble_stop,
|
||||
.new_config = new_config,
|
||||
.delete_config = delete_config,
|
||||
.set_config_service = set_config_service,
|
||||
.set_config_endpoint = set_config_endpoint,
|
||||
.wifi_mode = WIFI_MODE_STA
|
||||
};
|
@ -1,92 +0,0 @@
|
||||
// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_console.h>
|
||||
|
||||
#include "wifi_provisioning/scheme_console.h"
|
||||
#include "wifi_provisioning_priv.h"
|
||||
|
||||
static const char *TAG = "wifi_prov_scheme_console";
|
||||
|
||||
extern const wifi_prov_scheme_t wifi_prov_scheme_console;
|
||||
|
||||
static esp_err_t prov_start(protocomm_t *pc, void *config)
|
||||
{
|
||||
if (!pc) {
|
||||
ESP_LOGE(TAG, "Protocomm handle cannot be null");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot start with null configuration");
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
protocomm_console_config_t *console_config = (protocomm_console_config_t *) config;
|
||||
|
||||
/* Start protocomm console */
|
||||
esp_err_t err = protocomm_console_start(pc, console_config);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start protocomm HTTP server");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void *new_config(void)
|
||||
{
|
||||
protocomm_console_config_t *console_config = malloc(sizeof(protocomm_console_config_t));
|
||||
if (!console_config) {
|
||||
ESP_LOGE(TAG, "Error allocating memory for new configuration");
|
||||
return NULL;
|
||||
}
|
||||
protocomm_console_config_t default_config = PROTOCOMM_CONSOLE_DEFAULT_CONFIG();
|
||||
memcpy(console_config, &default_config, sizeof(default_config));
|
||||
return console_config;
|
||||
}
|
||||
|
||||
static void delete_config(void *config)
|
||||
{
|
||||
if (!config) {
|
||||
ESP_LOGE(TAG, "Cannot delete null configuration");
|
||||
return;
|
||||
}
|
||||
free(config);
|
||||
}
|
||||
|
||||
static esp_err_t set_config_service(void *config, const char *service_name, const char *service_key)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_endpoint(void *config, const char *endpoint_name, uint16_t uuid)
|
||||
{
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
const wifi_prov_scheme_t wifi_prov_scheme_console = {
|
||||
.prov_start = prov_start,
|
||||
.prov_stop = protocomm_console_stop,
|
||||
.new_config = new_config,
|
||||
.delete_config = delete_config,
|
||||
.set_config_service = set_config_service,
|
||||
.set_config_endpoint = set_config_endpoint,
|
||||
.wifi_mode = WIFI_MODE_STA
|
||||
};
|
@ -1,6 +0,0 @@
|
||||
# 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.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(ble_prov)
|
@ -1,9 +0,0 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := ble_prov
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -1,208 +0,0 @@
|
||||
| Supported Targets | ESP32 |
|
||||
| ----------------- | ----- |
|
||||
|
||||
# BLE based Provisioning Example (Legacy)
|
||||
|
||||
> Note: It is recommended to use the new `wifi_prov_mgr` example which is based on the simpler `wifi_provisioning` APIs. Check this example only if you wish to use lower level provisioning and protocomm APIs and want more control over the handlers.
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
`ble_prov` example demonstrates the implementation and integration of various IDF components for building a provisioning application.
|
||||
|
||||
For this example BLE is chosen as the mode of transport, over which the provisioning related communication is to take place, between the device (to be provisioned) and the client (owner of the device).
|
||||
|
||||
In the provisioning process the device is configured as a Wi-Fi station with specified credentials. Once configured, the device will retain the Wi-Fi configuration, until a flash erase is performed.
|
||||
|
||||
Right after provisioning is complete, BLE is turned off and disabled to free the memory used by the BLE stack. Though, that is specific to this example, and the user can choose to keep BLE on in their own application.
|
||||
|
||||
`ble_prov` uses the following components :
|
||||
* `wifi_provisioning` : provides data structures and protocomm endpoint handlers for Wi-Fi configuration
|
||||
* `protocomm` : for protocol based communication and secure session establishment
|
||||
* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures
|
||||
* `bt` : ESP32 BLE stack for transport of protobuf packets
|
||||
|
||||
This example can be used, as it is, for adding a provisioning service to any application intended for IoT.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Example should be able to run on any commonly available ESP32 development board.
|
||||
|
||||
### Application Required
|
||||
|
||||
Provisioning applications are available for various platforms. See below
|
||||
|
||||
#### Platform : Android
|
||||
|
||||
For Android, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-android](https://github.com/espressif/esp-idf-provisioning-android)
|
||||
|
||||
#### Platform : iOS
|
||||
|
||||
For iOS, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-ios](https://github.com/espressif/esp-idf-provisioning-ios)
|
||||
|
||||
#### Platform : Linux / Windows / macOS
|
||||
|
||||
To provision the device running this example, the `esp_prov.py` script needs to be run (found under `$IDF_PATH/tools/esp_prov`). Make sure to satisfy all the dependencies prior to running the script.
|
||||
|
||||
Presently, `esp_prov` supports BLE transport only for Linux platform. For Windows/macOS it falls back to console mode and requires another application (for BLE) through which the communication can take place.
|
||||
|
||||
There are various applications, specific to Windows and macOS platform which can be used. The `esp_prov` console will guide you through the provisioning process of locating the correct BLE GATT services and characteristics, the values to write, and input read values.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Under Example Configuration set the following :
|
||||
* Security Version (default 1)
|
||||
* Proof of Possession (default "abcd1234")
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (550) app: Starting BLE provisioning
|
||||
I (1130) app_prov: Provisioning started with BLE devname : PROV_261FCC
|
||||
```
|
||||
|
||||
Make sure to note down the BLE device name (starting with PROV_) displayed in the serial monitor log (eg. PROV_261FCC). This will depend on the MAC ID and will be unique for every device.
|
||||
|
||||
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration :
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_261FCC --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword
|
||||
```
|
||||
|
||||
Above command will perform the provisioning steps, and the monitor log should display something like this :
|
||||
|
||||
```
|
||||
I (682950) app_prov_handler: WiFi Credentials Received :
|
||||
ssid : myssid
|
||||
password : mypassword
|
||||
.
|
||||
.
|
||||
.
|
||||
I (683130) app_prov: STA Start
|
||||
I (683130) app_prov_handler: WiFi Credentials Applied
|
||||
.
|
||||
.
|
||||
.
|
||||
I (688270) app_prov_handler: Connecting state
|
||||
.
|
||||
.
|
||||
.
|
||||
I (688390) app_prov: STA Got IP
|
||||
I (688390) app: got ip:192.168.43.220
|
||||
I (693410) app_prov_handler: Connected state
|
||||
```
|
||||
|
||||
After sometime the provisioning app will exit and BLE will be turned off
|
||||
|
||||
```
|
||||
I (718390) app_prov: Stopping provisioning
|
||||
I (718670) app_prov: Provisioning stopped
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Provisioning failed
|
||||
|
||||
It is possible that the Wi-Fi credentials provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason) and the provisioning app will continue running, allowing the user to retry the process. Serial monitor log will display the failure along with disconnect reason :
|
||||
|
||||
```
|
||||
E (39291) app_prov: STA Disconnected
|
||||
E (39291) app_prov: Disconnect reason : 201
|
||||
I (39291) app_prov: STA AP Not found
|
||||
I (42021) app_prov_handler: Disconnected state
|
||||
```
|
||||
|
||||
### Provisioning does not start
|
||||
|
||||
If the serial monitor log is different, as shown below :
|
||||
|
||||
```
|
||||
I (539) app_prov: Found ssid myssid
|
||||
I (539) app_prov: Found password mypassword
|
||||
I (549) app: Starting WiFi station
|
||||
```
|
||||
|
||||
It means the Wi-Fi credentials were already set by some other application flashed previously to your device. To erase these credentials either do full erase and then flash the example
|
||||
|
||||
```
|
||||
make erase_flash
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution.
|
||||
|
||||
### Unsupported platform
|
||||
|
||||
If the platform requirement, for running `esp_prov` is not satisfied, then the script execution will fallback to console mode, in which case the full process (involving user inputs) will look like this :
|
||||
|
||||
```
|
||||
BLE client is running in console mode
|
||||
This could be due to your platform not being supported or dependencies not being met
|
||||
Please ensure all pre-requisites are met to run the full fledged client
|
||||
BLECLI >> Please connect to BLE device `PROV_261FCC` manually using your tool of choice
|
||||
BLECLI >> Was the device connected successfully? [y/n] y
|
||||
BLECLI >> List available attributes of the connected device
|
||||
BLECLI >> Is the service UUID '0000ffff-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff53-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff51-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff52-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
|
||||
==== Verifying protocol version ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff53-0000-1000-8000-00805f9b34fb' :
|
||||
>> 56302e31
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 53554343455353
|
||||
==== Verified protocol version successfully ====
|
||||
|
||||
==== Starting Session ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :
|
||||
>> 10015a25a201220a20ae6d9d5d1029f8c366892252d2d5a0ffa7ce1ee5829312545dd5f2aba057294d
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 10015a390801aa0134122048008bfc365fad4753dc75912e0c764d60749cb26dd609595b6fbc72e12614031a1089733af233c7448e7d7fb7963682c6d8
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :
|
||||
>> 10015a270802b2012212204051088dc294fe4621fac934a8ea22e948fcc3e8ac458aac088ce705c65dbfb9
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 10015a270803ba01221a20c8d38059d5206a3d92642973ac6ba8ac2f6ecf2b7a3632964eb35a0f20133adb
|
||||
==== Session Established ====
|
||||
|
||||
==== Sending Wifi credential to esp32 ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 98471ac4019a46765c28d87df8c8ae71c1ae6cfe0bc9c615bc6d2c
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 3271f39a
|
||||
==== Wifi Credentials sent successfully ====
|
||||
|
||||
==== Applying config to esp32 ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 5355
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 1664db24
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wifi connection state ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 290d
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 505f72a9f8521025c1964d7789c4d7edc56aedebd144e1b667bc7c0975757b80cc091aa9f3e95b06eaefbc30290fa1
|
||||
++++ WiFi state: connected ++++
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
The write data is to be copied from the console output ```>>``` to the platform specific application and the data read from the application is to be pasted at the user input prompt ```<<``` of the console, in the format (hex) indicated in above sample log.
|
@ -1,102 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
import re
|
||||
import os
|
||||
import time
|
||||
|
||||
import ttfw_idf
|
||||
import esp_prov
|
||||
|
||||
# Have esp_prov throw exception
|
||||
esp_prov.config_throw_except = True
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag="Example_WIFI_BT")
|
||||
def test_examples_provisioning_ble(env, extra_data):
|
||||
# Acquire DUT
|
||||
dut1 = env.get_dut("ble_prov", "examples/provisioning/legacy/ble_prov", dut_class=ttfw_idf.ESP32DUT)
|
||||
|
||||
# Get binary file
|
||||
binary_file = os.path.join(dut1.app.binary_path, "ble_prov.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("ble_prov_bin_size", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("ble_prov_bin_size", bin_size // 1024, dut1.TARGET)
|
||||
|
||||
# Upload binary and start testing
|
||||
dut1.start_app()
|
||||
|
||||
# Parse BLE devname
|
||||
devname = dut1.expect(re.compile(r"Provisioning started with BLE devname : '(PROV_\S\S\S\S\S\S)'"), timeout=60)[0]
|
||||
print("BLE Device Alias for DUT :", devname)
|
||||
|
||||
# Match additional headers sent in the request
|
||||
dut1.expect("BLE Provisioning started", timeout=30)
|
||||
|
||||
print("Starting Provisioning")
|
||||
verbose = False
|
||||
protover = "V0.1"
|
||||
secver = 1
|
||||
pop = "abcd1234"
|
||||
provmode = "ble"
|
||||
ap_ssid = "myssid"
|
||||
ap_password = "mypassword"
|
||||
|
||||
print("Getting security")
|
||||
security = esp_prov.get_security(secver, pop, verbose)
|
||||
if security is None:
|
||||
raise RuntimeError("Failed to get security")
|
||||
|
||||
print("Getting transport")
|
||||
transport = esp_prov.get_transport(provmode, devname)
|
||||
if transport is None:
|
||||
raise RuntimeError("Failed to get transport")
|
||||
|
||||
print("Verifying protocol version")
|
||||
if not esp_prov.version_match(transport, protover):
|
||||
raise RuntimeError("Mismatch in protocol version")
|
||||
|
||||
print("Starting Session")
|
||||
if not esp_prov.establish_session(transport, security):
|
||||
raise RuntimeError("Failed to start session")
|
||||
|
||||
print("Sending Wifi credential to DUT")
|
||||
if not esp_prov.send_wifi_config(transport, security, ap_ssid, ap_password):
|
||||
raise RuntimeError("Failed to send Wi-Fi config")
|
||||
|
||||
print("Applying config")
|
||||
if not esp_prov.apply_wifi_config(transport, security):
|
||||
raise RuntimeError("Failed to send apply config")
|
||||
|
||||
success = False
|
||||
while True:
|
||||
time.sleep(5)
|
||||
print("Wi-Fi connection state")
|
||||
ret = esp_prov.get_wifi_config(transport, security)
|
||||
if (ret == 1):
|
||||
continue
|
||||
elif (ret == 0):
|
||||
print("Provisioning was successful")
|
||||
success = True
|
||||
break
|
||||
|
||||
if not success:
|
||||
raise RuntimeError("Provisioning failed")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_provisioning_ble()
|
@ -1,4 +0,0 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c"
|
||||
INCLUDE_DIRS ".")
|
@ -1,40 +0,0 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_USE_SEC_1
|
||||
bool
|
||||
default y
|
||||
prompt "Use Security Version 1"
|
||||
help
|
||||
Security version 1 used Curve25519 key exchange for establishing
|
||||
secure session between device and client during provisioning
|
||||
|
||||
config EXAMPLE_USE_POP
|
||||
bool
|
||||
depends on EXAMPLE_USE_SEC_1
|
||||
default y
|
||||
prompt "Use proof-of-possession"
|
||||
help
|
||||
Proof-of-possession can be optionally used to prove that the device is indeed
|
||||
in possession of the user who is provisioning the device. This proof-of-possession
|
||||
is internally used to generate the shared secret through key exchange.
|
||||
|
||||
config EXAMPLE_POP
|
||||
string "Proof-of-possession"
|
||||
default "abcd1234"
|
||||
depends on EXAMPLE_USE_POP
|
||||
|
||||
config EXAMPLE_RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
int "Maximum AP connection attempts"
|
||||
default 5
|
||||
help
|
||||
Set the maximum connection attempts to perform when connecting to a Wi-Fi AP.
|
||||
|
||||
endmenu
|
@ -1,145 +0,0 @@
|
||||
/* BLE based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sys.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
#define EXAMPLE_AP_RECONN_ATTEMPTS CONFIG_EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
static void start_ble_provisioning(void);
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
static int s_retry_num_ap_not_found = 0;
|
||||
static int s_retry_num_ap_auth_fail = 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) {
|
||||
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
||||
switch (disconnected->reason) {
|
||||
case WIFI_REASON_AUTH_EXPIRE:
|
||||
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
||||
case WIFI_REASON_BEACON_TIMEOUT:
|
||||
case WIFI_REASON_AUTH_FAIL:
|
||||
case WIFI_REASON_ASSOC_FAIL:
|
||||
case WIFI_REASON_HANDSHAKE_TIMEOUT:
|
||||
ESP_LOGW(TAG, "connect to the AP fail : auth Error");
|
||||
if (s_retry_num_ap_auth_fail < EXAMPLE_AP_RECONN_ATTEMPTS) {
|
||||
s_retry_num_ap_auth_fail++;
|
||||
esp_wifi_connect();
|
||||
ESP_LOGI(TAG, "retry connecting to the AP...");
|
||||
} else {
|
||||
/* Restart provisioning if authentication fails */
|
||||
start_ble_provisioning();
|
||||
}
|
||||
break;
|
||||
case WIFI_REASON_NO_AP_FOUND:
|
||||
ESP_LOGW(TAG, "connect to the AP fail : not found");
|
||||
if (s_retry_num_ap_not_found < EXAMPLE_AP_RECONN_ATTEMPTS) {
|
||||
s_retry_num_ap_not_found++;
|
||||
esp_wifi_connect();
|
||||
ESP_LOGI(TAG, "retry to connecting to the AP...");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* None of the expected reasons */
|
||||
esp_wifi_connect();
|
||||
break;
|
||||
}
|
||||
} 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:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num_ap_not_found = 0;
|
||||
s_retry_num_ap_auth_fail = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_init_sta(void)
|
||||
{
|
||||
/* Set our event handling */
|
||||
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));
|
||||
|
||||
/* Start Wi-Fi in station mode with credentials set during provisioning */
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
static void start_ble_provisioning(void)
|
||||
{
|
||||
/* Security version */
|
||||
int security = 0;
|
||||
/* Proof of possession */
|
||||
const protocomm_security_pop_t *pop = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_USE_SEC_1
|
||||
security = 1;
|
||||
#endif
|
||||
|
||||
/* Having proof of possession is optional */
|
||||
#ifdef CONFIG_EXAMPLE_USE_POP
|
||||
const static protocomm_security_pop_t app_pop = {
|
||||
.data = (uint8_t *) CONFIG_EXAMPLE_POP,
|
||||
.len = (sizeof(CONFIG_EXAMPLE_POP)-1)
|
||||
};
|
||||
pop = &app_pop;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(app_prov_start_ble_provisioning(security, pop));
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize networking stack */
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* Create default event loop needed by the
|
||||
* main app and the provisioning service */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Initialize NVS needed by Wi-Fi */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* 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));
|
||||
|
||||
/* Check if device is provisioned */
|
||||
bool provisioned;
|
||||
if (app_prov_is_provisioned(&provisioned) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error getting device provisioning state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (provisioned == false) {
|
||||
/* If not provisioned, start provisioning via BLE */
|
||||
ESP_LOGI(TAG, "Starting BLE provisioning");
|
||||
start_ble_provisioning();
|
||||
} else {
|
||||
/* Else start as station with credentials set during provisioning */
|
||||
ESP_LOGI(TAG, "Starting WiFi station");
|
||||
wifi_init_sta();
|
||||
}
|
||||
}
|
@ -1,387 +0,0 @@
|
||||
/* BLE based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_bt.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#ifdef CONFIG_BT_NIMBLE_ENABLED
|
||||
#include "esp_nimble_hci.h"
|
||||
#include "nimble/nimble_port.h"
|
||||
#include "nimble/nimble_port_freertos.h"
|
||||
#include "host/ble_hs.h"
|
||||
#endif
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_ble.h>
|
||||
#include <protocomm_security0.h>
|
||||
#include <protocomm_security1.h>
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
static const char *TAG = "app_prov";
|
||||
static const char *ssid_prefix = "PROV_";
|
||||
|
||||
/* Handler for catching WiFi events */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t base, int id, void* data);
|
||||
|
||||
/* Handlers for wifi_config provisioning endpoint */
|
||||
extern wifi_prov_config_handlers_t wifi_prov_handlers;
|
||||
|
||||
/**
|
||||
* @brief Data relevant to provisioning application
|
||||
*/
|
||||
struct app_prov_data {
|
||||
protocomm_t *pc; /*!< Protocomm handler */
|
||||
int security; /*!< Type of security to use with protocomm */
|
||||
const protocomm_security_pop_t *pop; /*!< Pointer to proof of possession */
|
||||
esp_timer_handle_t timer; /*!< Handle to timer */
|
||||
|
||||
/* State of WiFi Station */
|
||||
wifi_prov_sta_state_t wifi_state;
|
||||
|
||||
/* Code for WiFi station disconnection (if disconnected) */
|
||||
wifi_prov_sta_fail_reason_t wifi_disconnect_reason;
|
||||
};
|
||||
|
||||
/* Pointer to provisioning application data */
|
||||
static struct app_prov_data *g_prov;
|
||||
|
||||
static esp_err_t app_prov_start_service(void)
|
||||
{
|
||||
/* Create new protocomm instance */
|
||||
g_prov->pc = protocomm_new();
|
||||
if (g_prov->pc == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create new protocomm instance");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Endpoint UUIDs */
|
||||
protocomm_ble_name_uuid_t nu_lookup_table[] = {
|
||||
{"prov-session", 0x0001},
|
||||
{"prov-config", 0x0002},
|
||||
{"proto-ver", 0x0003},
|
||||
};
|
||||
|
||||
/* Config for protocomm_ble_start() */
|
||||
protocomm_ble_config_t config = {
|
||||
.service_uuid = {
|
||||
/* LSB <---------------------------------------
|
||||
* ---------------------------------------> MSB */
|
||||
0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,
|
||||
0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,
|
||||
},
|
||||
.nu_lookup_count = sizeof(nu_lookup_table)/sizeof(nu_lookup_table[0]),
|
||||
.nu_lookup = nu_lookup_table
|
||||
};
|
||||
|
||||
/* With the above selection of 128bit primary service UUID and
|
||||
* 16bit endpoint UUIDs, the 128bit characteristic UUIDs will be
|
||||
* formed by replacing the 12th and 13th bytes of the service UUID
|
||||
* with the 16bit endpoint UUID, i.e. :
|
||||
* service UUID : 021a9004-0382-4aea-bff4-6b3f1c5adfb4
|
||||
* masked base : 021a____-0382-4aea-bff4-6b3f1c5adfb4
|
||||
* ------------------------------------------------------
|
||||
* resulting characteristic UUIDs :
|
||||
* 1) prov-session : 021a0001-0382-4aea-bff4-6b3f1c5adfb4
|
||||
* 2) prov-config : 021a0002-0382-4aea-bff4-6b3f1c5adfb4
|
||||
* 3) proto-ver : 021a0003-0382-4aea-bff4-6b3f1c5adfb4
|
||||
*
|
||||
* Also, note that each endpoint (characteristic) will have
|
||||
* an associated "Characteristic User Description" descriptor
|
||||
* with 16bit UUID 0x2901, each containing the corresponding
|
||||
* endpoint name. These descriptors can be used by a client
|
||||
* side application to figure out which characteristic is
|
||||
* mapped to which endpoint, without having to hardcode the
|
||||
* UUIDs */
|
||||
|
||||
uint8_t eth_mac[6];
|
||||
esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
|
||||
snprintf(config.device_name, sizeof(config.device_name), "%s%02X%02X%02X",
|
||||
ssid_prefix, eth_mac[3], eth_mac[4], eth_mac[5]);
|
||||
|
||||
/* Release BT memory, as we need only BLE */
|
||||
esp_err_t err = esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT);
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "bt_controller_mem_release failed %d", err);
|
||||
if (err != ESP_ERR_INVALID_STATE) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
/* Start protocomm layer on top of BLE */
|
||||
if (protocomm_ble_start(g_prov->pc, &config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start BLE provisioning");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Set protocomm version verification endpoint for protocol */
|
||||
protocomm_set_version(g_prov->pc, "proto-ver", "V0.1");
|
||||
|
||||
/* Set protocomm security type for endpoint */
|
||||
if (g_prov->security == 0) {
|
||||
protocomm_set_security(g_prov->pc, "prov-session", &protocomm_security0, NULL);
|
||||
} else if (g_prov->security == 1) {
|
||||
protocomm_set_security(g_prov->pc, "prov-session", &protocomm_security1, g_prov->pop);
|
||||
}
|
||||
|
||||
/* Add endpoint for provisioning to set wifi station config */
|
||||
if (protocomm_add_endpoint(g_prov->pc, "prov-config",
|
||||
wifi_prov_config_data_handler,
|
||||
(void *) &wifi_prov_handlers) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set provisioning endpoint");
|
||||
protocomm_ble_stop(g_prov->pc);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Provisioning started with BLE devname : '%s'", config.device_name);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void app_prov_stop_service(void)
|
||||
{
|
||||
/* Remove provisioning endpoint */
|
||||
protocomm_remove_endpoint(g_prov->pc, "prov-config");
|
||||
/* Unset provisioning security */
|
||||
protocomm_unset_security(g_prov->pc, "prov-session");
|
||||
/* Unset provisioning version endpoint */
|
||||
protocomm_unset_version(g_prov->pc, "proto-ver");
|
||||
/* Stop protocomm ble service */
|
||||
protocomm_ble_stop(g_prov->pc);
|
||||
/* Delete protocomm instance */
|
||||
protocomm_delete(g_prov->pc);
|
||||
|
||||
/* Remove event handler */
|
||||
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler);
|
||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler);
|
||||
|
||||
/* Release memory used by BT stack */
|
||||
esp_bt_mem_release(ESP_BT_MODE_BTDM);
|
||||
}
|
||||
|
||||
/* Task spawned by timer callback */
|
||||
static void stop_prov_task(void * arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "Stopping provisioning");
|
||||
app_prov_stop_service();
|
||||
|
||||
/* Timer not needed anymore */
|
||||
esp_timer_handle_t timer = g_prov->timer;
|
||||
esp_timer_delete(timer);
|
||||
g_prov->timer = NULL;
|
||||
|
||||
/* Free provisioning process data */
|
||||
free(g_prov);
|
||||
g_prov = NULL;
|
||||
ESP_LOGI(TAG, "Provisioning stopped");
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/* Callback to be invoked by timer */
|
||||
static void _stop_prov_cb(void * arg)
|
||||
{
|
||||
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
|
||||
/* Event handler for starting/stopping provisioning */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
/* If pointer to provisioning application data is NULL
|
||||
* then provisioning is not running */
|
||||
if (!g_prov) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
ESP_LOGI(TAG, "STA Start");
|
||||
/* Once configuration is received through protocomm,
|
||||
* device is started as station. Once station starts,
|
||||
* wait for connection to establish with configured
|
||||
* host SSID and password */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ESP_LOGI(TAG, "STA Got IP");
|
||||
/* Station got IP. That means configuration is successful.
|
||||
* Schedule timer to stop provisioning app after 30 seconds. */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
|
||||
if (g_prov && g_prov->timer) {
|
||||
esp_timer_start_once(g_prov->timer, 30000*1000U);
|
||||
}
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
ESP_LOGE(TAG, "STA Disconnected");
|
||||
/* Station couldn't connect to configured host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_DISCONNECTED;
|
||||
|
||||
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason);
|
||||
|
||||
/* Set code corresponding to the reason for disconnection */
|
||||
switch (disconnected->reason) {
|
||||
case WIFI_REASON_AUTH_EXPIRE:
|
||||
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
||||
case WIFI_REASON_BEACON_TIMEOUT:
|
||||
case WIFI_REASON_AUTH_FAIL:
|
||||
case WIFI_REASON_ASSOC_FAIL:
|
||||
case WIFI_REASON_HANDSHAKE_TIMEOUT:
|
||||
ESP_LOGI(TAG, "STA Auth Error");
|
||||
g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AUTH_ERROR;
|
||||
break;
|
||||
case WIFI_REASON_NO_AP_FOUND:
|
||||
ESP_LOGI(TAG, "STA AP Not found");
|
||||
g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AP_NOT_FOUND;
|
||||
break;
|
||||
default:
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
esp_wifi_connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state)
|
||||
{
|
||||
if (g_prov == NULL || state == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*state = g_prov->wifi_state;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason)
|
||||
{
|
||||
if (g_prov == NULL || reason == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (g_prov->wifi_state != WIFI_PROV_STA_DISCONNECTED) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*reason = g_prov->wifi_disconnect_reason;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_is_provisioned(bool *provisioned)
|
||||
{
|
||||
*provisioned = false;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
||||
nvs_flash_erase();
|
||||
#endif
|
||||
|
||||
/* Get WiFi Station configuration */
|
||||
wifi_config_t wifi_cfg;
|
||||
if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (strlen((const char*) wifi_cfg.sta.ssid)) {
|
||||
*provisioned = true;
|
||||
ESP_LOGI(TAG, "Found ssid %s", (const char*) wifi_cfg.sta.ssid);
|
||||
ESP_LOGI(TAG, "Found password %s", (const char*) wifi_cfg.sta.password);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
|
||||
{
|
||||
/* Configure WiFi as station */
|
||||
if (esp_wifi_set_mode(WIFI_MODE_STA) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi mode");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Configure WiFi station with host credentials
|
||||
* provided during provisioning */
|
||||
if (esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_cfg) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi configuration");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Start WiFi */
|
||||
if (esp_wifi_start() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi configuration");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Connect to AP */
|
||||
if (esp_wifi_connect() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to connect WiFi");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (g_prov) {
|
||||
/* Reset wifi station state for provisioning app */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_start_ble_provisioning(int security, const protocomm_security_pop_t *pop)
|
||||
{
|
||||
/* If provisioning app data present,
|
||||
* means provisioning app is already running */
|
||||
if (g_prov) {
|
||||
ESP_LOGI(TAG, "Invalid provisioning state");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Allocate memory for provisioning app data */
|
||||
g_prov = (struct app_prov_data *) calloc(1, sizeof(struct app_prov_data));
|
||||
if (!g_prov) {
|
||||
ESP_LOGI(TAG, "Unable to allocate prov data");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Initialize app data */
|
||||
g_prov->pop = pop;
|
||||
g_prov->security = security;
|
||||
|
||||
/* Create timer object as a member of app data */
|
||||
esp_timer_create_args_t timer_conf = {
|
||||
.callback = _stop_prov_cb,
|
||||
.arg = NULL,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "stop_ble_tm"
|
||||
};
|
||||
esp_err_t err = esp_timer_create(&timer_conf, &g_prov->timer);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create timer");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register WiFi event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register IP event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start provisioning service through BLE */
|
||||
err = app_prov_start_service();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Provisioning failed to start");
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "BLE Provisioning started");
|
||||
return ESP_OK;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/* BLE based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm_security.h>
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
/**
|
||||
* @brief Get state of WiFi Station during provisioning
|
||||
*
|
||||
* @note WiFi is initially configured as AP, when
|
||||
* provisioning starts. After provisioning data
|
||||
* is provided by user, the WiFi is reconfigured
|
||||
* to run as both AP and Station.
|
||||
*
|
||||
* @param[out] state Pointer to wifi_prov_sta_state_t variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved wifi state
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state);
|
||||
|
||||
/**
|
||||
* @brief Get reason code in case of WiFi station
|
||||
* disconnection during provisioning
|
||||
*
|
||||
* @param[out] reason Pointer to wifi_prov_sta_fail_reason_t variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved wifi disconnect reason
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason);
|
||||
|
||||
/**
|
||||
* @brief Checks if device is provisioned
|
||||
* *
|
||||
* @param[out] provisioned True if provisioned, else false
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Retrieved provision state successfully
|
||||
* - ESP_FAIL : Failed to retrieve provision state
|
||||
*/
|
||||
esp_err_t app_prov_is_provisioned(bool *provisioned);
|
||||
|
||||
/**
|
||||
* @brief Runs WiFi as Station
|
||||
*
|
||||
* Configures the WiFi station mode to connect to the
|
||||
* SSID and password specified in config structure,
|
||||
* and starts WiFi to run as station
|
||||
*
|
||||
* @param[in] wifi_cfg Pointer to WiFi cofiguration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : WiFi configured and started successfully
|
||||
* - ESP_FAIL : Failed to set configuration
|
||||
*/
|
||||
esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg);
|
||||
|
||||
/**
|
||||
* @brief Start provisioning via Bluetooth
|
||||
*
|
||||
* @param[in] security Security mode
|
||||
* @param[in] pop Pointer to proof of possession (NULL if not present)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Provisioning started successfully
|
||||
* - ESP_FAIL : Failed to start
|
||||
*/
|
||||
esp_err_t app_prov_start_ble_provisioning(int security, const protocomm_security_pop_t *pop);
|
@ -1,131 +0,0 @@
|
||||
/* SoftAP based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
/* This file is mostly a boiler-plate code that applications can use without much change */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_netif.h>
|
||||
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
static const char* TAG = "app_prov_handler";
|
||||
|
||||
/* Provide definition of wifi_prov_ctx_t */
|
||||
struct wifi_prov_ctx {
|
||||
wifi_config_t wifi_cfg;
|
||||
};
|
||||
|
||||
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
return (*ctx ? &(*ctx)->wifi_cfg : NULL);
|
||||
}
|
||||
|
||||
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
|
||||
return get_config(ctx);
|
||||
}
|
||||
|
||||
static void free_config(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
|
||||
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
/* Initialize to zero */
|
||||
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
|
||||
|
||||
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Prov app not running");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (resp_data->wifi_state == WIFI_PROV_STA_CONNECTED) {
|
||||
ESP_LOGI(TAG, "Connected state");
|
||||
|
||||
/* IP Addr assigned to STA */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
|
||||
|
||||
/* AP information to which STA is connected */
|
||||
wifi_ap_record_t ap_info;
|
||||
esp_wifi_sta_get_ap_info(&ap_info);
|
||||
memcpy(resp_data->conn_info.bssid, (char *)ap_info.bssid, sizeof(ap_info.bssid));
|
||||
memcpy(resp_data->conn_info.ssid, (char *)ap_info.ssid, sizeof(ap_info.ssid));
|
||||
resp_data->conn_info.channel = ap_info.primary;
|
||||
resp_data->conn_info.auth_mode = ap_info.authmode;
|
||||
} else if (resp_data->wifi_state == WIFI_PROV_STA_DISCONNECTED) {
|
||||
ESP_LOGI(TAG, "Disconnected state");
|
||||
|
||||
/* If disconnected, convey reason */
|
||||
app_prov_get_wifi_disconnect_reason(&resp_data->fail_reason);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Connecting state");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = get_config(ctx);
|
||||
if (wifi_cfg) {
|
||||
free_config(ctx);
|
||||
}
|
||||
|
||||
wifi_cfg = new_config(ctx);
|
||||
if (!wifi_cfg) {
|
||||
ESP_LOGE(TAG, "Unable to alloc wifi config");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s",
|
||||
req_data->ssid, req_data->password);
|
||||
|
||||
/* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard).
|
||||
* But this doesn't guarantee that the saved SSID will be null terminated, because
|
||||
* wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).
|
||||
* Although, this is not a matter for concern because esp_wifi library reads the SSID
|
||||
* upto 32 bytes in absence of null termination */
|
||||
strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid));
|
||||
strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = get_config(ctx);
|
||||
if (!wifi_cfg) {
|
||||
ESP_LOGE(TAG, "WiFi config not set");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
app_prov_configure_sta(wifi_cfg);
|
||||
ESP_LOGI(TAG, "WiFi Credentials Applied");
|
||||
|
||||
free_config(ctx);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
wifi_prov_config_handlers_t wifi_prov_handlers = {
|
||||
.get_status_handler = get_status_handler,
|
||||
.set_config_handler = set_config_handler,
|
||||
.apply_config_handler = apply_config_handler,
|
||||
.ctx = NULL
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
@ -1,5 +0,0 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1200000,
|
|
@ -1,10 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled and
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
|
||||
# Binary is larger than default size
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
@ -1,6 +0,0 @@
|
||||
# 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.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(console_prov)
|
@ -1,9 +0,0 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := console_prov
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -1,208 +0,0 @@
|
||||
# Console based Provisioning Example (Legacy)
|
||||
|
||||
> Check this example only if you wish to use console based provisioning. For any real applications, it is recommended to use the new `wifi_prov_mgr` example which is based on the simpler `wifi_provisioning` APIs.
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
`console_prov` example demonstrates the implementation and integration of various IDF components for building a console based provisioning application.
|
||||
|
||||
For this example UART console is chosen as the mode of transport, over which the provisioning related communication is to take place, between the device (to be provisioned) and the client (owner of the device).
|
||||
|
||||
In the provisioning process the device is configured as a Wi-Fi station with specified credentials. Once configured, the device will retain the Wi-Fi configuration, until a flash erase is performed.
|
||||
|
||||
Right after provisioning is complete, the UART console is deactivated.
|
||||
|
||||
`console_prov` uses the following components :
|
||||
* `wifi_provisioning` : provides data structures and protocomm endpoint handlers for Wi-Fi configuration
|
||||
* `protocomm` : for protocol based communication and secure session establishment
|
||||
* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures
|
||||
|
||||
This example can be used, as it is, for adding a provisioning service to any application intended for IoT. But it is more suitable for debugging protocomm and provisioning related components and feature additions.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Example should be able to run on any commonly available ESP32 development board.
|
||||
|
||||
### Application Required
|
||||
|
||||
To provision the device running this example, the `esp_prov.py` script needs to be run (found under `$IDF_PATH/tools/esp_prov`). This feature of `esp_prov` should work on all platforms, given the dependencies are satisfied.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Under Example Configuration set the following :
|
||||
* Security Version (default 1)
|
||||
* Proof of Possession (default "abcd1234")
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (388) app: Starting console provisioning
|
||||
I (398) app_prov: Console provisioning started
|
||||
.
|
||||
.
|
||||
.
|
||||
>>
|
||||
```
|
||||
|
||||
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, the script should be run as follows :
|
||||
|
||||
```
|
||||
python esp_prov.py --transport console --proto_ver "V0.1" --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword
|
||||
```
|
||||
|
||||
A console will open up and the `Client->Device` commands have to be copied manually to the serial monitor console prompt :
|
||||
|
||||
```
|
||||
==== Verifying protocol version ====
|
||||
Client->Device msg : proto-ver 0 56302e31
|
||||
Enter device->client msg :
|
||||
```
|
||||
|
||||
On pasting the command on the serial monitor console, a `Device->Client` message will appear for each command :
|
||||
|
||||
```
|
||||
>> proto-ver 0 56302e31
|
||||
53554343455353
|
||||
```
|
||||
|
||||
Copy this message back to the `esp_prov` console for proceeding to the next command :
|
||||
|
||||
```
|
||||
==== Verifying protocol version ====
|
||||
Client->Device msg : proto-ver 0 56302e31
|
||||
Enter device->client msg : 53554343455353
|
||||
==== Verified protocol version successfully ====
|
||||
|
||||
==== Starting Session ====
|
||||
Client->Device msg : prov-session 0 10015a25a201220a20677106cc2f5b2acb5d8da26f0ad443df006daa1cd5bb3d75a8324d81ec5ef970
|
||||
Enter device->client msg :
|
||||
```
|
||||
|
||||
This process keeps on till the device gets provisioned.
|
||||
|
||||
Note that the commands are in the following format :
|
||||
|
||||
```
|
||||
<endpoint name> <session id> <hex message>
|
||||
```
|
||||
|
||||
This is helpful in understanding the provisioning process and the order in which the endpoints are communicated with.
|
||||
|
||||
The full execution sequence of `esp_prov`, as seen on the console, is shown here :
|
||||
|
||||
```
|
||||
==== Verifying protocol version ====
|
||||
Client->Device msg : proto-ver 0 56302e31
|
||||
Enter device->client msg : 53554343455353
|
||||
==== Verified protocol version successfully ====
|
||||
|
||||
==== Starting Session ====
|
||||
Client->Device msg : prov-session 0 10015a25a201220a20677106cc2f5b2acb5d8da26f0ad443df006daa1cd5bb3d75a8324d81ec5ef970
|
||||
Enter device->client msg : 10015a390801aa013412207566f4de191f600ea42de5c2b1df73f1f16685c2edb43d7c3ffc83d6b81ff61b1a103db6476536a88db10b7e0a172d4adef8
|
||||
Client->Device msg : prov-session 0 10015a270802b20122122084ca311e51c904a94f8a249c049f7aed33b39671cc11f0b92b15b299ef5653b7
|
||||
Enter device->client msg : 10015a270803ba01221a203246230190d5c1f5d94c01b56ac8cace1086cfb2d937a4a46cb6c79db7a35a8b
|
||||
==== Session Established ====
|
||||
|
||||
==== Sending Wifi credential to esp32 ====
|
||||
Client->Device msg : prov-config 0 8f0c8cb6f2d53c4cc53b29be8ba1aac3edbb1dead39117c34687d6
|
||||
Enter device->client msg : 2e1f0eb0
|
||||
==== Wifi Credentials sent successfully ====
|
||||
|
||||
==== Applying config to esp32 ====
|
||||
Client->Device msg : prov-config 0 e8df
|
||||
Enter device->client msg : 245c83f0
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wifi connection state ====
|
||||
Client->Device msg : prov-config 0 2d36
|
||||
Enter device->client msg : 1b38a7411b6e2608aae50a6571807e04a6e90520b3b1e3c1e5b38cea4b9022e56485b92ff84289df218311972a42eb
|
||||
++++ WiFi state: connected ++++
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
The serial monitor console, for above sequence of commands, would look like :
|
||||
|
||||
```
|
||||
>> proto-ver 0 56302e31
|
||||
53554343455353
|
||||
>> prov-session 0 10015a25a201220a20677106cc2f5b2acb5d8da26f0ad443df006daa1cd5bb3d75a8324d81ec5ef970
|
||||
10015a390801aa013412207566f4de191f600ea42de5c2b1df73f1f16685c2edb43d7c3ffc83d6b81ff61b1a103db6476536a88db10b7e0a172d4adef8
|
||||
>> prov-session 0 10015a270802b20122122084ca311e51c904a94f8a249c049f7aed33b39671cc11f0b92b15b299ef5653b7
|
||||
10015a270803ba01221a203246230190d5c1f5d94c01b56ac8cace1086cfb2d937a4a46cb6c79db7a35a8b
|
||||
>> prov-config 0 8f0c8cb6f2d53c4cc53b29be8ba1aac3edbb1dead39117c34687d6
|
||||
I (1073738) app_prov_handler: WiFi Credentials Received :
|
||||
ssid : myssid
|
||||
password : mypassword
|
||||
|
||||
2e1f0eb0
|
||||
>> prov-config 0 e8df
|
||||
I (1084218) app_prov_handler: WiFi Credentials Applied
|
||||
|
||||
245c83f0
|
||||
>> prov-config 0 2d36
|
||||
I (1089728) app_prov: STA Got IP
|
||||
I (1089728) app: got ip:192.168.43.220
|
||||
I (1099698) app_prov_handler: Connected state
|
||||
|
||||
1b38a7411b6e2608aae50a6571807e04a6e90520b3b1e3c1e5b38cea4b9022e56485b92ff84289df218311972a42eb
|
||||
>>
|
||||
```
|
||||
|
||||
After sometime the provisioning app will exit and UART console will be stopped
|
||||
|
||||
```
|
||||
I (1119728) app_prov: Stopping provisioning
|
||||
I (1119728) protocomm_console: Stopping console...
|
||||
I (1119728) app_prov: Provisioning stopped
|
||||
I (1119748) protocomm_console: Console stopped
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Provisioning failed
|
||||
|
||||
It is possible that the Wi-Fi credentials provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason) and the provisioning app will continue running, allowing the user to retry the process. Serial monitor log will display the failure along with disconnect reason :
|
||||
|
||||
```
|
||||
E (39291) app_prov: STA Disconnected
|
||||
E (39291) app_prov: Disconnect reason : 201
|
||||
I (39291) app_prov: STA AP Not found
|
||||
I (42021) app_prov_handler: Disconnected state
|
||||
```
|
||||
|
||||
### Provisioning does not start
|
||||
|
||||
If the serial monitor log is different, as shown below :
|
||||
|
||||
```
|
||||
I (539) app_prov: Found ssid myssid
|
||||
I (539) app_prov: Found password mypassword
|
||||
I (549) app: Starting WiFi station
|
||||
```
|
||||
|
||||
It means the Wi-Fi credentials were already set by some other application flashed previously to your device. To erase these credentials either do full erase and then flash the example
|
||||
|
||||
```
|
||||
make erase_flash
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution.
|
@ -1,4 +0,0 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c"
|
||||
INCLUDE_DIRS ".")
|
@ -1,40 +0,0 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_USE_SEC_1
|
||||
bool
|
||||
default y
|
||||
prompt "Use Security Version 1"
|
||||
help
|
||||
Security version 1 used Curve25519 key exchange for establishing
|
||||
secure session between device and client during provisioning
|
||||
|
||||
config EXAMPLE_USE_POP
|
||||
bool
|
||||
depends on EXAMPLE_USE_SEC_1
|
||||
default y
|
||||
prompt "Use proof-of-possession"
|
||||
help
|
||||
Proof-of-possession can be optionally used to prove that the device is indeed
|
||||
in possession of the user who is provisioning the device. This proof-of-possession
|
||||
is internally used to generate the shared secret through key exchange.
|
||||
|
||||
config EXAMPLE_POP
|
||||
string "Proof-of-possession"
|
||||
default "abcd1234"
|
||||
depends on EXAMPLE_USE_POP
|
||||
|
||||
config EXAMPLE_RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
int "Maximum AP connection attempts"
|
||||
default 5
|
||||
help
|
||||
Set the maximum connection attempts to perform when connecting to a Wi-Fi AP.
|
||||
|
||||
endmenu
|
@ -1,116 +0,0 @@
|
||||
/* Console based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sys.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
#define EXAMPLE_AP_RECONN_ATTEMPTS CONFIG_EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int 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) {
|
||||
if (s_retry_num < EXAMPLE_AP_RECONN_ATTEMPTS) {
|
||||
esp_wifi_connect();
|
||||
s_retry_num++;
|
||||
ESP_LOGI(TAG, "retry to connect to the AP");
|
||||
}
|
||||
ESP_LOGI(TAG,"connect to the AP fail");
|
||||
} 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:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_init_sta(void)
|
||||
{
|
||||
/* Set our event handling */
|
||||
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));
|
||||
|
||||
/* Start Wi-Fi in station mode with credentials set during provisioning */
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
static void start_console_provisioning(void)
|
||||
{
|
||||
/* Security version */
|
||||
int security = 0;
|
||||
/* Proof of possession */
|
||||
const protocomm_security_pop_t *pop = NULL;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_USE_SEC_1
|
||||
security = 1;
|
||||
#endif
|
||||
|
||||
/* Having proof of possession is optional */
|
||||
#ifdef CONFIG_EXAMPLE_USE_POP
|
||||
const static protocomm_security_pop_t app_pop = {
|
||||
.data = (uint8_t *) CONFIG_EXAMPLE_POP,
|
||||
.len = (sizeof(CONFIG_EXAMPLE_POP)-1)
|
||||
};
|
||||
pop = &app_pop;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(app_prov_start_console_provisioning(security, pop));
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize networking stack */
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* Create default event loop needed by the
|
||||
* main app and the provisioning service */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Initialize NVS needed by Wi-Fi */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* 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));
|
||||
|
||||
/* Check if device is provisioned */
|
||||
bool provisioned;
|
||||
if (app_prov_is_provisioned(&provisioned) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error getting device provisioning state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (provisioned == false) {
|
||||
/* If not provisioned, start provisioning via console */
|
||||
ESP_LOGI(TAG, "Starting console provisioning");
|
||||
start_console_provisioning();
|
||||
} else {
|
||||
/* Else start as station with credentials set during provisioning */
|
||||
ESP_LOGI(TAG, "Starting WiFi station");
|
||||
wifi_init_sta();
|
||||
}
|
||||
}
|
@ -1,325 +0,0 @@
|
||||
/* Console based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_console.h>
|
||||
#include <protocomm_security0.h>
|
||||
#include <protocomm_security1.h>
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
static const char *TAG = "app_prov";
|
||||
|
||||
/* Handler for catching WiFi events */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t base, int id, void* data);
|
||||
|
||||
/* Handlers for wifi_config provisioning endpoint */
|
||||
extern wifi_prov_config_handlers_t wifi_prov_handlers;
|
||||
|
||||
/**
|
||||
* @brief Data relevant to provisioning application
|
||||
*/
|
||||
struct app_prov_data {
|
||||
protocomm_t *pc; /*!< Protocomm handler */
|
||||
int security; /*!< Type of security to use with protocomm */
|
||||
const protocomm_security_pop_t *pop; /*!< Pointer to proof of possession */
|
||||
esp_timer_handle_t timer; /*!< Handle to timer */
|
||||
|
||||
/* State of WiFi Station */
|
||||
wifi_prov_sta_state_t wifi_state;
|
||||
|
||||
/* Code for WiFi station disconnection (if disconnected) */
|
||||
wifi_prov_sta_fail_reason_t wifi_disconnect_reason;
|
||||
};
|
||||
|
||||
/* Pointer to provisioning application data */
|
||||
static struct app_prov_data *g_prov;
|
||||
|
||||
static esp_err_t app_prov_start_service(void)
|
||||
{
|
||||
/* Create new protocomm instance */
|
||||
g_prov->pc = protocomm_new();
|
||||
if (g_prov->pc == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to create new protocomm instance");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Config for protocomm_console_start() */
|
||||
protocomm_console_config_t config = PROTOCOMM_CONSOLE_DEFAULT_CONFIG();
|
||||
|
||||
/* Start protocomm using console */
|
||||
if (protocomm_console_start(g_prov->pc, &config) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to start console provisioning");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Set protocomm version verification endpoint for protocol */
|
||||
protocomm_set_version(g_prov->pc, "proto-ver", "V0.1");
|
||||
|
||||
/* Set protocomm security type for endpoint */
|
||||
if (g_prov->security == 0) {
|
||||
protocomm_set_security(g_prov->pc, "prov-session", &protocomm_security0, NULL);
|
||||
} else if (g_prov->security == 1) {
|
||||
protocomm_set_security(g_prov->pc, "prov-session", &protocomm_security1, g_prov->pop);
|
||||
}
|
||||
|
||||
/* Add endpoint for provisioning to set wifi station config */
|
||||
if (protocomm_add_endpoint(g_prov->pc, "prov-config",
|
||||
wifi_prov_config_data_handler,
|
||||
(void *) &wifi_prov_handlers) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set provisioning endpoint");
|
||||
protocomm_console_stop(g_prov->pc);
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Provisioning started");
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void app_prov_stop_service(void)
|
||||
{
|
||||
/* Remove provisioning endpoint */
|
||||
protocomm_remove_endpoint(g_prov->pc, "prov-config");
|
||||
/* Unset provisioning security */
|
||||
protocomm_unset_security(g_prov->pc, "prov-session");
|
||||
/* Unset provisioning version endpoint */
|
||||
protocomm_unset_version(g_prov->pc, "proto-ver");
|
||||
/* Stop protocomm console service */
|
||||
protocomm_console_stop(g_prov->pc);
|
||||
/* Delete protocomm instance */
|
||||
protocomm_delete(g_prov->pc);
|
||||
|
||||
/* Remove event handler */
|
||||
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler);
|
||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler);
|
||||
}
|
||||
|
||||
/* Task spawned by timer callback */
|
||||
static void stop_prov_task(void * arg)
|
||||
{
|
||||
ESP_LOGI(TAG, "Stopping provisioning");
|
||||
app_prov_stop_service();
|
||||
|
||||
/* Timer not needed anymore */
|
||||
esp_timer_handle_t timer = g_prov->timer;
|
||||
esp_timer_delete(timer);
|
||||
g_prov->timer = NULL;
|
||||
|
||||
/* Free provisioning process data */
|
||||
free(g_prov);
|
||||
g_prov = NULL;
|
||||
ESP_LOGI(TAG, "Provisioning stopped");
|
||||
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
/* Callback to be invoked by timer */
|
||||
static void _stop_prov_cb(void * arg)
|
||||
{
|
||||
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
|
||||
/* Event handler for starting/stopping provisioning */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
/* If pointer to provisioning application data is NULL
|
||||
* then provisioning is not running */
|
||||
if (!g_prov) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
ESP_LOGI(TAG, "STA Start");
|
||||
/* Once configuration is received through protocomm,
|
||||
* device is started as station. Once station starts,
|
||||
* wait for connection to establish with configured
|
||||
* host SSID and password */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ESP_LOGI(TAG, "STA Got IP");
|
||||
/* Station got IP. That means configuration is successful.
|
||||
* Schedule timer to stop provisioning app after 30 seconds. */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTED;
|
||||
if (g_prov && g_prov->timer) {
|
||||
esp_timer_start_once(g_prov->timer, 30000*1000U);
|
||||
}
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
ESP_LOGE(TAG, "STA Disconnected");
|
||||
/* Station couldn't connect to configured host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_DISCONNECTED;
|
||||
|
||||
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason);
|
||||
|
||||
/* Set code corresponding to the reason for disconnection */
|
||||
switch (disconnected->reason) {
|
||||
case WIFI_REASON_AUTH_EXPIRE:
|
||||
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
||||
case WIFI_REASON_BEACON_TIMEOUT:
|
||||
case WIFI_REASON_AUTH_FAIL:
|
||||
case WIFI_REASON_ASSOC_FAIL:
|
||||
case WIFI_REASON_HANDSHAKE_TIMEOUT:
|
||||
ESP_LOGI(TAG, "STA Auth Error");
|
||||
g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AUTH_ERROR;
|
||||
break;
|
||||
case WIFI_REASON_NO_AP_FOUND:
|
||||
ESP_LOGI(TAG, "STA AP Not found");
|
||||
g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AP_NOT_FOUND;
|
||||
break;
|
||||
default:
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
esp_wifi_connect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state)
|
||||
{
|
||||
if (g_prov == NULL || state == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*state = g_prov->wifi_state;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason)
|
||||
{
|
||||
if (g_prov == NULL || reason == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (g_prov->wifi_state != WIFI_PROV_STA_DISCONNECTED) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
*reason = g_prov->wifi_disconnect_reason;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_is_provisioned(bool *provisioned)
|
||||
{
|
||||
*provisioned = false;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
||||
nvs_flash_erase();
|
||||
#endif
|
||||
|
||||
/* Get WiFi Station configuration */
|
||||
wifi_config_t wifi_cfg;
|
||||
if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (strlen((const char*) wifi_cfg.sta.ssid)) {
|
||||
*provisioned = true;
|
||||
ESP_LOGI(TAG, "Found ssid %s", (const char*) wifi_cfg.sta.ssid);
|
||||
ESP_LOGI(TAG, "Found password %s", (const char*) wifi_cfg.sta.password);
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
|
||||
{
|
||||
/* Configure WiFi as station */
|
||||
if (esp_wifi_set_mode(WIFI_MODE_STA) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi mode");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Configure WiFi station with host credentials
|
||||
* provided during provisioning */
|
||||
if (esp_wifi_set_config(ESP_IF_WIFI_STA, wifi_cfg) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi configuration");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Start WiFi */
|
||||
if (esp_wifi_start() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi configuration");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
/* Connect to AP */
|
||||
if (esp_wifi_connect() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to connect WiFi");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (g_prov) {
|
||||
/* Reset wifi station state for provisioning app */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_start_console_provisioning(int security, const protocomm_security_pop_t *pop)
|
||||
{
|
||||
/* If provisioning app data present,
|
||||
* means provisioning app is already running */
|
||||
if (g_prov) {
|
||||
ESP_LOGI(TAG, "Invalid provisioning state");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Allocate memory for provisioning app data */
|
||||
g_prov = (struct app_prov_data *) calloc(1, sizeof(struct app_prov_data));
|
||||
if (!g_prov) {
|
||||
ESP_LOGI(TAG, "Unable to allocate prov data");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Initialize app data */
|
||||
g_prov->pop = pop;
|
||||
g_prov->security = security;
|
||||
|
||||
/* Create timer object as a member of app data */
|
||||
esp_timer_create_args_t timer_conf = {
|
||||
.callback = _stop_prov_cb,
|
||||
.arg = NULL,
|
||||
.dispatch_method = ESP_TIMER_TASK,
|
||||
.name = "stop_console_tm"
|
||||
};
|
||||
esp_err_t err = esp_timer_create(&timer_conf, &g_prov->timer);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create timer");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register WiFi event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register IP event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start provisioning service through console */
|
||||
err = app_prov_start_service();
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Provisioning failed to start");
|
||||
return err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Console provisioning started");
|
||||
return ESP_OK;
|
||||
}
|
@ -1,79 +0,0 @@
|
||||
/* Console based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <protocomm_security.h>
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
/**
|
||||
* @brief Get state of WiFi Station during provisioning
|
||||
*
|
||||
* @note WiFi is initially configured as AP, when
|
||||
* provisioning starts. After provisioning data
|
||||
* is provided by user, the WiFi is reconfigured
|
||||
* to run as both AP and Station.
|
||||
*
|
||||
* @param[out] state Pointer to wifi_prov_sta_state_t variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved wifi state
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state);
|
||||
|
||||
/**
|
||||
* @brief Get reason code in case of WiFi station
|
||||
* disconnection during provisioning
|
||||
*
|
||||
* @param[out] reason Pointer to wifi_prov_sta_fail_reason_t variable to be filled
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Successfully retrieved wifi disconnect reason
|
||||
* - ESP_FAIL : Provisioning app not running
|
||||
*/
|
||||
esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason);
|
||||
|
||||
/**
|
||||
* @brief Checks if device is provisioned
|
||||
* *
|
||||
* @param[out] provisioned True if provisioned, else false
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Retrieved provision state successfully
|
||||
* - ESP_FAIL : Failed to retrieve provision state
|
||||
*/
|
||||
esp_err_t app_prov_is_provisioned(bool *provisioned);
|
||||
|
||||
/**
|
||||
* @brief Runs WiFi as Station
|
||||
*
|
||||
* Configures the WiFi station mode to connect to the
|
||||
* SSID and password specified in config structure,
|
||||
* and starts WiFi to run as station
|
||||
*
|
||||
* @param[in] wifi_cfg Pointer to WiFi cofiguration structure
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : WiFi configured and started successfully
|
||||
* - ESP_FAIL : Failed to set configuration
|
||||
*/
|
||||
esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg);
|
||||
|
||||
/**
|
||||
* @brief Start provisioning via Console
|
||||
*
|
||||
* @param[in] security Security mode
|
||||
* @param[in] pop Pointer to proof of possession (NULL if not present)
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Provisioning started successfully
|
||||
* - ESP_FAIL : Failed to start
|
||||
*/
|
||||
esp_err_t app_prov_start_console_provisioning(int security, const protocomm_security_pop_t *pop);
|
@ -1,131 +0,0 @@
|
||||
/* Console based Provisioning Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
/* This file is mostly a boiler-plate code that applications can use without much change */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_netif.h>
|
||||
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
static const char* TAG = "app_prov_handler";
|
||||
|
||||
/* Provide definition of wifi_prov_ctx_t */
|
||||
struct wifi_prov_ctx {
|
||||
wifi_config_t wifi_cfg;
|
||||
};
|
||||
|
||||
static wifi_config_t *get_config(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
return (*ctx ? &(*ctx)->wifi_cfg : NULL);
|
||||
}
|
||||
|
||||
static wifi_config_t *new_config(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
(*ctx) = (wifi_prov_ctx_t *) calloc(1, sizeof(wifi_prov_ctx_t));
|
||||
return get_config(ctx);
|
||||
}
|
||||
|
||||
static void free_config(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
free(*ctx);
|
||||
*ctx = NULL;
|
||||
}
|
||||
|
||||
static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
/* Initialize to zero */
|
||||
memset(resp_data, 0, sizeof(wifi_prov_config_get_data_t));
|
||||
|
||||
if (app_prov_get_wifi_state(&resp_data->wifi_state) != ESP_OK) {
|
||||
ESP_LOGW(TAG, "Prov app not running");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (resp_data->wifi_state == WIFI_PROV_STA_CONNECTED) {
|
||||
ESP_LOGI(TAG, "Connected state");
|
||||
|
||||
/* IP Addr assigned to STA */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
|
||||
|
||||
/* AP information to which STA is connected */
|
||||
wifi_ap_record_t ap_info;
|
||||
esp_wifi_sta_get_ap_info(&ap_info);
|
||||
memcpy(resp_data->conn_info.bssid, (char *)ap_info.bssid, sizeof(ap_info.bssid));
|
||||
memcpy(resp_data->conn_info.ssid, (char *)ap_info.ssid, sizeof(ap_info.ssid));
|
||||
resp_data->conn_info.channel = ap_info.primary;
|
||||
resp_data->conn_info.auth_mode = ap_info.authmode;
|
||||
} else if (resp_data->wifi_state == WIFI_PROV_STA_DISCONNECTED) {
|
||||
ESP_LOGI(TAG, "Disconnected state");
|
||||
|
||||
/* If disconnected, convey reason */
|
||||
app_prov_get_wifi_disconnect_reason(&resp_data->fail_reason);
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Connecting state");
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data, wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = get_config(ctx);
|
||||
if (wifi_cfg) {
|
||||
free_config(ctx);
|
||||
}
|
||||
|
||||
wifi_cfg = new_config(ctx);
|
||||
if (!wifi_cfg) {
|
||||
ESP_LOGE(TAG, "Unable to alloc wifi config");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s",
|
||||
req_data->ssid, req_data->password);
|
||||
|
||||
/* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard).
|
||||
* But this doesn't guarantee that the saved SSID will be null terminated, because
|
||||
* wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).
|
||||
* Although, this is not a matter for concern because esp_wifi library reads the SSID
|
||||
* upto 32 bytes in absence of null termination */
|
||||
strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid));
|
||||
strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static esp_err_t apply_config_handler(wifi_prov_ctx_t **ctx)
|
||||
{
|
||||
wifi_config_t *wifi_cfg = get_config(ctx);
|
||||
if (!wifi_cfg) {
|
||||
ESP_LOGE(TAG, "WiFi config not set");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
app_prov_configure_sta(wifi_cfg);
|
||||
ESP_LOGI(TAG, "WiFi Credentials Applied");
|
||||
|
||||
free_config(ctx);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
wifi_prov_config_handlers_t wifi_prov_handlers = {
|
||||
.get_status_handler = get_status_handler,
|
||||
.set_config_handler = set_config_handler,
|
||||
.apply_config_handler = apply_config_handler,
|
||||
.ctx = NULL
|
||||
};
|
@ -1,8 +0,0 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
||||
|
@ -15,7 +15,7 @@
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include "esp_netif.h"
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sys.h>
|
||||
|
||||
@ -94,8 +94,6 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* Initialize Wi-Fi including netif with default config */
|
||||
esp_netif_create_default_wifi_sta();
|
||||
esp_netif_create_default_wifi_ap();
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include <nvs.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <task.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_timer.h>
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_httpd.h>
|
||||
#include <protocomm_security0.h>
|
||||
@ -211,6 +214,10 @@ static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_bas
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
if (disconnected->reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||
}
|
||||
esp_wifi_connect();
|
||||
}
|
||||
}
|
||||
|
@ -72,9 +72,10 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi
|
||||
ESP_LOGI(TAG, "Connected state");
|
||||
|
||||
/* IP Addr assigned to STA */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
|
||||
tcpip_adapter_ip_info_t ip_info;
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
|
||||
char *ip_addr = ip4addr_ntoa(&ip_info.ip);
|
||||
strcpy(resp_data->conn_info.ip_addr, ip_addr);
|
||||
|
||||
/* AP information to which STA is connected */
|
||||
wifi_ap_record_t ap_info;
|
||||
|
@ -0,0 +1 @@
|
||||
CONFIG_ENABLE_UNIFIED_PROVISIONING=y
|
@ -15,7 +15,7 @@
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include "esp_netif.h"
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sys.h>
|
||||
|
||||
@ -109,8 +109,6 @@ void app_main(void)
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* Initialize Wi-Fi including netif with default config */
|
||||
esp_netif_create_default_wifi_sta();
|
||||
esp_netif_create_default_wifi_ap();
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include <nvs.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <task.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_timer.h>
|
||||
#include <protocomm.h>
|
||||
#include <protocomm_httpd.h>
|
||||
#include <protocomm_security0.h>
|
||||
@ -197,6 +200,10 @@ static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_bas
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
if (disconnected->reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||
}
|
||||
esp_wifi_connect();
|
||||
}
|
||||
}
|
||||
|
@ -60,9 +60,10 @@ static esp_err_t get_status_handler(wifi_prov_config_get_data_t *resp_data, wifi
|
||||
ESP_LOGI(TAG, "Connected state");
|
||||
|
||||
/* IP Addr assigned to STA */
|
||||
esp_netif_ip_info_t ip_info;
|
||||
esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info);
|
||||
esp_ip4addr_ntoa(&ip_info.ip, resp_data->conn_info.ip_addr, sizeof(resp_data->conn_info.ip_addr));
|
||||
tcpip_adapter_ip_info_t ip_info;
|
||||
tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
|
||||
char *ip_addr = ip4addr_ntoa(&ip_info.ip);
|
||||
strcpy(resp_data->conn_info.ip_addr, ip_addr);
|
||||
|
||||
/* AP information to which STA is connected */
|
||||
wifi_ap_record_t ap_info;
|
||||
|
@ -0,0 +1 @@
|
||||
CONFIG_ENABLE_UNIFIED_PROVISIONING=y
|
@ -1,6 +0,0 @@
|
||||
# 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.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(wifi_prov_mgr)
|
@ -1,9 +0,0 @@
|
||||
#
|
||||
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
|
||||
# project subdirectory.
|
||||
#
|
||||
|
||||
PROJECT_NAME := wifi_prov_mgr
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -1,286 +0,0 @@
|
||||
# Wi-Fi Provisioning Manager Example
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
`wifi_prov_mgr` example demonstrates the usage of `wifi_provisioning` manager component for building a provisioning application.
|
||||
|
||||
For this example, BLE is chosen as the default mode of transport, over which the provisioning related communication is to take place. NimBLE has been configured as the default host, but you can also switch to Bluedroid using menuconfig -> Components -> Bluetooth -> Bluetooth Host.
|
||||
|
||||
> Note: Since ESP32-S2 does not support BLE, the SoftAP will be the default mode of transport in that case. Even for ESP32, you can change to SoftAP transport from menuconfig.
|
||||
|
||||
In the provisioning process the device is configured as a Wi-Fi station with specified credentials. Once configured, the device will retain the Wi-Fi configuration, until a flash erase is performed.
|
||||
|
||||
Right after provisioning is complete, BLE is turned off and disabled to free the memory used by the BLE stack. Though, that is specific to this example, and the user can choose to keep BLE stack intact in their own application.
|
||||
|
||||
`wifi_prov_mgr` uses the following components :
|
||||
* `wifi_provisioning` : provides manager, data structures and protocomm endpoint handlers for Wi-Fi configuration
|
||||
* `protocomm` : for protocol based communication and secure session establishment
|
||||
* `protobuf` : Google's protocol buffer library for serialization of protocomm data structures
|
||||
* `bt` : ESP32 BLE stack for transport of protobuf packets
|
||||
|
||||
This example can be used, as it is, for adding a provisioning service to any application intended for IoT.
|
||||
|
||||
## How to use example
|
||||
|
||||
### Hardware Required
|
||||
|
||||
Example should be able to run on any commonly available ESP32/ESP32-S2 development board.
|
||||
|
||||
### Application Required
|
||||
|
||||
Provisioning applications are available for various platforms. See below
|
||||
|
||||
#### Platform : Android
|
||||
|
||||
For Android, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-android](https://github.com/espressif/esp-idf-provisioning-android)
|
||||
|
||||
#### Platform : iOS
|
||||
|
||||
For iOS, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-ios](https://github.com/espressif/esp-idf-provisioning-ios)
|
||||
|
||||
#### Platform : Linux / Windows / macOS
|
||||
|
||||
To provision the device running this example, the `esp_prov.py` script needs to be run (found under `$IDF_PATH/tools/esp_prov`). Make sure to satisfy all the dependencies prior to running the script.
|
||||
|
||||
Presently, `esp_prov` supports BLE transport only for Linux platform. For Windows/macOS it falls back to console mode and requires another application (for BLE) through which the communication can take place.
|
||||
|
||||
There are various applications, specific to Windows and macOS platform which can be used. The `esp_prov` console will guide you through the provisioning process of locating the correct BLE GATT services and characteristics, the values to write, and input read values.
|
||||
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
idf.py menuconfig
|
||||
```
|
||||
* Set the BLE/Soft AP transport under "Example Configuration" options. ESP32-S2 will have only SoftAP option.
|
||||
|
||||
### Build and Flash
|
||||
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```
|
||||
I (445) app: Starting provisioning
|
||||
I (1035) app: Provisioning started
|
||||
I (1045) wifi_prov_mgr: Provisioning started with service name : PROV_261FCC
|
||||
```
|
||||
|
||||
Make sure to note down the BLE device name (starting with `PROV_`) displayed in the serial monitor log (eg. PROV_261FCC). This will depend on the MAC ID and will be unique for every device.
|
||||
|
||||
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (make sure to replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). Assuming default example configuration, which uses protocomm security scheme 1 and proof of possession PoP based authentication :
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_261FCC --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword
|
||||
```
|
||||
|
||||
Above command will perform the provisioning steps, and the monitor log should display something like this :
|
||||
|
||||
```
|
||||
I (39725) app: Received Wi-Fi credentials
|
||||
SSID : myssid
|
||||
Password : mypassword
|
||||
.
|
||||
.
|
||||
.
|
||||
I (45335) tcpip_adapter: sta ip: 192.168.43.243, mask: 255.255.255.0, gw: 192.168.43.1
|
||||
I (45345) app: Provisioning successful
|
||||
I (45345) app: Connected with IP Address:192.168.43.243
|
||||
I (46355) app: Hello World!
|
||||
I (47355) app: Hello World!
|
||||
I (48355) app: Hello World!
|
||||
I (49355) app: Hello World!
|
||||
.
|
||||
.
|
||||
.
|
||||
I (52315) wifi_prov_mgr: Provisioning stopped
|
||||
.
|
||||
.
|
||||
.
|
||||
I (52355) app: Hello World!
|
||||
I (53355) app: Hello World!
|
||||
I (54355) app: Hello World!
|
||||
I (55355) app: Hello World!
|
||||
```
|
||||
|
||||
### Wi-Fi Scanning
|
||||
|
||||
Provisioning manager also supports providing real-time Wi-Fi scan results (performed on the device) during provisioning. This allows the client side applications to choose the AP for which the device Wi-Fi station is to be configured. Various information about the visible APs is available, like signal strength (RSSI) and security type, etc. Also, the manager now provides capabilities information which can be used by client applications to determine the security type and availability of specific features (like `wifi_scan`).
|
||||
|
||||
When using the scan based provisioning, we don't need to specify the `--ssid` and `--passphrase` fields explicitly:
|
||||
|
||||
```
|
||||
python esp_prov.py --transport ble --service_name PROV_261FCC --pop abcd1234
|
||||
```
|
||||
|
||||
See below the sample output from `esp_prov` tool on running above command:
|
||||
|
||||
```
|
||||
Connecting...
|
||||
Connected
|
||||
Getting Services...
|
||||
Security scheme determined to be : 1
|
||||
|
||||
==== Starting Session ====
|
||||
==== Session Established ====
|
||||
|
||||
==== Scanning Wi-Fi APs ====
|
||||
++++ Scan process executed in 1.9967520237 sec
|
||||
++++ Scan results : 5
|
||||
|
||||
++++ Scan finished in 2.7374596596 sec
|
||||
==== Wi-Fi Scan results ====
|
||||
S.N. SSID BSSID CHN RSSI AUTH
|
||||
[ 1] MyHomeWiFiAP 788a20841996 1 -45 WPA2_PSK
|
||||
[ 2] MobileHotspot 7a8a20841996 11 -46 WPA2_PSK
|
||||
[ 3] MyHomeWiFiAP 788a208daa26 11 -54 WPA2_PSK
|
||||
[ 4] NeighborsWiFiAP 8a8a20841996 6 -61 WPA2_PSK
|
||||
[ 5] InsecureWiFiAP dca4caf1227c 7 -74 Open
|
||||
|
||||
Select AP by number (0 to rescan) : 1
|
||||
Enter passphrase for MyHomeWiFiAP :
|
||||
|
||||
==== Sending Wi-Fi credential to esp32 ====
|
||||
==== Wi-Fi Credentials sent successfully ====
|
||||
|
||||
==== Applying config to esp32 ====
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wi-Fi connection state ====
|
||||
++++ WiFi state: connected ++++
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
### Sending Custom Data
|
||||
|
||||
The provisioning manager allows applications to send some custom data during provisioning, which may be
|
||||
required for some other operations like connecting to some cloud service. This is achieved by creating
|
||||
and registering additional endpoints using the below APIs
|
||||
|
||||
```
|
||||
wifi_prov_mgr_endpoint_create();
|
||||
wifi_prov_mgr_endpoint_register();
|
||||
```
|
||||
|
||||
In this particular example, we have added an endpoint named "custom-data" which can be tested
|
||||
by passing the `--custom_data <MyCustomData>` option to the esp\_prov tool. Following output is
|
||||
expected on success:
|
||||
|
||||
```
|
||||
==== Sending Custom data to esp32 ====
|
||||
CustomData response: SUCCESS
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Provisioning failed
|
||||
|
||||
It is possible that the Wi-Fi credentials provided were incorrect, or the device was not able to establish connection to the network, in which the the `esp_prov` script will notify failure (with reason). Serial monitor log will display the failure along with disconnect reason :
|
||||
|
||||
```
|
||||
E (367015) app: Provisioning failed!
|
||||
Reason : Wi-Fi AP password incorrect
|
||||
Please reset to factory and retry provisioning
|
||||
```
|
||||
|
||||
Once credentials have been applied, even though wrong credentials were provided, the device will no longer go into provisioning mode on subsequent reboots until NVS is erased (see following section).
|
||||
|
||||
### Provisioning does not start
|
||||
|
||||
If the serial monitor log shows the following :
|
||||
|
||||
```
|
||||
I (465) app: Already provisioned, starting Wi-Fi STA
|
||||
```
|
||||
|
||||
it means either the device has been provisioned earlier with or without success (e.g. scenario covered in above section), or that the Wi-Fi credentials were already set by some other application flashed previously onto your device. On setting the log level to DEBUG this is clearly evident :
|
||||
|
||||
```
|
||||
D (455) wifi_prov_mgr: Found Wi-Fi SSID : myssid
|
||||
D (465) wifi_prov_mgr: Found Wi-Fi Password : m********d
|
||||
I (465) app: Already provisioned, starting Wi-Fi STA
|
||||
```
|
||||
|
||||
To fix this we simple need to erase the NVS partition from flash. First we need to find out its address and size. This can be seen from the monitor log on the top right after reboot.
|
||||
|
||||
```
|
||||
I (47) boot: Partition Table:
|
||||
I (50) boot: ## Label Usage Type ST Offset Length
|
||||
I (58) boot: 0 nvs WiFi data 01 02 00009000 00006000
|
||||
I (65) boot: 1 phy_init RF data 01 01 0000f000 00001000
|
||||
I (73) boot: 2 factory factory app 00 00 00010000 00124f80
|
||||
I (80) boot: End of partition table
|
||||
```
|
||||
|
||||
Now erase NVS partition by running the following commands :
|
||||
|
||||
```
|
||||
$IDF_PATH/components/esptool_py/esptool/esptool.py erase_region 0x9000 0x6000
|
||||
```
|
||||
|
||||
### Unsupported platform
|
||||
|
||||
If the platform requirement, for running `esp_prov` is not satisfied, then the script execution will fallback to console mode, in which case the full process (involving user inputs) will look like this :
|
||||
|
||||
```
|
||||
==== Esp_Prov Version: v1.0 ====
|
||||
BLE client is running in console mode
|
||||
This could be due to your platform not being supported or dependencies not being met
|
||||
Please ensure all pre-requisites are met to run the full fledged client
|
||||
BLECLI >> Please connect to BLE device `PROV_261FCC` manually using your tool of choice
|
||||
BLECLI >> Was the device connected successfully? [y/n] y
|
||||
BLECLI >> List available attributes of the connected device
|
||||
BLECLI >> Is the service UUID '0000ffff-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff53-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff51-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
BLECLI >> Is the characteristic UUID '0000ff52-0000-1000-8000-00805f9b34fb' listed among available attributes? [y/n] y
|
||||
|
||||
==== Verifying protocol version ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff53-0000-1000-8000-00805f9b34fb' :
|
||||
>> 56302e31
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 53554343455353
|
||||
==== Verified protocol version successfully ====
|
||||
|
||||
==== Starting Session ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :
|
||||
>> 10015a25a201220a20ae6d9d5d1029f8c366892252d2d5a0ffa7ce1ee5829312545dd5f2aba057294d
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 10015a390801aa0134122048008bfc365fad4753dc75912e0c764d60749cb26dd609595b6fbc72e12614031a1089733af233c7448e7d7fb7963682c6d8
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff51-0000-1000-8000-00805f9b34fb' :
|
||||
>> 10015a270802b2012212204051088dc294fe4621fac934a8ea22e948fcc3e8ac458aac088ce705c65dbfb9
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 10015a270803ba01221a20c8d38059d5206a3d92642973ac6ba8ac2f6ecf2b7a3632964eb35a0f20133adb
|
||||
==== Session Established ====
|
||||
|
||||
==== Sending Wifi credential to esp32 ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 98471ac4019a46765c28d87df8c8ae71c1ae6cfe0bc9c615bc6d2c
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 3271f39a
|
||||
==== Wifi Credentials sent successfully ====
|
||||
|
||||
==== Applying config to esp32 ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 5355
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 1664db24
|
||||
==== Apply config sent successfully ====
|
||||
|
||||
==== Wifi connection state ====
|
||||
BLECLI >> Write following data to characteristic with UUID '0000ff52-0000-1000-8000-00805f9b34fb' :
|
||||
>> 290d
|
||||
BLECLI >> Enter data read from characteristic (in hex) :
|
||||
<< 505f72a9f8521025c1964d7789c4d7edc56aedebd144e1b667bc7c0975757b80cc091aa9f3e95b06eaefbc30290fa1
|
||||
++++ WiFi state: connected ++++
|
||||
==== Provisioning was successful ====
|
||||
```
|
||||
|
||||
The write data is to be copied from the console output ```>>``` to the platform specific application and the data read from the application is to be pasted at the user input prompt ```<<``` of the console, in the format (hex) indicated in above sample log.
|
@ -1,2 +0,0 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
INCLUDE_DIRS ".")
|
@ -1,22 +0,0 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
choice EXAMPLE_PROV_TRANSPORT
|
||||
bool "Provisioning Transport"
|
||||
default EXAMPLE_PROV_TRANSPORT_BLE
|
||||
help
|
||||
Wi-Fi provisioning component offers both, SoftAP and BLE transports. Choose any one.
|
||||
|
||||
config EXAMPLE_PROV_TRANSPORT_BLE
|
||||
bool "BLE"
|
||||
select BT_ENABLED
|
||||
depends on IDF_TARGET_ESP32
|
||||
config EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
bool "Soft AP"
|
||||
endchoice
|
||||
|
||||
config EXAMPLE_PROV_TRANSPORT
|
||||
int
|
||||
default 1 if EXAMPLE_PROV_TRANSPORT_BLE
|
||||
default 2 if EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
|
||||
endmenu
|
@ -1,282 +0,0 @@
|
||||
/* Wi-Fi Provisioning Manager Example
|
||||
|
||||
This example code is in the Public Domain (or CC0 licensed, at your option.)
|
||||
|
||||
Unless required by applicable law or agreed to in writing, this
|
||||
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
||||
CONDITIONS OF ANY KIND, either express or implied.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <freertos/event_groups.h>
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include <wifi_provisioning/manager.h>
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
#include <wifi_provisioning/scheme_ble.h>
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
#include <wifi_provisioning/scheme_softap.h>
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
/* 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,
|
||||
int 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 app_main(void)
|
||||
{
|
||||
/* Initialize NVS partition */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
|
||||
/* NVS partition was truncated
|
||||
* and needs to be erased */
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
|
||||
/* Retry nvs_flash_init */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
}
|
||||
|
||||
/* 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();
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
esp_netif_create_default_wifi_ap();
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
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 */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
.scheme = wifi_prov_scheme_ble,
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
.scheme = wifi_prov_scheme_softap,
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
|
||||
/* 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*/
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
.scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP
|
||||
.scheme_event_handler = WIFI_PROV_EVENT_HANDLER_NONE
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_SOFTAP */
|
||||
};
|
||||
|
||||
/* 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 (!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;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_PROV_TRANSPORT_BLE
|
||||
/* 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);
|
||||
#endif /* CONFIG_EXAMPLE_PROV_TRANSPORT_BLE */
|
||||
|
||||
/* 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);
|
||||
|
||||
/* Start main application now */
|
||||
while (1) {
|
||||
ESP_LOGI(TAG, "Hello World!");
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
#
|
||||
# Main component makefile.
|
||||
#
|
||||
# This Makefile can be left empty. By default, it will take the sources in the
|
||||
# src/ directory, compile them and link them into lib(subdirectory_name).a
|
||||
# in the build directory. This behaviour is entirely configurable,
|
||||
# please read the ESP-IDF documents if you need to do this.
|
||||
#
|
@ -1,5 +0,0 @@
|
||||
# Name, Type, SubType, Offset, Size, Flags
|
||||
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
|
||||
nvs, data, nvs, 0x9000, 0x6000,
|
||||
phy_init, data, phy, 0xf000, 0x1000,
|
||||
factory, app, factory, 0x10000, 1200000,
|
|
@ -1,11 +0,0 @@
|
||||
# Override some defaults so BT stack is enabled and
|
||||
CONFIG_BT_ENABLED=y
|
||||
CONFIG_BTDM_CTRL_MODE_BLE_ONLY=y
|
||||
CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLY=n
|
||||
CONFIG_BTDM_CTRL_MODE_BTDM=n
|
||||
CONFIG_BT_NIMBLE_ENABLED=y
|
||||
|
||||
## For Bluedroid as binary is larger than default size
|
||||
CONFIG_PARTITION_TABLE_CUSTOM=y
|
||||
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
|
||||
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"
|
@ -1,118 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2018 Espressif Systems (Shanghai) PTE LTD
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import print_function
|
||||
import re
|
||||
import os
|
||||
import time
|
||||
|
||||
import ttfw_idf
|
||||
import esp_prov
|
||||
|
||||
# Have esp_prov throw exception
|
||||
esp_prov.config_throw_except = True
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag="Example_WIFI_BT")
|
||||
def test_examples_wifi_prov_mgr(env, extra_data):
|
||||
# Acquire DUT
|
||||
dut1 = env.get_dut("wifi_prov_mgr", "examples/provisioning/wifi_prov_mgr", dut_class=ttfw_idf.ESP32DUT)
|
||||
|
||||
# Get binary file
|
||||
binary_file = os.path.join(dut1.app.binary_path, "wifi_prov_mgr.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("wifi_prov_mgr_bin_size", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("wifi_prov_mgr_bin_size", bin_size // 1024, dut1.TARGET)
|
||||
|
||||
# Upload binary and start testing
|
||||
dut1.start_app()
|
||||
|
||||
# Check if BT memory is released before provisioning starts
|
||||
dut1.expect("wifi_prov_scheme_ble: BT memory released", timeout=60)
|
||||
|
||||
# Parse BLE devname
|
||||
devname = dut1.expect(re.compile(r"Provisioning started with service name : (PROV_\S\S\S\S\S\S)"), timeout=30)[0]
|
||||
print("BLE Device Alias for DUT :", devname)
|
||||
|
||||
print("Starting Provisioning")
|
||||
verbose = False
|
||||
protover = "v1.1"
|
||||
secver = 1
|
||||
pop = "abcd1234"
|
||||
provmode = "ble"
|
||||
ap_ssid = "myssid"
|
||||
ap_password = "mypassword"
|
||||
|
||||
print("Getting security")
|
||||
security = esp_prov.get_security(secver, pop, verbose)
|
||||
if security is None:
|
||||
raise RuntimeError("Failed to get security")
|
||||
|
||||
print("Getting transport")
|
||||
transport = esp_prov.get_transport(provmode, devname)
|
||||
if transport is None:
|
||||
raise RuntimeError("Failed to get transport")
|
||||
|
||||
print("Verifying protocol version")
|
||||
if not esp_prov.version_match(transport, protover):
|
||||
raise RuntimeError("Mismatch in protocol version")
|
||||
|
||||
print("Verifying scan list capability")
|
||||
if not esp_prov.has_capability(transport, 'wifi_scan'):
|
||||
raise RuntimeError("Capability not present")
|
||||
|
||||
print("Starting Session")
|
||||
if not esp_prov.establish_session(transport, security):
|
||||
raise RuntimeError("Failed to start session")
|
||||
|
||||
print("Sending Custom Data")
|
||||
if not esp_prov.custom_data(transport, security, "My Custom Data"):
|
||||
raise RuntimeError("Failed to send custom data")
|
||||
|
||||
print("Sending Wifi credential to DUT")
|
||||
if not esp_prov.send_wifi_config(transport, security, ap_ssid, ap_password):
|
||||
raise RuntimeError("Failed to send Wi-Fi config")
|
||||
|
||||
print("Applying config")
|
||||
if not esp_prov.apply_wifi_config(transport, security):
|
||||
raise RuntimeError("Failed to send apply config")
|
||||
|
||||
success = False
|
||||
retry = 0
|
||||
while True:
|
||||
time.sleep(5)
|
||||
print("Wi-Fi connection state")
|
||||
ret = esp_prov.get_wifi_config(transport, security)
|
||||
if (ret == 1):
|
||||
continue
|
||||
elif (ret == 0):
|
||||
print("Provisioning was successful")
|
||||
success = True
|
||||
elif (ret == 3 and retry < 3):
|
||||
retry = retry + 1
|
||||
print("Connection failed.. retry again...: ", ret)
|
||||
continue
|
||||
break
|
||||
|
||||
if not success:
|
||||
raise RuntimeError("Provisioning failed")
|
||||
|
||||
# Check if BTDM memory is released after provisioning finishes
|
||||
dut1.expect("wifi_prov_scheme_ble: BTDM memory released", timeout=30)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_wifi_prov_mgr()
|
Reference in New Issue
Block a user