// Copyright 2019 Espressif Systems (Shanghai) PTE LTD // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #pragma once #include #include #include "wifi_provisioning/wifi_config.h" #ifdef __cplusplus extern "C" { #endif ESP_EVENT_DECLARE_BASE(WIFI_PROV_EVENT); /** * @brief Events generated by manager * * These events are generated in order of declaration and, for the * stretch of time between initialization and de-initialization of * the manager, each event is signaled only once */ typedef enum { /** * Emitted when the manager is initialized */ WIFI_PROV_INIT, /** * Indicates that provisioning has started */ WIFI_PROV_START, /** * Emitted when Wi-Fi AP credentials are received via `protocomm` * endpoint `wifi_config`. The event data in this case is a pointer * to the corresponding `wifi_sta_config_t` structure */ WIFI_PROV_CRED_RECV, /** * Emitted when device fails to connect to the AP of which the * credentials were received earlier on event `WIFI_PROV_CRED_RECV`. * The event data in this case is a pointer to the disconnection * reason code with type `wifi_prov_sta_fail_reason_t` */ WIFI_PROV_CRED_FAIL, /** * Emitted when device successfully connects to the AP of which the * credentials were received earlier on event `WIFI_PROV_CRED_RECV` */ WIFI_PROV_CRED_SUCCESS, /** * Signals that provisioning service has stopped */ WIFI_PROV_END, /** * Signals that manager has been de-initialized */ WIFI_PROV_DEINIT, } wifi_prov_cb_event_t; typedef void (*wifi_prov_cb_func_t)(void *user_data, wifi_prov_cb_event_t event, void *event_data); /** * @brief Event handler that is used by the manager while * provisioning service is active */ typedef struct { /** * Callback function to be executed on provisioning events */ wifi_prov_cb_func_t event_cb; /** * User context data to pass as parameter to callback function */ void *user_data; } wifi_prov_event_handler_t; /** * @brief Event handler can be set to none if not used */ #define WIFI_PROV_EVENT_HANDLER_NONE { \ .event_cb = NULL, \ .user_data = NULL \ } /** * @brief Structure for specifying the provisioning scheme to be * followed by the manager * * @note Ready to use schemes are available: * - wifi_prov_scheme_ble : for provisioning over BLE transport + GATT server * - wifi_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server * - wifi_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging) */ typedef struct wifi_prov_scheme { /** * Function which is to be called by the manager when it is to * start the provisioning service associated with a protocomm instance * and a scheme specific configuration */ esp_err_t (*prov_start) (protocomm_t *pc, void *config); /** * Function which is to be called by the manager to stop the * provisioning service previously associated with a protocomm instance */ esp_err_t (*prov_stop) (protocomm_t *pc); /** * Function which is to be called by the manager to generate * a new configuration for the provisioning service, that is * to be passed to prov_start() */ void *(*new_config) (void); /** * Function which is to be called by the manager to delete a * configuration generated using new_config() */ void (*delete_config) (void *config); /** * Function which is to be called by the manager to set the * service name and key values in the configuration structure */ esp_err_t (*set_config_service) (void *config, const char *service_name, const char *service_key); /** * Function which is to be called by the manager to set a protocomm endpoint * with an identifying name and UUID in the configuration structure */ esp_err_t (*set_config_endpoint) (void *config, const char *endpoint_name, uint16_t uuid); /** * Sets mode of operation of Wi-Fi during provisioning * This is set to : * - WIFI_MODE_APSTA for SoftAP transport * - WIFI_MODE_STA for BLE transport */ wifi_mode_t wifi_mode; } wifi_prov_scheme_t; /** * @brief Structure for specifying the manager configuration */ typedef struct { /** * Provisioning scheme to use. Following schemes are already available: * - wifi_prov_scheme_ble : for provisioning over BLE transport + GATT server * - wifi_prov_scheme_softap : for provisioning over SoftAP transport + HTTP server + mDNS (optional) * - wifi_prov_scheme_console : for provisioning over Serial UART transport + Console (for debugging) */ wifi_prov_scheme_t scheme; /** * Event handler required by the scheme for incorporating scheme specific * behavior while provisioning manager is running. Various options may be * provided by the scheme for setting this field. Use WIFI_PROV_EVENT_HANDLER_NONE * when not used. When using scheme wifi_prov_scheme_ble, the following * options are available: * - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM * - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE * - WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT */ wifi_prov_event_handler_t scheme_event_handler; /** * Event handler that can be set for the purpose of incorporating application * specific behavior. Use WIFI_PROV_EVENT_HANDLER_NONE when not used. */ wifi_prov_event_handler_t app_event_handler; } wifi_prov_mgr_config_t; /** * @brief Security modes supported by the Provisioning Manager. * * These are same as the security modes provided by protocomm */ typedef enum wifi_prov_security { /** * No security (plain-text communication) */ WIFI_PROV_SECURITY_0 = 0, /** * This secure communication mode consists of * X25519 key exchange * + proof of possession (pop) based authentication * + AES-CTR encryption */ WIFI_PROV_SECURITY_1 } wifi_prov_security_t; /** * @brief Initialize provisioning manager instance * * Configures the manager and allocates internal resources * * Configuration specifies the provisioning scheme (transport) * and event handlers * * Event WIFI_PROV_INIT is emitted right after initialization * is complete * * @param[in] config Configuration structure * * @return * - ESP_OK : Success * - ESP_FAIL : Fail */ esp_err_t wifi_prov_mgr_init(wifi_prov_mgr_config_t config); /** * @brief Stop provisioning (if running) and release * resource used by the manager * * Event WIFI_PROV_DEINIT is emitted right after de-initialization * is finished * * If provisioning service is still active when this API is called, * it first stops the service, hence emitting WIFI_PROV_END, and * then performs the de-initialization */ void wifi_prov_mgr_deinit(void); /** * @brief Checks if device is provisioned * * This checks if Wi-Fi credentials are present on the NVS * * The Wi-Fi credentials are assumed to be kept in the same * NVS namespace as used by esp_wifi component * * If one were to call esp_wifi_set_config() directly instead * of going through the provisioning process, this function will * still yield true (i.e. device will be found to be provisioned) * * @note Calling wifi_prov_mgr_start_provisioning() automatically * resets the provision state, irrespective of what the * state was prior to making the call. * * @param[out] provisioned True if provisioned, else false * * @return * - ESP_OK : Retrieved provision state successfully * - ESP_FAIL : Wi-Fi not initialized * - ESP_ERR_INVALID_ARG : Null argument supplied * - ESP_ERR_INVALID_STATE : Manager not initialized */ esp_err_t wifi_prov_mgr_is_provisioned(bool *provisioned); /** * @brief Start provisioning service * * This starts the provisioning service according to the scheme * configured at the time of initialization. For scheme : * - wifi_prov_scheme_ble : This starts protocomm_ble, which internally initializes * BLE transport and starts GATT server for handling * provisioning requests * - wifi_prov_scheme_softap : This activates SoftAP mode of Wi-Fi and starts * protocomm_httpd, which internally starts an HTTP * server for handling provisioning requests (If mDNS is * active it also starts advertising service with type * _esp_wifi_prov._tcp) * * Event WIFI_PROV_START is emitted right after provisioning starts without failure * * @note This API will start provisioning service even if device is found to be * already provisioned, i.e. wifi_prov_mgr_is_provisioned() yields true * * @param[in] security Specify which protocomm security scheme to use : * - WIFI_PROV_SECURITY_0 : For no security * - WIFI_PROV_SECURITY_1 : x25519 secure handshake for session * establishment followed by AES-CTR encryption of provisioning messages * @param[in] pop Pointer to proof of possession string (NULL if not needed). This * is relevant only for protocomm security 1, in which case it is used * for authenticating secure session * @param[in] service_name Unique name of the service. This translates to: * - Wi-Fi SSID when provisioning mode is softAP * - Device name when provisioning mode is BLE * @param[in] service_key Key required by client to access the service (NULL if not needed). * This translates to: * - Wi-Fi password when provisioning mode is softAP * - ignored when provisioning mode is BLE * * @return * - ESP_OK : Provisioning started successfully * - ESP_FAIL : Failed to start provisioning service * - ESP_ERR_INVALID_STATE : Provisioning manager not initialized or already started */ esp_err_t wifi_prov_mgr_start_provisioning(wifi_prov_security_t security, const char *pop, const char *service_name, const char *service_key); /** * @brief Stop provisioning service * * If provisioning service is active, this API will initiate a process to stop * the service and return. Once the service actually stops, the event WIFI_PROV_END * will be emitted. * * If wifi_prov_mgr_deinit() is called without calling this API first, it will * automatically stop the provisioning service and emit the WIFI_PROV_END, followed * by WIFI_PROV_DEINIT, before returning. * * This API will generally be used along with wifi_prov_mgr_disable_auto_stop() * in the scenario when the main application has registered its own endpoints, * and wishes that the provisioning service is stopped only when some protocomm * command from the client side application is received. * * Calling this API inside an endpoint handler, with sufficient cleanup_delay, * will allow the response / acknowledgment to be sent successfully before the * underlying protocomm service is stopped. * * Cleaup_delay is set when calling wifi_prov_mgr_disable_auto_stop(). * If not specified, it defaults to 1000ms. * * For straightforward cases, using this API is usually not necessary as * provisioning is stopped automatically once WIFI_PROV_CRED_SUCCESS is emitted. * Stopping is delayed (maximum 30 seconds) thus allowing the client side * application to query for Wi-Fi state, i.e. after receiving the first query * and sending `Wi-Fi state connected` response the service is stopped immediately. */ void wifi_prov_mgr_stop_provisioning(void); /** * @brief Wait for provisioning service to finish * * Calling this API will block until provisioning service is stopped * i.e. till event WIFI_PROV_END is emitted. * * This will not block if provisioning is not started or not initialized. */ void wifi_prov_mgr_wait(void); /** * @brief Disable auto stopping of provisioning service upon completion * * By default, once provisioning is complete, the provisioning service is automatically * stopped, and all endpoints (along with those registered by main application) are * deactivated. * * This API is useful in the case when main application wishes to close provisioning service * only after it receives some protocomm command from the client side app. For example, after * connecting to Wi-Fi, the device may want to connect to the cloud, and only once that is * successfully, the device is said to be fully configured. But, then it is upto the main * application to explicitly call wifi_prov_mgr_stop_provisioning() later when the device is * fully configured and the provisioning service is no longer required. * * @note This must be called before executing wifi_prov_mgr_start_provisioning() * * @param[in] cleanup_delay Sets the delay after which the actual cleanup of transport related * resources is done after a call to wifi_prov_mgr_stop_provisioning() * returns. Minimum allowed value is 100ms. If not specified, this will * default to 1000ms. * * @return * - ESP_OK : Success * - ESP_ERR_INVALID_STATE : Manager not initialized or * provisioning service already started */ esp_err_t wifi_prov_mgr_disable_auto_stop(uint32_t cleanup_delay); /** * @brief Set application version and capabilities in the JSON data returned by * proto-ver endpoint * * This function can be called multiple times, to specify information about the various * application specific services running on the device, identified by unique labels. * * The provisioning service itself registers an entry in the JSON data, by the label "prov", * containing only provisioning service version and capabilities. Application services should * use a label other than "prov" so as not to overwrite this. * * @note This must be called before executing wifi_prov_mgr_start_provisioning() * * @param[in] label String indicating the application name. * * @param[in] version String indicating the application version. * There is no constraint on format. * * @param[in] capabilities Array of strings with capabilities. * These could be used by the client side app to know * the application registered endpoint capabilities * * @param[in] total_capabilities Size of capabilities array * * @return * - ESP_OK : Success * - ESP_ERR_INVALID_STATE : Manager not initialized or * provisioning service already started * - ESP_ERR_NO_MEM : Failed to allocate memory for version string * - ESP_ERR_INVALID_ARG : Null argument */ esp_err_t wifi_prov_mgr_set_app_info(const char *label, const char *version, const char**capabilities, size_t total_capabilities); /** * @brief Create an additional endpoint and allocate internal resources for it * * This API is to be called by the application if it wants to create an additional * endpoint. All additional endpoints will be assigned UUIDs starting from 0xFF54 * and so on in the order of execution. * * protocomm handler for the created endpoint is to be registered later using * wifi_prov_mgr_endpoint_register() after provisioning has started. * * @note This API can only be called BEFORE provisioning is started * * @note Additional endpoints can be used for configuring client provided * parameters other than Wi-Fi credentials, that are necessary for the * main application and hence must be set prior to starting the application * * @note After session establishment, the additional endpoints must be targeted * first by the client side application before sending Wi-Fi configuration, * because once Wi-Fi configuration finishes the provisioning service is * stopped and hence all endpoints are unregistered * * @param[in] ep_name unique name of the endpoint * * @return * - ESP_OK : Success * - ESP_FAIL : Failure */ esp_err_t wifi_prov_mgr_endpoint_create(const char *ep_name); /** * @brief Register a handler for the previously created endpoint * * This API can be called by the application to register a protocomm handler * to any endpoint that was created using wifi_prov_mgr_endpoint_create(). * * @note This API can only be called AFTER provisioning has started * * @note Additional endpoints can be used for configuring client provided * parameters other than Wi-Fi credentials, that are necessary for the * main application and hence must be set prior to starting the application * * @note After session establishment, the additional endpoints must be targeted * first by the client side application before sending Wi-Fi configuration, * because once Wi-Fi configuration finishes the provisioning service is * stopped and hence all endpoints are unregistered * * @param[in] ep_name Name of the endpoint * @param[in] handler Endpoint handler function * @param[in] user_ctx User data * * @return * - ESP_OK : Success * - ESP_FAIL : Failure */ esp_err_t wifi_prov_mgr_endpoint_register(const char *ep_name, protocomm_req_handler_t handler, void *user_ctx); /** * @brief Unregister the handler for an endpoint * * This API can be called if the application wants to selectively * unregister the handler of an endpoint while the provisioning * is still in progress. * * All the endpoint handlers are unregistered automatically when * the provisioning stops. * * @param[in] ep_name Name of the endpoint */ void wifi_prov_mgr_endpoint_unregister(const char *ep_name); /** * @brief Event handler for provisioning manager * * This is called from the main event handler and controls the * provisioning manager's internal state machine depending on * incoming Wi-Fi events * * @note : This function is DEPRECATED, because events are now * handled internally using the event loop library, esp_event. * Calling this will do nothing and simply return ESP_OK. * * @param[in] ctx Event context data * @param[in] event Event info * * @return * - ESP_OK : Event handled successfully */ esp_err_t wifi_prov_mgr_event_handler(void *ctx, system_event_t *event) __attribute__ ((deprecated)); /** * @brief Get state of Wi-Fi Station during provisioning * * @param[out] state Pointer to wifi_prov_sta_state_t * variable to be filled * * @return * - ESP_OK : Successfully retrieved Wi-Fi state * - ESP_FAIL : Provisioning app not running */ esp_err_t wifi_prov_mgr_get_wifi_state(wifi_prov_sta_state_t *state); /** * @brief Get reason code in case of Wi-Fi station * disconnection during provisioning * * @param[out] reason Pointer to wifi_prov_sta_fail_reason_t * variable to be filled * * @return * - ESP_OK : Successfully retrieved Wi-Fi disconnect reason * - ESP_FAIL : Provisioning app not running */ esp_err_t wifi_prov_mgr_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t *reason); /** * @brief Runs Wi-Fi as Station with the supplied configuration * * Configures the Wi-Fi station mode to connect to the AP with * SSID and password specified in config structure and sets * Wi-Fi to run as station. * * This is automatically called by provisioning service upon * receiving new credentials. * * If credentials are to be supplied to the manager via a * different mode other than through protocomm, then this * API needs to be called. * * Event WIFI_PROV_CRED_RECV is emitted after credentials have * been applied and Wi-Fi station started * * @param[in] wifi_cfg Pointer to Wi-Fi configuration structure * * @return * - ESP_OK : Wi-Fi configured and started successfully * - ESP_FAIL : Failed to set configuration */ esp_err_t wifi_prov_mgr_configure_sta(wifi_config_t *wifi_cfg); #ifdef __cplusplus } #endif