开源⼀个⼩程序,⽀持蓝⽛配⽹+WiFi双控制ESP32-C3应⽤⽰范;
(附带Demo)
⽂章⽬录
⼀、前⾔
前⾯已经给⼤家带来了如何实现⼩程序WiFi+蓝⽛控制ESP32-C3模组的原理,
借助⼩程序的浪潮,我们再开源⼀波⼲货,这篇给⼤家再开源⼀个⼩程序配⽹的代码;
遵循开源的原则,我们参考以下重要⼲货,感谢开源:
乐鑫蓝⽛配⽹资料:
半颗⼼脏整理资料:
⼆、 Blufi乐鑫⾃研的蓝⽛配⽹协议
BluFi 是⼀款基于蓝⽛通道的 Wi-Fi ⽹络配置功能,适⽤于 ESP32。它通过安全协议将 Wi-Fi 配置和证书传输到 ESP32,然后 ESP32可基于这些信息连接到 AP 或建⽴ SoftAP。
BluFi 流程的关键部分包括数据的分⽚、加密、校验和验证。
⽤户可按需⾃定义⽤于对称加密、⾮对称加密和校验的算法。这⾥我们采⽤ DH 算法进⾏密钥协商、128-AES 算法⽤于数据加密、CRC16 算法⽤于校验和验证。
ESP32 配⽹流程
1. ESP32 开启 GATT Server 功能,发送带有特定 adv data 的⼴播。你可以⾃定义该⼴播,该⼴播不属于 BluFi Profile。
2. 使⽤⼿机 APP 搜索到该特定⼴播,⼿机作为 GATT Client 连接 ESP32。你可以决定使⽤哪款⼿机 APP。
3. GATT 连接建⽴成功后,⼿机向 ESP32 发送“协商过程”数据帧(详情见 BluFi 传输格式 )。
4. ESP32 收到“协商过程”数据帧后,会按照使⽤者⾃定义的协商过程来解
5. 析。
6. ⼿机与 ESP32 进⾏密钥协商。协商过程可使⽤ DH/RSA/ECC 等加密算法进⾏。
7. 协商结束后,⼿机端向 ESP32 发送“设置安全模式”控制帧。
8. ESP32 收到“设置安全模式”控制帧后,使⽤经过协商的共享密钥以及配置的安全策略对通信数据进⾏加密和解密。
9. ⼿机向 ESP32 发送“BluFi 传输格式”定义的 SSID、Password 等⽤于 Wi-Fi 连接的必要信息。
10. ⼿机向 ESP32 发送“Wi-Fi 连接请求”控制帧,ESP32 收到之后,识别为⼿机已将必要的信息传输完毕,准备连接 Wi-Fi。
11. ESP32 连接到 Wi-Fi 后,发送“Wi-Fi 连接状态报告”控制帧到⼿机,以报告连接状态。⾄此配⽹结束。
流程图
三、相关代码
3.1 蓝⽛快速配⽹
这⾥是采⽤上述的BluFi原理做的⼀款⼩程序,效果如下:
功能特性如下:
1. 标准的乐鑫BluFi协议,⽀持ESP32和ESP32-C3模组配⽹,仅⽀持
2.4G频段AP热点连接,⽀持双频路由器配⽹;
2. 跨平台特性,⽆关Android和IOS平台,真正实现⼀套代码多复⽤;
3. 过滤搜索蓝⽛设备,筛选其他⾮BluFi协议的蓝⽛设备,实现快速选择设备配⽹;
3.2 蓝⽛本地控制
1. 乐鑫物联⽹操作框架 esp-idf 的 freeRtos 实时操作系统熟悉,包括任务创建/消息队列/进程间通讯;
2. ⼩程序开发基础,包括MQTT库/低功耗蓝⽛API接⼝使⽤,包括搜索/连接/通讯;
3. 使⽤乐鑫封装 RMT 驱动层单线驱动WS2812B,实现彩虹等效果;
4. 对ESP32/C3芯⽚的外设开发熟悉,对BLE API接⼝使⽤熟悉,包括⾃定义⼴播/名字/⾃定义UUID;
蓝⽛控制代码
设置蓝⽛⼴播名字
esp_ble_gap_set_device_name(TEST_DEVICE_NAME);
设置服务UUID
gl_profile_tab[0].service_id.is_primary = true;
gl_profile_tab[0].service_id.id.inst_id =0x00;
gl_profile_tab[0].service_id.id.uuid.len = ESP_UUID_LEN_16;
gl_profile_tab[0].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A;
主动通知上位机数据发⽣改动:
case ESP_GATTS_READ_EVT:
{
esp_gatt_rsp_t rsp;
memset(&rsp,0,sizeof(esp_gatt_rsp_t));
rsp.attr_value.handle = param->read.handle;
rsp.attr_value.len =3;
rsp.attr_value.value[0]= red;
rsp.attr_value.value[1]= green;
rsp.attr_value.value[2]= blue;
esp_ble_gatts_send_response(gatts_if, param-&_id, param-&ans_id, ESP_GATT_OK,&rsp);
break;
}
上位机主动发送数据到此并做出对应的处理:
case ESP_GATTS_WRITE_EVT:
{
if(!param->write.is_prep)
{
ESP_LOGI(GATTS_TAG,"GATT_WRITE_EVT, value len %d, value :", param->write.len);
esp_log_buffer_hex(GATTS_TAG, param->write.value, param->write.len);
//发送数据到队列
struct __User_data *pTmper;
sprintf(user_data.allData,"{\"red\":%d,\"green\":%d,\"blue\":%d}", param->write.value[0], param->write.value[1], param->write.value[2]);            pTmper =&user_data;
user_data.dataLen =strlen(user_data.allData);
xQueueSend(ParseJSONQueueHandler,(void*)&pTmper, portMAX_DELAY);
ESP_LOGI(GATTS_TAG,"%02x %02x %02x ", param->write.value[0], param->write.value[1], param->write.value[2]);
}
example_write_event_env(gatts_if,&a_prepare_write_env, param);
break;
}
WiFi控制代码
设置MQTT远程连接的参数
/*
* @Description: MQTT参数连接的配置
* @param:
* @return:
*/
void TaskXMqttRecieve(void*p)
{
//连接的配置参数
esp_mqtt_client_config_t mqtt_cfg ={
.host ="www.xuhong",//连接的域名,请务必修改为您的
.port =1883,//端⼝,请务必修改为您的
.username ="admin",//⽤户名,请务必修改为您的
.password ="xuhong123456",//密码,请务必修改为您的
.
client_id = deviceUUID,
.event_handle = MqttCloudsCallBack,//设置回调函数
.keepalive =120,//⼼跳
.disable_auto_reconnect = false,//开启⾃动重连
.disable_clean_session = false,//开启清除会话
};
client =esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_start(client);
vTaskDelete(NULL);
}
服务器下发的处理数据,送往消息队列处理:
/
/服务器下发消息到本地成功接收回调
case MQTT_EVENT_DATA:
{
printf("TOPIC=%.*s \r\n", event->topic_len, event->topic);
printf("DATA=%.*s \r\n\r\n", event->data_len, event->data);
//发送数据到队列
struct __User_data *pTmper;
sprintf(user_data.allData, "%s", event->data);
pTmper = &user_data;
user_data.dataLen = event->data_len;
xQueueSend(ParseJSONQueueHandler, (void *)&pTmper, portMAX_DELAY);
break;
}
2.3 外设驱动
七彩灯WS2812B的驱动代码初始化:
/**
* @description:  封装⼀层设置RGB灯效果
* @param {uint16_t} Red ⼊参红⾊
* @param {uint16_t} Green ⼊参绿⾊
* @param {uint16_t} Blue ⼊参蓝⾊
* @return {*}
*/
void set_rgb(uint16_t Red, uint16_t Green, uint16_t Blue)
{
for(int i =0; i <24; i++)
{
strip->set_pixel(strip, i, Red, Green, Blue);
}
red = Red;
green = Green;开源mqtt服务器
blue = Blue;
strip->refresh(strip,10);
}
/
**
* @description: 初始化LED
* @param {*}
* @return {*}
*/
void init_led()
{
rmt_config_t config =RMT_DEFAULT_CONFIG_TX(4, RMT_TX_CHANNEL);
// set counter clock to 40MHz
config.clk_div =2;
ESP_ERROR_CHECK(rmt_config(&config));
ESP_ERROR_CHECK(rmt_driver_install(config.channel,0,0));
// install ws2812 driver
led_strip_config_t strip_config =LED_STRIP_DEFAULT_CONFIG(24,(led_strip_dev_t)config.channel);    strip =led_strip_new_rmt_ws2812(&strip_config);
if(!strip)
{
ESP_LOGE(TAG,"install WS2812 driver failed");
}
// Clear LED strip (turn off all LEDs)
ESP_ERROR_CHECK(strip->clear(strip,100));
set_rgb(0,254,0);
}
消息队列处理逻辑:
/*
* @Description: 解析下发数据的队列逻辑处理
* @param: null
* @return:
*/
void Task_ParseJSON(void*pvParameters)
{
printf("[SY] Task_ParseJSON_Message creat ... \n");
while(1)
{
struct __User_data *pMqttMsg;
printf("Task_ParseJSON_Message xQueueReceive wait [%d] ... \n",esp_get_free_heap_size());
xQueueReceive(ParseJSONQueueHandler,&pMqttMsg, portMAX_DELAY);
printf("Task_ParseJSON_Message xQueueReceive get [%s] ... \n", pMqttMsg->allData);
⾸先整体判断是否为⼀个json格式的数据
cJSON *pJsonRoot =cJSON_Parse(pMqttMsg->allData);
//如果是否json格式数据
if(pJsonRoot ==NULL)
{
printf("[SY] Task_ParseJSON_Message xQueueReceive not json ... \n");
goto __cJSON_Delete;
}
cJSON *pJSON_Item_Red =cJSON_GetObjectItem(pJsonRoot,"red");
cJSON *pJSON_Item_Green =cJSON_GetObjectItem(pJsonRoot,"green");
cJSON *pJSON_Item_Blue =cJSON_GetObjectItem(pJsonRoot,"blue");
set_rgb(pJSON_Item_Red->valueint, pJSON_Item_Green->valueint, pJSON_Item_Blue->valueint);
__cJSON_Delete:
cJSON_Delete(pJsonRoot);
}
}
⼩程序核⼼代码
代码架构,UI主要采⽤第三⽅库:有 WeUI、Vant-UI库,其中的MQTT库采⽤开源的MQTT.JS库。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。