1 // Copyright 2019 Espressif Systems (Shanghai) PTE LTD 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #pragma once 16 17 #include <protocomm.h> 18 19 #include "esp_event.h" 20 #include "wifi_provisioning/wifi_config.h" 21 22 #ifdef __cplusplus 23 extern "C" { 24 #endif 25 26 ESP_EVENT_DECLARE_BASE(WIFI_PROV_EVENT); 27 28 /** 29 * @brief Events generated by manager 30 * 31 * These events are generated in order of declaration and, for the 32 * stretch of time between initialization and de-initialization of 33 * the manager, each event is signaled only once 34 */ 35 typedef enum { 36 /** 37 * Emitted when the manager is initialized 38 */ 39 WIFI_PROV_INIT, 40 41 /** 42 * Indicates that provisioning has started 43 */ 44 WIFI_PROV_START, 45 46 /** 47 * Emitted when Wi-Fi AP credentials are received via `protocomm` 48 * endpoint `wifi_config`. The event data in this case is a pointer 49 * to the corresponding `wifi_sta_config_t` structure 50 */ 51 WIFI_PROV_CRED_RECV, 52 53 /** 54 * Emitted when device fails to connect to the AP of which the 55 * credentials were received earlier on event `WIFI_PROV_CRED_RECV`. 56 * The event data in this case is a pointer to the disconnection 57 * reason code with type `wifi_prov_sta_fail_reason_t` 58 */ 59 WIFI_PROV_CRED_FAIL, 60 61 /** 62 * Emitted when device successfully connects to the AP of which the 63 * credentials were received earlier on event `WIFI_PROV_CRED_RECV` 64 */ 65 WIFI_PROV_CRED_SUCCESS, 66 67 /** 68 * Signals that provisioning service has stopped 69 */ 70 WIFI_PROV_END, 71 72 /** 73 * Signals that manager has been de-initialized 74 */ 75 WIFI_PROV_DEINIT, 76 } wifi_prov_cb_event_t; 77 78 typedef void (*wifi_prov_cb_func_t)(void *user_data, wifi_prov_cb_event_t event, void *event_data); 79 80 /** 81 * @brief Event handler that is used by the manager while 82 * provisioning service is active 83 */ 84 typedef struct { 85 /** 86 * Callback function to be executed on provisioning events 87 */ 88 wifi_prov_cb_func_t event_cb; 89 90 /** 91 * User context data to pass as parameter to callback function 92 */ 93 void *user_data; 94 } wifi_prov_event_handler_t; 95 96 /** 97 * @brief Event handler can be set to none if not used 98 */ 99 #define WIFI_PROV_EVENT_HANDLER_NONE { \ 100 .event_cb = NULL, \ 101 .user_data = NULL \ 102 } 103 104 /** 105 * @brief Structure for specifying the provisioning scheme to be 106 * followed by the manager 107 * 108 * @note Ready to use schemes are available: 109 * - wifi_prov_scheme_ble : for provisioning over BLE transport + GATT server 110 * - wifi_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server 111 * - wifi_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging) 112 */ 113 typedef struct wifi_prov_scheme { 114 /** 115 * Function which is to be called by the manager when it is to 116 * start the provisioning service associated with a protocomm instance 117 * and a scheme specific configuration 118 */ 119 esp_err_t (*prov_start) (protocomm_t *pc, void *config); 120 121 /** 122 * Function which is to be called by the manager to stop the 123 * provisioning service previously associated with a protocomm instance 124 */ 125 esp_err_t (*prov_stop) (protocomm_t *pc); 126 127 /** 128 * Function which is to be called by the manager to generate 129 * a new configuration for the provisioning service, that is 130 * to be passed to prov_start() 131 */ 132 void *(*new_config) (void); 133 134 /** 135 * Function which is to be called by the manager to delete a 136 * configuration generated using new_config() 137 */ 138 void (*delete_config) (void *config); 139 140 /** 141 * Function which is to be called by the manager to set the 142 * service name and key values in the configuration structure 143 */ 144 esp_err_t (*set_config_service) (void *config, const char *service_name, const char *service_key); 145 146 /** 147 * Function which is to be called by the manager to set a protocomm endpoint 148 * with an identifying name and UUID in the configuration structure 149 */ 150 esp_err_t (*set_config_endpoint) (void *config, const char *endpoint_name, uint16_t uuid); 151 152 /** 153 * Sets mode of operation of Wi-Fi during provisioning 154 * This is set to : 155 * - WIFI_MODE_APSTA for SoftAP transport 156 * - WIFI_MODE_STA for BLE transport 157 */ 158 wifi_mode_t wifi_mode; 159 } wifi_prov_scheme_t; 160 161 /** 162 * @brief Structure for specifying the manager configuration 163 */ 164 typedef struct { 165 /** 166 * Provisioning scheme to use. Following schemes are already available: 167 * - wifi_prov_scheme_ble : for provisioning over BLE transport + GATT server 168 * - wifi_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server + mDNS (optional) 169 * - wifi_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging) 170 */ 171 wifi_prov_scheme_t scheme; 172 173 /** 174 * Event handler required by the scheme for incorporating scheme specific 175 * behavior while provisioning manager is running. Various options may be 176 * provided by the scheme for setting this field. Use WIFI_PROV_EVENT_HANDLER_NONE 177 * when not used. When using scheme wifi_prov_scheme_ble, the following 178 * options are available: 179 * - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM 180 * - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE 181 * - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT 182 */ 183 wifi_prov_event_handler_t scheme_event_handler; 184 185 /** 186 * Event handler that can be set for the purpose of incorporating application 187 * specific behavior. Use WIFI_PROV_EVENT_HANDLER_NONE when not used. 188 */ 189 wifi_prov_event_handler_t app_event_handler; 190 } wifi_prov_mgr_config_t; 191 192 /** 193 * @brief Security modes supported by the Provisioning Manager. 194 * 195 * These are same as the security modes provided by protocomm 196 */ 197 typedef enum wifi_prov_security { 198 /** 199 * No security (plain-text communication) 200 */ 201 WIFI_PROV_SECURITY_0 = 0, 202 203 /** 204 * This secure communication mode consists of 205 * X25519 key exchange 206 * + proof of possession (pop) based authentication 207 * + AES-CTR encryption 208 */ 209 WIFI_PROV_SECURITY_1 210 } wifi_prov_security_t; 211 212 /** 213 * @brief Initialize provisioning manager instance 214 * 215 * Configures the manager and allocates internal resources 216 * 217 * Configuration specifies the provisioning scheme (transport) 218 * and event handlers 219 * 220 * Event WIFI_PROV_INIT is emitted right after initialization 221 * is complete 222 * 223 * @param[in] config Configuration structure 224 * 225 * @return 226 * - ESP_OK : Success 227 * - ESP_FAIL : Fail 228 */ 229 esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config); 230 231 /** 232 * @brief Stop provisioning (if running) and release 233 * resource used by the manager 234 * 235 * Event WIFI_PROV_DEINIT is emitted right after de-initialization 236 * is finished 237 * 238 * If provisioning service is still active when this API is called, 239 * it first stops the service, hence emitting WIFI_PROV_END, and 240 * then performs the de-initialization 241 */ 242 void wifi_prov_mgr_deinit(void); 243 244 /** 245 * @brief Checks if device is provisioned 246 * 247 * This checks if Wi-Fi credentials are present on the NVS 248 * 249 * The Wi-Fi credentials are assumed to be kept in the same 250 * NVS namespace as used by esp_wifi component 251 * 252 * If one were to call esp_wifi_set_config() directly instead 253 * of going through the provisioning process, this function will 254 * still yield true (i.e. device will be found to be provisioned) 255 * 256 * @note Calling wifi_prov_mgr_start_provisioning() automatically 257 * resets the provision state, irrespective of what the 258 * state was prior to making the call. 259 * 260 * @param[out] provisioned True if provisioned, else false 261 * 262 * @return 263 * - ESP_OK : Retrieved provision state successfully 264 * - ESP_FAIL : Wi-Fi not initialized 265 * - ESP_ERR_INVALID_ARG : Null argument supplied 266 * - ESP_ERR_INVALID_STATE : Manager not initialized 267 */ 268 esp_err_t wifi_prov_mgr_is_provisioned(bool *provisioned); 269 270 /** 271 * @brief Start provisioning service 272 * 273 * This starts the provisioning service according to the scheme 274 * configured at the time of initialization. For scheme : 275 * - wifi_prov_scheme_ble : This starts protocomm_ble, which internally initializes 276 * BLE transport and starts GATT server for handling 277 * provisioning requests 278 * - wifi_prov_scheme_softap : This activates SoftAP mode of Wi-Fi and starts 279 * protocomm_httpd, which internally starts an HTTP 280 * server for handling provisioning requests (If mDNS is 281 * active it also starts advertising service with type 282 * _esp_wifi_prov._tcp) 283 * 284 * Event WIFI_PROV_START is emitted right after provisioning starts without failure 285 * 286 * @note This API will start provisioning service even if device is found to be 287 * already provisioned, i.e. wifi_prov_mgr_is_provisioned() yields true 288 * 289 * @param[in] security Specify which protocomm security scheme to use : 290 * - WIFI_PROV_SECURITY_0 : For no security 291 * - WIFI_PROV_SECURITY_1 : x25519 secure handshake for session 292 * establishment followed by AES-CTR encryption of provisioning messages 293 * @param[in] pop Pointer to proof of possession string (NULL if not needed). This 294 * is relevant only for protocomm security 1, in which case it is used 295 * for authenticating secure session 296 * @param[in] service_name Unique name of the service. This translates to: 297 * - Wi-Fi SSID when provisioning mode is softAP 298 * - Device name when provisioning mode is BLE 299 * @param[in] service_key Key required by client to access the service (NULL if not needed). 300 * This translates to: 301 * - Wi-Fi password when provisioning mode is softAP 302 * - ignored when provisioning mode is BLE 303 * 304 * @return 305 * - ESP_OK : Provisioning started successfully 306 * - ESP_FAIL : Failed to start provisioning service 307 * - ESP_ERR_INVALID_STATE : Provisioning manager not initialized or already started 308 */ 309 esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop, 310 const char *service_name, const char *service_key); 311 312 /** 313 * @brief Stop provisioning service 314 * 315 * If provisioning service is active, this API will initiate a process to stop 316 * the service and return. Once the service actually stops, the event WIFI_PROV_END 317 * will be emitted. 318 * 319 * If wifi_prov_mgr_deinit() is called without calling this API first, it will 320 * automatically stop the provisioning service and emit the WIFI_PROV_END, followed 321 * by WIFI_PROV_DEINIT, before returning. 322 * 323 * This API will generally be used along with wifi_prov_mgr_disable_auto_stop() 324 * in the scenario when the main application has registered its own endpoints, 325 * and wishes that the provisioning service is stopped only when some protocomm 326 * command from the client side application is received. 327 * 328 * Calling this API inside an endpoint handler, with sufficient cleanup_delay, 329 * will allow the response / acknowledgment to be sent successfully before the 330 * underlying protocomm service is stopped. 331 * 332 * Cleaup_delay is set when calling wifi_prov_mgr_disable_auto_stop(). 333 * If not specified, it defaults to 1000ms. 334 * 335 * For straightforward cases, using this API is usually not necessary as 336 * provisioning is stopped automatically once WIFI_PROV_CRED_SUCCESS is emitted. 337 * Stopping is delayed (maximum 30 seconds) thus allowing the client side 338 * application to query for Wi-Fi state, i.e. after receiving the first query 339 * and sending `Wi-Fi state connected` response the service is stopped immediately. 340 */ 341 void wifi_prov_mgr_stop_provisioning(void); 342 343 /** 344 * @brief Wait for provisioning service to finish 345 * 346 * Calling this API will block until provisioning service is stopped 347 * i.e. till event WIFI_PROV_END is emitted. 348 * 349 * This will not block if provisioning is not started or not initialized. 350 */ 351 void wifi_prov_mgr_wait(void); 352 353 /** 354 * @brief Disable auto stopping of provisioning service upon completion 355 * 356 * By default, once provisioning is complete, the provisioning service is automatically 357 * stopped, and all endpoints (along with those registered by main application) are 358 * deactivated. 359 * 360 * This API is useful in the case when main application wishes to close provisioning service 361 * only after it receives some protocomm command from the client side app. For example, after 362 * connecting to Wi-Fi, the device may want to connect to the cloud, and only once that is 363 * successfully, the device is said to be fully configured. But, then it is upto the main 364 * application to explicitly call wifi_prov_mgr_stop_provisioning() later when the device is 365 * fully configured and the provisioning service is no longer required. 366 * 367 * @note This must be called before executing wifi_prov_mgr_start_provisioning() 368 * 369 * @param[in] cleanup_delay Sets the delay after which the actual cleanup of transport related 370 * resources is done after a call to wifi_prov_mgr_stop_provisioning() 371 * returns. Minimum allowed value is 100ms. If not specified, this will 372 * default to 1000ms. 373 * 374 * @return 375 * - ESP_OK : Success 376 * - ESP_ERR_INVALID_STATE : Manager not initialized or 377 * provisioning service already started 378 */ 379 esp_err_t wifi_prov_mgr_disable_auto_stop(uint32_t cleanup_delay); 380 381 /** 382 * @brief Set application version and capabilities in the JSON data returned by 383 * proto-ver endpoint 384 * 385 * This function can be called multiple times, to specify information about the various 386 * application specific services running on the device, identified by unique labels. 387 * 388 * The provisioning service itself registers an entry in the JSON data, by the label "prov", 389 * containing only provisioning service version and capabilities. Application services should 390 * use a label other than "prov" so as not to overwrite this. 391 * 392 * @note This must be called before executing wifi_prov_mgr_start_provisioning() 393 * 394 * @param[in] label String indicating the application name. 395 * 396 * @param[in] version String indicating the application version. 397 * There is no constraint on format. 398 * 399 * @param[in] capabilities Array of strings with capabilities. 400 * These could be used by the client side app to know 401 * the application registered endpoint capabilities 402 * 403 * @param[in] total_capabilities Size of capabilities array 404 * 405 * @return 406 * - ESP_OK : Success 407 * - ESP_ERR_INVALID_STATE : Manager not initialized or 408 * provisioning service already started 409 * - ESP_ERR_NO_MEM : Failed to allocate memory for version string 410 * - ESP_ERR_INVALID_ARG : Null argument 411 */ 412 esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version, 413 const char**capabilities, size_t total_capabilities); 414 415 /** 416 * @brief Create an additional endpoint and allocate internal resources for it 417 * 418 * This API is to be called by the application if it wants to create an additional 419 * endpoint. All additional endpoints will be assigned UUIDs starting from 0xFF54 420 * and so on in the order of execution. 421 * 422 * protocomm handler for the created endpoint is to be registered later using 423 * wifi_prov_mgr_endpoint_register() after provisioning has started. 424 * 425 * @note This API can only be called BEFORE provisioning is started 426 * 427 * @note Additional endpoints can be used for configuring client provided 428 * parameters other than Wi-Fi credentials, that are necessary for the 429 * main application and hence must be set prior to starting the application 430 * 431 * @note After session establishment, the additional endpoints must be targeted 432 * first by the client side application before sending Wi-Fi configuration, 433 * because once Wi-Fi configuration finishes the provisioning service is 434 * stopped and hence all endpoints are unregistered 435 * 436 * @param[in] ep_name unique name of the endpoint 437 * 438 * @return 439 * - ESP_OK : Success 440 * - ESP_FAIL : Failure 441 */ 442 esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name); 443 444 /** 445 * @brief Register a handler for the previously created endpoint 446 * 447 * This API can be called by the application to register a protocomm handler 448 * to any endpoint that was created using wifi_prov_mgr_endpoint_create(). 449 * 450 * @note This API can only be called AFTER provisioning has started 451 * 452 * @note Additional endpoints can be used for configuring client provided 453 * parameters other than Wi-Fi credentials, that are necessary for the 454 * main application and hence must be set prior to starting the application 455 * 456 * @note After session establishment, the additional endpoints must be targeted 457 * first by the client side application before sending Wi-Fi configuration, 458 * because once Wi-Fi configuration finishes the provisioning service is 459 * stopped and hence all endpoints are unregistered 460 * 461 * @param[in] ep_name Name of the endpoint 462 * @param[in] handler Endpoint handler function 463 * @param[in] user_ctx User data 464 * 465 * @return 466 * - ESP_OK : Success 467 * - ESP_FAIL : Failure 468 */ 469 esp_err_t wifi_prov_mgr_endpoint_register(const char *ep_name, 470 protocomm_req_handler_t handler, 471 void *user_ctx); 472 473 /** 474 * @brief Unregister the handler for an endpoint 475 * 476 * This API can be called if the application wants to selectively 477 * unregister the handler of an endpoint while the provisioning 478 * is still in progress. 479 * 480 * All the endpoint handlers are unregistered automatically when 481 * the provisioning stops. 482 * 483 * @param[in] ep_name Name of the endpoint 484 */ 485 void wifi_prov_mgr_endpoint_unregister(const char *ep_name); 486 487 /** 488 * @brief Event handler for provisioning manager 489 * 490 * This is called from the main event handler and controls the 491 * provisioning manager's internal state machine depending on 492 * incoming Wi-Fi events 493 * 494 * @note : This function is DEPRECATED, because events are now 495 * handled internally using the event loop library, esp_event. 496 * Calling this will do nothing and simply return ESP_OK. 497 * 498 * @param[in] ctx Event context data 499 * @param[in] event Event info 500 * 501 * @return 502 * - ESP_OK : Event handled successfully 503 */ 504 esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) __attribute__ ((deprecated)); 505 506 /** 507 * @brief Get state of Wi-Fi Station during provisioning 508 * 509 * @param[out] state Pointer to wifi_prov_sta_state_t 510 * variable to be filled 511 * 512 * @return 513 * - ESP_OK : Successfully retrieved Wi-Fi state 514 * - ESP_FAIL : Provisioning app not running 515 */ 516 esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state); 517 518 /** 519 * @brief Get reason code in case of Wi-Fi station 520 * disconnection during provisioning 521 * 522 * @param[out] reason Pointer to wifi_prov_sta_fail_reason_t 523 * variable to be filled 524 * 525 * @return 526 * - ESP_OK : Successfully retrieved Wi-Fi disconnect reason 527 * - ESP_FAIL : Provisioning app not running 528 */ 529 esp_err_t wifi_prov_mgr_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t *reason); 530 531 /** 532 * @brief Runs Wi-Fi as Station with the supplied configuration 533 * 534 * Configures the Wi-Fi station mode to connect to the AP with 535 * SSID and password specified in config structure and sets 536 * Wi-Fi to run as station. 537 * 538 * This is automatically called by provisioning service upon 539 * receiving new credentials. 540 * 541 * If credentials are to be supplied to the manager via a 542 * different mode other than through protocomm, then this 543 * API needs to be called. 544 * 545 * Event WIFI_PROV_CRED_RECV is emitted after credentials have 546 * been applied and Wi-Fi station started 547 * 548 * @param[in] wifi_cfg Pointer to Wi-Fi configuration structure 549 * 550 * @return 551 * - ESP_OK : Wi-Fi configured and started successfully 552 * - ESP_FAIL : Failed to set configuration 553 */ 554 esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg); 555 556 /** 557 * @brief Reset Wi-Fi provisioning config 558 * 559 * Calling this API will restore WiFi stack persistent settings to default values. 560 * 561 * @return 562 * - ESP_OK : Reset provisioning config successfully 563 * - ESP_FAIL : Failed to reset provisioning config 564 */ 565 esp_err_t wifi_prov_mgr_reset_provisioning(void); 566 567 /** 568 * @brief Reset internal state machine and clear provisioned credentials. 569 * 570 * This API can be used to restart provisioning in case invalid credentials are entered. 571 * 572 * @return 573 * - ESP_OK : Reset provisioning state machine successfully 574 * - ESP_FAIL : Failed to reset provisioning state machine 575 * - ESP_ERR_INVALID_STATE : Manager not initialized 576 */ 577 esp_err_t wifi_prov_mgr_reset_sm_state_on_failure(void); 578 579 #ifdef __cplusplus 580 } 581 #endif 582