近年来,在智能化、自动化高新技术的驱动下,智能家居工作进入了飞速展开时期。根据国家相关部委推动智慧城市建设布置,以及各地方政府的安排,我国发动智慧城市建设和在建智慧城市的城市数量逾越500个。跟着各地智慧城市建设提速,相关商场规划将有望扩容至千亿,甚至万亿等级。
智能家居是以住宅为平台,利用综合布线技术、网络通信技术、 安全防范技术、自动控制技术、音视频技术将家居生活有关的设施集成,构建高效的住宅设施与家庭日程事务的管理系统,提升家居安全性、便利性、舒适性、艺术性,并实现环保节能的居住环境。
智能家居可以说是一个自动化的物联网系统,你可以用这个系统享受更高效、更有趣的服务(懒人的福利),比如你可以让你通过你的手机或智能音响控制你空调的温度,控制你的扫地机器人扫地,控制你家的窗帘,或者当你离开家的时候家里的台灯,吊顶灯,床头灯都会自动关闭,智能音响会自动说对你说一路顺风,提高自己的生活体验。
智能家居是一个大框架,里面包含了家庭里所有的电器设备智能化,智能门窗、智能门锁、智能电视、智能影像、智能插座、智能空调、智能电饭煲、智能热水器等等。
这篇文章采用智能家居里的典范–智能门锁,来介绍如何让锁变得智能。
实现的核心: 将家里的门锁通过WIFI,通过MQTT协议连接上华为云IOT物联网平台,再开发一个配套的手机APP,完成远程开锁关锁的功能。华为云IOT服务器的响应速度非常快,在手机端点击开锁、关锁后,实体设备可以快速响应。
使用华为云物联网云平台完成智能门锁这个需求时,需要了解三个部分的知识点:
(1)如何通过华为云IOT物联网平台创建产品,创建设备。?
(2)如何让设备登录到华为云IOT平台(获取MQTT协议三元组信息) ?
(3)开发手机APP,开发电脑桌面软件、微信小程序时,如何与华为云IOT云平台进行对接?
接下来,下面就陆续介绍整个产品的开发过程,解决这3个疑问,文章里图片、文字描述、代码都会贴出来,只要认真看一遍,就可以对现在的智能家居、物联网、云平台这些概念有个了解了。
当前产品是做一个智能家居里的系列产品–智能门锁。为了模拟真实设备硬件,采用步进电机模拟门锁,STM32+ESP8266作为主控芯片和联网设备。
整体思路:
在华为云IOT物联网平台构建智能锁项目,配置好云端,设备端通过ESP8266连接华为物联网平台,实现数据上报,交互,实现远程开锁、关锁、获取锁的状态等功能,不用担心忘记出门关锁,也不用担心忘记带钥匙无法开门的情况。
ESP8266是物联网解决方案里比较热门的WIFI设备,支持串口+AT指令控制,任意支持串口的单片机都可以使用ESP8266快速实现联网。
步进电机采用常规28BYJ-48来模拟当做门锁的电机,驱动板采用ULN2003。
登录官网: https://www.huaweicloud.com/
直接搜索物联网,打开页面。
选择设备接入:
选择免费试用:
在产品页面,点击右上角创建产品:
填上产品信息:
得到产品ID,保存好ID,点击查看详情:
产品ID为:61b9ba3a2b2aa20288c1e7f1.
点击设备页面,注册设备:
填充信息进行注册:
保存设备密匙和设备ID,点击保存关闭会自动下载文件保存,后面生成密码和登录账号需要使用
关闭后就看到创建好的设备了:
点击产品页面,选择刚才创建的产品:
选择自定义模型—创建数据模型服务:
选择新增属性,创建设备的属性
设备创建完成接来下生成MQTT登录账号、密匙,方便设备登录云端平台。
官网工具地址: https://iot-tool.obs-website.cn-north-4.myhuaweicloud.com/
打开刚才创建设备时,下载的密匙文件,把内容复制出来对应的填进去,生成即可。
官方文档介绍: https://support.huaweicloud.com/devg-iothub/iot_01_2127.html
在产品页面可以,看到主题的全部格式:
总结的格式如下:
格式: $oc/devices/{device_id}/sys/messages/down
//订阅主题: 平台下发消息给设备
$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down
格式: $oc/devices/{device_id}/sys/properties/report
//设备上报数据
$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report
上属性的数据格式:
//上报的属性消息 (一次可以上报多个属性,在json里增加就行了)
{"services": [{"service_id": "lock","properties":{"门锁":1}}]}
上面属性里的服务ID和属性里的名称,在设备页面,影子设备页面查看。
下面使用MQTT客户端模拟设备登录服务器测试,看设备创建的是否OK。
服务器的IP地址是: 121.36.42.100
端口号是: 1883
打开MQTT客户端软件,按照提示,输入相关参数后,点击连接,然后再点击订阅主题,发布主题即可:
查看云端服务器的情况: 可以看到设备已经在线了,并且收到上传的数据。
修改一下锁的状态,上报属性再查看:
发现云端的状态也已经改变,现在设备上报已经OK。
接下来测试命令下发,实现远程开锁关锁的功能:
打开产品页面,新增加命令:
命令添加成功:
在设备页面,选择同步命令下发:
点击确定后,查看MQTT客户端,发现已经收到数据了:
$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497/sys/commands/request_id=88e2626f-290d-405e-962d-51554445a8fd{"paras":{"lock":1},"service_id":"lock","command_name":"lock"}
设备端解析收到的数据,就可以完成多步进电机的控制,完成开锁关锁。
在前面章节里完成产品的云端创建、设备创建、设备模拟登录,开锁关锁测试。本小节,就使用真实设备完成上云,登录华为云IOT平台,实现数据通信。
设备端使用的STM32作为主控芯片,IDE采用keil5,下面贴出了工程核心代码。
工程是keil5工程。
STM32连接华为云IOT的工程代码Get: https://download.csdn.net/download/xiaolong1126626497/81993720
main函数代码如下:
#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include
#include "timer.h"
#include "bluetooth.h"
#include "esp8266.h"
#include "mqtt.h"
//华为物联网服务器的设备信息
#define MQTT_ClientID "61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510"
#define MQTT_UserName "61b9ba3a2b2aa20288c1e7f1_QQ1126626497"
#define MQTT_PassWord "385ce91dfe7da5b7431868d5d87e7998163c493344040935d5a00024d6324242"
//订阅与发布的主题
#define SET_TOPIC "$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/messages/down" //订阅
#define POST_TOPIC "$oc/devices/61b9ba3a2b2aa20288c1e7f1_QQ1126626497_0_0_2021121510/sys/properties/report" //发布
char mqtt_message[200];//上报数据缓存区
int main()
{
u32 time_cnt=0;
u32 i;
u8 key;
LED_Init();
BEEP_Init();
KEY_Init();
USART1_Init(115200);
TIMER1_Init(72,20000); //超时时间20ms
USART2_Init(9600);//串口-蓝牙
TIMER2_Init(72,20000); //超时时间20ms
USART3_Init(115200);//串口-WIFI
TIMER3_Init(72,20000); //超时时间20ms
USART1_Printf("正在初始化WIFI请稍等.\n");
if(ESP8266_Init())
{
USART1_Printf("ESP8266硬件检测错误.\n");
}
else
{
//非加密端口
USART1_Printf("WIFI:%d\n",ESP8266_STA_TCP_Client_Mode("CMCC-Cqvn","99pu58cb","121.36.42.100",1883,1));
}
//2. MQTT协议初始化
MQTT_Init();
//3. 连接华为服务器
while(MQTT_Connect(MQTT_ClientID,MQTT_UserName,MQTT_PassWord))
{
USART1_Printf("服务器连接失败,正在重试...\n");
delay_ms(500);
}
USART1_Printf("服务器连接成功.\n");
//3. 订阅主题
if(MQTT_SubscribeTopic(SET_TOPIC,0,1))
{
USART1_Printf("主题订阅失败.\n");
}
else
{
USART1_Printf("主题订阅成功.\n");
}
while(1)
{
key=KEY_Scan(0);
if(key==2)
{
time_cnt=0;
sprintf(mqtt_message,"{\"services\": [{\"service_id\": \"lock\",\"properties\":{\"门锁\":1}}]}");
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("发送状态1\r\n");
}
else if(key==3)
{
time_cnt=0;
sprintf(mqtt_message,"{\"services\": [{\"service_id\": \"lock\",\"properties\":{\"门锁\":0}}]}");
MQTT_PublishData(POST_TOPIC,mqtt_message,0);
USART1_Printf("发送状态0\r\n");
}
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
for(i=0;i<USART3_RX_CNT;i++)
{
USART1_Printf("%c",USART3_RX_BUFFER[i]);
}
USART3_RX_CNT=0;
USART3_RX_FLAG=0;
}
//定时发送心跳包,保持连接
delay_ms(10);
time_cnt++;
if(time_cnt==500)
{
MQTT_SentHeart();//发送心跳包
time_cnt=0;
}
}
}
为了更方便的完成智能门锁开锁、关锁的操作,与设备完成交互,还需要开发一个配套的手机APP,官方提供了应用侧开发的API接口、SDK接口,为了方便通用一点,这里采用了API接口完成数据交互,上位机软件采用QT开发。QT支持跨平台开发,所有就可以顺便一起开发出Android、IOS、windows、Linux等平台的终端软件。还可以通过wasm技术,开发web网页程序,非常强大的框架。
下面就介绍上位机开发的流程,如何交互等等。
帮助文档地址: https://support.huaweicloud.com/usermanual-iothub/iot_01_0045.html
在文档页面可以看到,提供的接口有,创建产品、创建设备、查询设备属性,查询设备消息等等。
在设计手机APP时,可以直接通过提供的API接口,创建产品,设备,这样设备端就可以直接注册登录。
设备属性就是设备上传的传感器状态数据信息,应用侧提供了API接口,可以主动向设备端下发请求指令;设备端收到指令之后需要按照约定的数据格式上报数据;所以,要实现应用层与设备端的数据交互,需要应用层与设备端配合才能完成。
下面分别介绍应用测和设备测的实现流程。
(1)应用层下发的指令
帮助文档地址: https://support.huaweicloud.com/api-iothub/iot_06_v5_0034.html
接口的在线调试地址: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListProperties
如果请求参数和返回值不清楚,写代码前,先使用在线调试接口体验一下,验证数据交互是否OK。
请求参数里比较总要的两个必填参数,是设备ID和服务ID,这两个参数在第3章节就介绍过如何获取了,在产品页面创建自定义属性时可以看到服务ID。
请求接口总结:
请求方法 GET
URI地址 /v5/iot/{project_id}/devices/{device_id}/properties
传输协议 HTTPS
拼接好的地址:
https://iotda.cn-north-4.myhuaweicloud.com/v5/iot/0e5957be8a00f53c2fa7c0045e4d8fbf/devices/61df9a6bc7fb24029b0c160d_1126626497/properties?service_id=1126626497
其中的project_id和device_id需要根据自己的设备信息修改。
请求头:
{
"User-Agent": "API Explorer",
"X-Auth-Token": "******", 这个是鉴权用的token
"Content-Type": "application/json"
}
响应体(设备上传的数据)
{
"response": {
"services": [
{
"service_id": "lock",
"properties": {
"lock": 1
}
},
}
]
}
}
请求头里需要填X-Subject-Token
参数,这个参数只要是访问任何华为云都需要填,获取具体的流程可以看这里。https://bbs.huaweicloud.com/blogs/317759 翻到第3小节。
(2)设备上传数据
应用层向设备端请求查询设备属性
时,设备端会收到如下的消息:
$oc/devices/61df9a6bc7fb24029b0c160d_1126626497/sys/properties/get/request_id=336bcb57-0e0a-44d0-90f7-31386cb54a3c{"service_id":"1126626497"}
这个消息里有一个主要参数request_id
请求ID,设备端需要解析出这个参数,给应用层响应数据时,需要带上这个ID。
这个请求属性详细帮助文档看这里: https://support.huaweicloud.com/api-iothub/iot_06_v5_3011.html
设备响应的数据格式:
主题格式: $oc/devices/{device_id}/sys/properties/get/response/request_id={request_id}
示 例:
$oc/devices/61df9a6bc7fb24029b0c160d_1126626497/sys/properties/get/response/request_id=336bcb57-0e0a-44d0-90f7-31386cb54a3c
响应的数据格式:
{"services": [{"service_id": "healthy","properties":{"HeartRate":127}}]}
响应的数据格式可以看这里的介绍: https://support.huaweicloud.com/api-iothub/iot_06_v5_3010.html
下面使用MQTT客户端与在线API接口联合模拟一下接口效果:
(1)先打开调试页面: https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=IoTDA&api=ListProperties
然后填好设备DI和服务ID:
(2)、打开MQTT客户端,登录华为云物联网平台(也就是模拟设备上线):
(3)、打开在线API调试页面,点击调试: 点击后可以看到页面上已经在等待客户端的响应了。
(4)、MQTT客户端响应详细
按照前面说的响应格式,拼接好接口,数据。然后发布主题。
(5)、应用层收到客户端响应,调试成功
调试成功后,响应体里收到的就是设备端上传的设备属性数据。
/*
功能: 获取token
*/
void Widget::GetToken()
{
//表示获取token
function_select=3;
QString requestUrl;
QNetworkRequest request;
//设置请求地址
QUrl url;
//获取token请求地址
requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
.arg(SERVER_ID);
//自己创建的TCP服务器,测试用
//requestUrl="http://10.0.0.6:8080";
//设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));
//构造请求
url.setUrl(requestUrl);
request.setUrl(url);
QString text =QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":"
"{\"user\":{\"domain\": {"
"\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
"\"scope\":{\"project\":{\"name\":\"%4\"}}}}")
.arg(MAIN_USER)
.arg(IAM_USER)
.arg(IAM_PASSWORD)
.arg(SERVER_ID);
//发送请求
manager->post(request, text.toUtf8());
}
//查询设备属性
void Widget::Get_device_properties()
{
//表示获取token
function_select=0;
QString requestUrl;
QNetworkRequest request;
//设置请求地址
QUrl url;
//获取token请求地址
requestUrl = QString("https://iotda.%1.myhuaweicloud.com/v5/iot/%2/devices/%3/properties?service_id=%4")
.arg(SERVER_ID)
.arg(PROJECT_ID)
.arg(device_id)
.arg(service_id);
//自己创建的TCP服务器,测试用
//requestUrl="http://10.0.0.6:8080";
//设置数据提交格式
request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));
//设置token
request.setRawHeader("X-Auth-Token",Token);
//构造请求
url.setUrl(requestUrl);
request.setUrl(url);
//发送请求
manager->get(request);
}
到此,智能门锁完成。