当前位置: 首页 > news >正文

ESP32对接巴法云实现配网

目录

    • 序言
    • 准备工作
      • 巴法云注册与使用
      • Arduino准备
    • 开发
    • 开始配网

序言

本文部分内容摘抄原创作者巴法云-做优秀的物联网平台
代码有部分修改并测试运行正常

巴法云支持免费用户通过开发对接实现各智能音箱设备语音控制智能家居设备,并有自己的App进行配网和控制,在开发过程中省去了很多工作,推荐大家使用

巴法云关于个人开发者使用描述

准备工作

巴法云注册与使用

巴法云开发者文档
进入巴法云
下载App
首先需要在巴法云注册用户。
注册完成之后下载App并登录
至此巴法云准备工作就完成啦

Arduino准备

本次开发基于Arduino
请移步ESP32入门之arduino IDE环境搭建 1
或转载

开发

以下是实现的具体配网流程代码

//需要在arduino IDE软件中---工具-->管理库-->搜索arduinojson并安装
#include <WiFi.h>
#include <WiFiUDP.h>
#include <ArduinoJson.h>
#include <EEPROM.h>
#include <Ticker.h>
#include <HTTPClient.h>//根据需要修改的信息
String aptype = "009";   //设备类型,001插座设备,002灯类设备,003风扇设备,005空调,006开关,009窗帘
String Name = "窗帘";    //设备昵称,可随意修改
String verSion = "3.1";  //3是tcp设备端口8344,1是MQTT设备
String room = "卧室";    //房间。例如客厅、卧室等,默认空
int protoType = 3;       //3是tcp设备端口8344,1是MQTT设备
int adminID = 0;         //默认空即可。企业id,建议企业用户配置,该设备会自动绑定到该企业下,获取id方法见接入文档5.17节
WiFiClient client_bemfa_WiFiClient;
HTTPClient http_bemfa_HTTPClient;//检测是否是第一次连接WIFI
bool firstWIfiConfig = false;
String topic = "";
struct config_type {char stassid[32];char stapsw[16];char cuid[40];char ctopic[32];uint8_t reboot;uint8_t magic;
};
config_type config;char config_flag = 0;      //判断是否配网
#define MAGIC_NUMBER 0xAA  //判断是否配网
char packetBuffer[255];    //发送数据包
WiFiUDP Udp;/** 从EEPROM加载参数
*/
uint8_t* p = (uint8_t*)(&config);
void loadConfig() {uint8_t mac[6];Serial.println(" LoadConfig.......");WiFi.macAddress(mac);EEPROM.begin(512);for (int i = 0; i < sizeof(config); i++) {*(p + i) = EEPROM.read(i);}config.reboot = config.reboot + 1;if (config.reboot >= 4) {restoreFactory();}if (config.magic != 0xAA) {config_flag = 1;}EEPROM.begin(512);for (int i = 0; i < sizeof(config); i++) {EEPROM.write(i, *(p + i));}EEPROM.commit();delay(2000);Serial.println("loadConfig Over");EEPROM.begin(512);config.reboot = 0;for (int i = 0; i < sizeof(config); i++) {EEPROM.write(i, *(p + i));}EEPROM.commit();
}/* * 恢复出厂设置
*/
void restoreFactory() {Serial.println("\r\n Restore Factory....... ");config.magic = 0x00;strcpy(config.stassid, "");strcpy(config.stapsw, "");strcpy(config.cuid, "");strcpy(config.ctopic, "");config.magic = 0x00;saveConfig();delayRestart(1);
}
/*
保存WIFI信息
*/
void saveConfig() {config.reboot = 0;EEPROM.begin(512);  // 与loadConfig统一为512字节(足够存储config结构体)uint8_t* p = (uint8_t*)(&config);for (int i = 0; i < sizeof(config); i++) {EEPROM.write(i, *(p + i));}EEPROM.commit();
}
Ticker delayTimer;
void delayRestart(float t) {delayTimer.attach(t, []() {ESP.restart();});
}
void apConfig(String mac) {if (config_flag == 1) {WiFi.softAP("bemfa_" + mac);Udp.begin(8266);Serial.println("Started Ap Config...");}topic = mac + aptype;// Removed blocking while loop
}/*第一次配网检查WIFI,保存WIFI配置信息,并创建主题
*/
void checkFirstConfig() {if (firstWIfiConfig) {// 设置目标 URLhttp_bemfa_HTTPClient.begin(client_bemfa_WiFiClient, "http://pro.bemfa.com/vs/web/v1/deviceAddTopic");// 创建 JSON 对象StaticJsonDocument<200> jsonDoc;jsonDoc["uid"] = config.cuid;jsonDoc["name"] = Name;jsonDoc["topic"] = topic;jsonDoc["type"] = protoType;jsonDoc["room"] = room;jsonDoc["adminID"] = adminID;jsonDoc["wifiConfig"] = 1;  //必填字段// 将 JSON 对象转换为字符串String jsonString;serializeJson(jsonDoc, jsonString);http_bemfa_HTTPClient.addHeader("Content-Type", "application/json; charset=UTF-8");// 发送请求int httpCode = http_bemfa_HTTPClient.POST(jsonString);if (httpCode == 200) {Serial.println("POST succeeded with code:");Serial.println(httpCode);String payload = http_bemfa_HTTPClient.getString();Serial.println(payload);//json数据解析StaticJsonDocument<200> doc;DeserializationError error = deserializeJson(doc, payload);if (error) {Serial.print(F("deserializeJson() failed: "));Serial.println(error.c_str());}int code = doc["code"];if (code == 0) {int resCode = doc["data"]["code"];if (resCode == 40006 || resCode == 0) {String docUID = doc["uid"];Serial.print("create topic ok:");Serial.println(topic);if (firstWIfiConfig) {config.reboot = 0;config.magic = 0xAA;saveConfig();}} else {Serial.println(" config ERROR.........");}} else {Serial.println(" config ERROR.........");}} else if (httpCode != 200) {Serial.println("POST failed with code:");Serial.println(httpCode);} else {Serial.println("Unknown error");}http_bemfa_HTTPClient.end();}
}// 复位或上电后运行一次:
void setup() {//在这里加入初始化相关代码,只运行一次:Serial.begin(115200);String mac = WiFi.macAddress();mac.replace(":", "");                            //去掉:号topic = mac.substring(8) + aptype; //取mac地址的后半部分做主题用,并拼接设备类型// 初始化WiFi模式以确保MAC地址正确获取(关键修改)WiFi.mode(WIFI_STA);  // 设置为STA模式初始化硬件delay(1000);           // 等待WiFi模块初始化完成// 初始化配网(此时可正确获取MAC地址)mac = WiFi.macAddress();mac.replace(":", "");loadConfig();                                      //加载存储的数据apConfig(mac);                                   //加载ap// Only try to connect to WiFi if not in config modeif (config_flag == 0) {Serial.println("Connecting to WiFi...");WiFi.disconnect();                          //断开连接WiFi.mode(WIFI_STA);                        //STA模式WiFi.begin(config.stassid, config.stapsw);  //连接路由器// Removed blocking while loop here}
}//一直循环执行:
void loop() {if (config_flag == 1) { // If in config mode, handle UDP packetsint packetSize = Udp.parsePacket();if (packetSize) {Serial.print("Received packet of size ");Serial.println(packetSize);Serial.print("From ");IPAddress remoteIp = Udp.remoteIP();Serial.print(remoteIp);Serial.print(", port ");Serial.println(Udp.remotePort());int len = Udp.read(packetBuffer, 255);if (len > 0) {packetBuffer[len] = 0;}Serial.println("Contents:");Serial.println(packetBuffer);StaticJsonDocument<200> doc;DeserializationError error = deserializeJson(doc, packetBuffer);if (error) {Serial.print(F("deserializeJson() failed: "));Serial.println(error.f_str());return;}int cmdType = doc["cmdType"].as<int>();if (cmdType == 1) {const char* ssid = doc["ssid"];const char* password = doc["password"];const char* token = doc["token"];strcpy(config.stassid, ssid);strcpy(config.stapsw, password);strcpy(config.cuid, token);//收到信息,并回复String ReplyBuffer = "{\"cmdType\":2,\"productId\":\"" + topic + "\",\"deviceName\":\"" + Name + "\",\"protoVersion\":\"" + verSion + "\"}";const char* replyBufferData = ReplyBuffer.c_str();size_t replyBufferLength = ReplyBuffer.length();Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());Udp.write((const uint8_t*)replyBufferData, replyBufferLength);Udp.endPacket();} else if (cmdType == 3) {config_flag = 0;firstWIfiConfig = true;// 彻底停止UDP并清理网络资源Udp.stop();WiFi.disconnect(true);  // 强制断开所有连接(包括AP和STA)WiFi.mode(WIFI_OFF);    // 关闭所有WiFi模式delay(1500);            // 延长等待时间确保硬件完成释放// 切换为STA模式并连接WiFi(添加连接前的参数校验)Serial.println("Connecting to WiFi after provisioning...");if (strlen(config.stassid) == 0 || strlen(config.stapsw) == 0) {Serial.println("Error: SSID or password is empty");return;}WiFi.mode(WIFI_STA);WiFi.begin(config.stassid, config.stapsw);// 等待连接结果(设置超时避免永久阻塞)unsigned long start = millis();while (WiFi.status() != WL_CONNECTED && (millis() - start) < 15000) {delay(100);}if (WiFi.status() == WL_CONNECTED) {Serial.printf("Connected to %s, IP: %s\n", config.stassid, WiFi.localIP().toString().c_str());checkFirstConfig();} else {Serial.println("WiFi connection failed (timeout)");}}}} else { // If not in config mode, run normal operation// Your normal device operation code goes here// Serial.println("Config success"); // This will print repeatedly, move to setup or only print once// Removed delay(1000)}
}

代码中的aptype与Name变量将是你在配往后自动添加的设备类型与名称
代码中的protoType参数将会控制您在巴法云建立MQTT主题还是TCP主题,根据智能家居类型自行配置
自行烧录哦,如不会烧录请查询官方文档

开始配网

第一次开机后硬件会检查是否已配置网络,没有配置将会打开WiFi热点,名称为bemfa_mac地址

  1. 连接ESP32需要连接的WiFi不是ESP32的WiFi哦
  2. 打开巴法App-右上角+号或微信小程序搜索巴法,找到一键配网小程序
  3. 进入配网页面,切换协议为AP配网,小程序为Soft AP 配网
  4. WiFi名称会自动填写你当前连接的WiFi,输入WiFi密码,点击开始配网
  5. 此时会提示您连接到设备WiFi,点击打开设置,在WiFi界面连接bemfa开头的WiFi
  6. 回到App或小程序,此时将开始配网流程,硬件接收到信息后开始连接目标WiFi
  7. 连接成功后会在用户的巴法云控制台建立硬件主题,主题一般为:硬件mac地址+设备类型
  8. App或小程序检测到主题创建成功,代表配网结束,在App中就可以看到该设备啦

至此,配网功能结束
当然,该文章仅为使用巴法云方式实现配网功能,开发者也可以通过代码逻辑,来建立自己的MQTT服务,进行自己的个人后端开发,实现家庭智能


  1. ESP32-C6接入巴法云,Arduino方式 ↩︎

相关文章:

  • IntelliJ IDEA 中进行背景设置
  • Python使用
  • 【工作笔记】 WSL开启报错
  • 参数化建模(三):SOLIDWORKS中的参数化应用实例
  • docker部署自动化测试环境笔记
  • (21)量子计算对密码学的影响
  • Redis持久化机制
  • 力扣HOT100之动态规划:322. 零钱兑换
  • 【大模型】情绪对话模型项目研发
  • 区域未停留检测算法AI智能分析网关V4打造铁道/工厂/机场等场景应用方案
  • 2025 年 Solana 生态全景分析:它如何从以太坊「高速替代方案」成长为成熟的基础设施?
  • 换ip是换网络的意思吗?怎么换ip地址
  • write和read命令中的通道号指南
  • 使用Vditor将Markdown文档渲染成网页(Vite+JS+Vditor)
  • LangChain第二页_【教程】翻译完了
  • 将Kotti从Pyramid1.0升级到2.0 (失败的记录)
  • 【Linux 基础知识系列】第三篇-Linux 基本命令
  • JavaScript 变量声明:var vs let vs const详情
  • 如何使用windows下的vscode连接到本地虚拟机的linux
  • 数据库概念
  • 企业做网站的好处是什么/网络广告策划案例
  • 个人网站建设公司/免费行情软件网站大全
  • 自己做网站 有名/正规软件开发培训学校
  • 设计网站页面/免费个人网站申请
  • 日本做外贸网站设计/百度网站域名
  • 网站设计公司有哪些/百度推广广告收费标准