git地址:智能门禁(云IOT+微信小程序)
开关门效果
设备侧
产品创建
创建产品
创建产品,协议类型选择MQTT,数据格式选择JSON,其他参数自定
设备注册
找到所属产品,认证类型选择密钥,单击确定后注册成功
注册成功后出现如下页面,点击保存并关闭,会自动下载好"device_id"和"secret",保存好
模型定义
产品->选择你的产品->查看->模型定义->自定义模型->定义产品的服务
添加属性,定义好一系列参数点击确定
可参考技术文档 在线开发产品模型
添加命令,添加好下发参数和响应参数
产品连接
头文件包含
#include<WiFiMulti.h>
#include<Arduino.h>
#include<WebServer.h>
#include<PubsubClient.h>
#include<ArduinoJson.h>
静态参数定义
const char* wifiName = "";//ESP32连接的WiFi名称
const char* wifiPwd = "";//wifi密码
const char* mqttServer = "cdee1c2246.iot-mqtts.cn-north-4.myhuaweicloud.com";//华为云MQTT接入地址
const int mqtt = 1883;//端口
//下面三个参数为设备接入华为云iot的鉴权参数
const char* clientID = "";
const char* userName = "";
const char* passWord = "";
华为云接入地址可在总览->平台接入地址中查看
鉴权参数通过参数生成工具生成 MQTT ClientId生成工具
topic参数定义
topic参数在产品->选择要查看的产品->topic管理可查看
{device_id}需要替换为设备ID
const char* topic_report = "$oc/devices/6346a83e06cae4010b4d1387_esp32_door/sys/properties/report";//设备上报
const char* topic_command = "$oc/devices/6346a83e06cae4010b4d1387_esp32_door/sys/commands/#";//设备接收命令
const char* topic_command_response = "$oc/devices/6346a83e06cae4010b4d1387_esp32_door/sys/commands/response/request_id=";//设备发送响应
WIFI连接和MQTT连接
void WifiSetup()
{
wifiMulti.addAP(wifiName,wifiPwd);//wifi连接
Serial.print("connecting to:");
Serial.println(WiFi.SSID());//打印wifi名称
while(wifiMulti.run() != WL_CONNECTED)
{
delay(1000);
Serial.print(".");
}
Serial.println("connection success!");
Serial.println("IP address:");
Serial.println(WiFi.localIP());
}
void MQTT_Init()
{
client.setServer(mqttServer,mqtt);//设置mqtt服务器参数
client.setKeepAlive(60);//设置心跳时间
while(!client.connected())
{
Serial.println("Connecting to MQTT...");
if(client.connect(clientID,userName,passWord))//和华为云iot服务器建立mqtt连接
{
Serial.println("connected");
}else{
Serial.print("failed with state:");
Serial.print(client.state());
}
}
client.setCallback(callback);//监听平台下发命令
}
在callback函数定义需要的服务
属性上报和命令响应
属性上报
可参考技术文档 https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html
时间戳可有可无,设备上报数据不带该参数或参数格式错误时,则数据上报时间以平台时间为准
修改完成后使用ArduinoJSON官网生成代码 ArduinoJson
选择ESP32->序列化->String
修改后的JSON数据如下,根据参数不同自行修改
属性上报详细代码如下
void MQTT_Report()
{
String JSONmessageBuffer;//定义字符串接收序列化好的JSON数据
//以下将生成好的JSON格式消息格式化输出到字符数组中,便于下面通过PubSubClient库发送到服务器
StaticJsonDocument<96> doc;
JsonObject services_0 = doc["services"].createNestedObject();
services_0["service_id"] = "door";
services_0["properties"]["doorState"] = doorState;//doorState为全局变量
serializeJson(doc, JSONmessageBuffer);
Serial.println("Sending message to MQTT topic..");
Serial.println(JSONmessageBuffer);
if(client.publish(topic_report,JSONmessageBuffer.c_str())==true)//使用c_str函数将string转换为char
{
Serial.println("Success sending message");
}else{
Serial.println("Error sending message");
}
client.loop();//保持硬件活跃度
Serial.println("---------------");
}
命令下发
在产品模型中定义了命令下发和响应参数,就可以通过iot平台对设备下发命令,设备接收命令后按JSON格式像平台发送响应,平台收到响应后才确认下发成功
可参考技术文档 平台命令下发
const char* topic_command = "$oc/devices/6346a83e06cae4010b4d1387_esp32_door/sys/commands/#";//设备接收命令
const char* topic_command_response = "$oc/devices/6346a83e06cae4010b4d1387_esp32_door/sys/commands/response/request_id=";//设备发送响应
响应参数需要将request_id参数返回给平台,所以需要在callback函数中将平台下发的request_id提取出来
在下发命令中request_id可以使用通配符#代替,但是响应中的request_id必须与下发命令的request_id一致
上文定义的callback函数在此实现
需要提取request_id,打印JSON数据,对下发命令做出对应的硬件处理
void callback(char *topic,byte *payload,unsigned int length)
{
char *pstr = topic; //指向topic字符串,提取request_id用
/*串口打印出收到的平台消息或者命令*/
Serial.println();
Serial.println();
Serial.print("Message arrived [");
Serial.print(topic); //将收到消息的topic展示出来
Serial.print("] ");
Serial.println();
payload[length] = '\0'; //在收到的内容后面加上字符串结束符
char strPayload[255] = {0};
strcpy(strPayload, (const char*)payload);
Serial.println((char *)payload); //打印出收到的内容
Serial.println(strPayload);
/*request_id解析部分*///后文有详细解释为什么要提取下发命令的request_id
char arr[100]; //存放request_id
int flag = 0;
char *p = arr;
while(*pstr) //以'='为标志,提取出request_id
{
if(flag) *p ++ = *pstr;
if(*pstr == '=') flag = 1;
pstr++;
}
*p = '\0';
Serial.println(arr);
/*将命令响应topic与resquest_id结合起来*/
char topicRes[200] = {0};
strcat(topicRes, topic_command_response);
strcat(topicRes, arr);
Serial.println(topicRes);
// Stream& input;
StaticJsonDocument<192> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
return;
}
int paras_doorOpen = doc["paras"]["doorOpen"]; // 1
const char* service_id = doc["service_id"]; // "door"
const char* command_name = doc["command_name"]; // "doorControl"
if(paras_doorOpen == 1)
{
openDoor();//对应的硬件响应函数
delay(5000);
ledcWrite(channel, calculatePWM(0));
}if (paras_doorOpen == 0)
{
closeDoor();
}
MQTT_response(topicRes);//发送响应参数
}
内容根据具体需求修改
MQTT.fx
下载和详细操作可以查看文档,这里只做简单使用
使用MQTT.fx调测
可以使用MQTT.fx工具查看下发命令对应的JSON数据
点击apply
通过iot控制台 产品->选择你的产品->命令->同步命令下发
即可通过MQTT.fx工具查看到下发命令的JSON数据
复制到ArduinoJSON官网解析数据 ArduinoJson
选择ESP32->反序列化->Stream
命令响应
参考技术文档 平台命令下发
由于三个参数都是可选的,所以直接返回空JSON也是可以的
void MQTT_response(char *topic)
{
String response;
StaticJsonDocument<128> doc;
JsonObject response = doc.createNestedObject("response");
doc["result_code"] = 0;
doc["response_name"] = "doorControl";
doc["paras"]["doorRes"] = "1";
serializeJson(doc, response);
client.publish(topic,response.c_str());
Serial.println(response);
}
物理层面
使用舵机拉动门把手,延迟后归为即可实现简易的智能门禁系统
舵机控制
舵机是伺服电机的一种,伺服电机就是带有反馈环节的电机,我们可以通过伺服电机进行精确的位置控制或者输出较高的扭矩;
一般舵机的旋转范围是0°~ 180°。舵机是由可变宽度的脉冲控制。脉冲的参数有最小值、最大值和频率。一般而言,舵机的基准信号周期为20ms,所以频率为50kHz。脉冲宽度和舵机的转角0°~ 180°相对应的。
这里使用的是180°舵机MG995,如果门把手很难拉动,需要更换扭矩更大的舵机。
PWM信号线可以连接GPIO口上,具体可查看ESP32手册,这里接的是16IO口
代码如下
int freq = 50; // 频率(20ms周期)
int channel = 8; // 通道(高速通道(0 ~ 7)由80MHz时钟驱动,低速通道(8 ~ 15)由 1MHz 时钟驱动。)
int resolution = 8; // 分辨率
const int led = 16;
int calculatePWM(int degree)
{ //0-180度
//20ms周期,高电平0.5-2.5ms,对应0-180度角度
const float deadZone = 6.4;//对应0.5ms(0.5ms/(20ms/256)) 舵机转动角度与占空比的关系:(角度/90+0.5)*1023/20
const float max = 32;//对应2.5ms
if (degree < 0)
degree = 0;
if (degree > 180)
degree = 180;
return (int)(((max - deadZone) / 180) * degree + deadZone);
}
void closeDoor()
{
ledcWrite(channel, calculatePWM(0));
}
void openDoor()
{
ledcWrite(channel, calculatePWM(180));
}
接下来只需在callback函数中增加硬件响应函数,这里是对平台下发的doorOpen做判断
if(paras_doorOpen == 1)
{
openDoor();//对应的硬件响应函数
delay(5000);
ledcWrite(channel, calculatePWM(0));
}else if (paras_doorOpen == 0)
{
closeDoor();
}
应用侧
使用http请求调用API实现应用侧的开发
微信小程序
新建小程序
不使用云服务->JavaScript
删除模板文件pages->新建一个page->输入名称->回车自动生成4个配置文件
获取Token
Token在计算机系统中代表令牌(临时)的意思,拥有Token就代表拥有某种权限。Token认证就是在调用API的时候将Token加到请求消息头,从而通过身份认证,获得操作API的权限。
详情可查看文档 认证鉴权
wx.request方法
wx.request({
url: '',
data:'',
method: '', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
header: {}, // 设置请求的 header
success: function(res){// success
// success
},
fail:function(){
// fail
},
complete: function() {
// complete
}
});
包装request方法为gettoken方法
gettoken:function(){
var that=this;
wx.request({
url: '',
data:'',
method: '', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
header: {}, // 设置请求的 header
success: function(res){// success
// success
},
fail:function(){
// fail
},
complete: function() {
// complete
}
});
},
补全请求体
gettoken:function(){
var that=this;
wx.request({
url: 'https://iam.cn-north-4.myhuaweicloud.com/v3/auth/tokens',
data:'{ "auth": { "identity": { "methods":[ "password" ], "password": { "user": { "name": "hw82982217", "password": "", "domain": { "name": "hw82982217" } } } }, "scope": { "project": { "name": "cn-north-4" } } } }',
method: 'POST', // OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, CONNECT
header: {'Content-Type': 'application/json'}, // 设置请求的 header
success: function(res){// success
// success
var token='';
console.log(res);
token=JSON.stringify(res.header['X-Subject-Token']);//解析Token
token=token.replaceAll("\"","");
console.log("获取token=\n"+token);
that.settoken(token);
},
fail:function(){
// fail
},
complete: function() {
// complete
}
});
},
API Explorer调试
获取IAM用户Token(使用密码)
设置好参数->点击调试->可以看到响应头的Token
传出Token
settoken:function(_token){
this.data.token=_token;
wx.setStorageSync('token', _token);//将Token保存到缓存中
console.log('外部获取到token:'+this.data.token);
this.setData({result:"token认证成功"});
},
命令下发
issuecom1:function(){
var that=this;
var token=wx.getStorageSync('token');
wx.request({
url: 'https://cdee1c2246.iotda.cn-north-4.myhuaweicloud.com:443/v5/iot/0ab004b22500f4b72fa3c00977112a06/devices/6346a83e06cae4010b4d1387_esp32_door/commands',
data:'{"service_id": "door","command_name": "doorControl","paras": {"doorOpen": "1"} }',
method:'POST',
header:{"X-Auth-Token": token,"Content-Type": "application/json"},
success:function(res){
console.log("成功\n");
console.log(res);
},
fail:function(){
console.log("失败");
},
})
},
//关门
issuecom0:function(){
var that=this;
var token=wx.getStorageSync('token');
wx.request({
url: 'https://cdee1c2246.iotda.cn-north-4.myhuaweicloud.com:443/v5/iot/0ab004b22500f4b72fa3c00977112a06/devices/6346a83e06cae4010b4d1387_esp32_door/commands',
data:'{"service_id": "door","command_name": "doorControl","paras": {"doorOpen": "0"} }',
method:'POST',
header:{"X-Auth-Token": token,"Content-Type": "application/json"},
success:function(res){
console.log("成功\n");
console.log(res);
},
fail:function(){
console.log("失败");
},
})
},
页面设计
为界面添加两个按钮
设置相应的响应函数文章来源:https://www.toymoban.com/news/detail-425739.html
文章来源地址https://www.toymoban.com/news/detail-425739.html
到了这里,关于详细!基于ESP32的智能门禁系统(华为云iot+微信小程序)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!