mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
Merge branch 'docs/trans_wifi_provisioning' into 'master'
Docs: add CN translation for api-reference/provisioning/wifi_provisioning.rst Closes DOC-5319 See merge request espressif/esp-idf!24039
This commit is contained in:
commit
cefbecd41b
@ -3,21 +3,21 @@
|
||||
Wi-Fi Provisioning
|
||||
==================
|
||||
|
||||
:link_to_translation:`zh_CN:[中文]`
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This component provides APIs that control Wi-Fi provisioning service for receiving and configuring Wi-Fi credentials over SoftAP or BLE transport via secure :doc:`Protocol Communication (protocomm)<protocomm>` sessions. The set of ``wifi_prov_mgr_`` APIs help in quickly implementing a provisioning service having necessary features with minimal amount of code and sufficient flexibility.
|
||||
This component provides APIs that control the Wi-Fi provisioning service for receiving and configuring Wi-Fi credentials over SoftAP or Bluetooth LE transport via secure :doc:`protocomm` sessions. The set of ``wifi_prov_mgr_`` APIs help quickly implement a provisioning service that has necessary features with minimal amount of code and sufficient flexibility.
|
||||
|
||||
.. _wifi-prov-mgr-init:
|
||||
|
||||
Initialization
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
:cpp:func:`wifi_prov_mgr_init()` is called to configure and initialize the provisioning manager and thus this must be called prior to invoking any other ``wifi_prov_mgr_`` APIs. Note that the manager relies on other components of IDF, namely NVS, TCP/IP, Event Loop and Wi-Fi (and optionally mDNS), hence these must be initialized beforehand. The manager can be de-initialized at any moment by making a call to :cpp:func:`wifi_prov_mgr_deinit()`.
|
||||
:cpp:func:`wifi_prov_mgr_init()` is called to configure and initialize the provisioning manager, and thus must be called prior to invoking any other ``wifi_prov_mgr_`` APIs. Note that the manager relies on other components of ESP-IDF, namely NVS, TCP/IP, Event Loop and Wi-Fi, and optionally mDNS, hence these components must be initialized beforehand. The manager can be de-initialized at any moment by making a call to :cpp:func:`wifi_prov_mgr_deinit()`.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
.. code-block:: c
|
||||
|
||||
wifi_prov_mgr_config_t config = {
|
||||
.scheme = wifi_prov_scheme_ble,
|
||||
@ -27,26 +27,29 @@ Initialization
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_init(config) );
|
||||
|
||||
|
||||
The configuration structure ``wifi_prov_mgr_config_t`` has a few fields to specify the behavior desired of the manager :
|
||||
The configuration structure :cpp:type:`wifi_prov_mgr_config_t` has a few fields to specify the desired behavior of the manager:
|
||||
|
||||
* `scheme` : This is used to specify the provisioning scheme. Each scheme corresponds to one of the modes of transport supported by protocomm. Hence, we have three options :
|
||||
* :cpp:member:`wifi_prov_mgr_config_t::scheme` - This is used to specify the provisioning scheme. Each scheme corresponds to one of the modes of transport supported by protocomm. Hence, support the following options:
|
||||
|
||||
* ``wifi_prov_scheme_ble`` : BLE transport and GATT Server for handling provisioning commands
|
||||
* ``wifi_prov_scheme_softap`` : Wi-Fi SoftAP transport and HTTP Server for handling provisioning commands
|
||||
* ``wifi_prov_scheme_console`` : Serial transport and console for handling provisioning commands
|
||||
* ``wifi_prov_scheme_ble`` - Bluetooth LE transport and GATT Server for handling the provisioning commands.
|
||||
|
||||
* `scheme_event_handler` : An event handler defined along with scheme. Choosing appropriate scheme specific event handler allows the manager to take care of certain matters automatically. Presently this is not used for either SoftAP or Console based provisioning, but is very convenient for BLE. To understand how, we must recall that Bluetooth requires quite some amount of memory to function and once provisioning is finished, the main application may want to reclaim back this memory (or part of it, if it needs to use either BLE or classic BT). Also, upon every future reboot of a provisioned device, this reclamation of memory needs to be performed again. To reduce this complication in using ``wifi_prov_scheme_ble``, the scheme specific handlers have been defined, and depending upon the chosen handler, the BLE / classic BT / BTDM memory will be freed automatically when the provisioning manager is de-initialized. The available options are:
|
||||
* ``wifi_prov_scheme_softap`` - Wi-Fi SoftAP transport and HTTP Server for handling the provisioning commands.
|
||||
|
||||
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM`` - Free both classic BT and BLE (BTDM) memory. Used when main application doesn't require Bluetooth at all.
|
||||
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE`` - Free only BLE memory. Used when main application requires classic BT.
|
||||
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT`` - Free only classic BT. Used when main application requires BLE. In this case freeing happens right when the manager is initialized.
|
||||
* ``WIFI_PROV_EVENT_HANDLER_NONE`` - Don't use any scheme specific handler. Used when provisioning scheme is not BLE (i.e. SoftAP or Console), or when main application wants to handle the memory reclaiming on its own, or needs both BLE and classic BT to function.
|
||||
* ``wifi_prov_scheme_console`` - Serial transport and console for handling the provisioning commands.
|
||||
|
||||
* `app_event_handler` (Deprecated) : It is now recommended to catch ``WIFI_PROV_EVENT``s that are emitted to the default event loop handler. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Here is an excerpt showing some of the provisioning events:
|
||||
* :cpp:member:`wifi_prov_mgr_config_t::scheme_event_handler`: An event handler defined along with the scheme. Choosing the appropriate scheme-specific event handler allows the manager to take care of certain matters automatically. Presently, this option is not used for either the SoftAP or Console-based provisioning, but is very convenient for Bluetooth LE. To understand how, we must recall that Bluetooth requires a substantial amount of memory to function, and once the provisioning is finished, the main application may want to reclaim back this memory (or part of it) if it needs to use either Bluetooth LE or classic Bluetooth. Also, upon every future reboot of a provisioned device, this reclamation of memory needs to be performed again. To reduce this complication in using ``wifi_prov_scheme_ble``, the scheme-specific handlers have been defined, and depending upon the chosen handler, the Bluetooth LE/classic Bluetooth/BTDM memory is freed automatically when the provisioning manager is de-initialized. The available options are:
|
||||
|
||||
.. highlight:: c
|
||||
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM`` - Free both classic Bluetooth and Bluetooth LE/BTDM memory. Used when the main application does not require Bluetooth at all.
|
||||
|
||||
::
|
||||
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BLE`` - Free only Bluetooth LE memory. Used when main application requires classic Bluetooth.
|
||||
|
||||
* ``WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BT`` - Free only classic Bluetooth. Used when main application requires Bluetooth LE. In this case freeing happens right when the manager is initialized.
|
||||
|
||||
* ``WIFI_PROV_EVENT_HANDLER_NONE`` - Do not use any scheme specific handler. Used when the provisioning scheme is not Bluetooth LE, i.e., using SoftAP or Console, or when main application wants to handle the memory reclaiming on its own, or needs both Bluetooth LE and classic Bluetooth to function.
|
||||
|
||||
* :cpp:member:`wifi_prov_mgr_config_t::app_event_handler` (Deprecated) - It is now recommended to catch ``WIFI_PROV_EVENT`` that is emitted to the default event loop handler. See definition of ``wifi_prov_cb_event_t`` for the list of events that are generated by the provisioning service. Here is an excerpt showing some of the provisioning events:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
@ -89,41 +92,39 @@ The manager can be de-initialized at any moment by making a call to :cpp:func:`w
|
||||
|
||||
.. _wifi-prov-check-state:
|
||||
|
||||
Check Provisioning State
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Check the Provisioning State
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Whether device is provisioned or not can be checked at runtime by calling :cpp:func:`wifi_prov_mgr_is_provisioned()`. This internally checks if the Wi-Fi credentials are stored in NVS.
|
||||
Whether the device is provisioned or not can be checked at runtime by calling :cpp:func:`wifi_prov_mgr_is_provisioned()`. This internally checks if the Wi-Fi credentials are stored in NVS.
|
||||
|
||||
Note that presently manager does not have its own NVS namespace for storage of Wi-Fi credentials, instead it relies on the ``esp_wifi_`` APIs to set and get the credentials stored in NVS from the default location.
|
||||
Note that presently the manager does not have its own NVS namespace for storage of Wi-Fi credentials, instead it relies on the ``esp_wifi_`` APIs to set and get the credentials stored in NVS from the default location.
|
||||
|
||||
If provisioning state needs to be reset, any of the following approaches may be taken :
|
||||
If the provisioning state needs to be reset, any of the following approaches may be taken:
|
||||
|
||||
* the associated part of NVS partition has to be erased manually
|
||||
* main application must implement some logic to call ``esp_wifi_`` APIs for erasing the credentials at runtime
|
||||
* main application must implement some logic to force start the provisioning irrespective of the provisioning state
|
||||
* The associated part of NVS partition has to be erased manually
|
||||
* The main application must implement some logic to call ``esp_wifi_`` APIs for erasing the credentials at runtime
|
||||
* The main application must implement some logic to force start the provisioning irrespective of the provisioning state
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
.. code-block:: c
|
||||
|
||||
bool provisioned = false;
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_is_provisioned(&provisioned) );
|
||||
|
||||
|
||||
Start Provisioning Service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
Start the Provisioning Service
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
At the time of starting provisioning we need to specify a service name and the corresponding key. These translate to :
|
||||
At the time of starting provisioning we need to specify a service name and the corresponding key, that is to say:
|
||||
|
||||
* Wi-Fi SoftAP SSID and passphrase, respectively, when scheme is ``wifi_prov_scheme_softap``
|
||||
* BLE Device name (service key is ignored) when scheme is ``wifi_prov_scheme_ble``
|
||||
* A Wi-Fi SoftAP SSID and a passphrase, respectively, when the scheme is ``wifi_prov_scheme_softap``.
|
||||
* Bluetooth LE device name with the service key ignored when the scheme is ``wifi_prov_scheme_ble``.
|
||||
|
||||
Also, since internally the manager uses `protocomm`, we have the option of choosing one of the security features provided by it :
|
||||
Also, since internally the manager uses ``protocomm``, we have the option of choosing one of the security features provided by it:
|
||||
|
||||
* Security 1 is secure communication which consists of a prior handshake involving X25519 key exchange along with authentication using a proof of possession (`pop`), followed by AES-CTR for encryption/decryption of subsequent messages
|
||||
* Security 0 is simply plain text communication. In this case the `pop` is simply ignored
|
||||
* Security 1 is secure communication which consists of a prior handshake involving X25519 key exchange along with authentication using a proof of possession ``pop``, followed by AES-CTR for encryption or decryption of subsequent messages.
|
||||
* Security 0 is simply plain text communication. In this case the ``pop`` is simply ignored.
|
||||
|
||||
See :doc:`Provisioning<provisioning>` for details about the security features.
|
||||
See :doc:`provisioning` for details about the security features.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
@ -138,23 +139,21 @@ See :doc:`Provisioning<provisioning>` for details about the security features.
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key) );
|
||||
|
||||
|
||||
The provisioning service will automatically finish only if it receives valid Wi-Fi AP credentials followed by successfully connection of device to the AP (IP obtained). Regardless of that, the provisioning service can be stopped at any moment by making a call to :cpp:func:`wifi_prov_mgr_stop_provisioning()`.
|
||||
The provisioning service automatically finishes only if it receives valid Wi-Fi AP credentials followed by successful connection of device to the AP with IP obtained. Regardless of that, the provisioning service can be stopped at any moment by making a call to :cpp:func:`wifi_prov_mgr_stop_provisioning()`.
|
||||
|
||||
.. note::
|
||||
|
||||
If the device fails to connect with the provided credentials, it won't accept new credentials anymore, but the provisioning service will keep on running (only to convey failure to the client), until the device is restarted. Upon restart the provisioning state will turn out to be true this time (as credentials will be found in NVS), but device will again fail to connect with those same credentials (unless an AP with the matching credentials somehow does become available). This situation can be fixed by resetting the credentials in NVS or force starting the provisioning service. This has been explained above in :ref:`wifi-prov-check-state`.
|
||||
If the device fails to connect with the provided credentials, it does not accept new credentials anymore, but the provisioning service keeps on running, only to convey failure to the client, until the device is restarted. Upon restart, the provisioning state turns out to be true this time, as credentials are found in NVS, but the device does fail again to connect with those same credentials, unless an AP with the matching credentials somehow does become available. This situation can be fixed by resetting the credentials in NVS or force starting the provisioning service. This has been explained above in :ref:`wifi-prov-check-state`.
|
||||
|
||||
|
||||
Waiting For Completion
|
||||
Waiting for Completion
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Typically, the main application will wait for the provisioning to finish, then de-initialize the manager to free up resources and finally start executing its own logic.
|
||||
Typically, the main application waits for the provisioning to finish, then de-initializes the manager to free up resources, and finally starts executing its own logic.
|
||||
|
||||
There are two ways for making this possible. The simpler way is to use a blocking call to :cpp:func:`wifi_prov_mgr_wait()`.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
.. code-block:: c
|
||||
|
||||
// Start provisioning service
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key) );
|
||||
@ -166,17 +165,15 @@ There are two ways for making this possible. The simpler way is to use a blockin
|
||||
wifi_prov_mgr_deinit();
|
||||
|
||||
|
||||
The other way is to use the default event loop handler to catch ``WIFI_PROV_EVENT``s and call :cpp:func:`wifi_prov_mgr_deinit()` when event ID is ``WIFI_PROV_END``:
|
||||
The other way is to use the default event loop handler to catch ``WIFI_PROV_EVENT`` and call :cpp:func:`wifi_prov_mgr_deinit()` when event ID is ``WIFI_PROV_END``:
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
.. code-block:: c
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_END) {
|
||||
/* De-initialize manager once provisioning is finished */
|
||||
/* De-initialize the manager once the provisioning is finished */
|
||||
wifi_prov_mgr_deinit();
|
||||
}
|
||||
}
|
||||
@ -185,81 +182,93 @@ The other way is to use the default event loop handler to catch ``WIFI_PROV_EVEN
|
||||
User Side Implementation
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When the service is started, the device to be provisioned is identified by the advertised service name which, depending upon the selected transport, is either the BLE device name or the SoftAP SSID.
|
||||
When the service is started, the device to be provisioned is identified by the advertised service name, which, depending upon the selected transport, is either the Bluetooth LE device name or the SoftAP SSID.
|
||||
|
||||
When using SoftAP transport, for allowing service discovery, mDNS must be initialized before starting provisioning. In this case the hostname set by the main application is used, and the service type is internally set to `_esp_wifi_prov`.
|
||||
When using SoftAP transport, for allowing service discovery, mDNS must be initialized before starting provisioning. In this case, the host name set by the main application is used, and the service type is internally set to ``_esp_wifi_prov``.
|
||||
|
||||
When using BLE transport, a custom 128 bit UUID should be set using :cpp:func:`wifi_prov_scheme_ble_set_service_uuid()`. This UUID will be included in the BLE advertisement and will correspond to the primary GATT service that provides provisioning endpoints as GATT characteristics. Each GATT characteristic will be formed using the primary service UUID as base, with different auto assigned 12th and 13th bytes (assume counting starts from 0th byte). Since, an endpoint characteristic UUID is auto assigned, it shouldn't be used to identify the endpoint. Instead, client side applications should identify the endpoints by reading the User Characteristic Description (0x2901) descriptor for each characteristic, which contains the endpoint name of the characteristic. For example, if the service UUID is set to `55cc035e-fb27-4f80-be02-3c60828b7451`, each endpoint characteristic will be assigned a UUID like `55cc____-fb27-4f80-be02-3c60828b7451`, with unique values at the 12th and 13th bytes.
|
||||
When using Bluetooth LE transport, a custom 128-bit UUID should be set using :cpp:func:`wifi_prov_scheme_ble_set_service_uuid()`. This UUID is to be included in the Bluetooth LE advertisement and corresponds to the primary GATT service that provides provisioning endpoints as GATT characteristics. Each GATT characteristic is formed using the primary service UUID as the base, with different auto-assigned 12th and 13th bytes, presumably counting from the 0th byte. Since an endpoint characteristic UUID is auto-assigned, it should not be used to identify the endpoint. Instead, client-side applications should identify the endpoints by reading the User Characteristic Description (``0x2901``) descriptor for each characteristic, which contains the endpoint name of the characteristic. For example, if the service UUID is set to ``55cc035e-fb27-4f80-be02-3c60828b7451``, each endpoint characteristic is assigned a UUID like ``55cc____-fb27-4f80-be02-3c60828b7451``, with unique values at the 12th and 13th bytes.
|
||||
|
||||
Once connected to the device, the provisioning related protocomm endpoints can be identified as follows :
|
||||
Once connected to the device, the provisioning-related protocomm endpoints can be identified as follows:
|
||||
|
||||
.. list-table:: Endpoints provided by Provisioning Service
|
||||
:widths: 10 25 50
|
||||
.. |br| raw:: html
|
||||
|
||||
<br>
|
||||
|
||||
.. list-table:: Endpoints Provided by the Provisioning Service
|
||||
:widths: 35 35 30
|
||||
:header-rows: 1
|
||||
|
||||
* - Endpoint Name (BLE + GATT Server)
|
||||
- URI (SoftAP + HTTP Server + mDNS)
|
||||
* - Endpoint Name |br| i.e., Bluetooth LE + GATT Server
|
||||
- URI, i.e., SoftAP |br| + HTTP Server + mDNS
|
||||
- Description
|
||||
* - prov-session
|
||||
- http://<mdns-hostname>.local/prov-session
|
||||
- Security endpoint used for session establishment
|
||||
* - prov-scan
|
||||
- http://wifi-prov.local/prov-scan
|
||||
- Endpoint used for starting Wi-Fi scan and receiving scan results
|
||||
- the endpoint used for starting Wi-Fi scan and receiving scan results
|
||||
* - prov-ctrl
|
||||
- http://wifi-prov.local/prov-ctrl
|
||||
- Endpoint used for controlling Wi-Fi provisioning state
|
||||
- the endpoint used for controlling Wi-Fi provisioning state
|
||||
* - prov-config
|
||||
- http://<mdns-hostname>.local/prov-config
|
||||
- Endpoint used for configuring Wi-Fi credentials on device
|
||||
- the endpoint used for configuring Wi-Fi credentials on device
|
||||
* - proto-ver
|
||||
- http://<mdns-hostname>.local/proto-ver
|
||||
- Endpoint for retrieving version info
|
||||
- the endpoint for retrieving version info
|
||||
|
||||
Immediately after connecting, the client application may fetch the version / capabilities information from the `proto-ver` endpoint. All communications to this endpoint are un-encrypted, hence necessary information (that may be relevant for deciding compatibility) can be retrieved before establishing a secure session. The response is in JSON format and looks like : ``prov: { ver: v1.1, cap: [no_pop] }, my_app: { ver: 1.345, cap: [cloud, local_ctrl] },....``. Here label `prov` provides provisioning service version (`ver`) and capabilities (`cap`). For now, only `no_pop` capability is supported, which indicates that the service doesn't require proof of possession for authentication. Any application related version / capabilities will be given by other labels (like `my_app` in this example). These additional fields are set using :cpp:func:`wifi_prov_mgr_set_app_info()`.
|
||||
Immediately after connecting, the client application may fetch the version/capabilities information from the ``proto-ver`` endpoint. All communications to this endpoint are unencrypted, hence necessary information, which may be relevant for deciding compatibility, can be retrieved before establishing a secure session. The response is in JSON format and looks like : ``prov: { ver: v1.1, cap: [no_pop] }, my_app: { ver: 1.345, cap: [cloud, local_ctrl] },....``. Here label ``prov`` provides provisioning service version ``ver`` and capabilities ``cap``. For now, only the ``no_pop`` capability is supported, which indicates that the service does not require proof of possession for authentication. Any application-related version or capabilities are given by other labels, e.g., ``my_app`` in this example. These additional fields are set using :cpp:func:`wifi_prov_mgr_set_app_info()`.
|
||||
|
||||
User side applications need to implement the signature handshaking required for establishing and authenticating secure protocomm sessions as per the security scheme configured for use (this is not needed when manager is configured to use protocomm security 0).
|
||||
User side applications need to implement the signature handshaking required for establishing and authenticating secure protocomm sessions as per the security scheme configured for use, which is not needed when the manager is configured to use protocomm security 0.
|
||||
|
||||
See Unified Provisioning for more details about the secure handshake and encryption used. Applications must use the `.proto` files found under :component:`protocomm/proto`, which define the Protobuf message structures supported by `prov-session` endpoint.
|
||||
See :doc:`provisioning` for more details about the secure handshake and encryption used. Applications must use the ``.proto`` files found under :component:`protocomm/proto`, which define the Protobuf message structures supported by ``prov-session`` endpoint.
|
||||
|
||||
Once a session is established, Wi-Fi credentials are configured using the following set of `wifi_config` commands, serialized as Protobuf messages (the corresponding `.proto` files can be found under :component:`wifi_provisioning/proto`) :
|
||||
Once a session is established, Wi-Fi credentials are configured using the following set of ``wifi_config`` commands, serialized as Protobuf messages with the corresponding ``.proto`` files that can be found under :component:`wifi_provisioning/proto`:
|
||||
|
||||
* `get_status` - For querying the Wi-Fi connection status. The device will respond with a status which will be one of connecting / connected / disconnected. If status is disconnected, a disconnection reason will also be included in the status response.
|
||||
* `set_config` - For setting the Wi-Fi connection credentials
|
||||
* `apply_config` - For applying the credentials saved during `set_config` and start the Wi-Fi station
|
||||
* ``get_status`` - For querying the Wi-Fi connection status. The device responds with a status which is one of connecting, connected or disconnected. If the status is disconnected, a disconnection reason is also to be included in the status response.
|
||||
|
||||
After session establishment, client can also request Wi-Fi scan results from the device. The results returned is a list of AP SSIDs, sorted in descending order of signal strength. This allows client applications to display APs nearby to the device at the time of provisioning, and users can select one of the SSIDs and provide the password which is then sent using the `wifi_config` commands described above. The `wifi_scan` endpoint supports the following protobuf commands :
|
||||
* ``set_config`` - For setting the Wi-Fi connection credentials.
|
||||
|
||||
* `scan_start` - For starting Wi-Fi scan with various options :
|
||||
* ``apply_config`` - For applying the credentials saved during ``set_config`` and starting the Wi-Fi station.
|
||||
|
||||
* `blocking` (input) - If true, the command returns only when the scanning is finished
|
||||
* `passive` (input) - If true scan is started in passive mode (this may be slower) instead of active mode
|
||||
* `group_channels` (input) - This specifies whether to scan all channels in one go (when zero) or perform scanning of channels in groups, with 120ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager will wait for atleast 120ms after completing scan on a group of channels, and thus allow the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting group_channels to 4, will create 5 groups, with each group having 3 channels, except the last one which will have 14 % 3 = 2 channels. So, when scan is started, the first 3 channels will be scanned, followed by a 120ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned. One may need to adjust this parameter as having only few channels in a group may slow down the overall scan time, while having too many may again cause disconnection. Usually a value of 4 should work for most cases. Note that for any other mode of transport, e.g. BLE, this can be safely set to 0, and hence achieve the fastest overall scanning time.
|
||||
* `period_ms` (input) - Scan parameter specifying how long to wait on each channel
|
||||
* `scan_status` - Gives the status of scanning process :
|
||||
After session establishment, the client can also request Wi-Fi scan results from the device. The results returned is a list of AP SSIDs, sorted in descending order of signal strength. This allows client applications to display APs nearby to the device at the time of provisioning, and users can select one of the SSIDs and provide the password which is then sent using the ``wifi_config`` commands described above. The ``wifi_scan`` endpoint supports the following protobuf commands :
|
||||
|
||||
* `scan_finished` (output) - When scan has finished this returns true
|
||||
* `result_count` (output) - This gives the total number of results obtained till now. If scan is yet happening this number will keep on updating
|
||||
* `scan_result` - For fetching scan results. This can be called even if scan is still on going
|
||||
* ``scan_start`` - For starting Wi-Fi scan with various options:
|
||||
|
||||
* `start_index` (input) - Starting index from where to fetch the entries from the results list
|
||||
* `count` (input) - Number of entries to fetch from the starting index
|
||||
* `entries` (output) - List of entries returned. Each entry consists of `ssid`, `channel` and `rssi` information
|
||||
* ``blocking`` (input) - If true, the command returns only when the scanning is finished.
|
||||
|
||||
The client can also control the provisioning state of the device using `wifi_ctrl` endpoint. The `wifi_ctrl` endpoint supports the following protobuf commands:
|
||||
* ``passive`` (input) - If true, the scan is started in passive mode, which may be slower, instead of active mode.
|
||||
|
||||
* `ctrl_reset` - Resets internal state machine of the device and clears provisioned credentials only in case of provisioning failures.
|
||||
* ``group_channels`` (input) - This specifies whether to scan all channels in one go when zero, or perform scanning of channels in groups, with 120 ms delay between scanning of consecutive groups, and the value of this parameter sets the number of channels in each group. This is useful when transport mode is SoftAP, where scanning all channels in one go may not give the Wi-Fi driver enough time to send out beacons, and hence may cause disconnection with any connected stations. When scanning in groups, the manager waits for at least 120 ms after completing the scan on a group of channels, and thus allows the driver to send out the beacons. For example, given that the total number of Wi-Fi channels is 14, then setting ``group_channels`` to 3 creates 5 groups, with each group having 3 channels, except the last one which has 14 % 3 = 2 channels. So, when the scan is started, the first 3 channels will be scanned, followed by a 120 ms delay, and then the next 3 channels, and so on, until all the 14 channels have been scanned.One may need to adjust this parameter as having only a few channels in a group may increase the overall scan time, while having too many may again cause disconnection. Usually, a value of 4 should work for most cases. Note that for any other mode of transport, e.g. Bluetooth LE, this can be safely set to 0, and hence achieve the shortest overall scanning time.
|
||||
|
||||
* `ctrl_reprov` - Resets internal state machine of the device and clears provisioned credentials only in case the device is to be provisioned again for new credentials after a previous successful provisioning
|
||||
* ``period_ms`` (input) - The scan parameter specifying how long to wait on each channel.
|
||||
|
||||
* ``scan_status`` - It gives the status of scanning process:
|
||||
|
||||
* ``scan_finished`` (output) - When the scan has finished, this returns true.
|
||||
|
||||
* ``result_count`` (output) - This gives the total number of results obtained till now. If the scan is yet happening, this number keeps on updating.
|
||||
|
||||
* ``scan_result`` - For fetching the scan results. This can be called even if the scan is still on going.
|
||||
|
||||
* ``start_index`` (input) - Where the index starts from to fetch the entries from the results list.
|
||||
|
||||
* ``count`` (input) - The number of entries to fetch from the starting index.
|
||||
|
||||
* ``entries`` (output) - The list of entries returned. Each entry consists of ``ssid``, ``channel`` and ``rssi`` information.
|
||||
|
||||
The client can also control the provisioning state of the device using ``wifi_ctrl`` endpoint. The ``wifi_ctrl`` endpoint supports the following protobuf commands:
|
||||
|
||||
* ``ctrl_reset`` - Resets internal state machine of the device and clears provisioned credentials only in case of provisioning failures.
|
||||
|
||||
* ``ctrl_reprov`` - Resets internal state machine of the device and clears provisioned credentials only in case the device is to be provisioned again for new credentials after a previous successful provisioning.
|
||||
|
||||
Additional Endpoints
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
In case users want to have some additional protocomm endpoints customized to their requirements, this is done in two steps. First is creation of an endpoint with a specific name, and the second step is the registration of a handler for this endpoint. See :doc:`protocomm<protocomm>` for the function signature of an endpoint handler. A custom endpoint must be created after initialization and before starting the provisioning service. Whereas, the protocomm handler is registered for this endpoint only after starting the provisioning service.
|
||||
In case users want to have some additional protocomm endpoints customized to their requirements, this is done in two steps. First is creation of an endpoint with a specific name, and the second step is the registration of a handler for this endpoint. See :doc:`protocomm` for the function signature of an endpoint handler. A custom endpoint must be created after initialization and before starting the provisioning service. Whereas, the protocomm handler is registered for this endpoint only after starting the provisioning service.
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
.. code-block:: c
|
||||
|
||||
wifi_prov_mgr_init(config);
|
||||
wifi_prov_mgr_endpoint_create("custom-endpoint");
|
||||
@ -271,21 +280,21 @@ When the provisioning service stops, the endpoint is unregistered automatically.
|
||||
|
||||
One can also choose to call :cpp:func:`wifi_prov_mgr_endpoint_unregister()` to manually deactivate an endpoint at runtime. This can also be used to deactivate the internal endpoints used by the provisioning service.
|
||||
|
||||
When / How To Stop Provisioning Service?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
When/How to Stop the Provisioning Service?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The default behavior is that once the device successfully connects using the Wi-Fi credentials set by the `apply_config` command, the provisioning service will be stopped (and BLE / SoftAP turned off) automatically after responding to the next `get_status` command. If `get_status` command is not received by the device, the service will be stopped after a 30s timeout.
|
||||
The default behavior is that once the device successfully connects using the Wi-Fi credentials set by the ``apply_config`` command, the provisioning service stops, and Bluetooth LE or SoftAP turns off, automatically after responding to the next ``get_status`` command. If ``get_status`` command is not received by the device, the service stops after a 30s timeout.
|
||||
|
||||
On the other hand, if device was not able to connect using the provided Wi-Fi credentials, due to incorrect SSID / passphrase, the service will keep running, and `get_status` will keep responding with disconnected status and reason for disconnection. Any further attempts to provide another set of Wi-Fi credentials, will be rejected. These credentials will be preserved, unless the provisioning service is force started, or NVS erased.
|
||||
On the other hand, if device is not able to connect using the provided Wi-Fi credentials, due to incorrect SSID or passphrase, the service keeps running, and ``get_status`` keeps responding with disconnected status and reason for disconnection. Any further attempts to provide another set of Wi-Fi credentials, are to be rejected. These credentials are preserved, unless the provisioning service is force started, or NVS erased.
|
||||
|
||||
If this default behavior is not desired, it can be disabled by calling :cpp:func:`wifi_prov_mgr_disable_auto_stop()`. Now the provisioning service will only be stopped after an explicit call to :cpp:func:`wifi_prov_mgr_stop_provisioning()`, which returns immediately after scheduling a task for stopping the service. The service stops after a certain delay and WIFI_PROV_END event gets emitted. This delay is specified by the argument to :cpp:func:`wifi_prov_mgr_disable_auto_stop()`.
|
||||
If this default behavior is not desired, it can be disabled by calling :cpp:func:`wifi_prov_mgr_disable_auto_stop()`. Now the provisioning service stops only after an explicit call to :cpp:func:`wifi_prov_mgr_stop_provisioning()`, which returns immediately after scheduling a task for stopping the service. The service stops after a certain delay and ``WIFI_PROV_END`` event gets emitted. This delay is specified by the argument to :cpp:func:`wifi_prov_mgr_disable_auto_stop()`.
|
||||
|
||||
The customized behavior is useful for applications which want the provisioning service to be stopped some time after the Wi-Fi connection is successfully established. For example, if the application requires the device to connect to some cloud service and obtain another set of credentials, and exchange this credentials over a custom protocomm endpoint, then after successfully doing so stop the provisioning service by calling :cpp:func:`wifi_prov_mgr_stop_provisioning()` inside the protocomm handler itself. The right amount of delay ensures that the transport resources are freed only after the response from the protocomm handler reaches the client side application.
|
||||
The customized behavior is useful for applications which want the provisioning service to be stopped some time after the Wi-Fi connection is successfully established. For example, if the application requires the device to connect to some cloud service and obtain another set of credentials, and exchange these credentials over a custom protocomm endpoint, then after successfully doing so, stop the provisioning service by calling :cpp:func:`wifi_prov_mgr_stop_provisioning()` inside the protocomm handler itself. The right amount of delay ensures that the transport resources are freed only after the response from the protocomm handler reaches the client side application.
|
||||
|
||||
Application Examples
|
||||
--------------------
|
||||
|
||||
For complete example implementation see :example:`provisioning/wifi_prov_mgr`
|
||||
For complete example implementation see :example:`provisioning/wifi_prov_mgr`.
|
||||
|
||||
Provisioning Tools
|
||||
--------------------
|
||||
@ -293,16 +302,16 @@ Provisioning Tools
|
||||
Provisioning applications are available for various platforms, along with source code:
|
||||
|
||||
* Android:
|
||||
* `BLE Provisioning app on Play Store <https://play.google.com/store/apps/details?id=com.espressif.provble>`_.
|
||||
* `Bluetooth LE Provisioning app on Play Store <https://play.google.com/store/apps/details?id=com.espressif.provble>`_.
|
||||
* `SoftAP Provisioning app on Play Store <https://play.google.com/store/apps/details?id=com.espressif.provsoftap>`_.
|
||||
* Source code on GitHub: `esp-idf-provisioning-android <https://github.com/espressif/esp-idf-provisioning-android>`_.
|
||||
* iOS:
|
||||
* `BLE Provisioning app on app store <https://apps.apple.com/in/app/esp-ble-provisioning/id1473590141>`_.
|
||||
* `SoftAP Provisioning app on app Store <https://apps.apple.com/in/app/esp-softap-provisioning/id1474040630>`_.
|
||||
* `Bluetooth LE Provisioning app on App Store <https://apps.apple.com/in/app/esp-ble-provisioning/id1473590141>`_.
|
||||
* `SoftAP Provisioning app on App Store <https://apps.apple.com/in/app/esp-softap-provisioning/id1474040630>`_.
|
||||
* Source code on GitHub: `esp-idf-provisioning-ios <https://github.com/espressif/esp-idf-provisioning-ios>`_.
|
||||
* Linux/MacOS/Windows : :idf:`tools/esp_prov` (a python based command line tool for provisioning)
|
||||
* Linux/MacOS/Windows: :idf:`tools/esp_prov`, a Python-based command-line tool for provisioning.
|
||||
|
||||
The phone applications offer simple UI and thus more user centric, while the command line application is useful as a debugging tool for developers.
|
||||
The phone applications offer simple UI and are thus more user centric, while the command-line application is useful as a debugging tool for developers.
|
||||
|
||||
|
||||
API Reference
|
||||
|
@ -1 +1,324 @@
|
||||
.. include:: ../../../en/api-reference/provisioning/wifi_provisioning.rst
|
||||
:orphan:
|
||||
|
||||
Wi-Fi 配网
|
||||
====================
|
||||
|
||||
:link_to_translation:`en:[English]`
|
||||
|
||||
概述
|
||||
----------
|
||||
|
||||
该组件提供控制 Wi-Fi 配网服务的 API,可以通过 SoftAP 或低功耗蓝牙建立 :doc:`protocomm` 安全会话,接收和配置 Wi-Fi 凭证。通过一组 ``wifi_prov_mgr_`` API,可以快速实现配网服务,该服务具备必要功能、代码量少且足够灵活。
|
||||
|
||||
.. _wifi-prov-mgr-init:
|
||||
|
||||
初始化
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
调用 :cpp:func:`wifi_prov_mgr_init()` 可以配置和初始化配网管理器,因此在调用任何其他 ``wifi_prov_mgr_`` API 之前必须先调用此函数。请注意,该管理器依赖于 ESP-IDF 的其他组件,包括 NVS、TCP/IP、Event Loop 和 Wi-Fi,以及可选的 mDNS,因此在调用之前必须先初始化这些组件。调用 :cpp:func:`wifi_prov_mgr_deinit()` 可以随时反初始化管理器。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
wifi_prov_mgr_config_t config = {
|
||||
.scheme = wifi_prov_scheme_ble,
|
||||
.scheme_event_handler = WIFI_PROV_SCHEME_BLE_EVENT_HANDLER_FREE_BTDM
|
||||
};
|
||||
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_init(config) );
|
||||
|
||||
|
||||
以下配置结构体 :cpp:type:`wifi_prov_mgr_config_t` 里包含的部分字段可用于指定特定管理器行为:
|
||||
|
||||
* :cpp:member:`wifi_prov_mgr_config_t::scheme` - 用于指定配网方案。每个方案对应一种 protocomm 支持的传输模式,因此支持三个选项:
|
||||
|
||||
* ``wifi_prov_scheme_ble`` - 使用低功耗蓝牙传输和 GATT 服务器来处理配网命令。
|
||||
|
||||
* ``wifi_prov_scheme_softap`` - 使用 Wi-Fi SoftAP 传输和 HTTP 服务器来处理配网命令。
|
||||
|
||||
* ``wifi_prov_scheme_console`` - 使用串口传输和控制台来处理配网命令。
|
||||
|
||||
* :cpp:member:`wifi_prov_mgr_config_t::scheme_event_handler` - 为方案定义的专属事件处理程序。选择适当方案后,其专属事件处理程序支持管理器自动处理特定事项。目前,该选项不适用于 SoftAP 或基于控制台的配网方案,但对于低功耗蓝牙配网方案来说非常方便。因为蓝牙需要相当多内存才能正常工作,所以配网完成后,主应用程序需要使用低功耗蓝牙或经典蓝牙时,可能需要回收配网所占的全部或部分内存。此外,未来每当配网设备重启时,都需要再次回收内存。为了便于使用 ``wifi_prov_scheme_ble`` 选项,各方案定义了专属处理程序。设备会根据所选处理程序,在反初始化配网管理器时自动释放低功耗蓝牙、经典蓝牙或蓝牙双模的内存。可用选项包括:
|
||||
|
||||
* ``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_NONE`` - 不使用任何特定方案的专属处理程序。以下情况可使用该选项:不使用低功耗蓝牙配网方案,即使用 SoftAP 或控制台方案;主应用程序需要自行回收内存;主应用程序需要同时使用低功耗蓝牙和经典蓝牙。
|
||||
|
||||
* :cpp:member:`wifi_prov_mgr_config_t::app_event_handler` (不推荐)- 目前建议使用默认的事件循环处理程序捕获生成的 ``WIFI_PROV_EVENT``。关于配网服务生成事件的列表,请参阅 ``wifi_prov_cb_event_t`` 的定义。以下是配网事件示例摘录:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_PROV_EVENT) {
|
||||
switch (event_id) {
|
||||
case WIFI_PROV_START:
|
||||
ESP_LOGI(TAG, "Provisioning started");
|
||||
break;
|
||||
case WIFI_PROV_CRED_RECV: {
|
||||
wifi_sta_config_t *wifi_sta_cfg = (wifi_sta_config_t *)event_data;
|
||||
ESP_LOGI(TAG, "Received Wi-Fi credentials"
|
||||
"\n\tSSID : %s\n\tPassword : %s",
|
||||
(const char *) wifi_sta_cfg->ssid,
|
||||
(const char *) wifi_sta_cfg->password);
|
||||
break;
|
||||
}
|
||||
case WIFI_PROV_CRED_FAIL: {
|
||||
wifi_prov_sta_fail_reason_t *reason = (wifi_prov_sta_fail_reason_t *)event_data;
|
||||
ESP_LOGE(TAG, "Provisioning failed!\n\tReason : %s"
|
||||
"\n\tPlease reset to factory and retry provisioning",
|
||||
(*reason == WIFI_PROV_STA_AUTH_ERROR) ?
|
||||
"Wi-Fi station authentication failed" : "Wi-Fi access-point not found");
|
||||
break;
|
||||
}
|
||||
case WIFI_PROV_CRED_SUCCESS:
|
||||
ESP_LOGI(TAG, "Provisioning successful");
|
||||
break;
|
||||
case WIFI_PROV_END:
|
||||
/*配网完成后,反初始化管理器。*/
|
||||
wifi_prov_mgr_deinit();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
调用 :cpp:func:`wifi_prov_mgr_deinit()` 可以随时反初始化管理器。
|
||||
|
||||
.. _wifi-prov-check-state:
|
||||
|
||||
检查配网状态
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
在运行时,可以调用 :cpp:func:`wifi_prov_mgr_is_provisioned()` 检查设备是否配网完成,该函数会在内部检查 Wi-Fi 凭据是否存储在 NVS 中。
|
||||
|
||||
请注意,目前管理器并没有自己的 NVS 命名空间来存储 Wi-Fi 凭据,而是依赖 ``esp_wifi_`` API 来设置和获取存储在默认位置的 NVS 中的凭据。
|
||||
|
||||
可以采用以下任一方法重置配网状态:
|
||||
|
||||
* 手动擦除 NVS 分区的配网相关部分。
|
||||
* 主应用程序必须实现某种逻辑,以在运行时调用 ``esp_wifi_`` API 来擦除凭据。
|
||||
* 主应用程序必须实现某种逻辑,以在不考虑配网状态的情况下,强制启动配网。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
bool provisioned = false;
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_is_provisioned(&provisioned) );
|
||||
|
||||
|
||||
启动配网服务
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
在启动配网服务时,需要指定服务名称和相应密钥,即:
|
||||
|
||||
* 使用 ``wifi_prov_scheme_softap`` 方案时,服务名称对应 Wi-Fi SoftAP 的 SSID,密钥对应密码。
|
||||
* 使用 ``wifi_prov_scheme_ble`` 方案时,服务名称对应低功耗蓝牙设备名称,无需指定密钥。
|
||||
|
||||
此外,由于管理器内部使用了 ``protocomm``,可以选择其提供的任一安全功能:
|
||||
|
||||
* Security 1 是安全通信,该安全通信需要先握手,其中涉及 X25519 密钥交换和使用所有权证明 ``pop`` 完成身份验证,随后使用 AES-CTR 加密或解密后续消息。
|
||||
* Security 0 是纯文本通信,会直接忽略 ``pop``。
|
||||
|
||||
关于安全功能的更多详情,请参阅 :doc:`provisioning`。
|
||||
|
||||
.. highlight:: c
|
||||
|
||||
::
|
||||
|
||||
const char *service_name = "my_device";
|
||||
const char *service_key = "password";
|
||||
|
||||
wifi_prov_security_t security = WIFI_PROV_SECURITY_1;
|
||||
const char *pop = "abcd1234";
|
||||
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key) );
|
||||
|
||||
|
||||
如果收到有效的 Wi-Fi AP 凭据,且设备成功连接到该 AP 并获取了 IP,配网服务会自动结束。此外,调用 :cpp:func:`wifi_prov_mgr_stop_provisioning()` 可以随时停止配网服务。
|
||||
|
||||
.. note::
|
||||
|
||||
如果设备使用提供的凭据无法连接,则它不再接受新的凭据,但在设备重新启动前,配网服务仍然会继续运行,并向客户端传递连接失败的信息。设备重新启动后配网状态将变为已配网,因为在 NVS 中找到了凭据,但除非出现与凭据匹配的可用 AP,否则设备仍然无法使用原凭据进行连接。可以通过重置 NVS 中的凭据或强制启动配网服务来解决这个问题,详情请参阅上文 :ref:`wifi-prov-check-state`。
|
||||
|
||||
|
||||
等待配网完成
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
主应用程序通常会等待配网服务完成,然后反初始化管理器以释放资源,最后开始执行自己的逻辑。
|
||||
|
||||
有两种方法可以实现这一点,其中调用阻塞 :cpp:func:`wifi_prov_mgr_wait()` 更为简单。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
// 启动配网服务
|
||||
ESP_ERROR_CHECK( wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key) );
|
||||
|
||||
// 等待服务完成
|
||||
wifi_prov_mgr_wait();
|
||||
|
||||
// 最后反初始化管理器
|
||||
wifi_prov_mgr_deinit();
|
||||
|
||||
|
||||
另一种方法是使用默认的事件循环处理程序捕获 ``WIFI_PROV_EVENT`` 并在事件 ID 为 ``WIFI_PROV_END`` 时调用 :cpp:func:`wifi_prov_mgr_deinit()`:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
if (event_base == WIFI_PROV_EVENT && event_id == WIFI_PROV_END) {
|
||||
/* 配网完成后反初始化管理器 */
|
||||
wifi_prov_mgr_deinit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
用户端实现
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
启动服务时,通过广播服务名称识别即将配网的设备。根据选择的传输方式,该服务名称为低功耗蓝牙设备的名称或 SoftAP SSID。
|
||||
|
||||
使用 SoftAP 传输方式时,为便于服务发现,必须在启动配网之前初始化 mDNS。在这种情况下,应使用主应用程序设置的主机名,并且在内部将服务类型设置为 ``_esp_wifi_prov``。
|
||||
|
||||
使用低功耗蓝牙传输方式时,应使用 :cpp:func:`wifi_prov_scheme_ble_set_service_uuid()` 设置一个自定义的 128 位 UUID。该 UUID 将包含在低功耗蓝牙广播中,并对应于提供配网端点作为 GATT 特征的主要服务。每个 GATT 特征都基于主要服务 UUID 形成,其中从第 0 个字节开始计数,第 12 和第 13 个字节为自动分配的不同字节。由于端点特征 UUID 自动分配,因此不应将其用于识别端点。客户端应用程序应通过读取每个特征的用户特征描述符 (``0x2901``) 来识别端点,该描述符包含特征的端点名称。例如,如果将服务 UUID 设置为 ``55cc035e-fb27-4f80-be02-3c60828b7451``,每个端点特征将分配到一个类似于 ``55cc____-fb27-4f80-be02-3c60828b7451`` 的 UUID,其中第 12 和第 13 个字节具有唯一值。
|
||||
|
||||
连接设备后,可以通过以下方式识别与配网相关的 protocomm 端点:
|
||||
|
||||
.. |br| raw:: html
|
||||
|
||||
<br>
|
||||
|
||||
.. list-table:: 配网服务提供的端点
|
||||
:widths: 35 35 30
|
||||
:header-rows: 1
|
||||
|
||||
* - 端点名称 |br| 即低功耗蓝牙 + GATT 服务器
|
||||
- URI 即 SoftAP |br| + HTTP 服务器 + mDNS
|
||||
- 描述
|
||||
* - prov-session
|
||||
- http://<mdns-hostname>.local/prov-session
|
||||
- 用于建立会话的安全端点
|
||||
* - prov-scan
|
||||
- http://wifi-prov.local/prov-scan
|
||||
- 用于启动 Wi-Fi 扫描和接收扫描结果的端点
|
||||
* - prov-ctrl
|
||||
- http://wifi-prov.local/prov-ctrl
|
||||
- 用于控制 Wi-Fi 配网状态的端点
|
||||
* - prov-config
|
||||
- http://<mdns-hostname>.local/prov-config
|
||||
- 用于在设备上配置 Wi-Fi 凭据的端点
|
||||
* - proto-ver
|
||||
- http://<mdns-hostname>.local/proto-ver
|
||||
- 用于获取版本信息的端点
|
||||
|
||||
连接后,客户端应用程序可以立即从 ``proto-ver`` 端点获取版本或属性信息。所有与此端点的通信均未加密,因此在建立安全会话前,可以检索相关必要信息,确保会话兼容。响应结果以 JSON 格式返回,格式类似于 ``prov: { ver: v1.1, cap: [no_pop] }, my_app: { ver: 1.345, cap: [cloud, local_ctrl] },....``。其中 ``prov`` 标签提供了配网服务的版本 ``ver`` 和属性 ``cap``。目前仅支持 ``no_pop`` 属性,表示该服务不需要验证所有权证明。任何与应用程序相关的版本或属性将由其他标签给出,如本示例中的 ``my_app``。使用 :cpp:func:`wifi_prov_mgr_set_app_info()` 可以设置这些附加字段。
|
||||
|
||||
用户端应用程序需要根据所配置的安全方案实现签名握手,以建立和认证 protocomm 安全会话。当管理器配置为使用 protocomm security 0 时,则不需要实现签名握手。
|
||||
|
||||
关于安全握手和加密的详情,请参阅 :doc:`provisioning`。应用程序必须使用 :component:`protocomm/proto` 中的 ``.proto`` 文件。``.proto`` 文件定义了 ``prov-session`` 端点支持的 protobuf 消息结构。
|
||||
|
||||
建立会话后,以下 ``wifi_config`` 命令集可用于配置 Wi-Fi 凭据,这些命令会被序列化为 protobuf 消息,对应的 ``.proto`` 文件存放在 :component:`wifi_provisioning/proto` 中。
|
||||
|
||||
* ``get_status`` - 用于查询 Wi-Fi 连接状态。设备响应状态为连接中、已连接或已断开。如果状态为已断开,则还会包含断开原因。
|
||||
|
||||
* ``set_config`` - 用于设置 Wi-Fi 连接凭据。
|
||||
|
||||
* ``apply_config`` - 用于应用先前保存的凭据,即由 ``set_config`` 设置的凭据,并启动 Wi-Fi 站点。
|
||||
|
||||
建立会话后,客户端还可以从设备请求 Wi-Fi 扫描结果。返回结果为 AP SSID 的列表,按信号强度降序排序。由此,客户端应用程序可以在设备配网时显示附近的 AP,并且用户可以选择其中一个 SSID 并提供密码,然后使用上述 ``wifi_config`` 命令发送密码。``wifi_scan`` 端点支持以下 protobuf 命令:
|
||||
|
||||
* ``scan_start`` - 启动 Wi-Fi 扫描有多个选项,具体如下:
|
||||
|
||||
* ``blocking`` (输入) - 如果参数为 true,则命令只会在扫描完成后返回。
|
||||
|
||||
* ``passive`` (输入) - 如果参数为 true,则以被动模式启动扫描,扫描速度可能更慢。
|
||||
|
||||
* ``group_channels`` (输入) - 该参数用于指定是否分组扫描。如果参数为 0,表示一次性扫描所有信道;如果参数为非零值,则表示分组扫描信道且参数值为每组中的信道数,每个连续组之间有 120 毫秒的延迟。分组扫描非常适用于使用 SoftAP 的传输模式,因为一次性扫描所有信道可能会导致 Wi-Fi 驱动没有足够时间发送信标,进而导致与部分站点断连。分组扫描时,管理器每扫描完一组信道,至少会等待 120 毫秒,确保驱动程序有足够时间发送信标。例如,假设共有 14 个 Wi-Fi 信道,将 ``group_channels`` 设置为 3 则将创建 5 个分组,每个分组包含 3 个信道,最后一个分组则为 14 除以 3 余下的 2 个信道。因此,扫描开始时,首先会扫描前 3 个信道,然后等待 120 毫秒,再继续扫描后 3 个信道,以此类推,直到扫描完 14 个信道。可以根据实际情况调整此参数,因为分组中信道数量过少可能会增加整体扫描时间,而信道数量过多则可能会导致连接再次断开。大多数情况下,将参数值设置为 4 即可。请注意,对于低功耗蓝牙等其他传输模式,可以放心将该参数设置为 0,从而在最短时间内完成扫描。
|
||||
|
||||
* ``period_ms`` (输入) - 该扫描参数用于设置在每个信道上的等待时间。
|
||||
|
||||
* ``scan_status`` - 可以返回扫描过程的状态:
|
||||
|
||||
* ``scan_finished`` (输出) - 扫描完成时,该参数返回为 true。
|
||||
|
||||
* ``result_count`` (输出) - 该参数返回到目前为止获取的结果总数。如果扫描仍在进行,该数字会不断更新。
|
||||
|
||||
* ``scan_result`` - 用于获取扫描结果。即使扫描仍在进行,也可以调用此函数。
|
||||
|
||||
* ``start_index`` (输入) - 从结果列表中获取条目的起始索引位置。
|
||||
|
||||
* ``count`` (输入) - 从起始索引位置获取的条目数目。
|
||||
|
||||
* ``entries`` (输出) - 返回条目的列表。每个条目包含 ``ssid``、``channel`` 和 ``rssi`` 信息。
|
||||
|
||||
客户端还可以使用 ``wifi_ctrl`` 端点来控制设备的配网状态。``wifi_ctrl`` 端点支持的 protobuf 命令如下:
|
||||
|
||||
* ``ctrl_reset`` - 仅在配网失败时,重置设备的内部状态机并清除已配置的凭据。
|
||||
|
||||
* ``ctrl_reprov`` - 仅在设备已成功配网的前提下,设备需要重新配网获取新的凭据时,重置设备的内部状态机并清除已配置的凭据。
|
||||
|
||||
附加端点
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
如果用户想要根据自己的需求定制一些附加 protocomm 端点,可以通过两步完成。第一步是创建一个具有特定名称的端点,第二步是为该端点注册一个处理程序。关于端点处理程序的函数签名,请参阅 :doc:`protocomm`。自定义端点必须在初始化后、配网服务启动之前创建,但只能在配网服务启动后为该端点注册 protocomm 处理程序。
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
wifi_prov_mgr_init(config);
|
||||
wifi_prov_mgr_endpoint_create("custom-endpoint");
|
||||
wifi_prov_mgr_start_provisioning(security, pop, service_name, service_key);
|
||||
wifi_prov_mgr_endpoint_register("custom-endpoint", custom_ep_handler, custom_ep_data);
|
||||
|
||||
|
||||
配网服务停止时,端点会自动取消注册。
|
||||
|
||||
在运行时,可以调用 :cpp:func:`wifi_prov_mgr_endpoint_unregister()` 来手动停用某个端点。该函数也可以用于停用配网服务使用的内部端点。
|
||||
|
||||
何时以及如何停止配网服务?
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
当设备使用 ``apply_config`` 命令设置的 Wi-Fi 凭据成功连接,配网服务将默认停止,并在响应下一个 ``get_status`` 命令后自动关闭低功耗蓝牙或 softAP。如果设备没有收到 ``get_status`` 命令,配网服务将在超时 30 秒后停止。
|
||||
|
||||
如果设备因 SSID 或密码不正确等原因无法使用 Wi-Fi 凭据成功连接,配网服务将继续运行,并通过 ``get_status`` 命令持续响应为断连状态,并提供断连原因。此时设备不会再接受任何新的 Wi-Fi 凭据。除非强制启动配网服务或擦除 NVS 存储,这些凭据将保留。
|
||||
|
||||
可以调用 :cpp:func:`wifi_prov_mgr_disable_auto_stop()` 来禁用默认设置。禁用后,只有在显式调用 :cpp:func:`wifi_prov_mgr_stop_provisioning()` 之后,配网服务才会停止,且该函数会安排一个任务来停止配网服务,之后立即返回。配网服务将在一定延迟后停止,并触发 ``WIFI_PROV_END`` 事件。该延迟时间可以由 :cpp:func:`wifi_prov_mgr_disable_auto_stop()` 的参数指定。
|
||||
|
||||
如果需要在成功建立 Wi-Fi 连接后的某个时间再停止配网服务,应用程序可以采取定制行为。例如,如果应用程序需要设备连接到某个云服务并获取另一组凭证,继而通过自定义 protocomm 端点交换凭证,那么成功完成此操作后,可以在 protocomm 处理程序中调用 :cpp:func:`wifi_prov_mgr_stop_provisioning()` 来停止配网服务。设定适当的延迟时间可以确保 protocomm 处理程序的响应到达客户端应用程序后,才释放传输资源。
|
||||
|
||||
应用程序示例
|
||||
---------------------
|
||||
|
||||
关于完整实现示例,请参阅 :example:`provisioning/wifi_prov_mgr`。
|
||||
|
||||
配网工具
|
||||
--------------------
|
||||
|
||||
以下为各平台相应的配网应用程序,并附带源代码:
|
||||
|
||||
* Android:
|
||||
* `Play Store 上的低功耗蓝牙配网应用程序 <https://play.google.com/store/apps/details?id=com.espressif.provble>`_。
|
||||
* `Play Store 上的 SoftAP 配网应用程序 <https://play.google.com/store/apps/details?id=com.espressif.provsoftap>`_。
|
||||
* GitHub 上的源代码: `esp-idf-provisioning-android <https://github.com/espressif/esp-idf-provisioning-android>`_。
|
||||
* iOS:
|
||||
* `App Store 上的低功耗蓝牙配网应用程序 <https://apps.apple.com/in/app/esp-ble-provisioning/id1473590141>`_。
|
||||
* `App Store 上的 SoftAP 配网应用程序 <https://apps.apple.com/in/app/esp-softap-provisioning/id1474040630>`_。
|
||||
* GitHub 上的源代码: `esp-idf-provisioning-ios <https://github.com/espressif/esp-idf-provisioning-ios>`_。
|
||||
* Linux/MacOS/Windows: 基于 Python 的命令行工具 :idf:`tools/esp_prov`,可用于设备配网。
|
||||
|
||||
手机应用程序界面简洁,便于用户使用,而开发者可以使用命令行应用程序,便于调试。
|
||||
|
||||
|
||||
API 参考
|
||||
-------------
|
||||
|
||||
.. include-build-file:: inc/manager.inc
|
||||
.. include-build-file:: inc/scheme_ble.inc
|
||||
.. include-build-file:: inc/scheme_softap.inc
|
||||
.. include-build-file:: inc/scheme_console.inc
|
||||
.. include-build-file:: inc/wifi_config.inc
|
||||
|
Loading…
Reference in New Issue
Block a user