3535#include <qrcode.h>
3636#include <nvs.h>
3737#include <nvs_flash.h>
38+ #include <esp_timer.h>
3839#include "app_wifi_with_homekit.h"
3940
41+ ESP_EVENT_DEFINE_BASE (APP_WIFI_EVENT );
4042#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
4143#include <hap_wac.h>
4244#endif /* CONFIG_APP_WIFI_USE_WAC_PROVISIONING */
@@ -54,21 +56,35 @@ static EventGroupHandle_t wifi_event_group;
5456#define CREDENTIALS_NAMESPACE "rmaker_creds"
5557#define RANDOM_NVS_KEY "random"
5658
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+
5766static void app_wifi_print_qr (const char * name , const char * pop , const char * transport )
5867{
59- if (!name || !pop || ! transport ) {
68+ if (!name || !transport ) {
6069 ESP_LOGW (TAG , "Cannot generate QR code payload. Data missing." );
6170 return ;
6271 }
6372 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+ }
6782#ifdef CONFIG_APP_WIFI_PROV_SHOW_QR
6883 ESP_LOGI (TAG , "Scan this QR code from the phone app for Provisioning." );
6984 qrcode_display (payload );
7085#endif /* CONFIG_APP_WIFI_PROV_SHOW_QR */
7186 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 );
7288}
7389
7490#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
@@ -97,6 +113,9 @@ static void app_wac_sta_connect(wifi_config_t *wifi_cfg)
97113static void event_handler (void * arg , esp_event_base_t event_base ,
98114 int32_t event_id , void * event_data )
99115{
116+ #ifdef CONFIG_APP_WIFI_RESET_PROV_ON_FAILURE
117+ static int retries = 0 ;
118+ #endif
100119 if (event_base == WIFI_PROV_EVENT ) {
101120 switch (event_id ) {
102121 case WIFI_PROV_START :
@@ -116,12 +135,33 @@ static void event_handler(void* arg, esp_event_base_t event_base,
116135 "\n\tPlease reset to factory and retry provisioning" ,
117136 (* reason == WIFI_PROV_STA_AUTH_ERROR ) ?
118137 "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
119151 break ;
120152 }
121153 case WIFI_PROV_CRED_SUCCESS :
122154 ESP_LOGI (TAG , "Provisioning successful" );
155+ #ifdef CONFIG_APP_WIFI_RESET_PROV_ON_FAILURE
156+ retries = 0 ;
157+ #endif
123158 break ;
124159 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+ }
125165#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
126166 hap_wac_stop ();
127167#endif
@@ -209,14 +249,14 @@ static esp_err_t read_random_bytes_from_nvs(uint8_t **random_bytes, size_t *len)
209249static esp_err_t get_device_service_name (char * service_name , size_t max )
210250{
211251 uint8_t * nvs_random = NULL ;
212- const char * ssid_prefix = "PROV_" ;
252+ const char * ssid_prefix = CONFIG_APP_WIFI_PROV_NAME_PREFIX ;
213253 size_t nvs_random_size = 0 ;
214254 if ((read_random_bytes_from_nvs (& nvs_random , & nvs_random_size ) != ESP_OK ) || nvs_random_size < 3 ) {
215255 uint8_t eth_mac [6 ];
216256 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 ]);
218258 } 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 ],
220260 nvs_random [nvs_random_size - 2 ], nvs_random [nvs_random_size - 1 ]);
221261 }
222262 if (nvs_random ) {
@@ -226,34 +266,45 @@ static esp_err_t get_device_service_name(char *service_name, size_t max)
226266}
227267
228268
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 )
230270{
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 ;
233278 }
234279
235280 if (pop_type == POP_TYPE_MAC ) {
236281 uint8_t eth_mac [6 ];
237282 esp_err_t err = esp_wifi_get_mac (WIFI_IF_STA , eth_mac );
238283 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 ;
241286 } else {
242- return err ;
287+ ESP_LOGE (TAG , "Failed to get MAC address to generate PoP." );
288+ goto pop_err ;
243289 }
244290 } else if (pop_type == POP_TYPE_RANDOM ) {
245- uint8_t * nvs_random ;
291+ uint8_t * nvs_random = NULL ;
246292 size_t nvs_random_size = 0 ;
247293 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 ;
249299 } 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 ]);
251301 free (nvs_random );
252- return ESP_OK ;
302+ return pop ;
253303 }
254- } else {
255- return ESP_ERR_INVALID_ARG ;
256304 }
305+ pop_err :
306+ free (pop );
307+ return NULL ;
257308}
258309
259310void app_wifi_with_homekit_init (void )
@@ -288,6 +339,35 @@ void app_wifi_with_homekit_init(void)
288339 ESP_ERROR_CHECK (esp_wifi_init (& cfg ));
289340}
290341
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+
291371esp_err_t app_wifi_with_homekit_start (app_wifi_pop_type_t pop_type )
292372{
293373 /* Configuration for the provisioning manager */
@@ -329,7 +409,6 @@ esp_err_t app_wifi_with_homekit_start(app_wifi_pop_type_t pop_type)
329409#ifdef ESP_NETIF_SUPPORTED
330410 esp_netif_create_default_wifi_ap ();
331411#endif
332-
333412 /* What is the Device Service Name that we want
334413 * This translates to :
335414 * - 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)
338417 char service_name [12 ];
339418 get_device_service_name (service_name , sizeof (service_name ));
340419
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+
341426 /* What is the security level that we want (0 or 1):
342427 * - WIFI_PROV_SECURITY_0 is simply plain text communication.
343428 * - 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)
350435 * - this should be a string with length > 0
351436 * - NULL if not used
352437 */
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 ;
358441 }
359442
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-
366443#ifdef CONFIG_APP_WIFI_PROV_TRANSPORT_BLE
367444 /* This step is only useful when scheme is wifi_prov_scheme_ble. This will
368445 * 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)
379456 0xb4 , 0xdf , 0x5a , 0x1c , 0x3f , 0x6b , 0xf4 , 0xbf ,
380457 0xea , 0x4a , 0x82 , 0x03 , 0x04 , 0x90 , 0x1a , 0x02 ,
381458 };
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 );
383460 if (err != ESP_OK ) {
384461 ESP_LOGE (TAG , "wifi_prov_scheme_ble_set_service_uuid failed %d" , err );
385462 return err ;
386463 }
387464#endif /* CONFIG_APP_WIFI_PROV_TRANSPORT_BLE */
465+
466+
388467#ifdef CONFIG_APP_WIFI_PROV_TRANSPORT_SOFTAP
389468 wifi_prov_scheme_softap_set_httpd_handle (hap_platform_httpd_get_handle ());
390469#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)
397476#else /* CONFIG_APP_WIFI_PROV_TRANSPORT_SOFTAP */
398477 app_wifi_print_qr (service_name , pop , PROV_TRANSPORT_SOFTAP );
399478#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 ();
401481#ifdef CONFIG_APP_WIFI_USE_WAC_PROVISIONING
402482 esp_event_handler_register (HAP_WAC_EVENT , ESP_EVENT_ANY_ID , & event_handler , NULL );
483+ if (pop ) {
484+ free (pop );
485+ }
403486 hap_wac_start ();
404487#endif /* CONFIG_APP_WIFI_USE_WAC_PROVISIONING */
405488 } else {
0 commit comments