阿里云平台的设置
参考文章:
http://t.csdn.cn/RzLGqhttp://t.csdn.cn/RzLGq
Blufi配网
1.简介
BluFi 是一款基于蓝牙通道的 Wi-Fi 网络配置功能,适用于 ESP32。它通过安全协议将 Wi-Fi 配置和证书传输到 ESP32,然后 ESP32 可基于这些信息连接到 AP 或建立 SoftAP。
BluFi 流程的关键部分包括数据的分片、加密、校验和验证。
用户可按需自定义用于对称加密、非对称加密和校验的算法。这里我们采用 DH 算法进行密钥协商、128-AES 算法用于数据加密、CRC16 算法用于校验和验证。
2.BluFi 流程
BluFi 配网流程包含配置 SoftAP 和配置 Station 两部分。
下面以配置 Station 为例,介绍了广播、连接、服务发现、协商共享密钥、传输数据、回传连接状态等关键步骤。
-
ESP32 开启 GATT Server 模式,发送带有特定 advertising data 的广播。该广播不属于 BluFi Profile,可以按需对其进行自定义。
-
使用手机应用程序搜索到该广播后,手机将作为 GATT Client 连接 ESP32。该步骤对具体使用哪款手机应用程序并无特殊要求。
-
成功建立 GATT 连接后,手机会向 ESP32 发送数据帧进行密钥协商(详见 BluFi 中定义的帧格式 )。
-
ESP32 收到密钥协商的数据帧后,会按照自定义的协商方法进行解析。
-
手机与 ESP32 进行密钥协商。协商过程可使用 DH/RSA/ECC 等加密算法。
-
协商结束后,手机端向 ESP32 发送控制帧,用于设置安全模式。
-
ESP32 收到控制帧后,使用共享密钥以及安全配置对通信数据进行加密和解密。
-
手机向 ESP32 发送 BluFi 中定义的帧格式 中定义的数据帧,包括 SSID、密码等 Wi-Fi 配置信息。
-
手机向 ESP32 发送 Wi-Fi 连接请求的控制帧。ESP32 收到控制帧后,即默认手机已完成必要信息的传输,准备连接 Wi-Fi。
-
连接到 Wi-Fi 后,ESP32 发送 Wi-Fi 连接状态报告的控制帧到手机。至此,配网结束。
BluFi 流程图
蓝牙配网代码
/*通过蓝牙进行配网操作*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_mac.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"
#include "esp_blufi_api.h"
#include "blufi_example.h"
#include "blufi_example_main.h"
#include "esp_blufi.h"
#include "smartconfig_led.h"
// WiFi 连接重试次数的常量
#define EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY CONFIG_EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY
//表示一个无效的原因代码
#define EXAMPLE_INVALID_REASON 255
//表示一个无效的信号强度值(RSSI) 通常用于表示未能成功获取到实际的 RSSI 值
#define EXAMPLE_INVALID_RSSI -128
int is_configured=0; //判断WiFi连接的标志,因为加入了按键长按清除配网信息
typedef enum {
wifi_unconfiged = 0x00,
wifi_configed = 0xAA,
}wifi_info_storage_t;
//该函数是用作蓝牙低功耗(Bluetooth Low Energy, BLE)的回调函数,用于处理与蓝牙协议相关的事件。
//具体的事件类型和参数可以在 esp_blufi_cb_event_t 和 esp_blufi_cb_param_t 中定义和传递。
static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param);
//表示 Wi-Fi 扫描到的 AP 列表中最多包含的 AP 数量。
#define WIFI_LIST_NUM 10
static wifi_config_t sta_config;//用于存储 Wi-Fi 的配置信息
static wifi_config_t ap_config;
//是一个 FreeRTOS 事件组(Event Group)的句柄(handle)
//该事件组用于在连接成功并准备好发起请求时进行信号传递
static EventGroupHandle_t wifi_event_group;
//表示与接入点(AP)建立连接的状态
const int CONNECTED_BIT = BIT0;
//用于记录 Wi-Fi 连接失败时的重试次数
static uint8_t example_wifi_retry = 0;
/*
这段代码定义了一系列静态变量,用于存储与连接状态和连接相关的信息。下面是对每个变量的说明:
gl_sta_connected:一个布尔类型的变量,用于表示 Wi-Fi 站点(station)是否已连接。
gl_sta_got_ip:一个布尔类型的变量,用于表示 Wi-Fi 站点是否已获取到 IP 地址。
ble_is_connected:一个布尔类型的变量,用于表示 BLE 是否已连接。
gl_sta_bssid:一个长度为 6 的无符号 8 位整数数组,用于存储 Wi-Fi 站点的 BSSID(基本服务集标识符)。
gl_sta_ssid:一个长度为 32 的无符号 8 位整数数组,用于存储 Wi-Fi 站点的 SSID(服务集标识符)。
gl_sta_ssid_len:一个整数变量,用于存储 Wi-Fi 站点的 SSID 长度。
gl_sta_list:一个结构体变量,用于存储 Wi-Fi 站点列表信息。
gl_sta_is_connecting:一个布尔类型的变量,用于表示 Wi-Fi 站点当前是否正在连接中。
gl_sta_conn_info:一个结构体变量,用于存储与 Wi-Fi 站点连接相关的额外信息。
*/
static bool gl_sta_connected = false;
static bool gl_sta_got_ip = false;
static bool ble_is_connected = false;
static uint8_t gl_sta_bssid[6];
static uint8_t gl_sta_ssid[32];
static int gl_sta_ssid_len;
static wifi_sta_list_t gl_sta_list;
static bool gl_sta_is_connecting = false;
static esp_blufi_extra_info_t gl_sta_conn_info;
/*
该函数的作用是记录 Wi-Fi 连接的相关信息,并将其存储在 gl_sta_conn_info 变量中
gl_sta_is_connecting 为真(即 Wi-Fi 正在连接中)
gl_sta_is_connecting 为假,则表示 Wi-Fi 已连接或连接失败
*/
static void example_record_wifi_conn_info(int rssi, uint8_t reason)
{
memset(&gl_sta_conn_info, 0, sizeof(esp_blufi_extra_info_t));
if (gl_sta_is_connecting) {
gl_sta_conn_info.sta_max_conn_retry_set = true;
gl_sta_conn_info.sta_max_conn_retry = EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY;
} else {
gl_sta_conn_info.sta_conn_rssi_set = true;
gl_sta_conn_info.sta_conn_rssi = rssi;
gl_sta_conn_info.sta_conn_end_reason_set = true;
gl_sta_conn_info.sta_conn_end_reason = reason;
}
}
/*启动 Wi-Fi 连接过程
esp_wifi_connect 函数来开始 Wi-Fi 连接。
如果连接成功,
gl_sta_is_connecting 变量会被设置为 true,否则为 false
*/
static void example_wifi_connect(void)
{
example_wifi_retry = 0;
gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK);
example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON);
}
/*
尝试重新连接 Wi-Fi
调用 example_record_wifi_conn_info 函数,
将连接信息记录到 gl_sta_conn_info 变量中。
这里传递的 rssi 参数为 EXAMPLE_INVALID_RSSI,表示初始信号强度未知;reason 参数为 EXAMPLE_INVALID_REASON,表示连接结束原因未知。
将 ret 设置为真,表示重新连接成功。
*/
static bool example_wifi_reconnect(void)
{
bool ret;
if (gl_sta_is_connecting && example_wifi_retry++ < EXAMPLE_WIFI_CONNECTION_MAXIMUM_RETRY) {
BLUFI_INFO("BLUFI WiFi starts reconnection\n");
gl_sta_is_connecting = (esp_wifi_connect() == ESP_OK);
example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON);
ret = true;
} else {
ret = false;
}
return ret;
}
static int softap_get_current_connection_number(void)
{
esp_err_t ret;
ret = esp_wifi_ap_get_sta_list(&gl_sta_list);
if (ret == ESP_OK)
{
return gl_sta_list.num;
}
return 0;
}
/*获取当前连接到 SoftAP(软件接入点)的设备数量。*/
static void ip_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
wifi_mode_t mode;
switch (event_id) {
case IP_EVENT_STA_GOT_IP: {
esp_blufi_extra_info_t info;
xEventGroupSetBits(wifi_event_group, CONNECTED_BIT);
esp_wifi_get_mode(&mode);
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
memcpy(info.sta_bssid, gl_sta_bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = gl_sta_ssid;
info.sta_ssid_len = gl_sta_ssid_len;
gl_sta_got_ip = true;
if (ble_is_connected == true) {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_SUCCESS, softap_get_current_connection_number(), &info);
} else {
BLUFI_INFO("1BLUFI BLE is not connected yet\n");
if(is_configured==1)
{
printf("Wi-fi Connected\n");
break;
}
}
break;
}
default:
break;
}
return;
}
/*
WiFi事件处理函数
当收到WIFI_EVENT_STA_START事件时,调用delegate_wifi_connecting_status()函数,表示WiFi正在连接,然后调用example_wifi_connect()函数开始连接WiFi。
当收到WIFI_EVENT_STA_CONNECTED事件时,表示WiFi已成功连接。设置gl_sta_connected为true,表示已连接,gl_sta_is_connecting为false,表示连接过程已结束。将连接的BSSID和SSID保存在全局变量gl_sta_bssid和gl_sta_ssid中,并更新gl_sta_ssid_len。然后调用delegate_wifi_connected_status()函数,表示WiFi已连接。
当收到WIFI_EVENT_STA_DISCONNECTED事件时,表示WiFi连接断开。如果gl_sta_connected为false并且example_wifi_reconnect()返回false,表示无法重新连接WiFi,则将gl_sta_is_connecting设置为false,表示连接过程已结束。调用delegate_wifi_disconnect_status()函数,表示WiFi连接失败。同时,记录断开连接的原因和信号强度。然后重置连接相关的全局变量,并清除WiFi连接标志位。
当收到WIFI_EVENT_AP_START事件时,表示启动了SoftAP模式。获取当前的WiFi模式,并根据情况发送连接报告给BLE设备。
当收到WIFI_EVENT_SCAN_DONE事件时,表示WiFi扫描完成。如果扫描到了AP,则将扫描结果发送给BLE设备。然后停止WiFi扫描,并释放扫描结果的内存。
当收到WIFI_EVENT_AP_STACONNECTED事件时,表示有设备连接到SoftAP。记录连接的设备MAC地址和AID。
当收到WIFI_EVENT_AP_STADISCONNECTED事件时,表示有设备断开了与SoftAP的连接。记录断开连接的设备MAC地址和AID。
*/
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
wifi_event_sta_connected_t *event;
wifi_event_sta_disconnected_t *disconnected_event;
wifi_mode_t mode;
switch (event_id) {
case WIFI_EVENT_STA_START:
delegate_wifi_connecting_status();wifi正在连接LED快闪
example_wifi_connect();
break;
case WIFI_EVENT_STA_CONNECTED:
is_configured = 1;
gl_sta_connected = true;
gl_sta_is_connecting = false;
event = (wifi_event_sta_connected_t*) event_data;
memcpy(gl_sta_bssid, event->bssid, 6);
memcpy(gl_sta_ssid, event->ssid, event->ssid_len);
gl_sta_ssid_len = event->ssid_len;
delegate_wifi_connected_status(); wifi连接LED熄灭
break;
case WIFI_EVENT_STA_DISCONNECTED:
/* Only handle reconnection during connecting */
is_configured = 0;
if (gl_sta_connected == false && example_wifi_reconnect() == false) {
gl_sta_is_connecting = false;
delegate_wifi_disconnect_status(); wifi连接失败LED慢闪
disconnected_event = (wifi_event_sta_disconnected_t*) event_data;
example_record_wifi_conn_info(disconnected_event->rssi, disconnected_event->reason);
}
/* This is a workaround as ESP32 WiFi libs don't currently
auto-reassociate. */
gl_sta_connected = false;
gl_sta_got_ip = false;
memset(gl_sta_ssid, 0, 32);
memset(gl_sta_bssid, 0, 6);
gl_sta_ssid_len = 0;
xEventGroupClearBits(wifi_event_group, CONNECTED_BIT);
break;
case WIFI_EVENT_AP_START:
esp_wifi_get_mode(&mode);
/* TODO: get config or information of softap, then set to report extra_info */
if (ble_is_connected == true) {
if (gl_sta_connected) {
esp_blufi_extra_info_t info;
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
memcpy(info.sta_bssid, gl_sta_bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = gl_sta_ssid;
info.sta_ssid_len = gl_sta_ssid_len;
esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
} else if (gl_sta_is_connecting) {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
} else {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
}
} else {
BLUFI_INFO("123BLUFI BLE is not connected yet\n");
printf("123\n");
}
break;
case WIFI_EVENT_SCAN_DONE: {
uint16_t apCount = 0;
esp_wifi_scan_get_ap_num(&apCount);
if (apCount == 0) {
BLUFI_INFO("Nothing AP found");
break;
}
wifi_ap_record_t *ap_list = (wifi_ap_record_t *)malloc(sizeof(wifi_ap_record_t) * apCount);
if (!ap_list) {
BLUFI_ERROR("malloc error, ap_list is NULL");
break;
}
ESP_ERROR_CHECK(esp_wifi_scan_get_ap_records(&apCount, ap_list));
esp_blufi_ap_record_t * blufi_ap_list = (esp_blufi_ap_record_t *)malloc(apCount * sizeof(esp_blufi_ap_record_t));
if (!blufi_ap_list) {
if (ap_list) {
free(ap_list);
}
BLUFI_ERROR("malloc error, blufi_ap_list is NULL");
break;
}
for (int i = 0; i < apCount; ++i)
{
blufi_ap_list[i].rssi = ap_list[i].rssi;
memcpy(blufi_ap_list[i].ssid, ap_list[i].ssid, sizeof(ap_list[i].ssid));
}
if (ble_is_connected == true) {
esp_blufi_send_wifi_list(apCount, blufi_ap_list);
} else {
BLUFI_INFO("12 BLUFI BLE is not connected yet\n");
printf("12\n");
}
esp_wifi_scan_stop();
free(ap_list);
free(blufi_ap_list);
break;
}
case WIFI_EVENT_AP_STACONNECTED: {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
BLUFI_INFO("station "MACSTR" join, AID=%d", MAC2STR(event->mac), event->aid);
break;
}
case WIFI_EVENT_AP_STADISCONNECTED: {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
BLUFI_INFO("station "MACSTR" leave, AID=%d", MAC2STR(event->mac), event->aid);
break;
}
default:
break;
}
return;
}
/*
这是一个初始化WiFi的函数,以下是对其操作的简要说明:
调用esp_netif_init()函数进行ESP-NETIF网络接口的初始化。
使用xEventGroupCreate()函数创建一个事件组,用于处理WiFi事件。
调用esp_event_loop_create_default()函数创建默认的事件循环。
调用esp_netif_create_default_wifi_sta()函数创建默认的STA(Station)模式网络接口,并将返回的网络接口指针保存在sta_netif中。
调用esp_netif_create_default_wifi_ap()函数创建默认的AP(Access Point)模式网络接口,并将返回的网络接口指针保存在ap_netif中。
调用esp_event_handler_register()函数注册WiFi事件处理函数wifi_event_handler,以处理所有WiFi事件。
调用esp_event_handler_register()函数注册IP事件处理函数ip_event_handler,以处理STA(Station)获取IP地址的事件。
创建一个默认的WiFi初始化配置结构体cfg,并通过调用esp_wifi_init()函数进行WiFi初始化。
调用esp_wifi_set_mode()函数将WiFi模式设置为STA模式。
调用example_record_wifi_conn_info()函数记录无效的RSSI(信号强度)和无效的连接原因。
调用esp_wifi_start()函数启动WiFi。
*/
static void initialise_wifi(void)
{
ESP_ERROR_CHECK(esp_netif_init());
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);
esp_netif_t *ap_netif = esp_netif_create_default_wifi_ap();
assert(ap_netif);
ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL));
ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &ip_event_handler, NULL));
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) );
example_record_wifi_conn_info(EXAMPLE_INVALID_RSSI, EXAMPLE_INVALID_REASON);
ESP_ERROR_CHECK( esp_wifi_start() );
}
/*
这是一个ESP-BLE-MESH蓝牙Mesh设备中的蓝牙低功耗(BLE)配置回调函数结构体esp_blufi_callbacks_t的初始化。以下是对其成员函数的简要说明:
.event_cb:指向用于处理蓝牙事件的回调函数example_event_callback的指针。
.negotiate_data_handler:指向用于处理数据协商的回调函数blufi_dh_negotiate_data_handler的指针。
.encrypt_func:指向用于加密数据的回调函数blufi_aes_encrypt的指针。
.decrypt_func:指向用于解密数据的回调函数blufi_aes_decrypt的指针。
.checksum_func:指向用于计算校验和的回调函数blufi_crc_checksum的指针。*/
static esp_blufi_callbacks_t example_callbacks = {
.event_cb = example_event_callback,
.negotiate_data_handler = blufi_dh_negotiate_data_handler,
.encrypt_func = blufi_aes_encrypt,
.decrypt_func = blufi_aes_decrypt,
.checksum_func = blufi_crc_checksum,
};
/*
这是一个使用 ESP32 蓝牙功能的示例代码中的事件回调函数。该函数根据不同的事件类型执行相应的操作。
- `ESP_BLUFI_EVENT_INIT_FINISH`:蓝牙功能初始化完成时调用,启动广播。
- `ESP_BLUFI_EVENT_DEINIT_FINISH`:蓝牙功能关闭完成时调用。
- `ESP_BLUFI_EVENT_BLE_CONNECT`:蓝牙连接建立时调用,停止广播,并初始化安全设置。
- `ESP_BLUFI_EVENT_BLE_DISCONNECT`:蓝牙连接断开时调用,重新开始广播,并清除安全设置。
- `ESP_BLUFI_EVENT_SET_WIFI_OPMODE`:设置 Wi-Fi 工作模式时调用,根据参数设置 ESP8266 的 Wi-Fi 模式。
- `ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP`:请求连接到 AP 时调用,断开当前 Wi-Fi 连接并连接到指定 AP。
- `ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP`:请求断开与 AP 的连接时调用。
- `ESP_BLUFI_EVENT_REPORT_ERROR`:报告错误时调用,发送错误信息给手机端。
- `ESP_BLUFI_EVENT_GET_WIFI_STATUS`:获取 Wi-Fi 状态时调用,发送当前 Wi-Fi 连接状态给手机端。
- `ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE`:接收到从设备断开连接的事件时调用,断开与从设备的 GATT 连接。
- `ESP_BLUFI_EVENT_DEAUTHENTICATE_STA`:待实现的事件,用于取消认证的 STA。
- `ESP_BLUFI_EVENT_RECV_STA_BSSID`:接收到 STA 的 BSSID 时调用,设置 STA 配置的 BSSID。
- `ESP_BLUFI_EVENT_RECV_STA_SSID`:接收到 STA 的 SSID 时调用,设置 STA 配置的 SSID。
- `ESP_BLUFI_EVENT_RECV_STA_PASSWD`:接收到 STA 的密码时调用,设置 STA 配置的密码。
- `ESP_BLUFI_EVENT_RECV_SOFTAP_SSID`:接收到 SoftAP 的 SSID 时调用,设置 SoftAP 的 SSID。
- `ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD`:接收到 SoftAP 的密码时调用,设置 SoftAP 的密码。
- `ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM`:接收到 SoftAP 的最大连接数时调用,设置 SoftAP 的最大连接数。
- `ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE`:接收到 SoftAP 的认证模式时调用,设置 SoftAP 的认证模式。
- `ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL`:接收到 SoftAP 的信道时调用,设置 SoftAP 的信道。
- `ESP_BLUFI_EVENT_GET_WIFI_LIST`:获取 Wi-Fi 列表时调用,开启 Wi-Fi 扫描并发送扫描结果给手机端。
- `ESP_BLUFI_EVENT_RECV_CUSTOM_DATA`:接收到自定义数据时调用,打印数据内容。
- `ESP_BLUFI_EVENT_RECV_USERNAME`:待处理的事件,用于接收用户名。
- `ESP_BLUFI_EVENT_RECV_CA_CERT`:待处理的事件,用于接收 CA 证书。
- `ESP_BLUFI_EVENT_RECV_CLIENT_CERT`:待处理的事件,用于接收客户端证书。
- `ESP_BLUFI_EVENT_RECV_SERVER_CERT`:待处理的事件,用于接收服务器证书。
- `ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY`:待处理的事件,用于接收客户端私钥。
- `ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY`:待处理的事件,用于接收服务器私钥。
*/
static void example_event_callback(esp_blufi_cb_event_t event, esp_blufi_cb_param_t *param)
{
/* actually, should post to blufi_task handle the procedure,
* now, as a example, we do it more simply */
switch (event) {
case ESP_BLUFI_EVENT_INIT_FINISH:
BLUFI_INFO("BLUFI init finish\n");
esp_blufi_adv_start();
break;
case ESP_BLUFI_EVENT_DEINIT_FINISH:
BLUFI_INFO("BLUFI deinit finish\n");
break;
case ESP_BLUFI_EVENT_BLE_CONNECT:
BLUFI_INFO("BLUFI ble connect\n");
ble_is_connected = true;
esp_blufi_adv_stop();
blufi_security_init();
break;
case ESP_BLUFI_EVENT_BLE_DISCONNECT:
BLUFI_INFO("BLUFI ble disconnect\n");
ble_is_connected = false;
blufi_security_deinit();
esp_blufi_adv_start();
break;
case ESP_BLUFI_EVENT_SET_WIFI_OPMODE:
BLUFI_INFO("BLUFI Set WIFI opmode %d\n", param->wifi_mode.op_mode);
ESP_ERROR_CHECK( esp_wifi_set_mode(param->wifi_mode.op_mode) );
break;
case ESP_BLUFI_EVENT_REQ_CONNECT_TO_AP:
BLUFI_INFO("BLUFI requset wifi connect to AP\n");
/* there is no wifi callback when the device has already connected to this wifi
so disconnect wifi before connection.
*/
esp_wifi_disconnect();
example_wifi_connect();
break;
case ESP_BLUFI_EVENT_REQ_DISCONNECT_FROM_AP:
BLUFI_INFO("BLUFI requset wifi disconnect from AP\n");
esp_wifi_disconnect();
break;
case ESP_BLUFI_EVENT_REPORT_ERROR:
BLUFI_ERROR("BLUFI report error, error code %d\n", param->report_error.state);
esp_blufi_send_error_info(param->report_error.state);
break;
case ESP_BLUFI_EVENT_GET_WIFI_STATUS: {
wifi_mode_t mode;
esp_blufi_extra_info_t info;
esp_wifi_get_mode(&mode);
if (gl_sta_connected) {
memset(&info, 0, sizeof(esp_blufi_extra_info_t));
memcpy(info.sta_bssid, gl_sta_bssid, 6);
info.sta_bssid_set = true;
info.sta_ssid = gl_sta_ssid;
info.sta_ssid_len = gl_sta_ssid_len;
esp_blufi_send_wifi_conn_report(mode, gl_sta_got_ip ? ESP_BLUFI_STA_CONN_SUCCESS : ESP_BLUFI_STA_NO_IP, softap_get_current_connection_number(), &info);
} else if (gl_sta_is_connecting) {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONNECTING, softap_get_current_connection_number(), &gl_sta_conn_info);
} else {
esp_blufi_send_wifi_conn_report(mode, ESP_BLUFI_STA_CONN_FAIL, softap_get_current_connection_number(), &gl_sta_conn_info);
}
BLUFI_INFO("BLUFI get wifi status from AP\n");
break;
}
case ESP_BLUFI_EVENT_RECV_SLAVE_DISCONNECT_BLE:
BLUFI_INFO("blufi close a gatt connection");
esp_blufi_disconnect();
break;
case ESP_BLUFI_EVENT_DEAUTHENTICATE_STA:
/* TODO */
break;
case ESP_BLUFI_EVENT_RECV_STA_BSSID:
memcpy(sta_config.sta.bssid, param->sta_bssid.bssid, 6);
sta_config.sta.bssid_set = 1;
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
BLUFI_INFO("Recv STA BSSID %s\n", sta_config.sta.ssid);
break;
case ESP_BLUFI_EVENT_RECV_STA_SSID:
strncpy((char *)sta_config.sta.ssid, (char *)param->sta_ssid.ssid, param->sta_ssid.ssid_len);
sta_config.sta.ssid[param->sta_ssid.ssid_len] = '\0';
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
BLUFI_INFO("Recv STA SSID %s\n", sta_config.sta.ssid);
break;
case ESP_BLUFI_EVENT_RECV_STA_PASSWD:
strncpy((char *)sta_config.sta.password, (char *)param->sta_passwd.passwd, param->sta_passwd.passwd_len);
sta_config.sta.password[param->sta_passwd.passwd_len] = '\0';
esp_wifi_set_config(WIFI_IF_STA, &sta_config);
BLUFI_INFO("Recv STA PASSWORD %s\n", sta_config.sta.password);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_SSID:
strncpy((char *)ap_config.ap.ssid, (char *)param->softap_ssid.ssid, param->softap_ssid.ssid_len);
ap_config.ap.ssid[param->softap_ssid.ssid_len] = '\0';
ap_config.ap.ssid_len = param->softap_ssid.ssid_len;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP SSID %s, ssid len %d\n", ap_config.ap.ssid, ap_config.ap.ssid_len);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_PASSWD:
strncpy((char *)ap_config.ap.password, (char *)param->softap_passwd.passwd, param->softap_passwd.passwd_len);
ap_config.ap.password[param->softap_passwd.passwd_len] = '\0';
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP PASSWORD %s len = %d\n", ap_config.ap.password, param->softap_passwd.passwd_len);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_MAX_CONN_NUM:
if (param->softap_max_conn_num.max_conn_num > 4) {
return;
}
ap_config.ap.max_connection = param->softap_max_conn_num.max_conn_num;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP MAX CONN NUM %d\n", ap_config.ap.max_connection);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_AUTH_MODE:
if (param->softap_auth_mode.auth_mode >= WIFI_AUTH_MAX) {
return;
}
ap_config.ap.authmode = param->softap_auth_mode.auth_mode;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP AUTH MODE %d\n", ap_config.ap.authmode);
break;
case ESP_BLUFI_EVENT_RECV_SOFTAP_CHANNEL:
if (param->softap_channel.channel > 13) {
return;
}
ap_config.ap.channel = param->softap_channel.channel;
esp_wifi_set_config(WIFI_IF_AP, &ap_config);
BLUFI_INFO("Recv SOFTAP CHANNEL %d\n", ap_config.ap.channel);
break;
case ESP_BLUFI_EVENT_GET_WIFI_LIST:{
wifi_scan_config_t scanConf = {
.ssid = NULL,
.bssid = NULL,
.channel = 0,
.show_hidden = false
};
esp_err_t ret = esp_wifi_scan_start(&scanConf, true);
if (ret != ESP_OK) {
esp_blufi_send_error_info(ESP_BLUFI_WIFI_SCAN_FAIL);
}
break;
}
case ESP_BLUFI_EVENT_RECV_CUSTOM_DATA:
BLUFI_INFO("Recv Custom Data %" PRIu32 "\n", param->custom_data.data_len);
esp_log_buffer_hex("Custom Data", param->custom_data.data, param->custom_data.data_len);
break;
case ESP_BLUFI_EVENT_RECV_USERNAME:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_CA_CERT:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_CLIENT_CERT:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_SERVER_CERT:
/* Not handle currently */
break;
case ESP_BLUFI_EVENT_RECV_CLIENT_PRIV_KEY:
/* Not handle currently */
break;;
case ESP_BLUFI_EVENT_RECV_SERVER_PRIV_KEY:
/* Not handle currently */
break;
default:
break;
}
}
/**********************************************
* *函数名:clearWifiConfigFlag
* *功能描述:清除配网标记,如果运行这个函数,可以配合esp_restart(),复位系统。重新配网
* * -- 主要是取代nvs_flash_erase()函数,这个函数把所有的数据都擦除,是不对的。
* *******************************************/
void clearWifiConfigFlag(void)
{
nvs_handle my_handle;
// 0.打开
nvs_open("WIFI_CONFIG", NVS_READWRITE, &my_handle);
// 1.写入标记 0x00,清除配网标记
nvs_set_u8(my_handle, "WifiConfigFlag", wifi_unconfiged);
// 2.提交 并保存表的内容
ESP_ERROR_CHECK(nvs_commit(my_handle));
// 3.退出
nvs_close(my_handle);
}
void Init_blufi(void)
{
//printf("is_configured = %d\n", is_configured);
if(is_configured==0)
{
esp_err_t ret;
// Initialize NVS
ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK( ret );
initialise_wifi();
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);
if (ret) {
BLUFI_ERROR("%s initialize bt controller failed: %s\n", __func__, esp_err_to_name(ret));
}
ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
if (ret) {
BLUFI_ERROR("%s enable bt controller failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
ret = esp_blufi_host_and_cb_init(&example_callbacks);
if (ret) {
BLUFI_ERROR("%s initialise failed: %s\n", __func__, esp_err_to_name(ret));
return;
}
BLUFI_INFO("BLUFI VERSION %04x\n", esp_blufi_get_version());
printf("is_configured = %d\n", is_configured);
}
else if (is_configured==1)
{
//printf("is_configured = %d\n", is_configured);
printf("wifi connected\n");
}
}
MQTT连接参数
然后使用MQTT签名工具获取以下信息
将上面的信息进行对应替换
如何计算MQTT签名参数_阿里云物联网平台-阿里云帮助中心 (aliyun.com)
MQTT连接代码
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include "esp_wifi.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "lwip/sockets.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "os.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "mqtt.h"
esp_mqtt_client_handle_t client;
static const char *TAG = "MQTT_EXAMPLE";
#define Aliyun_host "h54wTCsZDZU.iot-as-mqtt.cn-shanghai.aliyuncs.com"
#define Aliyun_port 1883
#define Aliyun_client_id "LCH|securemode=2,signmethod=hmacsha1,timestamp=1694742596956|"
#define Aliyun_username "Device_1&h54wTCsZDZU"
#define Aliyun_password "75B16F77A2FA77FF3CA5ACADF984928E7F2AF018"
#define AliyunSubscribeTopic_user_get "/h54wTCsZDZU/Device_1/user/get"
#define AliyunPublishTopic_user_update "/h54wTCsZDZU/Device_1/user/update"
//#define AliyunSubscribeTopic_post "/sys/h54wTCsZDZU/Device_1/thing/event/property/post"
//#define AliyunSubscribeTopic_post_reply "/sys/h54wTCsZDZU/Device_1/thing/event/property/post_reply"
char mqtt_message[256]={0};
char mqtt_publish_data1[] = "mqtt connect ok ";
char mqtt_publish_data2[] = "mqtt subscribe successful";
char mqtt_publish_data3[] = "mqtt i am esp32";
/*
这是一个用于检查错误代码并打印错误信息的辅助函数。下面是函数的具体解析:
函数接受两个参数:message 是用于描述错误的字符串,error_code 是要检查的错误代码。
函数会检查 error_code 是否为非零值。如果是非零值,表示发生了错误。
如果发生了错误,函数会使用 ESP-IDF 的日志函数打印错误信息。错误信息包括 message 字符串和十六进制表示的错误代码。
如果 error_code 为零,表示没有发生错误,函数不会执行任何操作。
*/
static void log_error_if_nonzero(const char *message, int error_code)
{
if (error_code != 0) {
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
}
}
/*
这是一个用于处理 MQTT 事件的回调函数。下面是函数的具体解析:
函数接受四个参数:handler_args 是回调函数的参数,base 是事件基础类型,event_id 是事件 ID,event_data 是事件数据。
函数会使用 ESP-IDF 的日志函数打印事件基础类型和事件 ID。
根据事件 ID 的不同,函数会执行相应的操作:
如果事件 ID 是 MQTT_EVENT_CONNECTED,表示已连接到 MQTT 服务器。
函数会发布一条主题为 AliyunPublishTopic_user_update,负载为 "mqtt_publish_data1" 的消息,并记录消息的 ID。
如果事件 ID 是 MQTT_EVENT_DISCONNECTED,表示与 MQTT 服务器的连接断开。
如果事件 ID 是 MQTT_EVENT_SUBSCRIBED,表示成功订阅了一个主题。
函数会发布一条主题为 AliyunPublishTopic_user_update,负载为 "mqtt_publish_data2" 的消息,并记录消息的 ID。
如果事件 ID 是 MQTT_EVENT_UNSUBSCRIBED,表示成功取消订阅了一个主题。
如果事件 ID 是 MQTT_EVENT_PUBLISHED,表示成功发布了一条消息。
如果事件 ID 是 MQTT_EVENT_DATA,表示接收到了一条消息。函数会打印主题和消息的内容。
如果事件 ID 是 MQTT_EVENT_ERROR,表示发生了 MQTT 错误。函数会根据错误类型打印相应的错误信息。
如果事件 ID 是其他值,表示其他类型的事件,函数会打印事件 ID。
该回调函数通过检测不同的 MQTT 事件来执行相应的操作。在使用 ESP-IDF 的 MQTT 客户端时,你可以将该回调函数注册为事件处理程序,并在接收到 MQTT 事件时进行相应的处理。例如,在连接到 MQTT 服务器后,你可以在 MQTT_EVENT_CONNECTED 事件中发布消息或者订阅主题,在收到消息时处理 MQTT_EVENT_DATA 事件。这样可以方便地与 MQTT 服务器进行通信和处理消息。*/
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32 "", base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
msg_id = esp_mqtt_client_publish(client, AliyunPublishTopic_user_update, mqtt_publish_data1, strlen(mqtt_publish_data1), 1, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
msg_id = esp_mqtt_client_subscribe(client, AliyunSubscribeTopic_user_get, 0);
ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, AliyunPublishTopic_user_update, mqtt_publish_data2, strlen(mqtt_publish_data2), 0, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
printf("DATA=%.*s\r\n", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));
}
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}
void user_mqtt_app_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.hostname = Aliyun_host,
.broker.address.port = Aliyun_port,
.broker.address.transport = MQTT_TRANSPORT_OVER_TCP,
.credentials.client_id = Aliyun_client_id,
.credentials.username = Aliyun_username,
.credentials.authentication.password = Aliyun_password,
};
client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt_event_handler, client);
esp_mqtt_client_start(client);
}