mirror of
https://github.com/espressif/ESP8266_RTOS_SDK.git
synced 2025-09-25 08:26:31 +08:00
Merge branch 'feature/update_wifi_provisioning_from_idf' into 'master'
feat(provisioning): update wifi provisioning from idf See merge request sdk/ESP8266_RTOS_SDK!1501
This commit is contained in:
@ -1,6 +1,25 @@
|
||||
# Provisioning Application Examples
|
||||
|
||||
These consist of the following examples :
|
||||
This primarily consists of a single unified example wifi_prov_mgr
|
||||
|
||||
* wifi_prov_mgr
|
||||
Abstracts out most of the complexity of Wi-Fi provisioning and allows easy switching between the SoftAP (using HTTP) and BLE transports. It also demonstrates how applications can register and use additional custom data endpoints.
|
||||
|
||||
Provisioning applications are available for various platforms:
|
||||
|
||||
* Android:
|
||||
- [BLE 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)
|
||||
- Source code on GitHub: [esp-idf-provisioning-ios](https://github.com/espressif/esp-idf-provisioning-ios)
|
||||
* For all other platforms a python based command line tool is provided under "$IDF_PATH/tools/esp_prov"
|
||||
|
||||
## Legacy Examples
|
||||
|
||||
The legacy examples require own implementation of provisioning functions and handlers. The Wi-Fi provisioning component abstracts out most of this complexity and provides a simpler interface and so, that is recommended for use. However, if you want to use lower level provisioning and protocomm APIs, you can check the these examples under legacy/ folder:
|
||||
|
||||
* softap_prov
|
||||
Provisioning involves Wi-Fi station configuration via an HTTP server running on the device, which is initially configured to be in SoftAP mode. After provisioning, device runs in Wi-Fi station mode only and connects to the AP whose credentials were provided during provisioning.
|
||||
@ -14,10 +33,4 @@ These consist of the following examples :
|
||||
* custom_config
|
||||
Similar to softap_prov examples, but allows for configuration of custom (device-local) information during provisioning. This is intended as an example for implementing custom provisioning schemes.
|
||||
|
||||
Provisioning applications are available for various platforms:
|
||||
|
||||
* For Android, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-android](https://github.com/espressif/esp-idf-provisioning-android)
|
||||
* For iOS, a provisioning application along with source code is available on GitHub : [esp-idf-provisioning-ios](https://github.com/espressif/esp-idf-provisioning-ios)
|
||||
* For all other platforms a python based command line tool is provided under "$IDF_PATH/tools/esp_prov"
|
||||
|
||||
Refer to the README.md files in each example directory for more information.
|
||||
|
@ -1,8 +0,0 @@
|
||||
set(COMPONENT_ADD_INCLUDEDIRS include)
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS proto-c)
|
||||
set(COMPONENT_SRCS "src/custom_config.c"
|
||||
"proto-c/custom_config.pb-c.c")
|
||||
|
||||
set(COMPONENT_PRIV_REQUIRES protobuf-c)
|
||||
|
||||
register_component()
|
@ -1,11 +0,0 @@
|
||||
# Protobuf files for defining custom config-data packet structures
|
||||
|
||||
This is an example proto file defining custom configuration related data packet structures, namely -
|
||||
1. CustomConfigRequest - for sending configuration data consisting of various fields (Info and Version)
|
||||
2. CustomConfigResponse - for receiving configuration status (fail/success)
|
||||
|
||||
Note : These proto files are not automatically compiled during the build process.
|
||||
|
||||
Run "make" (Optional) to generate the respective C and Python files. The generated C files are used by protocomm itself to create, delete and manipulate transaction packets. The generated Python files can be used by python based applications for implementing client side interface to protocomm layer.
|
||||
|
||||
Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under "protocomm/proto-c" and "protocomm/python" directories, and thus running make (and installing the Protobuf compilers) is optional.
|
@ -1,6 +0,0 @@
|
||||
set(COMPONENT_SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
@ -1,58 +0,0 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config SOFTAP_SSID
|
||||
string "WiFi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config SOFTAP_PASS
|
||||
string "WiFi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config USE_SEC_1
|
||||
bool
|
||||
default n
|
||||
prompt "Use Security Version 1"
|
||||
help
|
||||
Security version 1 used Curve25519 key exchange for establishing
|
||||
secure session between device and client during provisioning
|
||||
|
||||
config USE_POP
|
||||
bool
|
||||
depends on USE_SEC_1
|
||||
default n
|
||||
prompt "Use proof-of-possession"
|
||||
help
|
||||
Proof-of-possession can be optionally used to prove that the device is indeed
|
||||
in possession of the user who is provisioning the device. This proof-of-possession
|
||||
is internally used to generate the shared secret through key exchange.
|
||||
|
||||
config POP
|
||||
string "Proof-of-possession"
|
||||
default "abcd1234"
|
||||
depends on USE_POP
|
||||
|
||||
config PROTOCOMM_HTTPD_PORT
|
||||
int "Protocomm HTTP Port"
|
||||
default 80
|
||||
help
|
||||
Port on which to run Protocomm HTTP based provisioning service
|
||||
|
||||
config RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the WiFi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
int "Maximum AP connection attempts"
|
||||
default 5
|
||||
help
|
||||
Set the maximum connection attempts to perform when connecting to a Wi-Fi AP.
|
||||
|
||||
endmenu
|
@ -1,3 +0,0 @@
|
||||
CONFIG_ENABLE_UNIFIED_PROVISIONING=y
|
||||
CONFIG_LWIP_NETIF_LOOPBACK=y
|
||||
CONFIG_LWIP_LOOPBACK_MAX_PBUFS=1
|
@ -2,9 +2,5 @@
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(custom_config)
|
@ -5,7 +5,5 @@
|
||||
|
||||
PROJECT_NAME := custom_config
|
||||
|
||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -1,4 +1,6 @@
|
||||
# SoftAP + HTTPD based Provisioning Example featuring Custom configuration
|
||||
# SoftAP + HTTPD based Provisioning Example featuring Custom configuration (Legacy)
|
||||
|
||||
> Note: It is recommended to use the new `wifi_prov_mgr` example which is based on the simpler `wifi_provisioning` APIs. Check this example only if you wish to use lower level provisioning and protocomm APIs and want more control over the handlers.
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
@ -29,11 +31,9 @@ To provision the device running this example, the `esp_prov.py` script needs to
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
make menuconfig
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Set serial port under Serial Flasher Options.
|
||||
|
||||
* Under Example Configuration set the following :
|
||||
* SoftAP SSID (Defaults to PROV_<MACID>)
|
||||
* SoftAP Password (Defaults to PROV_PASS)
|
||||
@ -45,7 +45,7 @@ make menuconfig
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
@ -68,7 +68,7 @@ I (519482) tcpip_adapter: softAP assign IP to station,IP is: 192.168.4.2
|
||||
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace the values corresponding to the parameters `--custom_info` and `--custom_ver` with your desired values for the custom configuration). Assuming default example configuration, the script should be run as follows :
|
||||
|
||||
```
|
||||
python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 0 --transport softap --softap_endpoint 192.168.4.1:80 --custom_config --custom_info "some string" --custom_ver 4321
|
||||
python esp_prov.py --transport softap --service_name "192.168.4.1:80" --sec_ver 0 --ssid myssid --passphrase mypassword --custom_config --custom_info "some string" --custom_ver 4321
|
||||
```
|
||||
|
||||
Above command will perform the provisioning steps, and the monitor log should display something like this :
|
||||
@ -138,7 +138,7 @@ It means the Wi-Fi credentials were already set by some other application flashe
|
||||
|
||||
```
|
||||
make erase_flash
|
||||
make -j4 flash monitor
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution.
|
@ -0,0 +1,5 @@
|
||||
idf_component_register(SRCS "src/custom_config.c"
|
||||
"proto-c/custom_config.pb-c.c"
|
||||
INCLUDE_DIRS include
|
||||
PRIV_INCLUDE_DIRS proto-c
|
||||
PRIV_REQUIRES protobuf-c)
|
@ -14,7 +14,6 @@
|
||||
|
||||
#ifndef _CUSTOM_PROV_CONFIG_H_
|
||||
#define _CUSTOM_PROV_CONFIG_H_
|
||||
#include <stdlib.h>
|
||||
|
||||
/**
|
||||
* @brief Custom config data received by device
|
@ -0,0 +1,26 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(PROTO_COMPILER "protoc")
|
||||
set(PROTO_C_COMPILER "protoc-c")
|
||||
set(C_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../proto-c")
|
||||
set(PY_OUT_PATH "${CMAKE_CURRENT_LIST_DIR}/../python")
|
||||
|
||||
set(PROTO_SRCS "custom_config.proto")
|
||||
|
||||
add_custom_target(c_proto
|
||||
COMMAND ${PROTO_C_COMPILER} --c_out=${C_OUT_PATH} -I . ${PROTO_SRCS}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
add_custom_target(python_proto
|
||||
COMMAND ${PROTO_COMPILER} --python_out=${PY_OUT_PATH} -I . ${PROTO_SRCS}
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
||||
|
||||
add_custom_target(proto ALL
|
||||
DEPENDS c_proto python_proto
|
||||
VERBATIM
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
|
||||
)
|
@ -0,0 +1,27 @@
|
||||
# Protobuf files for defining custom config-data packet structures
|
||||
|
||||
This is an example proto file defining custom configuration related data packet structures, namely -
|
||||
1. CustomConfigRequest - for sending configuration data consisting of various fields (Info and Version)
|
||||
2. CustomConfigResponse - for receiving configuration status (fail/success)
|
||||
|
||||
Note : These proto files are not automatically compiled during the build process.
|
||||
|
||||
# Compilation
|
||||
|
||||
Compilation requires protoc (Protobuf Compiler) and protoc-c (Protobuf C Compiler) installed. Since the generated files are to remain the same, as long as the proto files are not modified, therefore the generated files are already available under `examples/provisioning/custom_config/components/custom_provisioning/proto-c` and `examples/provisioning/custom_config/components/custom_provisioning/python` directories, and thus running cmake / make (and installing the Protobuf compilers) is optional.
|
||||
|
||||
If using `cmake` follow the below steps. If using `make`, jump to Step 2 directly.
|
||||
|
||||
## Step 1 (Only for cmake)
|
||||
|
||||
When using cmake, first create a build directory and call cmake from inside:
|
||||
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
```
|
||||
|
||||
## Step 2
|
||||
|
||||
Simply run `make` to generate the respective C and Python files. The newly created files will overwrite those under `examples/provisioning/custom_config/components/custom_provisioning/proto-c` and `examples/provisioning/custom_config/components/custom_provisioning/python`
|
@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <esp_log.h>
|
||||
#include <string.h>
|
||||
#include <esp_err.h>
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,58 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_SSID
|
||||
string "Wi-Fi SSID"
|
||||
default "myssid"
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config EXAMPLE_PASS
|
||||
string "Wi-Fi Password"
|
||||
default "mypassword"
|
||||
help
|
||||
Wi-Fi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config EXAMPLE_USE_SEC_1
|
||||
bool
|
||||
default n
|
||||
prompt "Use Security Version 1"
|
||||
help
|
||||
Security version 1 used Curve25519 key exchange for establishing
|
||||
secure session between device and client during provisioning
|
||||
|
||||
config EXAMPLE_USE_POP
|
||||
bool
|
||||
depends on EXAMPLE_USE_SEC_1
|
||||
default n
|
||||
prompt "Use proof-of-possession"
|
||||
help
|
||||
Proof-of-possession can be optionally used to prove that the device is indeed
|
||||
in possession of the user who is provisioning the device. This proof-of-possession
|
||||
is internally used to generate the shared secret through key exchange.
|
||||
|
||||
config EXAMPLE_POP
|
||||
string "Proof-of-possession"
|
||||
default "abcd1234"
|
||||
depends on EXAMPLE_USE_POP
|
||||
|
||||
config EXAMPLE_PROTOCOMM_HTTPD_PORT
|
||||
int "Protocomm HTTP Port"
|
||||
default 80
|
||||
help
|
||||
Port on which to run Protocomm HTTP based provisioning service
|
||||
|
||||
config EXAMPLE_RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
int "Maximum AP connection attempts"
|
||||
default 5
|
||||
help
|
||||
Set the maximum connection attempts to perform when connecting to a Wi-Fi AP.
|
||||
|
||||
endmenu
|
@ -8,27 +8,23 @@
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
#include "esp_netif.h"
|
||||
#include "esp_event.h"
|
||||
#include "protocol_examples_common.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sys.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
#define EXAMPLE_AP_RECONN_ATTEMPTS CONFIG_EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
@ -45,44 +41,50 @@ static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
ESP_LOGI(TAG,"connect to the AP fail");
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
ESP_LOGI(TAG, "got ip:%s",
|
||||
ip4addr_ntoa(&event->ip_info.ip));
|
||||
ESP_LOGI(TAG, "got ip: " IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_init_sta()
|
||||
static void wifi_init_sta(void)
|
||||
{
|
||||
/* Set our event handling */
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK(esp_wifi_start() );
|
||||
/* Start Wi-Fi in station mode with credentials set during provisioning */
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
void app_main()
|
||||
static void start_softap_provisioning(void)
|
||||
{
|
||||
/* Security version */
|
||||
int security = 0;
|
||||
/* Proof of possession */
|
||||
const protocomm_security_pop_t *pop = NULL;
|
||||
|
||||
#ifdef CONFIG_USE_SEC_1
|
||||
#ifdef CONFIG_EXAMPLE_USE_SEC_1
|
||||
security = 1;
|
||||
#endif
|
||||
|
||||
/* Having proof of possession is optional */
|
||||
#ifdef CONFIG_USE_POP
|
||||
#ifdef CONFIG_EXAMPLE_USE_POP
|
||||
const static protocomm_security_pop_t app_pop = {
|
||||
.data = (uint8_t *) CONFIG_POP,
|
||||
.len = (sizeof(CONFIG_POP)-1)
|
||||
.data = (uint8_t *) CONFIG_EXAMPLE_POP,
|
||||
.len = (sizeof(CONFIG_EXAMPLE_POP)-1)
|
||||
};
|
||||
pop = &app_pop;
|
||||
#endif
|
||||
|
||||
ESP_ERROR_CHECK(app_prov_start_softap_provisioning(
|
||||
CONFIG_EXAMPLE_SSID, CONFIG_EXAMPLE_PASS, security, pop));
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize networking stack */
|
||||
tcpip_adapter_init();
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* Create default event loop needed by the
|
||||
* main app and the provisioning service */
|
||||
@ -91,6 +93,10 @@ void app_main()
|
||||
/* Initialize NVS needed by Wi-Fi */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* Initialize Wi-Fi including netif with default config */
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
/* Check if device is provisioned */
|
||||
bool provisioned;
|
||||
if (app_prov_is_provisioned(&provisioned) != ESP_OK) {
|
||||
@ -101,11 +107,10 @@ void app_main()
|
||||
if (provisioned == false) {
|
||||
/* If not provisioned, start provisioning via soft AP */
|
||||
ESP_LOGI(TAG, "Starting WiFi SoftAP provisioning");
|
||||
app_prov_start_softap_provisioning(CONFIG_SOFTAP_SSID, CONFIG_SOFTAP_PASS,
|
||||
security, pop);
|
||||
start_softap_provisioning();
|
||||
} else {
|
||||
/* Start WiFi station with credentials set during provisioning */
|
||||
ESP_LOGI(TAG, "Starting WiFi station");
|
||||
wifi_init_sta(NULL);
|
||||
wifi_init_sta();
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
#include <esp_wifi.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <task.h>
|
||||
#include <stdlib.h>
|
||||
@ -28,6 +29,9 @@
|
||||
|
||||
static const char *TAG = "app_prov";
|
||||
|
||||
/* Handler for catching WiFi events */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t base, int id, void* data);
|
||||
|
||||
/* Handlers for provisioning endpoints */
|
||||
extern wifi_prov_config_handlers_t wifi_prov_handlers;
|
||||
extern custom_prov_config_handler_t custom_prov_handler;
|
||||
@ -117,6 +121,10 @@ static void app_prov_stop_service(void)
|
||||
protocomm_httpd_stop(g_prov->pc);
|
||||
/* Delete protocomm instance */
|
||||
protocomm_delete(g_prov->pc);
|
||||
|
||||
/* Remove event handler */
|
||||
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler);
|
||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler);
|
||||
}
|
||||
|
||||
/* Task spawned by timer callback */
|
||||
@ -145,33 +153,24 @@ static void _stop_prov_cb(void * arg)
|
||||
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
|
||||
/* Event handler for starting/stopping provisioning.
|
||||
* To be called from within the context of the main
|
||||
* event handler.
|
||||
*/
|
||||
esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
|
||||
/* Event handler for starting/stopping provisioning */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
/* For accessing reason codes in case of disconnection */
|
||||
system_event_info_t *info = &event->event_info;
|
||||
|
||||
/* If pointer to provisioning application data is NULL
|
||||
* then provisioning is not running, therefore return without
|
||||
* error */
|
||||
* then provisioning is not running */
|
||||
if (!g_prov) {
|
||||
return ESP_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
ESP_LOGI(TAG, "STA Start");
|
||||
/* Once configuration is received by protocomm server,
|
||||
* device is restarted as both AP and Station.
|
||||
* Once station starts, wait for connection to
|
||||
* establish with configured host SSID and password */
|
||||
/* Once configuration is received through protocomm,
|
||||
* device is started as station. Once station starts,
|
||||
* wait for connection to establish with configured
|
||||
* host SSID and password */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ESP_LOGI(TAG, "STA Got IP");
|
||||
/* Station got IP. That means configuration is successful.
|
||||
* Schedule timer to stop provisioning app after 30 seconds. */
|
||||
@ -188,16 +187,16 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
|
||||
* signaling a failure in provisioning. */
|
||||
esp_timer_start_once(g_prov->timer, 30000*1000U);
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
ESP_LOGE(TAG, "STA Disconnected");
|
||||
/* Station couldn't connect to configured host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_DISCONNECTED;
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason);
|
||||
|
||||
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason);
|
||||
|
||||
/* Set code corresponding to the reason for disconnection */
|
||||
switch (info->disconnected.reason) {
|
||||
switch (disconnected->reason) {
|
||||
case WIFI_REASON_AUTH_EXPIRE:
|
||||
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
||||
case WIFI_REASON_BEACON_TIMEOUT:
|
||||
@ -215,18 +214,13 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
if (disconnected->reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||
}
|
||||
esp_wifi_connect();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state)
|
||||
@ -255,25 +249,15 @@ esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reaso
|
||||
|
||||
esp_err_t app_prov_is_provisioned(bool *provisioned)
|
||||
{
|
||||
#ifdef CONFIG_RESET_PROVISIONED
|
||||
*provisioned = false;
|
||||
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
||||
nvs_flash_erase();
|
||||
#endif
|
||||
|
||||
if (nvs_flash_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to init NVS");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
if (esp_wifi_init(&cfg) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to init wifi");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Get WiFi Station configuration */
|
||||
wifi_config_t wifi_cfg;
|
||||
if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) {
|
||||
*provisioned = false;
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@ -318,14 +302,6 @@ esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
|
||||
|
||||
static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
|
||||
{
|
||||
/* Initialize WiFi with default configuration */
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
esp_err_t err = esp_wifi_init(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to init WiFi : %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Build WiFi configuration for AP mode */
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
@ -333,19 +309,18 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
|
||||
},
|
||||
};
|
||||
|
||||
strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
|
||||
wifi_config.ap.ssid_len = strlen(ssid);
|
||||
strlcpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
|
||||
|
||||
if (strlen(pass) == 0) {
|
||||
memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password));
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
} else {
|
||||
strncpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
|
||||
strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
|
||||
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
|
||||
}
|
||||
|
||||
/* Start WiFi in AP mode with configuration built above */
|
||||
err = esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi mode : %d", err);
|
||||
return err;
|
||||
@ -381,7 +356,7 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass,
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
/* Initialise app data */
|
||||
/* Initialize app data */
|
||||
g_prov->pop = pop;
|
||||
g_prov->security = security;
|
||||
|
||||
@ -398,6 +373,18 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register WiFi event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register IP event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start WiFi softAP with specified ssid and password */
|
||||
err = start_wifi_ap(ssid, pass);
|
||||
if (err != ESP_OK) {
|
@ -9,7 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_event_loop.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <protocomm_security.h>
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
@ -43,21 +43,6 @@ esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state);
|
||||
*/
|
||||
esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason);
|
||||
|
||||
/**
|
||||
* @brief Event handler for provisioning app
|
||||
*
|
||||
* This is called from the main event handler and controls the
|
||||
* provisioning application, depeding on WiFi events
|
||||
*
|
||||
* @param[in] ctx Event context data
|
||||
* @param[in] event Event info
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Event handled successfully
|
||||
* - ESP_FAIL : Failed to start server on event AP start
|
||||
*/
|
||||
esp_err_t app_prov_event_handler(void *ctx, system_event_t *event);
|
||||
|
||||
/**
|
||||
* @brief Checks if device is provisioned
|
||||
* *
|
@ -15,7 +15,7 @@
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_wifi.h>
|
||||
#include <tcpip_adapter.h>
|
||||
#include <esp_netif.h>
|
||||
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
#include <custom_provisioning/custom_config.h>
|
||||
@ -110,10 +110,14 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data,
|
||||
|
||||
ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s",
|
||||
req_data->ssid, req_data->password);
|
||||
memcpy((char *) wifi_cfg->sta.ssid, req_data->ssid,
|
||||
strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid)));
|
||||
memcpy((char *) wifi_cfg->sta.password, req_data->password,
|
||||
strnlen(req_data->password, sizeof(wifi_cfg->sta.password)));
|
||||
|
||||
/* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard).
|
||||
* But this doesn't guarantee that the saved SSID will be null terminated, because
|
||||
* wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).
|
||||
* Although, this is not a matter for concern because esp_wifi library reads the SSID
|
||||
* upto 32 bytes in absence of null termination */
|
||||
strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid));
|
||||
strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
CONFIG_ENABLE_UNIFIED_PROVISIONING=y
|
@ -2,9 +2,5 @@
|
||||
# in this exact order for cmake to work correctly
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
# (Not part of the boilerplate)
|
||||
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
|
||||
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(softap_prov)
|
@ -5,7 +5,5 @@
|
||||
|
||||
PROJECT_NAME := softap_prov
|
||||
|
||||
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
|
||||
|
||||
include $(IDF_PATH)/make/project.mk
|
||||
|
@ -1,4 +1,6 @@
|
||||
# SoftAP + HTTPD based Provisioning Example
|
||||
# SoftAP + HTTPD based Provisioning Example (Legacy)
|
||||
|
||||
> Note: It is recommended to use the new `wifi_prov_mgr` example which is based on the simpler `wifi_provisioning` APIs. Check this example only if you wish to use lower level provisioning and protocomm APIs and want more control over the handlers.
|
||||
|
||||
(See the README.md file in the upper level 'examples' directory for more information about examples.)
|
||||
|
||||
@ -42,11 +44,9 @@ To provision the device running this example, the `esp_prov.py` script needs to
|
||||
### Configure the project
|
||||
|
||||
```
|
||||
make menuconfig
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
* Set serial port under Serial Flasher Options.
|
||||
|
||||
* Under Example Configuration set the following :
|
||||
* SoftAP SSID (Defaults to PROV_<MACID>)
|
||||
* SoftAP Password (Defaults to PROV_PASS)
|
||||
@ -58,7 +58,7 @@ make menuconfig
|
||||
Build the project and flash it to the board, then run monitor tool to view serial output:
|
||||
|
||||
```
|
||||
make -j4 flash monitor
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
@ -81,7 +81,7 @@ I (519482) tcpip_adapter: softAP assign IP to station,IP is: 192.168.4.2
|
||||
In a separate terminal run the `esp_prov.py` script under `$IDP_PATH/tools/esp_prov` directory (please replace `myssid` and `mypassword` with the credentials of the AP to which the device is supposed to connect to after provisioning). The SoftAP endpoint corresponds to the IP and port of the device on the SoftAP network, but this is usually same as the default value and may be left out. Assuming default example configuration, the script should be run as follows :
|
||||
|
||||
```
|
||||
python esp_prov.py --ssid myssid --passphrase mypassword --sec_ver 1 --pop abcd1234 --transport softap --softap_endpoint 192.168.4.1:80
|
||||
python esp_prov.py --transport softap --service_name "192.168.4.1:80" --sec_ver 1 --pop abcd1234 --ssid myssid --passphrase mypassword
|
||||
```
|
||||
|
||||
Above command will perform the provisioning steps, and the monitor log should display something like this :
|
||||
@ -145,7 +145,7 @@ It means the Wi-Fi credentials were already set by some other application flashe
|
||||
|
||||
```
|
||||
make erase_flash
|
||||
make -j4 flash monitor
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
Or, enable `Reset Provisioning` option under `Example Configuration` under menuconfig. But this will erase the saved Wi-Fi credentials every time the device boots, so this is not the preferred solution.
|
@ -0,0 +1,4 @@
|
||||
idf_component_register(SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c"
|
||||
INCLUDE_DIRS ".")
|
@ -0,0 +1,59 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config EXAMPLE_SSID_SET_MAC
|
||||
bool "Use MAC as SSID"
|
||||
default y
|
||||
help
|
||||
Set SoftAP SSID as PROV_<MAC>.
|
||||
|
||||
config EXAMPLE_SSID
|
||||
string "Wi-Fi SSID"
|
||||
default "PROV_SSID"
|
||||
depends on !EXAMPLE_SSID_SET_MAC
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config EXAMPLE_PASS
|
||||
string "Wi-Fi Password"
|
||||
default "PROV_PASS"
|
||||
help
|
||||
Wi-Fi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config EXAMPLE_USE_SEC_1
|
||||
bool
|
||||
default y
|
||||
prompt "Use Security Version 1"
|
||||
help
|
||||
Security version 1 used Curve25519 key exchange for establishing
|
||||
secure session between device and client during provisioning
|
||||
|
||||
config EXAMPLE_USE_POP
|
||||
bool
|
||||
depends on EXAMPLE_USE_SEC_1
|
||||
default y
|
||||
prompt "Use proof-of-possession"
|
||||
help
|
||||
Proof-of-possession can be optionally used to prove that the device is indeed
|
||||
in possession of the user who is provisioning the device. This proof-of-possession
|
||||
is internally used to generate the shared secret through key exchange.
|
||||
|
||||
config EXAMPLE_POP
|
||||
string "Proof-of-possession"
|
||||
default "abcd1234"
|
||||
depends on EXAMPLE_USE_POP
|
||||
|
||||
config EXAMPLE_RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the Wi-Fi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
int "Maximum AP connection attempts"
|
||||
default 5
|
||||
help
|
||||
Set the maximum connection attempts to perform when connecting to a Wi-Fi AP.
|
||||
|
||||
endmenu
|
@ -12,19 +12,19 @@
|
||||
#include <freertos/task.h>
|
||||
#include <esp_system.h>
|
||||
#include <esp_wifi.h>
|
||||
#include <esp_event_loop.h>
|
||||
#include <esp_event.h>
|
||||
#include <esp_log.h>
|
||||
#include <nvs_flash.h>
|
||||
|
||||
#include "esp_netif.h"
|
||||
#include <lwip/err.h>
|
||||
#include <lwip/sys.h>
|
||||
|
||||
#include "app_prov.h"
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
#define EXAMPLE_AP_RECONN_ATTEMPTS CONFIG_EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
|
||||
static const char *TAG = "app";
|
||||
|
||||
static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
@ -41,66 +41,46 @@ static void event_handler(void* arg, esp_event_base_t event_base,
|
||||
ESP_LOGI(TAG,"connect to the AP fail");
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
|
||||
ESP_LOGI(TAG, "got ip:%s",
|
||||
ip4addr_ntoa(&event->ip_info.ip));
|
||||
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
|
||||
s_retry_num = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void wifi_init_sta()
|
||||
static void wifi_init_sta(void)
|
||||
{
|
||||
/* Set our event handling */
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler, NULL));
|
||||
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler, NULL));
|
||||
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
|
||||
ESP_ERROR_CHECK(esp_wifi_start() );
|
||||
/* Start Wi-Fi in station mode with credentials set during provisioning */
|
||||
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
|
||||
ESP_ERROR_CHECK(esp_wifi_start());
|
||||
}
|
||||
|
||||
void app_main()
|
||||
static void start_softap_provisioning(void)
|
||||
{
|
||||
/* Security version */
|
||||
int security = 0;
|
||||
/* Proof of possession */
|
||||
const protocomm_security_pop_t *pop = NULL;
|
||||
|
||||
#ifdef CONFIG_USE_SEC_1
|
||||
#ifdef CONFIG_EXAMPLE_USE_SEC_1
|
||||
security = 1;
|
||||
#endif
|
||||
|
||||
/* Having proof of possession is optional */
|
||||
#ifdef CONFIG_USE_POP
|
||||
#ifdef CONFIG_EXAMPLE_USE_POP
|
||||
const static protocomm_security_pop_t app_pop = {
|
||||
.data = (uint8_t *) CONFIG_POP,
|
||||
.len = (sizeof(CONFIG_POP)-1)
|
||||
.data = (uint8_t *) CONFIG_EXAMPLE_POP,
|
||||
.len = (sizeof(CONFIG_EXAMPLE_POP)-1)
|
||||
};
|
||||
pop = &app_pop;
|
||||
#endif
|
||||
|
||||
/* Initialize networking stack */
|
||||
tcpip_adapter_init();
|
||||
|
||||
/* Create default event loop needed by the
|
||||
* main app and the provisioning service */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Initialize NVS needed by Wi-Fi */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* Check if device is provisioned */
|
||||
bool provisioned;
|
||||
if (app_prov_is_provisioned(&provisioned) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error getting device provisioning state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (provisioned == false) {
|
||||
/* If not provisioned, start provisioning via soft AP */
|
||||
ESP_LOGI(TAG, "Starting WiFi SoftAP provisioning");
|
||||
|
||||
const char *ssid = NULL;
|
||||
|
||||
#ifdef CONFIG_SOFTAP_SSID
|
||||
ssid = CONFIG_SOFTAP_SSID;
|
||||
#ifdef CONFIG_EXAMPLE_SSID
|
||||
ssid = CONFIG_EXAMPLE_SSID;
|
||||
#else
|
||||
uint8_t eth_mac[6];
|
||||
esp_wifi_get_mac(WIFI_IF_STA, eth_mac);
|
||||
@ -112,11 +92,40 @@ void app_main()
|
||||
ssid = ssid_with_mac;
|
||||
#endif
|
||||
|
||||
app_prov_start_softap_provisioning(ssid, CONFIG_SOFTAP_PASS,
|
||||
security, pop);
|
||||
ESP_ERROR_CHECK(app_prov_start_softap_provisioning(
|
||||
ssid, CONFIG_EXAMPLE_PASS, security, pop));
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
/* Initialize networking stack */
|
||||
ESP_ERROR_CHECK(esp_netif_init());
|
||||
|
||||
/* Create default event loop needed by the
|
||||
* main app and the provisioning service */
|
||||
ESP_ERROR_CHECK(esp_event_loop_create_default());
|
||||
|
||||
/* Initialize NVS needed by Wi-Fi */
|
||||
ESP_ERROR_CHECK(nvs_flash_init());
|
||||
|
||||
/* Initialize Wi-Fi including netif with default config */
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
|
||||
|
||||
/* Check if device is provisioned */
|
||||
bool provisioned;
|
||||
if (app_prov_is_provisioned(&provisioned) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Error getting device provisioning state");
|
||||
return;
|
||||
}
|
||||
|
||||
if (provisioned == false) {
|
||||
/* If not provisioned, start provisioning via soft AP */
|
||||
ESP_LOGI(TAG, "Starting WiFi SoftAP provisioning");
|
||||
start_softap_provisioning();
|
||||
} else {
|
||||
/* Start WiFi station with credentials set during provisioning */
|
||||
ESP_LOGI(TAG, "Starting WiFi station");
|
||||
wifi_init_sta(NULL);
|
||||
wifi_init_sta();
|
||||
}
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
#include <esp_wifi.h>
|
||||
#include <nvs_flash.h>
|
||||
#include <nvs.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <task.h>
|
||||
#include <stdlib.h>
|
||||
@ -27,6 +28,9 @@
|
||||
|
||||
static const char *TAG = "app_prov";
|
||||
|
||||
/* Handler for catching WiFi events */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t base, int id, void* data);
|
||||
|
||||
/* Handlers for wifi_config provisioning endpoint */
|
||||
extern wifi_prov_config_handlers_t wifi_prov_handlers;
|
||||
|
||||
@ -103,6 +107,10 @@ static void app_prov_stop_service(void)
|
||||
protocomm_httpd_stop(g_prov->pc);
|
||||
/* Delete protocomm instance */
|
||||
protocomm_delete(g_prov->pc);
|
||||
|
||||
/* Remove event handler */
|
||||
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler);
|
||||
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler);
|
||||
}
|
||||
|
||||
/* Task spawned by timer callback */
|
||||
@ -131,33 +139,24 @@ static void _stop_prov_cb(void * arg)
|
||||
xTaskCreate(&stop_prov_task, "stop_prov", 2048, NULL, tskIDLE_PRIORITY, NULL);
|
||||
}
|
||||
|
||||
/* Event handler for starting/stopping provisioning.
|
||||
* To be called from within the context of the main
|
||||
* event handler.
|
||||
*/
|
||||
esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
|
||||
/* Event handler for starting/stopping provisioning */
|
||||
static void app_prov_event_handler(void* handler_arg, esp_event_base_t event_base,
|
||||
int event_id, void* event_data)
|
||||
{
|
||||
/* For accessing reason codes in case of disconnection */
|
||||
system_event_info_t *info = &event->event_info;
|
||||
|
||||
/* If pointer to provisioning application data is NULL
|
||||
* then provisioning is not running, therefore return without
|
||||
* error */
|
||||
* then provisioning is not running */
|
||||
if (!g_prov) {
|
||||
return ESP_OK;
|
||||
return;
|
||||
}
|
||||
|
||||
switch(event->event_id) {
|
||||
case SYSTEM_EVENT_STA_START:
|
||||
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
|
||||
ESP_LOGI(TAG, "STA Start");
|
||||
/* Once configuration is received by protocomm server,
|
||||
* device is restarted as both AP and Station.
|
||||
* Once station starts, wait for connection to
|
||||
* establish with configured host SSID and password */
|
||||
/* Once configuration is received through protocomm,
|
||||
* device is started as station. Once station starts,
|
||||
* wait for connection to establish with configured
|
||||
* host SSID and password */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_GOT_IP:
|
||||
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
|
||||
ESP_LOGI(TAG, "STA Got IP");
|
||||
/* Station got IP. That means configuration is successful.
|
||||
* Schedule timer to stop provisioning app after 30 seconds. */
|
||||
@ -174,16 +173,16 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
|
||||
* signaling a failure in provisioning. */
|
||||
esp_timer_start_once(g_prov->timer, 30000*1000U);
|
||||
}
|
||||
break;
|
||||
|
||||
case SYSTEM_EVENT_STA_DISCONNECTED:
|
||||
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
|
||||
ESP_LOGE(TAG, "STA Disconnected");
|
||||
/* Station couldn't connect to configured host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_DISCONNECTED;
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", info->disconnected.reason);
|
||||
|
||||
wifi_event_sta_disconnected_t* disconnected = (wifi_event_sta_disconnected_t*) event_data;
|
||||
ESP_LOGE(TAG, "Disconnect reason : %d", disconnected->reason);
|
||||
|
||||
/* Set code corresponding to the reason for disconnection */
|
||||
switch (info->disconnected.reason) {
|
||||
switch (disconnected->reason) {
|
||||
case WIFI_REASON_AUTH_EXPIRE:
|
||||
case WIFI_REASON_4WAY_HANDSHAKE_TIMEOUT:
|
||||
case WIFI_REASON_BEACON_TIMEOUT:
|
||||
@ -198,21 +197,16 @@ esp_err_t app_prov_event_handler(void *ctx, system_event_t *event)
|
||||
g_prov->wifi_disconnect_reason = WIFI_PROV_STA_AP_NOT_FOUND;
|
||||
break;
|
||||
default:
|
||||
if (info->disconnected.reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||
}
|
||||
/* If none of the expected reasons,
|
||||
* retry connecting to host SSID */
|
||||
g_prov->wifi_state = WIFI_PROV_STA_CONNECTING;
|
||||
if (disconnected->reason == WIFI_REASON_BASIC_RATE_NOT_SUPPORT) {
|
||||
/*Switch to 802.11 bgn mode */
|
||||
esp_wifi_set_protocol(ESP_IF_WIFI_STA, WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N);
|
||||
}
|
||||
esp_wifi_connect();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state)
|
||||
@ -243,21 +237,10 @@ esp_err_t app_prov_is_provisioned(bool *provisioned)
|
||||
{
|
||||
*provisioned = false;
|
||||
|
||||
#ifdef CONFIG_RESET_PROVISIONED
|
||||
#ifdef CONFIG_EXAMPLE_RESET_PROVISIONED
|
||||
nvs_flash_erase();
|
||||
#endif
|
||||
|
||||
if (nvs_flash_init() != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to init NVS");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
if (esp_wifi_init(&cfg) != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to init wifi");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
/* Get WiFi Station configuration */
|
||||
wifi_config_t wifi_cfg;
|
||||
if (esp_wifi_get_config(ESP_IF_WIFI_STA, &wifi_cfg) != ESP_OK) {
|
||||
@ -305,14 +288,6 @@ esp_err_t app_prov_configure_sta(wifi_config_t *wifi_cfg)
|
||||
|
||||
static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
|
||||
{
|
||||
/* Initialize WiFi with default configuration */
|
||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
||||
esp_err_t err = esp_wifi_init(&cfg);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to init WiFi : %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Build WiFi configuration for AP mode */
|
||||
wifi_config_t wifi_config = {
|
||||
.ap = {
|
||||
@ -320,19 +295,18 @@ static esp_err_t start_wifi_ap(const char *ssid, const char *pass)
|
||||
},
|
||||
};
|
||||
|
||||
strncpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
|
||||
wifi_config.ap.ssid_len = strlen(ssid);
|
||||
strlcpy((char *) wifi_config.ap.ssid, ssid, sizeof(wifi_config.ap.ssid));
|
||||
|
||||
if (strlen(pass) == 0) {
|
||||
memset(wifi_config.ap.password, 0, sizeof(wifi_config.ap.password));
|
||||
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
|
||||
} else {
|
||||
strncpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
|
||||
strlcpy((char *) wifi_config.ap.password, pass, sizeof(wifi_config.ap.password));
|
||||
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
|
||||
}
|
||||
|
||||
/* Start WiFi in AP mode with configuration built above */
|
||||
err = esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
esp_err_t err = esp_wifi_set_mode(WIFI_MODE_AP);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to set WiFi mode : %d", err);
|
||||
return err;
|
||||
@ -385,6 +359,18 @@ esp_err_t app_prov_start_softap_provisioning(const char *ssid, const char *pass,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register WiFi event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, app_prov_event_handler, NULL);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to register IP event handler");
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Start WiFi softAP with specified ssid and password */
|
||||
err = start_wifi_ap(ssid, pass);
|
||||
if (err != ESP_OK) {
|
@ -9,7 +9,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <esp_event_loop.h>
|
||||
#include <esp_event.h>
|
||||
|
||||
#include <protocomm_security.h>
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
@ -42,21 +42,6 @@ esp_err_t app_prov_get_wifi_state(wifi_prov_sta_state_t* state);
|
||||
*/
|
||||
esp_err_t app_prov_get_wifi_disconnect_reason(wifi_prov_sta_fail_reason_t* reason);
|
||||
|
||||
/**
|
||||
* @brief Event handler for provisioning app
|
||||
*
|
||||
* This is called from the main event handler and controls the
|
||||
* provisioning application, depeding on WiFi events
|
||||
*
|
||||
* @param[in] ctx Event context data
|
||||
* @param[in] event Event info
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK : Event handled successfully
|
||||
* - ESP_FAIL : Failed to start server on event AP start
|
||||
*/
|
||||
esp_err_t app_prov_event_handler(void *ctx, system_event_t *event);
|
||||
|
||||
/**
|
||||
* @brief Checks if device is provisioned
|
||||
* *
|
@ -15,7 +15,7 @@
|
||||
#include <esp_log.h>
|
||||
|
||||
#include <esp_wifi.h>
|
||||
#include <tcpip_adapter.h>
|
||||
#include <esp_netif.h>
|
||||
|
||||
#include <wifi_provisioning/wifi_config.h>
|
||||
|
||||
@ -98,10 +98,14 @@ static esp_err_t set_config_handler(const wifi_prov_config_set_data_t *req_data,
|
||||
|
||||
ESP_LOGI(TAG, "WiFi Credentials Received : \n\tssid %s \n\tpassword %s",
|
||||
req_data->ssid, req_data->password);
|
||||
memcpy((char *) wifi_cfg->sta.ssid, req_data->ssid,
|
||||
strnlen(req_data->ssid, sizeof(wifi_cfg->sta.ssid)));
|
||||
memcpy((char *) wifi_cfg->sta.password, req_data->password,
|
||||
strnlen(req_data->password, sizeof(wifi_cfg->sta.password)));
|
||||
|
||||
/* Using strncpy allows the max SSID length to be 32 bytes (as per 802.11 standard).
|
||||
* But this doesn't guarantee that the saved SSID will be null terminated, because
|
||||
* wifi_cfg->sta.ssid is also 32 bytes long (without extra 1 byte for null character).
|
||||
* Although, this is not a matter for concern because esp_wifi library reads the SSID
|
||||
* upto 32 bytes in absence of null termination */
|
||||
strncpy((char *) wifi_cfg->sta.ssid, req_data->ssid, sizeof(wifi_cfg->sta.ssid));
|
||||
strlcpy((char *) wifi_cfg->sta.password, req_data->password, sizeof(wifi_cfg->sta.password));
|
||||
return ESP_OK;
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
CONFIG_ENABLE_UNIFIED_PROVISIONING=y
|
116
examples/provisioning/legacy/softap_prov/softap_prov_test.py
Normal file
116
examples/provisioning/legacy/softap_prov/softap_prov_test.py
Normal file
@ -0,0 +1,116 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright 2018 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.
|
||||
|
||||
from __future__ import print_function
|
||||
import re
|
||||
import os
|
||||
import time
|
||||
|
||||
import ttfw_idf
|
||||
import esp_prov
|
||||
import wifi_tools
|
||||
|
||||
# Have esp_prov throw exception
|
||||
esp_prov.config_throw_except = True
|
||||
|
||||
|
||||
@ttfw_idf.idf_example_test(env_tag="Example_WIFI_BT")
|
||||
def test_examples_provisioning_softap(env, extra_data):
|
||||
# Acquire DUT
|
||||
dut1 = env.get_dut("softap_prov", "examples/provisioning/legacy/softap_prov", dut_class=ttfw_idf.ESP32DUT)
|
||||
|
||||
# Get binary file
|
||||
binary_file = os.path.join(dut1.app.binary_path, "softap_prov.bin")
|
||||
bin_size = os.path.getsize(binary_file)
|
||||
ttfw_idf.log_performance("softap_prov_bin_size", "{}KB".format(bin_size // 1024))
|
||||
ttfw_idf.check_performance("softap_prov_bin_size", bin_size // 1024, dut1.TARGET)
|
||||
|
||||
# Upload binary and start testing
|
||||
dut1.start_app()
|
||||
|
||||
# Parse IP address of STA
|
||||
dut1.expect("Starting WiFi SoftAP provisioning", timeout=60)
|
||||
[ssid, password] = dut1.expect(re.compile(r"SoftAP Provisioning started with SSID '(\S+)', Password '(\S+)'"), timeout=30)
|
||||
|
||||
iface = wifi_tools.get_wiface_name()
|
||||
if iface is None:
|
||||
raise RuntimeError("Failed to get Wi-Fi interface on host")
|
||||
print("Interface name : " + iface)
|
||||
print("SoftAP SSID : " + ssid)
|
||||
print("SoftAP Password : " + password)
|
||||
|
||||
ctrl = wifi_tools.wpa_cli(iface, reset_on_exit=True)
|
||||
print("Connecting to DUT SoftAP...")
|
||||
ip = ctrl.connect(ssid, password)
|
||||
got_ip = dut1.expect(re.compile(r"DHCP server assigned IP to a station, IP is: (\d+.\d+.\d+.\d+)"), timeout=30)[0]
|
||||
if ip != got_ip:
|
||||
raise RuntimeError("SoftAP connected to another host! " + ip + "!=" + got_ip)
|
||||
print("Connected to DUT SoftAP")
|
||||
|
||||
print("Starting Provisioning")
|
||||
verbose = False
|
||||
protover = "V0.1"
|
||||
secver = 1
|
||||
pop = "abcd1234"
|
||||
provmode = "softap"
|
||||
ap_ssid = "myssid"
|
||||
ap_password = "mypassword"
|
||||
softap_endpoint = ip.split('.')[0] + "." + ip.split('.')[1] + "." + ip.split('.')[2] + ".1:80"
|
||||
|
||||
print("Getting security")
|
||||
security = esp_prov.get_security(secver, pop, verbose)
|
||||
if security is None:
|
||||
raise RuntimeError("Failed to get security")
|
||||
|
||||
print("Getting transport")
|
||||
transport = esp_prov.get_transport(provmode, softap_endpoint)
|
||||
if transport is None:
|
||||
raise RuntimeError("Failed to get transport")
|
||||
|
||||
print("Verifying protocol version")
|
||||
if not esp_prov.version_match(transport, protover):
|
||||
raise RuntimeError("Mismatch in protocol version")
|
||||
|
||||
print("Starting Session")
|
||||
if not esp_prov.establish_session(transport, security):
|
||||
raise RuntimeError("Failed to start session")
|
||||
|
||||
print("Sending Wifi credential to DUT")
|
||||
if not esp_prov.send_wifi_config(transport, security, ap_ssid, ap_password):
|
||||
raise RuntimeError("Failed to send Wi-Fi config")
|
||||
|
||||
print("Applying config")
|
||||
if not esp_prov.apply_wifi_config(transport, security):
|
||||
raise RuntimeError("Failed to send apply config")
|
||||
|
||||
success = False
|
||||
while True:
|
||||
time.sleep(5)
|
||||
print("Wi-Fi connection state")
|
||||
ret = esp_prov.get_wifi_config(transport, security)
|
||||
if (ret == 1):
|
||||
continue
|
||||
elif (ret == 0):
|
||||
print("Provisioning was successful")
|
||||
success = True
|
||||
break
|
||||
|
||||
if not success:
|
||||
raise RuntimeError("Provisioning failed")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_examples_provisioning_softap()
|
@ -1,6 +0,0 @@
|
||||
set(COMPONENT_SRCS "app_main.c"
|
||||
"app_prov.c"
|
||||
"app_prov_handlers.c")
|
||||
set(COMPONENT_ADD_INCLUDEDIRS ".")
|
||||
|
||||
register_component()
|
@ -1,59 +0,0 @@
|
||||
menu "Example Configuration"
|
||||
|
||||
config SOFTAP_SSID_SET_MAC
|
||||
bool "Use MAC as SSID"
|
||||
default y
|
||||
help
|
||||
Set SoftAP SSID as PROV_<MAC>.
|
||||
|
||||
config SOFTAP_SSID
|
||||
string "WiFi SSID"
|
||||
default "PROV_SSID"
|
||||
depends on !SOFTAP_SSID_SET_MAC
|
||||
help
|
||||
SSID (network name) for the example to connect to.
|
||||
|
||||
config SOFTAP_PASS
|
||||
string "WiFi Password"
|
||||
default "PROV_PASS"
|
||||
help
|
||||
WiFi password (WPA or WPA2) for the example to use.
|
||||
|
||||
config USE_SEC_1
|
||||
bool
|
||||
default y
|
||||
prompt "Use Security Version 1"
|
||||
help
|
||||
Security version 1 used Curve25519 key exchange for establishing
|
||||
secure session between device and client during provisioning
|
||||
|
||||
config USE_POP
|
||||
bool
|
||||
depends on USE_SEC_1
|
||||
default y
|
||||
prompt "Use proof-of-possession"
|
||||
help
|
||||
Proof-of-possession can be optionally used to prove that the device is indeed
|
||||
in possession of the user who is provisioning the device. This proof-of-possession
|
||||
is internally used to generate the shared secret through key exchange.
|
||||
|
||||
config POP
|
||||
string "Proof-of-possession"
|
||||
default "abcd1234"
|
||||
depends on USE_POP
|
||||
|
||||
config RESET_PROVISIONED
|
||||
bool
|
||||
default n
|
||||
prompt "Reset provisioned status of the device"
|
||||
help
|
||||
This erases the NVS to reset provisioned status of the device on every reboot.
|
||||
Provisioned status is determined by the WiFi STA configuration, saved on the NVS.
|
||||
|
||||
config EXAMPLE_AP_RECONN_ATTEMPTS
|
||||
int "Maximum AP connection attempts"
|
||||
default 5
|
||||
help
|
||||
Set the maximum connection attempts to perform when connecting to a Wi-Fi AP.
|
||||
|
||||
endmenu
|
@ -1,3 +0,0 @@
|
||||
CONFIG_ENABLE_UNIFIED_PROVISIONING=y
|
||||
CONFIG_LWIP_NETIF_LOOPBACK=y
|
||||
CONFIG_LWIP_LOOPBACK_MAX_PBUFS=1
|
@ -1,98 +0,0 @@
|
||||
# Copyright 2018 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.
|
||||
#
|
||||
|
||||
import dbus
|
||||
import dbus.mainloop.glib
|
||||
import netifaces
|
||||
import time
|
||||
|
||||
def get_wiface_name():
|
||||
for iface in netifaces.interfaces():
|
||||
if iface.startswith('w'):
|
||||
return iface
|
||||
return None
|
||||
|
||||
def get_wiface_IPv4(iface):
|
||||
try:
|
||||
[info] = netifaces.ifaddresses(iface)[netifaces.AF_INET]
|
||||
return info['addr']
|
||||
except KeyError:
|
||||
return None
|
||||
|
||||
class wpa_cli:
|
||||
def __init__(self, iface, reset_on_exit = False):
|
||||
self.iface_name = iface
|
||||
self.iface_obj = None
|
||||
self.iface_ifc = None
|
||||
self.old_network = None
|
||||
self.new_network = None
|
||||
self.connected = False
|
||||
self.reset_on_exit = reset_on_exit
|
||||
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
|
||||
bus = dbus.SystemBus()
|
||||
|
||||
service = dbus.Interface(bus.get_object("fi.w1.wpa_supplicant1", "/fi/w1/wpa_supplicant1"), "fi.w1.wpa_supplicant1")
|
||||
paths = service.Get("fi.w1.wpa_supplicant1", "Interfaces", dbus_interface='org.freedesktop.DBus.Properties')
|
||||
iface_path = service.GetInterface(self.iface_name)
|
||||
self.iface_obj = bus.get_object("fi.w1.wpa_supplicant1", iface_path)
|
||||
self.iface_ifc = dbus.Interface(self.iface_obj, "fi.w1.wpa_supplicant1.Interface")
|
||||
if self.iface_ifc == None:
|
||||
raise RuntimeError('supplicant : Failed to fetch interface')
|
||||
|
||||
self.old_network = self.iface_obj.Get("fi.w1.wpa_supplicant1.Interface", "CurrentNetwork", dbus_interface='org.freedesktop.DBus.Properties')
|
||||
if self.old_network == '/':
|
||||
self.old_network = None
|
||||
else:
|
||||
self.connected = True
|
||||
|
||||
def connect(self, ssid, password):
|
||||
if self.connected == True:
|
||||
self.iface_ifc.Disconnect()
|
||||
self.connected = False
|
||||
|
||||
if self.new_network != None:
|
||||
self.iface_ifc.RemoveNetwork(self.new_network)
|
||||
|
||||
self.new_network = self.iface_ifc.AddNetwork({"ssid": ssid, "psk": password})
|
||||
self.iface_ifc.SelectNetwork(self.new_network)
|
||||
|
||||
ip = None
|
||||
retry = 10
|
||||
while retry > 0:
|
||||
time.sleep(5)
|
||||
ip = get_wiface_IPv4(self.iface_name)
|
||||
if ip != None:
|
||||
self.connected = True
|
||||
return ip
|
||||
retry -= 1
|
||||
|
||||
self.reset()
|
||||
raise RuntimeError('wpa_cli : Connection failed')
|
||||
|
||||
def reset(self):
|
||||
if self.iface_ifc != None:
|
||||
if self.connected == True:
|
||||
self.iface_ifc.Disconnect()
|
||||
self.connected = False
|
||||
if self.new_network != None:
|
||||
self.iface_ifc.RemoveNetwork(self.new_network)
|
||||
self.new_network = None
|
||||
if self.old_network != None:
|
||||
self.iface_ifc.SelectNetwork(self.old_network)
|
||||
self.old_network = None
|
||||
|
||||
def __del__(self):
|
||||
if self.reset_on_exit == True:
|
||||
self.reset()
|
Reference in New Issue
Block a user