一、ESP32 配網(wǎng)簡(jiǎn)介
ESP32主要有以下配網(wǎng)方式:
1. SmartConfig
采用組播/廣播方式,將WIFI信息編碼到IEEE802.11底層通訊幀實(shí)現(xiàn)配網(wǎng)。
- 優(yōu)點(diǎn):易于使用,用戶只需要通過 APP 將配置信息發(fā)送給設(shè)備即可。
- 缺點(diǎn):需要額外的 APP,有一定的安全風(fēng)險(xiǎn),不支持 WPA3 安全協(xié)議。
2. SoftAp 配網(wǎng)
配網(wǎng)時(shí)將ESP32置于AP熱點(diǎn)模式,手機(jī)連接此熱點(diǎn)建立通訊,把WIFI賬號(hào)和密碼發(fā)給模塊。
3. AirKiss
微信提出的一種配網(wǎng)方式,支持通過微信小程序配網(wǎng)。
4. 藍(lán)牙配網(wǎng)
通過低功耗藍(lán)牙來傳輸WIFI賬號(hào)與密碼實(shí)現(xiàn)配網(wǎng)。
5. 其它配網(wǎng)方式
- ESP32 Easy ConnectTM(DPP) 配網(wǎng):支持NFC等輔助配網(wǎng);
- NFC輔助配網(wǎng):需要增加支持NFC的芯片;
- 直接配網(wǎng):通過SPI,UART,I2C,SDIO等接口傳輸配網(wǎng)信息;
- WPS路由器配網(wǎng);
- 零配網(wǎng):ZeroConfig,通過一臺(tái)已配網(wǎng)設(shè)備給另一臺(tái)設(shè)備配網(wǎng);
- 手機(jī)AP配網(wǎng):手機(jī)啟動(dòng)AP熱點(diǎn),讓模塊連接此熱點(diǎn)實(shí)現(xiàn)配網(wǎng)。
二、使用ESP32的一鍵配網(wǎng)
ESP32的example有完整的SmartConfig demo,可以直接創(chuàng)建項(xiàng)目使用。
1. 流程分析
配網(wǎng)主要執(zhí)行以下流程:
(1)初始化網(wǎng)絡(luò)接口并為應(yīng)用程序創(chuàng)建事件組。
ESP_ERROR_CHECK(esp_netif_init());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
(2)注冊(cè)事件處理函數(shù)
為 WIFI_EVENT、IP_EVENT 和 SC_EVENT 注冊(cè)事件處理函數(shù)。
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_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
(3)啟動(dòng) WiFi 站點(diǎn)模式
設(shè)置站點(diǎn)模式的事件處理函數(shù)。
(4)創(chuàng)建 smartconfig 任務(wù)
當(dāng)使用STA模式時(shí),連接到WiFi網(wǎng)絡(luò)時(shí)觸發(fā)事件 WIFI_EVENT_STA_START ,這時(shí)創(chuàng)建一個(gè)名為“smartconfig_example_task”的新任務(wù)。
(5)查找到信道事件
當(dāng) SC_EVENT_FOUND_CHANNEL 事件被觸發(fā)時(shí),表示 smartconfig 已經(jīng)找到一個(gè)信道。一鍵配網(wǎng)一般通過先找到信道、再通訊的方式以提高配網(wǎng)效率 。
(6)獲取到SSID和密碼事件
當(dāng) SC_EVENT_GOT_SSID_PSWD 事件被觸發(fā)時(shí),就可以從事件數(shù)據(jù)中獲取 SSID 和密碼,配置 WiFi 接口并連接到 AP。
這時(shí)要記錄 SSID 和密碼,如果 smartconfig 類型為 ESPTOUCH_V2,則獲取 RVD_DATA 并記錄它。
(7)記錄WIFI已經(jīng)連接
在“smartconfig_example_task”函數(shù)中,將 smartconfig 類型設(shè)置為 SC_TYPE_ESPTOUCH,啟動(dòng) smartconfig,并等待事件組中的 CONNECTED_BIT 和 ESPTOUCH_DONE_BIT。
如果兩個(gè)位都設(shè)置了,則記錄一條消息,指示 WiFi 已連接并且 smartconfig 已結(jié)束。停止 smartconfig 并刪除任務(wù)。
(8)調(diào)用
在 app_main 函數(shù)中初始化 NVS 閃存并調(diào)用 initialize_wifi 函數(shù)。
2. 源碼
/* Esptouch example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include
#include
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wpa2.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_netif.h"
#include "esp_smartconfig.h"
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event,
but we only care about one event - are we connected
to the AP with an IP? */
static const int CONNECTED_BIT = BIT0;
static const int ESPTOUCH_DONE_BIT = BIT1;
static const char *TAG = "smartconfig_example";
static void smartconfig_example_task(void * parm);
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
xTaskCreate(smartconfig_example_task, "smartconfig_example_task", 4096, NULL, 3, NULL);
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
esp_wifi_connect();
xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT);
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SCAN_DONE) {
ESP_LOGI(TAG, "Scan done");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_FOUND_CHANNEL) {
ESP_LOGI(TAG, "Found channel");
} else if (event_base == SC_EVENT && event_id == SC_EVENT_GOT_SSID_PSWD) {
ESP_LOGI(TAG, "Got SSID and password");
smartconfig_event_got_ssid_pswd_t *evt = (smartconfig_event_got_ssid_pswd_t *)event_data;
wifi_config_t wifi_config;
uint8_t ssid[33] = { 0 };
uint8_t password[65] = { 0 };
uint8_t rvd_data[33] = { 0 };
bzero(&wifi_config, sizeof(wifi_config_t));
memcpy(wifi_config.sta.ssid, evt->ssid, sizeof(wifi_config.sta.ssid));
memcpy(wifi_config.sta.password, evt->password, sizeof(wifi_config.sta.password));
wifi_config.sta.bssid_set = evt->bssid_set;
if (wifi_config.sta.bssid_set == true) {
memcpy(wifi_config.sta.bssid, evt->bssid, sizeof(wifi_config.sta.bssid));
}
memcpy(ssid, evt->ssid, sizeof(evt->ssid));
memcpy(password, evt->password, sizeof(evt->password));
ESP_LOGI(TAG, "SSID:%s", ssid);
ESP_LOGI(TAG, "PASSWORD:%s", password);
if (evt->type == SC_TYPE_ESPTOUCH_V2) {
ESP_ERROR_CHECK( esp_smartconfig_get_rvd_data(rvd_data, sizeof(rvd_data)) );
ESP_LOGI(TAG, "RVD_DATA:");
for (int i=0; i<33; i++) {
printf("%02x ", rvd_data[i]);
}
printf("\\n");
}
ESP_ERROR_CHECK( esp_wifi_disconnect() );
ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) );
esp_wifi_connect();
} else if (event_base == SC_EVENT && event_id == SC_EVENT_SEND_ACK_DONE) {
xEventGroupSetBits(s_wifi_event_group, ESPTOUCH_DONE_BIT);
}
}
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_t *sta_netif = esp_netif_create_default_wifi_sta();
assert(sta_netif);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
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_event_handler_register(SC_EVENT, ESP_EVENT_ANY_ID, &event_handler, NULL) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK( esp_wifi_start() );
}
static void smartconfig_example_task(void * parm)
{
EventBits_t uxBits;
ESP_ERROR_CHECK( esp_smartconfig_set_type(SC_TYPE_ESPTOUCH) );
smartconfig_start_config_t cfg = SMARTCONFIG_START_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_smartconfig_start(&cfg) );
while (1) {
uxBits = xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT | ESPTOUCH_DONE_BIT, true, false, portMAX_DELAY);
if(uxBits & CONNECTED_BIT) {
ESP_LOGI(TAG, "WiFi Connected to ap");
}
if(uxBits & ESPTOUCH_DONE_BIT) {
ESP_LOGI(TAG, "smartconfig over");
esp_smartconfig_stop();
vTaskDelete(NULL);
}
}
}
void app_main(void)
{
ESP_ERROR_CHECK( nvs_flash_init() );
initialise_wifi();
}
3. 執(zhí)行效果
三、安卓端
1. ESP32提供的測(cè)試APP
2. 使用SDK
從官方找到下載地址:
https://www.espressif.com.cn/zh-hans/support/download/apps
下載 aar文件集成到自己項(xiàng)目中使用,主要是以下幾步:
(1)添加Smart Config SDK庫
設(shè)置build.gradle
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
添加引用,esptouch:
implementation 'com.github.EspressifApp:lib-esptouch-android:1.1.1'
或 esptouch-v2
implementation 'com.github.EspressifApp:lib-esptouch-v2-android:2.2.1'
(2)添加權(quán)限
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
(3)API
EspTouch v1
// 創(chuàng)建任務(wù)實(shí)例
Context context; // Set Applicatioin context
byte[] apSsid = {}; // Set AP's SSID
byte[] apBssid = {}; // Set AP's BSSID
byte[] apPassword = {}; // Set AP's password
EsptouchTask task = new EsptouchTask(apSsid, apBssid, apPassword, context);
task.setPackageBroadcast(true); // if true send broadcast packets, else send multicast packets
// 設(shè)置回調(diào)
task.setEsptouchListener(new IEsptouchListener() {
@Override
public void onEsptouchResultAdded(IEsptouchResult result) {
// Result callback
}
});
// 執(zhí)行任務(wù)
int expectResultCount = 1;
List
ESP touch v2
// 創(chuàng)建實(shí)例
Context context; // Set Application Context
EspProvisioner provisioner = new EspProvisioner(context);
// 設(shè)置監(jiān)聽
EspSyncListener listener = new EspSyncListener() {
@Override
public void onStart() {
}
@Override
public void onStop() {
}
@Override
public void onError(Exception e) {
}
};
// 發(fā)同步包
provisioner.startSync(listener); // listener is nullable
// 停止同步包
provisioner.stopSync();
// 開始
Context context; // Set Application Context
EspProvisioningRequest request = new EspProvisioningRequest.Builder(context)
.setSSID(ssid) // AP's SSID, nullable
.setBSSID(bssid) // AP's BSSID, nonnull
.setPassword(password) // AP's password, nullable if the AP is open
.setReservedData(customData) // User's custom data, nullable. If not null, the max length is 64
.setAESKey(aesKey) // nullable, if not null, it must be 16 bytes. App developer should negotiate an AES key with Device developer first.
.build();
EspProvisioningListener listener = new EspProvisioningListener() {
@Override
public void onStart() {
}
@Override
public void onResponse(EspProvisionResult result) {
// Result callback
}
@Override
public void onStop() {
}
@Override
public void onError(Exception e) {
}
};
provisioner.startProvisioning(request, listener); // request is nonnull, listener is nullable
// 停止配網(wǎng)
provisioner.stopProvisioning();
// 關(guān)閉配網(wǎng)
provisioner.close()
-
藍(lán)牙
+關(guān)注
關(guān)注
114文章
5869瀏覽量
171228 -
nfc
+關(guān)注
關(guān)注
59文章
1632瀏覽量
180971 -
WIFI
+關(guān)注
關(guān)注
81文章
5309瀏覽量
204798 -
配網(wǎng)
+關(guān)注
關(guān)注
0文章
155瀏覽量
9108 -
ESP32
+關(guān)注
關(guān)注
18文章
978瀏覽量
17531
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論