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管理可查看
{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=";//设备发送响应
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工具查看下发命令对应的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认证就是在调用API的时候将Token加到请求消息头,从而通过身份认证,获得操作API的权限。
详情可查看文档 认证鉴权
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: '',
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
}
});
},
获取IAM用户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("失败");
},
})
},
为界面添加两个按钮
设置相应的响应函数
文章浏览阅读331次。第一部分:准备工作1 安装虚拟机2 安装centos73 安装JDK以上三步是准备工作,至此已经完成一台已安装JDK的主机第二部分:准备3台虚拟机以下所有工作最好都在root权限下操作1 克隆上面已经有一台虚拟机了,现在对master进行克隆,克隆出另外2台子机;1.1 进行克隆21.2 下一步1.3 下一步1.4 下一步1.5 根据子机需要,命名和安装路径1.6 ..._创建一个hadoop项目
文章浏览阅读1.7k次。心脏滴血漏洞HeartBleed CVE-2014-0160 是由heartbeat功能引入的,本文从深入码层面的分析该漏洞产生的原因_heartbleed代码分析
文章浏览阅读1.4k次。前言ofd是国家文档标准,其对标的文档格式是pdf。ofd文档是容器格式文件,ofd其实就是压缩包。将ofd文件后缀改为.zip,解压后可看到文件包含的内容。ofd文件分析工具下载:点我下载。ofd文件解压后,可以看到如下内容: 对于xml文件,可以用文本工具查看。但是对于印章文件(Seal.esl)、签名文件(SignedValue.dat)就无法查看其内容了。本人开发一款ofd内容查看器,..._signedvalue.dat
文章浏览阅读1.8w次,点赞29次,收藏313次。整体系统设计本设计主要是对ADC和DAC的使用,主要实现功能流程为:首先通过串口向FPGA发送控制信号,控制DAC芯片tlv5618进行DA装换,转换的数据存在ROM中,转换开始时读取ROM中数据进行读取转换。其次用按键控制adc128s052进行模数转换100次,模数转换数据存储到FIFO中,再从FIFO中读取数据通过串口输出显示在pc上。其整体系统框图如下:图1:FPGA数据采集系统框图从图中可以看出,该系统主要包括9个模块:串口接收模块、按键消抖模块、按键控制模块、ROM模块、D.._基于fpga的信息采集
文章浏览阅读2.5w次。1.背景错误信息:-- [http-nio-9904-exec-5] o.s.c.n.z.filters.post.SendErrorFilter : Error during filteringcom.netflix.zuul.exception.ZuulException: Forwarding error at org.springframework.cloud..._com.netflix.zuul.exception.zuulexception
文章浏览阅读358次。1.介绍图的相关概念 图是由顶点的有穷非空集和一个描述顶点之间关系-边(或者弧)的集合组成。通常,图中的数据元素被称为顶点,顶点间的关系用边表示,图通常用字母G表示,图的顶点通常用字母V表示,所以图可以定义为: G=(V,E)其中,V(G)是图中顶点的有穷非空集合,E(G)是V(G)中顶点的边的有穷集合1.1 无向图:图中任意两个顶点构成的边是没有方向的1.2 有向图:图中..._给定一个邻接矩阵未必能够造出一个图
文章浏览阅读321次。(十二)、WDS服务器安装通过前面的测试我们会发现,每次安装的时候需要加域光盘映像,这是一个比较麻烦的事情,试想一个上万个的公司,你天天带着一个光盘与光驱去给别人装系统,这将是一个多么痛苦的事情啊,有什么方法可以解决这个问题了?答案是肯定的,下面我们就来简单说一下。WDS服务器,它是Windows自带的一个免费的基于系统本身角色的一个功能,它主要提供一种简单、安全的通过网络快速、远程将Window..._doc server2012上通过wds+mdt无人值守部署win11系统.doc
文章浏览阅读219次。python–xlrd/xlwt/xlutilsxlrd只能读取,不能改,支持 xlsx和xls 格式xlwt只能改,不能读xlwt只能保存为.xls格式xlutils能将xlrd.Book转为xlwt.Workbook,从而得以在现有xls的基础上修改数据,并创建一个新的xls,实现修改xlrd打开文件import xlrdexcel=xlrd.open_workbook('E:/test.xlsx') 返回值为xlrd.book.Book对象,不能修改获取sheett_xlutils模块可以读xlsx吗
文章浏览阅读8.2w次,点赞267次,收藏656次。运行Selenium出现'WebDriver' object has no attribute 'find_element_by_id'或AttributeError: 'WebDriver' object has no attribute 'find_element_by_xpath'等定位元素代码错误,是因为selenium更新到了新的版本,以前的一些语法经过改动。..............._unresolved attribute reference 'find_element_by_id' for class 'webdriver
文章浏览阅读198次。一:模态窗口//父页面JSwindow.showModalDialog(ifrmehref, window, 'dialogWidth:550px;dialogHeight:150px;help:no;resizable:no;status:no');//子页面获取父页面DOM对象//window.showModalDialog的DOM对象var v=parentWin..._jquery获取父window下的dom对象
文章浏览阅读1.7w次,点赞15次,收藏129次。算法(algorithm)是解决一系列问题的清晰指令,也就是,能对一定规范的输入,在有限的时间内获得所要求的输出。 简单来说,算法就是解决一个问题的具体方法和步骤。算法是程序的灵 魂。二、算法的特征1.可行性 算法中执行的任何计算步骤都可以分解为基本可执行的操作步,即每个计算步都可以在有限时间里完成(也称之为有效性) 算法的每一步都要有确切的意义,不能有二义性。例如“增加x的值”,并没有说增加多少,计算机就无法执行明确的运算。 _算法
文章浏览阅读1.5k次,点赞18次,收藏26次。网络安全的标准和规范是网络安全领域的重要组成部分。它们为网络安全提供了技术依据,规定了网络安全的技术要求和操作方式,帮助我们构建安全的网络环境。下面,我们将详细介绍一些主要的网络安全标准和规范,以及它们在实际操作中的应用。_网络安全标准规范