mirror of
https://gitee.com/beecue/fastbee.git
synced 2025-12-19 17:35:54 +08:00
添加智能灯固件代码
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# 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)
|
||||
@@ -0,0 +1,9 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
# 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.
|
||||
@@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c"
|
||||
INCLUDE_DIRS ".")
|
||||
@@ -0,0 +1,40 @@
|
||||
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
|
||||
@@ -0,0 +1,116 @@
|
||||
/* 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();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,325 @@
|
||||
/* 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;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/* 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);
|
||||
@@ -0,0 +1,135 @@
|
||||
/* 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 memcpy 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 */
|
||||
const size_t ssid_len = strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid));
|
||||
/* Ensure SSID less than 32 bytes is null terminated */
|
||||
memset(wifi_cfg->sta.ssid, 0, sizeof(wifi_cfg->sta.ssid));
|
||||
memcpy(wifi_cfg->sta.ssid, req_data->ssid, ssid_len);
|
||||
|
||||
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
|
||||
};
|
||||
@@ -0,0 +1,8 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
Reference in New Issue
Block a user