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方式 ↩︎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/bicheng/83744.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习习题3

1.训练神经网络过程中&#xff0c;损失函数在一些时期&#xff08;Epoch&#xff09;不再减小, 原因可能是&#xff1a; 1.学习率太低 2.正则参数太大 3.卡在了局部最小值 A1 and 2 B. 2 and 3 C. 1 and 3 D. 都是 2.对于分类任务&#xff0c;我们不是将神经网络中的随机权重…

【EasyExcel】导出时添加页眉页脚

一、需求 使用 EasyExcel 导出时添加页眉页脚 二、添加页眉页脚的方法 通过配置WriteSheet或WriteTable对象来添加页眉和页脚。以下是具体实现步骤&#xff1a; 1. 创建自定义页眉页脚实现类 public class CustomFooterHandler implements SheetWriteHandler {private final…

c++ 类型转换函数

测试代码&#xff1a; void testTypeTransfer() { // 测试类型转换函数class Distance {private:int meters;public:// 类型转换函数&#xff0c;int表示转化为int类型operator int() {std::cout << "调用了类型转换函数" << endl;return meters; }Dist…

Conda 基本使用命令大全

Conda 基本使用命令大全 Conda 是一个开源的包管理和环境管理系统&#xff0c;广泛用于 Python 开发、数据科学和机器学习。以下是 最常用的 Conda 命令&#xff0c;涵盖环境管理、包安装、配置等核心操作。 1. 环境管理 创建环境 conda create --name myenv # 创…

基于SpringBoot和PostGIS的OSM时空路网数据入库实践

目录 前言 一、空间表的设计 1、属性信息 2、空间表结构设计 二、路网数据入库 1、实体类设计 2、路网数据写入 3、pgAdmin数据查询 三、总结 前言 在当今数字化时代&#xff0c;随着信息技术的飞速发展&#xff0c;地理空间数据的应用范围越来越广泛&#xff0c;尤其是…

代付入账是什么意思?怎么操作?

代付入账就是指商户委托银行通过企业银行账户向指定持卡人账户划付款项&#xff0c;款项划入指定账户即为入账。 具体操作流程如下&#xff1a; 1. 向第三方支付公司指定账户充值加款。 2. 通过操作后台提交代付银行卡信息。 3. 第三方支付公司受理业务申请。 4. 第三方审…

数学复习笔记 27

前言 太难受了。因为一些事情。和朋友倾诉了一下&#xff0c;也没啥用&#xff0c;几年之后不知道自己再想到的时候&#xff0c;会怎么考虑呢。另外&#xff0c;笔记还是有框架一点比较好&#xff0c;这样比较有逻辑感受。不然太乱了。这篇笔记是关于线代第五章&#xff0c;特…

第四十五天打卡

知识点回顾&#xff1a; tensorboard的发展历史和原理 tensorboard的常见操作 tensorboard在cifar上的实战&#xff1a;MLP和CNN模型 效果展示如下&#xff0c;很适合拿去组会汇报撑页数&#xff1a; 作业&#xff1a;对resnet18在cifar10上采用微调策略下&#xff0c;用tensor…

使用高斯朴素贝叶斯算法对鸢尾花数据集进行分类

高斯朴素贝叶斯算法通常用于特征变量是连续变量&#xff0c;符合高素分布的情况。 使用高斯朴素贝叶斯算法对鸢尾花数据集进行分类 """ 使用高斯贝叶斯堆鸢尾花进行分类 """ #导入需要的库 from sklearn.datasets import load_iris from skle…

【docker】Windows安装docker

环境及工具&#xff08;点击下载&#xff09; Docker Desktop Installer.exe &#xff08;windows 环境下运行docker的一款产品&#xff09; wsl_update_x64 &#xff08;Linux 内核包&#xff09; 前期准备 系统要求2&#xff1a; Windows 11&#xff1a;64 位系统&am…

量化Quantization初步之--带量化(QAT)的XOR异或pyTorch版250501

量化(Quantization)这词儿听着玄&#xff0c;经常和量化交易Quantitative Trading (量化交易)混淆。 其实机器学习(深度学习)领域的量化Quantization是和节约内存、提高运算效率相关的概念&#xff08;因大模型的普及&#xff0c;这个量化问题尤为迫切&#xff09;。 揭秘机器…

【Redis】zset 类型

zset 一. zset 类型介绍二. zset 命令zaddzcard、zcountzrange、zrevrange、zrangebyscorezpopmax、zpopminzrank、zrevrank、zscorezrem、zremrangebyrank、zremrangebyscorezincrby阻塞版本命令&#xff1a;bzpopmax、bzpopmin集合间操作&#xff1a;zinterstore、zunionstor…

Mermaid 绘图--以企业权限视图为例

文章目录 一、示例代码二、基础结构设计2.1 组织架构树2.2 权限视图设计 三、销售数据权限系统四、关键语法技巧汇总 一、示例代码 在企业管理系统开发中&#xff0c;清晰的权限视图设计至关重要。本文将分享如何使用 Mermaid 绘制直观的企业权限关系图&#xff0c;复制以下代…

[pdf、epub]300道《软件方法》强化自测题业务建模需求分析共257页(202505更新)

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 在本账号CSDN资源下载&#xff0c;或者访问链接&#xff1a; http://www.umlchina.com/url/quizad.html 如果需要提取码&#xff1a;umlc 文件夹中的“300道软件方法强化自测题2025…

std__map,std__unordered_map,protobuf__map之间的性能比较

简单比较下 std::map、std::unordered_map 和 protobuf::Map 的性能&#xff0c;主要关注在 插入、查找 和 删除 操作上的效率以及内存管理的差异。 std::map 底层实现&#xff1a;std::map 使用红黑树作为底层数据结构&#xff0c;红黑树是一种平衡二叉查找树的变体结构&…

文档处理组件Aspose.Words 25.5全新发布 :六大新功能与性能深度优化

在数字化办公日益普及的今天&#xff0c;文档处理的效率与质量直接影响到企业的运营效率。Aspose.Words 作为业界领先的文档处理控件&#xff0c;其最新发布的 25.5 版本带来了六大新功能和多项性能优化&#xff0c;旨在为开发者和企业用户提供更强大、高效的文档处理能力。 六…

Three.js + Vue3 加载GLB模型项目代码详解

本说明结合 src/App.vue 代码,详细解释如何在 Vue3 项目中用 three.js 加载并显示 glb 模型。 1. 依赖与插件导入 import {onMounted, onUnmounted } from vue import * as THREE from three import Stats from stats.js import {OrbitControls } from three/examples/jsm/co…

Flutter如何支持原生View

在 Flutter 中集成原生 View&#xff08;如 Android 的 SurfaceView、iOS 的 WKWebView&#xff09;是通过 平台视图&#xff08;Platform View&#xff09; 实现的。这一机制允许在 Flutter UI 中嵌入原生组件&#xff0c;解决了某些场景下 Flutter 自身渲染能力的不足&#x…

vue-11(命名路由和命名视图)

命名路由和命名视图 命名路由和命名视图提供了组织和导航 Vue.js 应用程序的强大方法&#xff0c;尤其是在它们的复杂性增加时。它们提供了一种语义更合理、可维护的路由方法&#xff0c;使您的代码更易于理解和修改。命名路由允许您按名称引用路由&#xff0c;而不是依赖 URL…

微软认证考试科目众多?该如何选择?

在云计算、人工智能、数据分析等技术快速发展的今天&#xff0c;微软认证&#xff08;Microsoft Certification&#xff09;已成为IT从业者、开发者、数据分析师提升竞争力的重要凭证。但面对众多考试科目&#xff0c;很多人不知道如何选择。本文将详细介绍微软认证的考试方向、…