当前位置:   article > 正文

物联网实战--平台篇之(十一)设备管理后台_物联网管理后台

物联网管理后台

目录

一、设备数据库

二、添加设备

三、排序设备

四、重命名设备

五、删除设备

六、移动设备


本项目的交流QQ群:701889554

物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html

物联网实战--驱动篇https://blog.csdn.net/ypp240124016/category_12631333.html

一、设备数据库

        上图是设备管理数据库,跟分组管理同一个数据库,库表为设备表device_tb,放在不同的应用下,内容主要是设备sn,父设备sn和设备名称,对于跟mqtt服务器直连的设备,父设备sn为0;对于节点设备,它所在的网关就是它的父设备,这在设备组网的时候经常会用到。下面是数据库的主要代码:

  1. bool GroupSqlite::createDeviceTable(void)
  2. {
  3. QString str_query = QString::asprintf("CREATE TABLE If Not Exists device_tb ("
  4. "devSn bigint NOT NULL,"
  5. "devStr varchar(20) NOT NULL,"
  6. "parentSn bigint DEFAULT 0,"
  7. "parentStr varchar(20) DEFAULT 0,"
  8. "devName varchar(10000) DEFAULT 0,"
  9. "createTime timestamp DEFAULT (datetime(\'now\',\'localtime\')),"
  10. "PRIMARY KEY (devSn)"
  11. ")"
  12. );
  13. // qDebug()<<"str_query= "<<str_query;
  14. if(runSqlQuery(str_query)==false)
  15. {
  16. qDebug()<<"createDeviceTable error";
  17. return false;
  18. }
  19. else
  20. {
  21. qDebug()<<"createDeviceTable ok: ";
  22. }
  23. return true;
  24. }
  25. bool GroupSqlite::insertDeviceNode(u32 devSn, u32 parentSn)
  26. {
  27. QString dev_str=QString::asprintf("%08X", devSn);
  28. QString parent_str=QString::asprintf("%08X", parentSn);
  29. QString str_query = QString::asprintf("INSERT INTO device_tb (devSn, parentSn, devStr, parentStr) VALUES ( %u, %u, \"%s\", \"%s\")",
  30. devSn, parentSn, dev_str.toLatin1().data(), parent_str.toLatin1().data());
  31. // qDebug()<<str_query;
  32. if( runSqlQuery(str_query))
  33. {
  34. qDebug("insertDeviceNode ok 001!");
  35. return true;
  36. }
  37. else
  38. {
  39. createDeviceTable();
  40. if( runSqlQuery(str_query))
  41. {
  42. qDebug("insertDeviceNode ok 002!");
  43. return true;
  44. }
  45. }
  46. return false;
  47. }
  48. bool GroupSqlite::updateDeviceName(u32 devSn, QString devName)
  49. {
  50. QString str_query = QString::asprintf("UPDATE device_tb SET devName=\"%s\" WHERE devSn=%u",
  51. devName.toUtf8().data(), devSn);
  52. // qDebug()<<str_query;
  53. if( runSqlQuery(str_query))
  54. {
  55. qDebug("updateDeviceName ok!");
  56. return true;
  57. }
  58. return false;
  59. }
  60. bool GroupSqlite::updateDeviceParentSn(u32 devSn, u32 parentSn)
  61. {
  62. QString parent_str=QString::asprintf("%08X", parentSn);
  63. QString str_query = QString::asprintf("UPDATE device_tb SET parentSn=%u, parentStr=\"%s\" WHERE devSn=%u",
  64. parentSn, parent_str.toLatin1().data(),devSn);
  65. // qDebug()<<str_query;
  66. if( runSqlQuery(str_query))
  67. {
  68. qDebug("updateDeviceParentSn ok!");
  69. return true;
  70. }
  71. return false;
  72. }
  73. bool GroupSqlite::selectDeviceNode(u32 devSn, DeviceNodeStruct &workNode)
  74. {
  75. QString str_query = QString::asprintf("SELECT devSn, parentSn, devName, createTime FROM device_tb WHERE devSn=%u" ,
  76. devSn);
  77. // qDebug()<<str_query;
  78. if(runSqlQuery(str_query)==false)
  79. {
  80. qDebug("selectDeviceNode error_01!");
  81. return false;
  82. }
  83. while(m_sqlQuery.next())
  84. {
  85. int ptr=0;
  86. workNode.devSn=m_sqlQuery.value(ptr++).toUInt();
  87. workNode.parentSn=m_sqlQuery.value(ptr++).toUInt();
  88. workNode.devName=m_sqlQuery.value(ptr++).toString();
  89. workNode.createTime=m_sqlQuery.value(ptr++).toString();
  90. break;
  91. }
  92. m_sqlQuery.finish();
  93. return true;
  94. }
  95. bool GroupSqlite::selectDeviceList(QList<DeviceNodeStruct> &workList)
  96. {
  97. QString str_query = QString::asprintf("SELECT devSn, parentSn, devName, createTime FROM device_tb");
  98. // qDebug()<<str_query;
  99. if(runSqlQuery(str_query)==false)
  100. {
  101. qDebug("selectDeviceList error_01!");
  102. return false;
  103. }
  104. while(m_sqlQuery.next())
  105. {
  106. int ptr=0;
  107. DeviceNodeStruct workNode;
  108. workNode.devSn=m_sqlQuery.value(ptr++).toUInt();
  109. workNode.parentSn=m_sqlQuery.value(ptr++).toUInt();
  110. workNode.devName=m_sqlQuery.value(ptr++).toString();
  111. workNode.createTime=m_sqlQuery.value(ptr++).toString();
  112. workList.append(workNode);
  113. }
  114. m_sqlQuery.finish();
  115. return true;
  116. }
  117. bool GroupSqlite::delDeviceNode(u32 devSn)
  118. {
  119. QString str_query = QString::asprintf("DELETE FROM device_tb WHERE devSn=%u", devSn);
  120. // qDebug()<<str_query;
  121. if( runSqlQuery(str_query))
  122. {
  123. qDebug("delDeviceNode ok!");
  124. return true;
  125. }
  126. return false;
  127. }

二、添加设备

        添加设备一般是由用户发起的,主要通过扫码或者手动输入SN,跟设备联动完成添加,在这里因为扫码这块后续要单独讲解,而且还没有设备可以联动配合,所以我们先程序内部直接添加,其用户端APP添加函数如下:

  1. void CenterMan::requestAddDevice(u32 dev_sn, u32 parent_sn)
  2. {
  3. QJsonObject root_obj;
  4. QJsonDocument json_doc;
  5. root_obj.insert("account", m_loginAccount);
  6. root_obj.insert("rand_num", m_randNum);
  7. root_obj.insert("mac", m_macStr);
  8. root_obj.insert("cmd_type", "add_dev");
  9. root_obj.insert("app_id", (qint64)m_currAppWork.appID);
  10. root_obj.insert("dev_sn", (qint64)dev_sn);
  11. root_obj.insert("parent_sn", (qint64)parent_sn);
  12. json_doc.setObject(root_obj);
  13. QByteArray msg_ba = json_doc.toJson(QJsonDocument::Indented);
  14. QString topic=makePubTopic("device");
  15. emit sigMqttPushMessage(topic, msg_ba);
  16. }

        在定时器里每秒添加一个,添加10个为止,这里的序列号是0xA1010001~0xA101000A十个,其中A101代表型号,这是自定义,我这里就是定义为一种净化器设备,0001~000A就是地址码了,至于这个设备的具体定义,实际上是一个物模型,包含C++文件和QML文件,这个后面跟硬件结合起来要单独讲解,在这里也先保留,只展示一些文件信息,了解结构:

        由上图可知,在手机APP项目里,我们对物模型进行了单独的定义和存放,modelCpp和modelQml分别存放后端程序和前端代码,这样,在手机APP的主体结构完成后,对于要增加新的硬件产品,只需要对应增加物模型的代码就行了,其它不变,这也是物联网 端到端开发的核心所在。

        在服务器后台,接收到请求后会将设备添加到数据库,并返回反馈信息。

  1. else if(cmd_type=="add_dev")
  2. {
  3. u32 dev_sn=0, parent_sn=0;
  4. if(root_obj.contains("dev_sn"))
  5. {
  6. QJsonValue value = root_obj.value("dev_sn");
  7. dev_sn=value.toDouble();
  8. }
  9. if(root_obj.contains("parent_sn"))
  10. {
  11. QJsonValue value = root_obj.value("parent_sn");
  12. parent_sn=value.toDouble();
  13. }
  14. tag_groupSqlite.insertDeviceNode(dev_sn, parent_sn);//添加设备到数据库
  15. ack_str=QString::asprintf("设备%08X 添加成功!", dev_sn);
  16. ackAddDevice(account, mac_str, rand_num, app_id, dev_sn, parent_sn, result, ack_str);
  17. }

        用户端收到后将新设备添加到工作列表和"全部"分组,这样一个完整的添加流程就完成了。

  1. else if(cmd_type=="add_dev")//新增设备
  2. {
  3. u32 dev_sn=root_obj.value("dev_sn").toDouble();
  4. u32 parent_sn=root_obj.value("parent_sn").toDouble();
  5. addWorkDevice(dev_sn, parent_sn, "");//添加到工作列表
  6. emit siqAddDevice2Group("全部", dev_sn);//添加到全部分组
  7. }

三、排序设备

        用户在界面调整每个分组设备的顺序后,需要发送到后台服务器进行更新,以下的请求代码和后台更新代码:

  1. void CenterMan::requestSortDevice(QString group_name, QList<qint64> dev_list)
  2. {
  3. QJsonArray dev_array;
  4. QJsonObject root_obj;
  5. QJsonDocument json_doc;
  6. qDebug()<<"group_name="<<group_name;
  7. qDebug()<<"dev_list="<<dev_list;
  8. int nSize=dev_list.size();
  9. for(int i=0; i<nSize; i++)
  10. {
  11. u32 dev_sn=dev_list.at(i);
  12. if(dev_sn>0)
  13. {
  14. dev_array.append((qint64)dev_sn);
  15. }
  16. }
  17. root_obj.insert("account", m_loginAccount);
  18. root_obj.insert("rand_num", m_randNum);
  19. root_obj.insert("mac", m_macStr);
  20. root_obj.insert("app_id", (qint64)m_currAppWork.appID);
  21. root_obj.insert("group_name", group_name);
  22. root_obj.insert("dev_list", dev_array);
  23. root_obj.insert("cmd_type", "sort_dev");
  24. json_doc.setObject(root_obj);
  25. QByteArray msg_ba = json_doc.toJson(QJsonDocument::Indented);
  26. QString topic=makePubTopic("device");
  27. emit sigMqttPushMessage(topic, msg_ba);
  28. }

  1. if(cmd_type=="sort_dev")
  2. {
  3. QString group_name="";
  4. if(root_obj.contains("group_name"))
  5. {
  6. QJsonValue value = root_obj.value("group_name");
  7. group_name=value.toString();
  8. }
  9. QJsonArray dev_array;
  10. QList<u32>dev_list;
  11. if(root_obj.contains("dev_list"))
  12. {
  13. QJsonValue value = root_obj.value("dev_list");
  14. dev_array=value.toArray();
  15. }
  16. int nSize=dev_array.size();
  17. for(int i=0; i<nSize; i++)
  18. {
  19. u32 dev_sn=dev_array.at(i).toDouble();
  20. dev_list.append((qint64)dev_sn);
  21. }
  22. tag_groupSqlite.updateDevList(group_name, dev_list);//更新数据库
  23. ack_str="排序成功!";
  24. ackSortDevice(account, mac_str, rand_num, app_id, group_name, dev_array, result, ack_str);
  25. }

        排序完成后会返回到用户端,以下是用户端代码,主要是更新该分组在前端显示的顺序,完成最终的排序任务。

  1. else if(cmd_type=="sort_dev")//重新排序分组内的设备
  2. {
  3. QString group_name="";
  4. if(root_obj.contains("group_name"))
  5. {
  6. QJsonValue value = root_obj.value("group_name");
  7. group_name=value.toString();
  8. }
  9. GroupNodeStruct *pGroupNode=searchGroupNode(group_name);
  10. if(pGroupNode)//更新分组内的设备
  11. {
  12. QJsonArray dev_array;
  13. if(root_obj.contains("dev_list"))
  14. {
  15. QJsonValue value = root_obj.value("dev_list");
  16. dev_array=value.toArray();
  17. }
  18. emit siqClearDevice(group_name);
  19. pGroupNode->devList.clear();
  20. int nSize=dev_array.size();
  21. for(int i=0; i<nSize; i++)
  22. {
  23. u32 dev_sn=dev_array.at(i).toDouble();
  24. pGroupNode->devList.append(dev_sn);
  25. emit siqAddDevice2Group(group_name, dev_sn);//添加设备到分组
  26. }
  27. emit siqUpdateGroupTotalNum(group_name, pGroupNode->devList.size());//更新设备数量
  28. }
  29. }

四、重命名设备

        设备重命名流程与分组重命名类似,首先是用户端请求,服务器更新返回,最后用户端更新显示,下面是请求代码,

  1. void CenterMan::requestRenameDevice(u32 dev_sn, QString new_name)
  2. {
  3. QJsonObject root_obj;
  4. QJsonDocument json_doc;
  5. root_obj.insert("account", m_loginAccount);
  6. root_obj.insert("rand_num", m_randNum);
  7. root_obj.insert("mac", m_macStr);
  8. root_obj.insert("cmd_type", "rename_dev");
  9. root_obj.insert("app_id", (qint64)m_currAppWork.appID);
  10. root_obj.insert("dev_sn", (qint64)dev_sn);
  11. root_obj.insert("new_name", new_name);
  12. json_doc.setObject(root_obj);
  13. QByteArray msg_ba = json_doc.toJson(QJsonDocument::Indented);
  14. QString topic=makePubTopic("device");
  15. emit sigMqttPushMessage(topic, msg_ba);
  16. }

        服务器更新数据库设备名称:

  1. else if(cmd_type=="rename_dev")
  2. {
  3. u32 dev_sn=0;
  4. if(root_obj.contains("dev_sn"))
  5. {
  6. QJsonValue value = root_obj.value("dev_sn");
  7. dev_sn=value.toDouble();
  8. }
  9. QString new_name;
  10. if(root_obj.contains("new_name"))
  11. {
  12. QJsonValue value = root_obj.value("new_name");
  13. new_name=value.toString();
  14. }
  15. if(dev_sn>0 &&!new_name.isEmpty())
  16. {
  17. tag_groupSqlite.updateDeviceName(dev_sn, new_name);
  18. ack_str="重命名成功!";
  19. }
  20. else
  21. {
  22. ack_str="重命名失败!";
  23. result=1;
  24. }
  25. ackRenameDevice(account, mac_str, rand_num, app_id, dev_sn, new_name, result, ack_str);
  26. }

        用户端更新前端显示:

  1. else if(cmd_type=="rename_dev")//重命名设备
  2. {
  3. u32 dev_sn=root_obj.value("dev_sn").toDouble();
  4. QString new_name=root_obj.value("new_name").toString();
  5. updateWorkName(dev_sn, new_name);//更新设备名称
  6. }
五、删除设备

        删除设备可以是多个的,所以参数是一个设备列表:

  1. void CenterMan::requestDelDevice(QList<qint64> dev_list)
  2. {
  3. QJsonArray dev_array;
  4. QJsonObject root_obj;
  5. QJsonDocument json_doc;
  6. qDebug()<<"del dev_list="<<dev_list;
  7. int nSize=dev_list.size();
  8. for(int i=0; i<nSize; i++)
  9. {
  10. u32 dev_sn=dev_list.at(i);
  11. if(dev_sn>0)
  12. {
  13. dev_array.append((qint64)dev_sn);
  14. }
  15. }
  16. root_obj.insert("account", m_loginAccount);
  17. root_obj.insert("rand_num", m_randNum);
  18. root_obj.insert("mac", m_macStr);
  19. root_obj.insert("app_id", (qint64)m_currAppWork.appID);
  20. root_obj.insert("dev_list", dev_array);
  21. root_obj.insert("cmd_type", "del_dev");
  22. json_doc.setObject(root_obj);
  23. QByteArray msg_ba = json_doc.toJson(QJsonDocument::Indented);
  24. QString topic=makePubTopic("device");
  25. emit sigMqttPushMessage(topic, msg_ba);
  26. }

        服务器解析后从数据库中一个个删除设备:

  1. else if(cmd_type=="del_dev")
  2. {
  3. QJsonArray dev_array;
  4. if(root_obj.contains("dev_list"))
  5. {
  6. QJsonValue value = root_obj.value("dev_list");
  7. dev_array=value.toArray();
  8. }
  9. int nSize=dev_array.size();
  10. for(int i=0; i<nSize; i++)
  11. {
  12. u32 dev_sn=dev_array.at(i).toDouble();
  13. tag_groupSqlite.delDeviceNode(dev_sn);//删除设备
  14. }
  15. ack_str="删除成功!";
  16. ackDelDevice(account, mac_str, rand_num, app_id, dev_array, result, ack_str);
  17. }

        用户端也要删除对应的前端显示,在删除最后一个后,需要重新排序设备,这样才能更新服务器内的分组信息。

  1. else if(cmd_type=="del_dev")//移除设备
  2. {
  3. QJsonArray dev_array;
  4. if(root_obj.contains("dev_list"))
  5. {
  6. QJsonValue value = root_obj.value("dev_list");
  7. dev_array=value.toArray();
  8. }
  9. int nSize=dev_array.size();
  10. for(int i=0; i<nSize; i++)
  11. {
  12. u32 dev_sn=dev_array.at(i).toDouble();
  13. delWorkDevice(dev_sn);//删除工作设备
  14. emit siqDelDevice(dev_sn, i==nSize-1);//删除显示设备
  15. }
  16. }

六、移动设备

        移动设备相对来讲是比较复杂的,首先有两个分组,一个是源分组,就是设备要移出的分组;另一个是目标分组,就是设备要移到的分组,设备是多个的。所以,对于源分组,我们要删除要移出的设备,这里排除“全部”这个分组;对于目标分组,我们要新增移出来的设备,这里对于重复的设备要检查,各自任务完成后就是请求重新排序就可以了,具体代码如下:

  1. void CenterMan::requestMoveDevice(QString src_group, QString dst_group, QList<qint64> dev_list)
  2. {
  3. GroupNodeStruct *pGroupNodeSrc=searchGroupNode(src_group);
  4. GroupNodeStruct *pGroupNodeDst=searchGroupNode(dst_group);
  5. int nSize=dev_list.size();
  6. if(pGroupNodeSrc==nullptr || pGroupNodeDst==nullptr || nSize<=0)
  7. return;
  8. qDebug()<<"move src_group="<<src_group;
  9. qDebug()<<"move dst_group="<<dst_group;
  10. qDebug()<<"move dev_list="<<dev_list;
  11. qDebug()<<"src dev list="<<pGroupNodeSrc->devList;
  12. qDebug()<<"dst dev list="<<pGroupNodeDst->devList;
  13. if(src_group!="全部")
  14. {
  15. for(auto iter : dev_list)//先移除源分组设备
  16. {
  17. qDebug()<<"will remove dev sn="<<iter<<", dev_list="<<pGroupNodeSrc->devList;
  18. for(int i=0; i<pGroupNodeSrc->devList.size(); i++)
  19. {
  20. if(iter==pGroupNodeSrc->devList.at(i))
  21. {
  22. qDebug()<<"remove dev_sn="<<iter;
  23. pGroupNodeSrc->devList.removeAt(i);
  24. break;
  25. }
  26. }
  27. }
  28. requestSortDevice(src_group, pGroupNodeSrc->devList);//重新排序
  29. }
  30. if(dst_group!="全部")
  31. {
  32. for(auto iter : dev_list)//添加到目标分组
  33. {
  34. bool flag=false;
  35. for(int i=0; i<pGroupNodeDst->devList.size(); i++)
  36. {
  37. if(iter==pGroupNodeDst->devList.at(i))//重复,不能添加
  38. {
  39. flag=true;
  40. break;
  41. }
  42. }
  43. if(flag==false)
  44. {
  45. pGroupNodeDst->devList.append(iter);
  46. }
  47. }
  48. requestSortDevice(dst_group, pGroupNodeDst->devList);//重新排序
  49. }
  50. }

        这里有几点需要提一下,首先,"全部"分组是比较特殊的,它是包含所有设备的,所以设备从"全部"分组移出后自身不会删除;反过来,如果其它分组的设备想移除,但不是删除,那么可以将设备 移动到"全部"分组即可。另外一点,米家APP的每一个设备只能存放在一个分组内,那我们这边对这个没做限制,用户可以根据自己的需求和习惯,将一个设备放在不同分组内。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/酷酷是懒虫/article/detail/753623
推荐阅读
相关标签
  

闽ICP备14008679号