35
35
#include <qrcode.h>
36
36
#include <nvs.h>
37
37
#include <nvs_flash.h>
38
+ #include <esp_timer.h>
38
39
#include "app_wifi_with_homekit.h"
39
40
41
+ ESP_EVENT_DEFINE_BASE (APP_WIFI_EVENT );
40
42
#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
41
43
#include <hap_wac.h>
42
44
#endif /* CONFIG_APP_WIFI_USE_WAC_PROVISIONING */
@@ -54,21 +56,35 @@ static EventGroupHandle_t wifi_event_group;
54
56
#define CREDENTIALS_NAMESPACE "rmaker_creds"
55
57
#define RANDOM_NVS_KEY "random"
56
58
59
+ #define POP_STR_SIZE 9
60
+ static esp_timer_handle_t prov_stop_timer ;
61
+ /* Timeout period in minutes */
62
+ #define APP_WIFI_PROV_TIMEOUT_PERIOD CONFIG_APP_WIFI_PROV_TIMEOUT_PERIOD
63
+ /* Autofetch period in micro-seconds */
64
+ static uint64_t prov_timeout_period = (APP_WIFI_PROV_TIMEOUT_PERIOD * 60 * 1000000LL );
65
+
57
66
static void app_wifi_print_qr (const char * name , const char * pop , const char * transport )
58
67
{
59
- if (!name || !pop || ! transport ) {
68
+ if (!name || !transport ) {
60
69
ESP_LOGW (TAG , "Cannot generate QR code payload. Data missing." );
61
70
return ;
62
71
}
63
72
char payload [150 ];
64
- snprintf (payload , sizeof (payload ), "{\"ver\":\"%s\",\"name\":\"%s\"" \
65
- ",\"pop\":\"%s\",\"transport\":\"%s\"}" ,
66
- PROV_QR_VERSION , name , pop , transport );
73
+ if (pop ) {
74
+ snprintf (payload , sizeof (payload ), "{\"ver\":\"%s\",\"name\":\"%s\"" \
75
+ ",\"pop\":\"%s\",\"transport\":\"%s\"}" ,
76
+ PROV_QR_VERSION , name , pop , transport );
77
+ } else {
78
+ snprintf (payload , sizeof (payload ), "{\"ver\":\"%s\",\"name\":\"%s\"" \
79
+ ",\"transport\":\"%s\"}" ,
80
+ PROV_QR_VERSION , name , transport );
81
+ }
67
82
#ifdef CONFIG_APP_WIFI_PROV_SHOW_QR
68
83
ESP_LOGI (TAG , "Scan this QR code from the phone app for Provisioning." );
69
84
qrcode_display (payload );
70
85
#endif /* CONFIG_APP_WIFI_PROV_SHOW_QR */
71
86
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 );
87
+ esp_event_post (APP_WIFI_EVENT , APP_WIFI_EVENT_QR_DISPLAY , payload , strlen (payload ) + 1 , portMAX_DELAY );
72
88
}
73
89
74
90
#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
@@ -97,6 +113,9 @@ static void app_wac_sta_connect(wifi_config_t *wifi_cfg)
97
113
static void event_handler (void * arg , esp_event_base_t event_base ,
98
114
int32_t event_id , void * event_data )
99
115
{
116
+ #ifdef CONFIG_APP_WIFI_RESET_PROV_ON_FAILURE
117
+ static int retries = 0 ;
118
+ #endif
100
119
if (event_base == WIFI_PROV_EVENT ) {
101
120
switch (event_id ) {
102
121
case WIFI_PROV_START :
@@ -116,12 +135,33 @@ static void event_handler(void* arg, esp_event_base_t event_base,
116
135
"\n\tPlease reset to factory and retry provisioning" ,
117
136
(* reason == WIFI_PROV_STA_AUTH_ERROR ) ?
118
137
"Wi-Fi station authentication failed" : "Wi-Fi access-point not found" );
138
+ #ifdef CONFIG_APP_WIFI_RESET_PROV_ON_FAILURE
139
+ retries ++ ;
140
+ if (retries >= CONFIG_APP_WIFI_PROV_MAX_RETRY_CNT ) {
141
+ #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL (4 , 3 , 1 )
142
+ ESP_LOGI (TAG , "Failed to connect with provisioned AP, reseting provisioned credentials" );
143
+ wifi_prov_mgr_reset_sm_state_on_failure ();
144
+ esp_event_post (APP_WIFI_EVENT , APP_WIFI_EVENT_PROV_RESTART , NULL , 0 , portMAX_DELAY );
145
+ #else
146
+ ESP_LOGW (TAG , "Failed to connect with provisioned AP, please reset to provisioning manually" );
147
+ #endif
148
+ retries = 0 ;
149
+ }
150
+ #endif
119
151
break ;
120
152
}
121
153
case WIFI_PROV_CRED_SUCCESS :
122
154
ESP_LOGI (TAG , "Provisioning successful" );
155
+ #ifdef CONFIG_APP_WIFI_RESET_PROV_ON_FAILURE
156
+ retries = 0 ;
157
+ #endif
123
158
break ;
124
159
case WIFI_PROV_END :
160
+ if (prov_stop_timer ) {
161
+ esp_timer_stop (prov_stop_timer );
162
+ esp_timer_delete (prov_stop_timer );
163
+ prov_stop_timer = NULL ;
164
+ }
125
165
#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
126
166
hap_wac_stop ();
127
167
#endif
@@ -209,14 +249,14 @@ static esp_err_t read_random_bytes_from_nvs(uint8_t **random_bytes, size_t *len)
209
249
static esp_err_t get_device_service_name (char * service_name , size_t max )
210
250
{
211
251
uint8_t * nvs_random = NULL ;
212
- const char * ssid_prefix = "PROV_" ;
252
+ const char * ssid_prefix = CONFIG_APP_WIFI_PROV_NAME_PREFIX ;
213
253
size_t nvs_random_size = 0 ;
214
254
if ((read_random_bytes_from_nvs (& nvs_random , & nvs_random_size ) != ESP_OK ) || nvs_random_size < 3 ) {
215
255
uint8_t eth_mac [6 ];
216
256
esp_wifi_get_mac (WIFI_IF_STA , eth_mac );
217
- snprintf (service_name , max , "%s %02x%02x%02x" , ssid_prefix , eth_mac [3 ], eth_mac [4 ], eth_mac [5 ]);
257
+ snprintf (service_name , max , "%s_ %02x%02x%02x" , ssid_prefix , eth_mac [3 ], eth_mac [4 ], eth_mac [5 ]);
218
258
} else {
219
- snprintf (service_name , max , "%s %02x%02x%02x" , ssid_prefix , nvs_random [nvs_random_size - 3 ],
259
+ snprintf (service_name , max , "%s_ %02x%02x%02x" , ssid_prefix , nvs_random [nvs_random_size - 3 ],
220
260
nvs_random [nvs_random_size - 2 ], nvs_random [nvs_random_size - 1 ]);
221
261
}
222
262
if (nvs_random ) {
@@ -226,34 +266,45 @@ static esp_err_t get_device_service_name(char *service_name, size_t max)
226
266
}
227
267
228
268
229
- static esp_err_t get_device_pop ( char * pop , size_t max , app_wifi_pop_type_t pop_type )
269
+ static char * get_device_pop ( app_wifi_pop_type_t pop_type )
230
270
{
231
- if (!pop || !max ) {
232
- return ESP_ERR_INVALID_ARG ;
271
+ if (pop_type == POP_TYPE_NONE ) {
272
+ return NULL ;
273
+ }
274
+ char * pop = calloc (1 , POP_STR_SIZE );
275
+ if (!pop ) {
276
+ ESP_LOGE (TAG , "Failed to allocate memory for PoP." );
277
+ return NULL ;
233
278
}
234
279
235
280
if (pop_type == POP_TYPE_MAC ) {
236
281
uint8_t eth_mac [6 ];
237
282
esp_err_t err = esp_wifi_get_mac (WIFI_IF_STA , eth_mac );
238
283
if (err == ESP_OK ) {
239
- snprintf (pop , max , "%02x%02x%02x%02x" , eth_mac [2 ], eth_mac [3 ], eth_mac [4 ], eth_mac [5 ]);
240
- return ESP_OK ;
284
+ snprintf (pop , POP_STR_SIZE , "%02x%02x%02x%02x" , eth_mac [2 ], eth_mac [3 ], eth_mac [4 ], eth_mac [5 ]);
285
+ return pop ;
241
286
} else {
242
- return err ;
287
+ ESP_LOGE (TAG , "Failed to get MAC address to generate PoP." );
288
+ goto pop_err ;
243
289
}
244
290
} else if (pop_type == POP_TYPE_RANDOM ) {
245
- uint8_t * nvs_random ;
291
+ uint8_t * nvs_random = NULL ;
246
292
size_t nvs_random_size = 0 ;
247
293
if ((read_random_bytes_from_nvs (& nvs_random , & nvs_random_size ) != ESP_OK ) || nvs_random_size < 4 ) {
248
- return ESP_ERR_NOT_FOUND ;
294
+ ESP_LOGE (TAG , "Failed to read random bytes from NVS to generate PoP." );
295
+ if (nvs_random ) {
296
+ free (nvs_random );
297
+ }
298
+ goto pop_err ;
249
299
} else {
250
- snprintf (pop , max , "%02x%02x%02x%02x" , nvs_random [0 ], nvs_random [1 ], nvs_random [2 ], nvs_random [3 ]);
300
+ snprintf (pop , POP_STR_SIZE , "%02x%02x%02x%02x" , nvs_random [0 ], nvs_random [1 ], nvs_random [2 ], nvs_random [3 ]);
251
301
free (nvs_random );
252
- return ESP_OK ;
302
+ return pop ;
253
303
}
254
- } else {
255
- return ESP_ERR_INVALID_ARG ;
256
304
}
305
+ pop_err :
306
+ free (pop );
307
+ return NULL ;
257
308
}
258
309
259
310
void app_wifi_with_homekit_init (void )
@@ -288,6 +339,35 @@ void app_wifi_with_homekit_init(void)
288
339
ESP_ERROR_CHECK (esp_wifi_init (& cfg ));
289
340
}
290
341
342
+ static void app_wifi_prov_stop (void * priv )
343
+ {
344
+ ESP_LOGW (TAG , "Provisioning timed out. Please reboot device to restart provisioning." );
345
+ wifi_prov_mgr_stop_provisioning ();
346
+ esp_event_post (APP_WIFI_EVENT , APP_WIFI_EVENT_PROV_TIMEOUT , NULL , 0 , portMAX_DELAY );
347
+ }
348
+
349
+ esp_err_t app_wifi_start_timer (void )
350
+ {
351
+ if (prov_timeout_period == 0 ) {
352
+ return ESP_OK ;
353
+ }
354
+ esp_timer_create_args_t prov_stop_timer_conf = {
355
+ .callback = app_wifi_prov_stop ,
356
+ .arg = NULL ,
357
+ .dispatch_method = ESP_TIMER_TASK ,
358
+ .name = "app_wifi_prov_stop_tm"
359
+ };
360
+ if (esp_timer_create (& prov_stop_timer_conf , & prov_stop_timer ) == ESP_OK ) {
361
+ esp_timer_start_once (prov_stop_timer , prov_timeout_period );
362
+ ESP_LOGI (TAG , "Provisioning will auto stop after %d minute(s)." ,
363
+ APP_WIFI_PROV_TIMEOUT_PERIOD );
364
+ return ESP_OK ;
365
+ } else {
366
+ ESP_LOGE (TAG , "Failed to create Provisioning auto stop timer." );
367
+ }
368
+ return ESP_FAIL ;
369
+ }
370
+
291
371
esp_err_t app_wifi_with_homekit_start (app_wifi_pop_type_t pop_type )
292
372
{
293
373
/* Configuration for the provisioning manager */
@@ -329,7 +409,6 @@ esp_err_t app_wifi_with_homekit_start(app_wifi_pop_type_t pop_type)
329
409
#ifdef ESP_NETIF_SUPPORTED
330
410
esp_netif_create_default_wifi_ap ();
331
411
#endif
332
-
333
412
/* What is the Device Service Name that we want
334
413
* This translates to :
335
414
* - Wi-Fi SSID when scheme is wifi_prov_scheme_softap
@@ -338,6 +417,12 @@ esp_err_t app_wifi_with_homekit_start(app_wifi_pop_type_t pop_type)
338
417
char service_name [12 ];
339
418
get_device_service_name (service_name , sizeof (service_name ));
340
419
420
+ /* What is the service key (Wi-Fi password)
421
+ * NULL = Open network
422
+ * This is ignored when scheme is wifi_prov_scheme_ble
423
+ */
424
+ const char * service_key = NULL ;
425
+
341
426
/* What is the security level that we want (0 or 1):
342
427
* - WIFI_PROV_SECURITY_0 is simply plain text communication.
343
428
* - WIFI_PROV_SECURITY_1 is secure communication which consists of secure handshake
@@ -350,19 +435,11 @@ esp_err_t app_wifi_with_homekit_start(app_wifi_pop_type_t pop_type)
350
435
* - this should be a string with length > 0
351
436
* - NULL if not used
352
437
*/
353
- char pop [9 ];
354
- esp_err_t err = get_device_pop (pop , sizeof (pop ), pop_type );
355
- if (err != ESP_OK ) {
356
- ESP_LOGE (TAG , "Error: %d. Failed to get PoP from NVS, Please perform Claiming." , err );
357
- return err ;
438
+ char * pop = get_device_pop (pop_type );
439
+ if ((pop_type != POP_TYPE_NONE ) && (pop == NULL )) {
440
+ return ESP_ERR_NO_MEM ;
358
441
}
359
442
360
- /* What is the service key (Wi-Fi password)
361
- * NULL = Open network
362
- * This is ignored when scheme is wifi_prov_scheme_ble
363
- */
364
- const char * service_key = NULL ;
365
-
366
443
#ifdef CONFIG_APP_WIFI_PROV_TRANSPORT_BLE
367
444
/* This step is only useful when scheme is wifi_prov_scheme_ble. This will
368
445
* set a custom 128 bit UUID which will be included in the BLE advertisement
@@ -379,12 +456,14 @@ esp_err_t app_wifi_with_homekit_start(app_wifi_pop_type_t pop_type)
379
456
0xb4 , 0xdf , 0x5a , 0x1c , 0x3f , 0x6b , 0xf4 , 0xbf ,
380
457
0xea , 0x4a , 0x82 , 0x03 , 0x04 , 0x90 , 0x1a , 0x02 ,
381
458
};
382
- err = wifi_prov_scheme_ble_set_service_uuid (custom_service_uuid );
459
+ esp_err_t err = wifi_prov_scheme_ble_set_service_uuid (custom_service_uuid );
383
460
if (err != ESP_OK ) {
384
461
ESP_LOGE (TAG , "wifi_prov_scheme_ble_set_service_uuid failed %d" , err );
385
462
return err ;
386
463
}
387
464
#endif /* CONFIG_APP_WIFI_PROV_TRANSPORT_BLE */
465
+
466
+
388
467
#ifdef CONFIG_APP_WIFI_PROV_TRANSPORT_SOFTAP
389
468
wifi_prov_scheme_softap_set_httpd_handle (hap_platform_httpd_get_handle ());
390
469
#endif /* CONFIG_APP_WIFI_PROV_TRANSPORT_SOFTAP */
@@ -397,9 +476,13 @@ esp_err_t app_wifi_with_homekit_start(app_wifi_pop_type_t pop_type)
397
476
#else /* CONFIG_APP_WIFI_PROV_TRANSPORT_SOFTAP */
398
477
app_wifi_print_qr (service_name , pop , PROV_TRANSPORT_SOFTAP );
399
478
#endif /* CONFIG_APP_WIFI_PROV_TRANSPORT_BLE */
400
- ESP_LOGI (TAG , "Provisioning Started. Name : %s, POP : %s" , service_name , pop );
479
+ ESP_LOGI (TAG , "Provisioning Started. Name : %s, POP : %s" , service_name , pop ? pop : "<null>" );
480
+ app_wifi_start_timer ();
401
481
#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
402
482
esp_event_handler_register (HAP_WAC_EVENT , ESP_EVENT_ANY_ID , & event_handler , NULL );
483
+ if (pop ) {
484
+ free (pop );
485
+ }
403
486
hap_wac_start ();
404
487
#endif /* CONFIG_APP_WIFI_USE_WAC_PROVISIONING */
405
488
} else {
0 commit comments