智能家居物联 UI 界面开发

项目路径为 4/01_smarthome/01_smarthome/01_smarthome.pro,先看项目界面。项目界面如
下,采用暗黑主题设计,结合黄色作为亮色,让用户一目了然。界面笔者从一些智能家居界面
中找到灵感的,编写设计完成的效果不错!请自行查阅源码,掌握了本教程前面第七章的内容,
就可以理解这个界面是如何设计的。

原子云 API 接口

我们想要与原子云通信,那么必须先了解原子云平台的 API 接口。请参阅原子云平台 API

文档 V1.2.pdf 文档。原子云平台 API 写的非常详细了,请自行翻阅。需要我们从原子云平台了
解原子云 API 的通信流程。

下图是原子云平台 API 的使用流程图。
我们写 Qt 应用就应该重点放在 HTTPS 与 WebSocket 方向上。查阅原子云平台 API 可以知
道,下面是重点!一些帐号信息,与设备信息是通过 HTTPS 协议接口获取的,通信用 WebSocket

协议接口。那么我们就按原子云平台的协议流程编写应用程序。
源码路径为 4/01_smarthome/webapi/webapi.cpp。内容如下。

 /****************************************************************** Copyright © Deng Zhimao Co., Ltd. 1990-2021. All rights reserved. * @projectName webapi * @brief webapi.cpp * @author Deng Zhimao * @email 1252699831@qq.com * @net www.openedv.com * @date 2021-05-27 *******************************************************************/ 1 #include "webapi.h" 2 #include <QUuid> 3 #include <QRegularExpression> 4 5 Webapi::Webapi(QObject *parent) 6 { 7 this->setParent(parent); 8 /* 数组清空 */ 9 groupID.clear(); 10 deviceID.clear(); 11 deviceNumber.clear(); 12 13 timer = new QTimer();
14 connect(timer, SIGNAL(timeout()), this, SLOT(onTimerTimeOut())); 15 16 networkAccessManager = new QNetworkAccessManager(this); 17 18 orgURL = "https://cloud.alientek.com/api/orgs"; 19 /* 请填写自己的 token 信息!!! */ 20 api_token = "bf591984c8fa417584d18f6328e0ef73"; 21 22 /* 获取账号机构列表 */ 23 getOrgURL(); 24 25 QUuid uuid = QUuid::createUuid(); 26 random_token = uuid.toString(); 27 28 webSocket = new QWebSocket(); 29 /* 需要加一些安全配置才能访问 https */ 30 QSslConfiguration config; 31 config.setPeerVerifyMode(QSslSocket::VerifyNone); 32 config.setProtocol(QSsl::TlsV1SslV3); 33 webSocket->setSslConfiguration(config); 34 35 connect(webSocket, SIGNAL(connected()), 36 this, SLOT(webSocketConnected())); 37 connect(webSocket, SIGNAL(binaryMessageReceived(QByteArray)), 38 this, SLOT(onBinaryMessageReceived(QByteArray))); 39 } 40 41 Webapi::~Webapi() 42 { 43 delete timer; 44 delete webSocket; 45 webSocket = nullptr; 46 } 47 48 void Webapi::getOrgURL() 49 { 50 getDataFromWeb(QUrl(orgURL)); 51 } 52 53 /* 获取设备分组列表 */ 54 void Webapi::getGroupListUrl() 55 { 56 getDataFromWeb(QUrl(groupListUrl)); 57 } 58 59 /* 获取设备的信息 */ 60 void Webapi::getDevOfGroupUrl() 61 { 62 getDataFromWeb(QUrl(devOfGroupUrl)); 63 } 64 65 /* 获取设备连接状态 */ 66 void Webapi::getConStateUrl() 67 { 68 getDataFromWeb(QUrl(conStateUrl)); 69 } 70 71 /* 从云服务器获取数据 */ 72 void Webapi::getDataFromWeb(QUrl url) 73 { 74 /* 网络请求 */ 75 QNetworkRequest networkRequest; 76 77 /* 需要加一些安全配置才能访问 https */ 78 QSslConfiguration config; 79 config.setPeerVerifyMode(QSslSocket::VerifyNone); 80 config.setProtocol(QSsl::TlsV1SslV3); 81 networkRequest.setSslConfiguration(config); 82 83 /* 设置访问的地址 */ 84 networkRequest.setUrl(url); 85 86 /* 网络响应 */ 87 networkRequest.setHeader(QNetworkRequest::ContentTypeHeader, 88 "application/json;charset=UTF-8"); 89 90 /* 参数二为原子云帐号的 token 信息,填写自己的 */ 91 networkRequest.setRawHeader("token", api_token.toLatin1()); 92 93 QNetworkReply *newReply = 94 networkAccessManager->get(networkRequest); 95 96 connect(newReply, SIGNAL(finished()), 97 this, SLOT(replyFinished())); 98 connect(newReply, SIGNAL(readyRead()), 99 this, SLOT(readyReadData())); 100 101 } 102 void Webapi::replyFinished() 103 { 104 QNetworkReply *reply = (QNetworkReply *)sender(); 105 106 if (reply->url() == QUrl(orgURL)) { 107 /* 设备分组列表 ID */ 108 getID(dataString, reply); 109 } 110 111 if (reply->url() == QUrl(groupListUrl)) { 112 /* 列表 ID */ 113 getID(dataString, reply); 114 115 /* 获取到组 ID 再开启定时器 */ 116 if (!timer->isActive()) 117 timer->start(2000); 118 } 119 120 /* 设备的信息 */ 121 if (reply->url() == QUrl(devOfGroupUrl)) { 122 getID(dataString, reply); 123 getNumber(dataString); 124 getName(dataString); 125 } 126 127 /* 设备的连接状态 */ 128 if (reply->url() == QUrl(conStateUrl)) { 129 getConnectState(dataString); 130 } 131 132 reply->deleteLater(); 133 reply = nullptr; 134 } 135 void Webapi::readyReadData() 136 { 137 QNetworkReply *reply = (QNetworkReply *)sender(); 138 QByteArray data = reply->readAll(); 139 dataString = QString(data); 140 qDebug()<<dataString<<endl; 141 } 142 143 /* 获取 ID,包括分组 id,设备 id */ 144 void Webapi::getID(QString data, QNetworkReply *reply) 145 { 146 /* 多个匹配,因为可能有多个合适的字段 */ 147 QRegularExpression pattern("\"id\":(\\d+)"); 148 149 QRegularExpressionMatchIterator i = pattern.globalMatch(data); 150 while (i.hasNext()) { 151 QRegularExpressionMatch match = i.next(); 152 if (match.hasMatch()) { 153 if (reply->url() == QUrl(orgURL)) { 154 org_id = match.captured(1); 155 groupListUrl = "https://cloud.alientek.com/api/orgs/" 156 + org_id + "/grouplist"; 157 getGroupListUrl(); 158 /* Socket 连接 */ 159
webSocket->open(QUrl(QString("wss://cloud.alientek.com/connection/%1/or
g/%2?token=%3") 160 .arg(api_token).arg(org_id).arg(rando
m_token))); 161 } 162 163 if (reply->url() == QUrl(groupListUrl)) { 164 group_id = match.captured(1); 165 /* 存储组 ID,再由定时器根据组的 ID 获取设备信息 */ 166 groupID.append(group_id); 167 qDebug()<<"组 ID:"<<group_id<<endl; 168 169 } 170 171 if (reply->url() == QUrl(devOfGroupUrl)) { 172 device_id = match.captured(1); 173 /* 存储设备 ID,再由定时器根据设备的 ID 获取连接状态 */ 174 deviceID.append(device_id); 175 qDebug()<<"设备 ID:"<<device_id<<endl; 176 } 177 } 178 } 179 } 180 181 void Webapi::getNumber(QString data) 182 { 183 QRegularExpression pattern("\"number\":\"(\\d+)\""); 184 185 QRegularExpressionMatchIterator i = pattern.globalMatch(data); 186 while (i.hasNext()) { 187 QRegularExpressionMatch match = i.next(); 188 if (match.hasMatch()) { 189 device_number = match.captured(1); 190 deviceNumber.append(device_number); 191 qDebug()<<"设备编号:"<<device_number<<endl; 192 } 193 } 194 } 195 196 void Webapi::getName(QString data) 197 { 198 /* 匹配中文字符,设备起名需要为中文 */ 199 QRegularExpression pattern("\"name\":\"([\u4e00-\u9fa5]*)"); 200 201 QRegularExpressionMatchIterator i = pattern.globalMatch(data); 202 while (i.hasNext()) { 203 QRegularExpressionMatch match = i.next(); 204 if (match.hasMatch()) { 205 device_name = match.captured(1); 206 deviceName.append(device_name); 207 qDebug()<<"设备名称:"<<device_name<<endl; 208 } 209 } 210 } 211 212 /* 获取设备的连接状态 */ 213 void Webapi::getConnectState(QString data) 214 { 215 QString pattern = "\"data\":\"(\\S*)\""; 216 QRegularExpression regularExpression(pattern); 217 QRegularExpressionMatch match = regularExpression.match(data, 0); 218 if(match.hasMatch()) { 219 qDebug()<<"设备连接状态"<<match.captured(1); 220 deviceConnectState.append(match.captured(1)); 221 } 222 } 223 224 void Webapi::webSocketConnected() 225 { 226 qDebug()<<"webSocket 连接原子云成功"<<endl; 227 } 228 229 void Webapi::onBinaryMessageReceived(QByteArray str) 230 { 231 232 QString temp(str); 233 if (temp.contains("online")) { 234 for (int i = 0; i < deviceNumber.count() ; i++) { 235 if (temp.contains(deviceNumber[i])) { 236 /* 发送如客厅灯在线信号*/ 237 emit deviceStateChanged(deviceName[i] + "|在线"); 238 qDebug()<<deviceName[i] + "|在线"<<endl; 239 break; 240 } 241 } 242 } 243 } 244 245 /* 延时函数 */ 246 void Webapi::sleep(double second) 247 { 248 usleep(second * 1000000); 249 } 250 251 void Webapi::onTimerTimeOut() 252 { 253 static int i = 0; 254 if (i < groupID.count()) { 255 /* 获取分组下的设备列表 */ 256 devOfGroupUrl = "https://cloud.alientek.com/api/orgs/" 257 + org_id + "/groups/" 258 + groupID[i] + "/devices"; 259 dataString.clear(); 260 getDevOfGroupUrl(); 261 } else if (i >= groupID.count() 262 && i < groupID.count() + deviceID.count() ) { 263 timer->start(1000); 264 conStateUrl = "https://cloud.alientek.com/api/orgs/" 265 + org_id + "/devicestate/" 266 + deviceID[i - groupID.count()]; 267 getConStateUrl(); 268 269 } else { 270 /* 订阅设备的消息 */ 271 for (int j = 0; j < deviceNumber.count(); j++) { 272 QByteArray cmd; 273 cmd[0] = 0x01; 274 sendCmd(deviceNumber[j], cmd); 275 } 276 277 timer->stop(); 278 } 279 280 i++; 281 } 282 283 /* 订阅指定设备的消息,cmd = 0x01 */ 284 void Webapi::sendCmd(QString number, QByteArray cmd) 285 { 286 QStringList list = number.split(""); 287 for (int i = 0; i < list.count(); i++) { 288 if (!list[i].isEmpty()) { 289 cmd.append(list[i]); 290 } 291 } 292 293 webSocket->sendBinaryMessage(cmd); 294 } 295 296 /* 发送消息到指定设备,cmd = 0x03 */ 297 void Webapi::sendCmdMessage(QString number, 298 QByteArray cmd, QString message) 299 { 300 QStringList list = number.split(""); 301 for (int i = 0; i < list.count(); i++) { 302 if (!list[i].isEmpty()) { 303 cmd.append(list[i]); 304 } 305 } 306 307 cmd.append(message); 308 309 webSocket->sendBinaryMessage(cmd); 310 } 311 312 void Webapi::whichDeviceNameSendCmd(QString name, 313 QString message) { 314 315 for (int i = 0; i < deviceName.count(); i++) { 316 if (name == deviceName[i]) { 317 QByteArray cmd; 318 cmd[0] = 0x03; 319 sendCmdMessage(deviceNumber[i], cmd, message); 320 break; 321 } 322 } 323 }

第 20 行,需要填写自己的原子云平台帐号 api_token 信息,请在原子云》帐号信息中查看!
剩余的代码都按照原子云平台 API 文档编写,首先是通过网络请求 networkRequest,访问
需要访问的地址,然后通过网络回应对象 newReply 来接收网络回复的结果。结果是 JSION 格
式的文本,笔者使用正则表达式提取回复的内容,作为下一个地址的参数,如此反复,就可以
将原子云服务器的帐号下的设备信息提取出来。
第 159 行,提取出来的信息转交 webSocket 对象,让 webSocket 获取原子云平台的鉴权,
就可以实现通信了。
流程都是按照原子云平台 API 文档的走,剩下的就是 webSocket 通信了,与 TCP,UDP 的

socket 通信相似,这里就不多解释了,和第十一章的 TCP/UDP Socket 通信内容相似。重点是流
程,再参考代码看。

QT学习开发笔记(项目实战之智能家居物联 UI 界面开发 )相关推荐

  1. python爬虫开发环境_python爬虫开发教程下载|Python爬虫开发与项目实战(范传辉 著)pdf 完整版_ - 极光下载站...

    Python爬虫开发与项目实战pdf扫描版下载.Python爬虫开发是一个Pthyon编程语言与HTML基础知识引领读者入门知识,重点讲述了云计算的相关内容及其在爬虫中的应用,进而介绍如何设计自己的爬 ...

  2. 【创科之龙】零基础学习嵌入式开发以及项目实战开发【第二期视频】

    [创科之龙]零基础学习嵌入式开发以及项目实战开发[学习交流零基础火热进行ing] 大家好,我是aiku,上期的项目学习资料在电子发烧友论坛上分享,大家觉得都很好. 在这里我首先要感谢电子发烧友给我们的 ...

  3. Hi3861鸿蒙物联网项目实战:智能安防报警

    华清远见FS-Hi3861开发套件,支持HarmonyOS 3.0系统.开发板主控Hi3861芯片内置WiFi功能,开发板板载资源丰富,包括传感器.执行器.NFC.显示屏等,同时还配套丰富的拓展模块. ...

  4. Hi3861鸿蒙物联网项目实战:智能测距仪

    华清远见FS-Hi3861开发套件,支持HarmonyOS 3.0系统.开发板主控Hi3861芯片内置WiFi功能,开发板板载资源丰富,包括传感器.执行器.NFC.显示屏等,同时还配套丰富的拓展模块. ...

  5. 《Python爬虫开发与项目实战》——第1章 回顾Python编程 1.1 安装Python

    本节书摘来自华章计算机<Python爬虫开发与项目实战>一书中的第1章,第1.1节,作者:范传辉著,更多章节内容可以访问云栖社区"华章计算机"公众号查看 第1章 回顾P ...

  6. Vue3+TypeScript从入门到进阶(六)——TypeScript知识点——附沿途学习案例及项目实战代码

    文章目录 一.简介 二.Vue2和Vue3区别 三.Vue知识点学习 四.TypeScript知识点 一.JavaScript和TypeScript 二.TypeScript的安装和使用 1.Type ...

  7. Android零基础开发到项目实战

    Android零基础开发到项目实战(目录) 前言:本教程适合零基础学习安卓开发的伙伴,下面是目录,本博主会每天定时更新每一章节的教程,未完..... 一.Java基础阶段 day01_Java语言概述 ...

  8. Python编程:从入门到实践+爬虫开发与项目实战+网络编程基础+项目开发实战

    给还在苦苦自学Python的小伙伴们分享一波学习教程~有了它们,至少能节省50%的时间,少走一半的弯路. 书不在多,而在于精~ <Python编程:从入门到实践>豆瓣评分9.2 本书是针对 ...

  9. 视频教程-微信小程序项目实战之我画你猜视频课程-微信开发

    微信小程序项目实战之我画你猜视频课程 精通PHP软件开发和WEB前端开发技术,熟悉PHP.Java.Javascript.HTML等语言,熟悉HTTP协议及W3C相关互联网规范,曾在山西某知名公司担任 ...

最新文章

  1. css控制显示行数,多出部分显示省略号
  2. recycleview 清空数据 滚动顶部_爱剪辑:制作数字滚动效果,翻滚吧字幕!
  3. 发现 postman 自动生成接口调用代码的一个问题
  4. 依赖注入容器 Castle windsor的使用
  5. 前端学习(3084):vue+element今日头条管理-表单数据绑定2
  6. 使用iBATIS3.0完成增删改查
  7. 微信小程序实现文字跑马灯
  8. linux nand 坏块_韦东山-NAND 上面都是坏块怎么办啊? - 百问网嵌入式问答社区
  9. python学习笔记(十一):网络编程
  10. js进阶 10-1 JQuery是什么
  11. 5款自动爬取数据的神器!
  12. VRF-Virtual Routing Forwarding
  13. WordPress建站主机推荐
  14. 常用计算机英文缩写,计算机常用英文缩写
  15. rancher应用商店的使用
  16. springboot搭建redis时提示RedisCommandExecutionException: CLUSTERDOWN Hash slot not served解决办法
  17. 悉尼大学商业数据科学与计算机学院,留学攻略—澳洲悉尼大学数据科学专业
  18. 软件公司的岗位职责 - IT项目经理
  19. 一个有趣推理题的答案
  20. 洛谷P1034矩形覆盖题解--zhengjun

热门文章

  1. 一对一、一对多、多对多模型关系的建立和增删改查要注意的问题
  2. react的路由守卫,路由鉴权,路由守卫的封装
  3. 联盟链技术应用的难点
  4. java使用Aspose.word保存word更新目录页码报错以及样式错乱解决
  5. python实现二叉树的创建
  6. wait_event_interruptible()和wait_up_interruptible()
  7. nanopc-T4 开发板通过USB麦克风采集录制音频
  8. ROS 导航安装及实现(二十二)
  9. 关于LayoutInflater.from(context).inflate()的使用的问题
  10. element table手动实现自定义筛选(手动实现)