Skip to content

Commit d796985

Browse files
committed
app_wifi: Minor feature additions to provisioning workflow
- Provide an option of provisioning without PoP pin (use with caution). - Config option for provisioning timeout (set to 30 min by default). Useful especially when there is no PoP, and so you want to keep the device in provisioning mode only for a few minutes after boot up.
1 parent 174a38b commit d796985

File tree

4 files changed

+123
-30
lines changed

4 files changed

+123
-30
lines changed

CHANGES.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changes
22

3+
## 25-Jan-2022 (app_wifi: Minor feature additions to provisioning workflow)
4+
5+
Added a 30 minute timeout for Wi-Fi provisioning as a security measure. A device reboot will be
6+
required to restart provisioning after it times out. The value can changed using the
7+
`CONFIG_APP_WIFI_PROV_TIMEOUT_PERIOD` config option. A value of 0 will disable the timeout logic.
8+
`APP_WIFI_EVENT_PROV_TIMEOUT` event will be triggerd to indicate that the provisioning has timed out.
9+
310
## 25-Jan-2022 (examples: Enable some security features and change order of component dirs)
411

512
A couple of security features were added some time back, viz.

examples/common/app_wifi/Kconfig.projbuild

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,12 @@ menu "ESP RainMaker App Wi-Fi Provisioning"
3131
help
3232
Show some intro text for demos in order to help users understand more about ESP RainMaker.
3333

34+
config APP_WIFI_PROV_TIMEOUT_PERIOD
35+
int "Provisioning Timeout"
36+
default 30
37+
help
38+
Timeout (in minutes) after which the provisioning will auto stop. A reboot will be required
39+
to restart provisioning. Set to 0 if you do not want provisioning to auto stop.
40+
It is recommended to set this to some non zero value if provisioning does not have PoP.
41+
3442
endmenu

examples/common/app_wifi/app_wifi.c

Lines changed: 91 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@
3434
#include <qrcode.h>
3535
#include <nvs.h>
3636
#include <nvs_flash.h>
37+
#include <esp_timer.h>
3738
#include "app_wifi.h"
3839

40+
ESP_EVENT_DEFINE_BASE(APP_WIFI_EVENT);
3941
static const char *TAG = "app_wifi";
4042
static const int WIFI_CONNECTED_EVENT = BIT0;
4143
static EventGroupHandle_t wifi_event_group;
@@ -49,6 +51,12 @@ static EventGroupHandle_t wifi_event_group;
4951
#define CREDENTIALS_NAMESPACE "rmaker_creds"
5052
#define RANDOM_NVS_KEY "random"
5153

54+
#define POP_STR_SIZE 9
55+
static esp_timer_handle_t prov_stop_timer;
56+
/* Timeout period in minutes */
57+
#define APP_WIFI_PROV_TIMEOUT_PERIOD CONFIG_APP_WIFI_PROV_TIMEOUT_PERIOD
58+
/* Autofetch period in micro-seconds */
59+
static uint64_t prov_timeout_period = (APP_WIFI_PROV_TIMEOUT_PERIOD * 60 * 1000000LL);
5260
#ifdef CONFIG_APP_WIFI_SHOW_DEMO_INTRO_TEXT
5361

5462
#define ESP_RAINMAKER_GITHUB_EXAMPLES_PATH "https://github.com/espressif/esp-rainmaker/blob/master/examples"
@@ -94,19 +102,26 @@ static void intro_print(bool provisioned)
94102

95103
static void app_wifi_print_qr(const char *name, const char *pop, const char *transport)
96104
{
97-
if (!name || !pop || !transport) {
105+
if (!name || !transport) {
98106
ESP_LOGW(TAG, "Cannot generate QR code payload. Data missing.");
99107
return;
100108
}
101109
char payload[150];
102-
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
103-
",\"pop\":\"%s\",\"transport\":\"%s\"}",
104-
PROV_QR_VERSION, name, pop, transport);
110+
if (pop) {
111+
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
112+
",\"pop\":\"%s\",\"transport\":\"%s\"}",
113+
PROV_QR_VERSION, name, pop, transport);
114+
} else {
115+
snprintf(payload, sizeof(payload), "{\"ver\":\"%s\",\"name\":\"%s\"" \
116+
",\"transport\":\"%s\"}",
117+
PROV_QR_VERSION, name, transport);
118+
}
105119
#ifdef CONFIG_APP_WIFI_PROV_SHOW_QR
106120
ESP_LOGI(TAG, "Scan this QR code from the ESP RainMaker phone app for Provisioning.");
107121
qrcode_display(payload);
108122
#endif /* CONFIG_APP_WIFI_PROV_SHOW_QR */
109123
ESP_LOGI(TAG, "If QR code is not visible, copy paste the below URL in a browser.\n%s?data=%s", QRCODE_BASE_URL, payload);
124+
esp_event_post(APP_WIFI_EVENT, APP_WIFI_EVENT_QR_DISPLAY, payload, strlen(payload) + 1, portMAX_DELAY);
110125
}
111126

112127
/* Event handler for catching system events */
@@ -138,6 +153,11 @@ static void event_handler(void* arg, esp_event_base_t event_base,
138153
ESP_LOGI(TAG, "Provisioning successful");
139154
break;
140155
case WIFI_PROV_END:
156+
if (prov_stop_timer) {
157+
esp_timer_stop(prov_stop_timer);
158+
esp_timer_delete(prov_stop_timer);
159+
prov_stop_timer = NULL;
160+
}
141161
/* De-initialize manager once provisioning is finished */
142162
wifi_prov_mgr_deinit();
143163
break;
@@ -212,34 +232,45 @@ static esp_err_t get_device_service_name(char *service_name, size_t max)
212232
}
213233

214234

215-
static esp_err_t get_device_pop(char *pop, size_t max, app_wifi_pop_type_t pop_type)
235+
static char *get_device_pop(app_wifi_pop_type_t pop_type)
216236
{
217-
if (!pop || !max) {
218-
return ESP_ERR_INVALID_ARG;
237+
if (pop_type == POP_TYPE_NONE) {
238+
return NULL;
239+
}
240+
char *pop = calloc(1, POP_STR_SIZE);
241+
if (!pop) {
242+
ESP_LOGE(TAG, "Failed to allocate memory for PoP.");
243+
return NULL;
219244
}
220245

221246
if (pop_type == POP_TYPE_MAC) {
222247
uint8_t eth_mac[6];
223248
esp_err_t err = esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
224249
if (err == ESP_OK) {
225-
snprintf(pop, max, "%02x%02x%02x%02x", eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]);
226-
return ESP_OK;
250+
snprintf(pop, POP_STR_SIZE, "%02x%02x%02x%02x", eth_mac[2], eth_mac[3], eth_mac[4], eth_mac[5]);
251+
return pop;
227252
} else {
228-
return err;
253+
ESP_LOGE(TAG, "Failed to get MAC address to generate PoP.");
254+
goto pop_err;
229255
}
230256
} else if (pop_type == POP_TYPE_RANDOM) {
231-
uint8_t *nvs_random;
257+
uint8_t *nvs_random = NULL;
232258
size_t nvs_random_size = 0;
233259
if ((read_random_bytes_from_nvs(&nvs_random, &nvs_random_size) != ESP_OK) || nvs_random_size < 4) {
234-
return ESP_ERR_NOT_FOUND;
260+
ESP_LOGE(TAG, "Failed to read random bytes from NVS to generate PoP.");
261+
if (nvs_random) {
262+
free(nvs_random);
263+
}
264+
goto pop_err;
235265
} else {
236-
snprintf(pop, max, "%02x%02x%02x%02x", nvs_random[0], nvs_random[1], nvs_random[2], nvs_random[3]);
266+
snprintf(pop, POP_STR_SIZE, "%02x%02x%02x%02x", nvs_random[0], nvs_random[1], nvs_random[2], nvs_random[3]);
237267
free(nvs_random);
238-
return ESP_OK;
268+
return pop;
239269
}
240-
} else {
241-
return ESP_ERR_INVALID_ARG;
242270
}
271+
pop_err:
272+
free(pop);
273+
return NULL;
243274
}
244275

245276
void app_wifi_init(void)
@@ -268,6 +299,35 @@ void app_wifi_init(void)
268299
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
269300
}
270301

302+
static void app_wifi_prov_stop(void *priv)
303+
{
304+
ESP_LOGW(TAG, "Provisioning timed out. Please reboot device to restart provisioning.");
305+
wifi_prov_mgr_stop_provisioning();
306+
esp_event_post(APP_WIFI_EVENT, APP_WIFI_EVENT_PROV_TIMEOUT, NULL, 0, portMAX_DELAY);
307+
}
308+
309+
esp_err_t app_wifi_start_timer(void)
310+
{
311+
if (prov_timeout_period == 0) {
312+
return ESP_OK;
313+
}
314+
esp_timer_create_args_t prov_stop_timer_conf = {
315+
.callback = app_wifi_prov_stop,
316+
.arg = NULL,
317+
.dispatch_method = ESP_TIMER_TASK,
318+
.name = "app_wifi_prov_stop_tm"
319+
};
320+
if (esp_timer_create(&prov_stop_timer_conf, &prov_stop_timer) == ESP_OK) {
321+
esp_timer_start_once(prov_stop_timer, prov_timeout_period);
322+
ESP_LOGI(TAG, "Provisioning will auto stop after %d minute(s).",
323+
APP_WIFI_PROV_TIMEOUT_PERIOD);
324+
return ESP_OK;
325+
} else {
326+
ESP_LOGE(TAG, "Failed to create Provisioning auto stop timer.");
327+
}
328+
return ESP_FAIL;
329+
}
330+
271331
esp_err_t app_wifi_start(app_wifi_pop_type_t pop_type)
272332
{
273333
/* Configuration for the provisioning manager */
@@ -317,6 +377,12 @@ esp_err_t app_wifi_start(app_wifi_pop_type_t pop_type)
317377
char service_name[12];
318378
get_device_service_name(service_name, sizeof(service_name));
319379

380+
/* What is the service key (Wi-Fi password)
381+
* NULL = Open network
382+
* This is ignored when scheme is wifi_prov_scheme_ble
383+
*/
384+
const char *service_key = NULL;
385+
320386
/* What is the security level that we want (0 or 1):
321387
* - WIFI_PROV_SECURITY_0 is simply plain text communication.
322388
* - WIFI_PROV_SECURITY_1 is secure communication which consists of secure handshake
@@ -329,19 +395,11 @@ esp_err_t app_wifi_start(app_wifi_pop_type_t pop_type)
329395
* - this should be a string with length > 0
330396
* - NULL if not used
331397
*/
332-
char pop[9];
333-
esp_err_t err = get_device_pop(pop, sizeof(pop), pop_type);
334-
if (err != ESP_OK) {
335-
ESP_LOGE(TAG, "Error: %d. Failed to get PoP from NVS, Please perform Claiming.", err);
336-
return err;
398+
char *pop = get_device_pop(pop_type);
399+
if ((pop_type != POP_TYPE_NONE) && (pop == NULL)) {
400+
return ESP_ERR_NO_MEM;
337401
}
338402

339-
/* What is the service key (Wi-Fi password)
340-
* NULL = Open network
341-
* This is ignored when scheme is wifi_prov_scheme_ble
342-
*/
343-
const char *service_key = NULL;
344-
345403
#ifdef CONFIG_APP_WIFI_PROV_TRANSPORT_BLE
346404
/* This step is only useful when scheme is wifi_prov_scheme_ble. This will
347405
* set a custom 128 bit UUID which will be included in the BLE advertisement
@@ -358,7 +416,7 @@ esp_err_t app_wifi_start(app_wifi_pop_type_t pop_type)
358416
0xb4, 0xdf, 0x5a, 0x1c, 0x3f, 0x6b, 0xf4, 0xbf,
359417
0xea, 0x4a, 0x82, 0x03, 0x04, 0x90, 0x1a, 0x02,
360418
};
361-
err = wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid);
419+
esp_err_t err = wifi_prov_scheme_ble_set_service_uuid(custom_service_uuid);
362420
if (err != ESP_OK) {
363421
ESP_LOGE(TAG, "wifi_prov_scheme_ble_set_service_uuid failed %d", err);
364422
return err;
@@ -374,7 +432,11 @@ esp_err_t app_wifi_start(app_wifi_pop_type_t pop_type)
374432
app_wifi_print_qr(service_name, pop, PROV_TRANSPORT_SOFTAP);
375433
#endif /* CONFIG_APP_WIFI_PROV_TRANSPORT_BLE */
376434
intro_print(provisioned);
377-
ESP_LOGI(TAG, "Provisioning Started. Name : %s, POP : %s", service_name, pop);
435+
ESP_LOGI(TAG, "Provisioning Started. Name : %s, POP : %s", service_name, pop ? pop : "<null>");
436+
if (pop) {
437+
free(pop);
438+
}
439+
app_wifi_start_timer();
378440
} else {
379441
ESP_LOGI(TAG, "Already provisioned, starting Wi-Fi STA");
380442
intro_print(provisioned);

examples/common/app_wifi/app_wifi.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,29 @@
77
*/
88
#pragma once
99
#include <esp_err.h>
10+
#include <esp_event.h>
11+
12+
/** ESP RainMaker Event Base */
13+
ESP_EVENT_DECLARE_BASE(APP_WIFI_EVENT);
14+
15+
/** App Wi-Fir Events */
16+
typedef enum {
17+
/** QR code available for display. Associated data is the NULL terminated QR payload. */
18+
APP_WIFI_EVENT_QR_DISPLAY = 1,
19+
/** Provisioning timed out */
20+
APP_WIFI_EVENT_PROV_TIMEOUT,
21+
} app_wifi_event_t;
1022

1123
/** Types of Proof of Possession */
1224
typedef enum {
1325
/** Use MAC address to generate PoP */
1426
POP_TYPE_MAC,
1527
/** Use random stream generated and stored in fctry partition during claiming process as PoP */
16-
POP_TYPE_RANDOM
28+
POP_TYPE_RANDOM,
29+
/** Do not use any PoP.
30+
* Use this option with caution. Consider using `CONFIG_APP_WIFI_PROV_TIMEOUT_PERIOD` with this.
31+
*/
32+
POP_TYPE_NONE
1733
} app_wifi_pop_type_t;
1834

1935
void app_wifi_init();

0 commit comments

Comments
 (0)