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("失败");
        },
      })
    },

页面设计

为界面添加两个按钮

在这里插入图片描述

设置相应的响应函数

在这里插入图片描述

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐