基于工业数据的三维仿真系统
一、前言
建筑与施工团队正在经历全面的转型,建筑信息模型和虚拟数据中心已经从根本上改变了设计、建造、施工和运营。虚拟测试方法正在大幅降低风险,并带来各种创新解决方案。这就是工业化建筑时代中的生存和发展之道。
- 本项目针对塔机设备进行 Android APP 开发。
二、环境配置
- 开发环境
操作系统 | Microsoft Windows 10 专业工作站版 |
IDE名称 | Android Studio 3.2 |
Android 虚拟机 | Nexus Android 9.0 x86 |
JDK | JDK 1.8.191 |
三、系统设计
1、系统结构功能图
整个APP应用架构分为四大模块:
- 登录模块
- 用户信息模块
- 设备信息模块
- 控制台模块
共分为九个部分:
- 账户登录
- 账号注册
- 用户信息修改
- 用户信息查看
- 设备信息添加
- 设备信息查看
- 设备信息修改
- 添加维修记录
- 查看维修记录
系统结构功能图如下:
2、APP系统时序(MVP设计模式)
- 时序图如下:
- 登录请求时序
当用户点击登陆按钮时,P层(Presenter层,即业务逻辑层)通过调用登陆按钮响应事件,把V层(View层,即用户界面层)的账号密码通过简单的有效性检查后,保存到M层(Model层,即数据模型层),再提交到服务器,服务器将提交的信息通过逻辑判断后,从而对数据库进行相应操作,接着将结果逐层返回,最后在V层(View层,即用户界面层)将结果呈现。
- 其他请求时序:
其他事件发起请求时,P层通过调用相应的响应事件,把M层数据做简单的有效性检查和权限检验后,没有权限的事件直接返回,通过Toast组件给用户提示。通过权限校验事件向服务器提交请求,服务器将提交的信息通过逻辑判断后,从而对数据库进行相应操作,接着将结果逐层返回,最后在V层(View层,即用户界面层)将结果呈现。
四 、后台接口
1、 登录模块
a、登录到服务器
- 接口地址:/sign_in
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 说明 |
---|---|---|
Username | String | 账号 |
Password | String | 密码 |
Type_APP | String | 登陆类型 |
- 请求示例:
http://192.168.199.152:3001/sign_in?Username=12345678&Password=12345678&Type_APP=load
- JSON返回实例
[
{
Success: "yes",
Type_APP: "registe",
Sever_Work: "yes",
User_rights: "Administrators"
}
]
b、注册到服务器
- 接口地址:/sign_in
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 说明 |
---|---|---|
Username | String | 账号 |
Password | String | 密码 |
Type_APP | String | 登陆类型 |
User_rights | String | 注册码 |
- 请求示例:
http://192.168.199.152:3001/sign_in?Username=12345678&Password=12345678&Type_APP=registe&User_rights=888
- JSON返回实例
[
{
Success: "yes",
Type_APP: "registe",
Sever_Work: "yes",
User_rights: "Administrators"
}
]
2、设备信息模块
a、查看设备信息
- 接口地址:/Operation
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 说明 |
---|---|---|
Username | String | 账号 |
Password | String | 密码 |
Operation_Type | String | 操作类型 |
Tower_crane | String | 设备型号 |
- 请求示例:
http://192.168.199.152:3001/Operation?Username=12345678&Password=12345678&Operation_Type=Read&Tower_crane=Tower_crane1
- JSON返回实例
[
{
Operation_Success: "yes",
Operation_Type: "Read",
Sever_Work: "yes",
Data: [
{
Tower_crane: "Tower_crane1",
Using_Customer: null,
Using_Place: null,
Lease_Time: null,
Equipment_Name: null,
Equipment_Number: null,
Time: null,
Contract: null
}
]
}
]
b、修改设备信息
- 接口地址:/Operation
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 举例 | 说明 |
---|---|---|---|
Username | String | 12345678 | 账号 |
Password | String | 12345678 | 密码 |
Operation_Type | String | Change | 操作类型 |
Using_Customer | String | 张三 | 操作员 |
Tower_crane | String | Tower_crane1 | 设备型号 |
- 请求示例:
http://192.168.199.152:3001/Operation?Username=12345678&Password=12345678&Operation_Type=Change&Using_Customer=张三&Using_Place=广州&Tower_crane=Tower_crane1
- JSON返回实例
[
{
"Operation_Success": "yes",
"Operation_Type": "Change",
"Sever_Work": "yes",
"Data": [
"Tower_crane": "Tower_crane1",
"Using_Customer": "张三",
"Using_Place": "广州",
"Lease_Time": null,
"Equipment_Name": null,
"Equipment_Number": null,
"Time": null,
"Contract": null
}]
}
]
c、登录到服务器
- 接口地址:/Operation
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 举例 | 说明 |
---|---|---|---|
Username | String | 12345678 | 账号 |
Password | String | 12345678 | 密码 |
Operation_Type | String | Write | 操作类型 |
Using_Customer | String | 李四 | 操作员 |
Tower_crane | String | Tower_crane3 | 设备型号 |
- 请求示例:
http://192.168.199.152:3001/Operation?Username=12345678&Password=12345678&Operation_Type=Write&Using_Customer=李四&Using_Place=广州&Lease_Time=12&Tower_crane=Tower_crane3
- JSON返回实例
[
{
Operation_Success: "yes",
Operation_Type: "Write",
Sever_Work: "yes"
}
]
d、添加设备信息
- 接口地址:/Operation
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 说明 |
---|---|---|
Username | String | 账号 |
Password | String | 密码 |
Operation_Type | String | Change |
Using_Customer | String | 张三 |
Tower_crane | String | Tower_crane1 |
- 请求示例:
http://192.168.199.152:3001/Operation?Username=12345678&Password=12345678&Operation_Type=Change&Using_Customer=张三&Using_Place=广州&Tower_crane=Tower_crane1
- JSON返回实例
[{
"Operation_Success": "yes",
"Operation_Type": "Change",
"Sever_Work": "yes",
"Data": [
"Tower_crane": "Tower_crane1",
"Using_Customer": "张三",
"Using_Place": "广州",
"Lease_Time": null,
"Equipment_Name": null,
"Equipment_Number": null,
"Time": null,
"Contract": null
}]
}]
3、控制台模块
a、添加设备检查记录
- 接口地址:/No_Equipment_Check
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 举例 | 说明 |
---|---|---|---|
Username | String | 12345678 | 账号 |
Password | String | 12345678 | 密码 |
Operation_Type | String | Write | 操作类型 |
Tower_crane | String | Tower_crane1 | 设备型号 |
Using_Customer | String | 张三 | 操作员 |
Check_Result | String | 正确 | 检查结果 |
Check_Equipment | String | 无 | 设备型号 |
Check_Result | String | 无 | 添加时间 |
- 请求示例:
http://192.168.199.152:3001/No_Equipment_Check?Username=12345678&Password=12345678&Operation_Type=Write&Tower_crane=Tower_crane1&Operator=李四&Check_Result=正确&Check_Equipment=正常&Time=20190101
- JSON返回实例
[
{
"Success": "yes",
"Type_APP": "Write",
"Sever_Work": "yes"
}
]
b、查看设备维护记录
- 接口地址:/Repair_Data
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 举例 | 说明 |
---|---|---|---|
Username | String | 12345678 | 账号 |
Password | String | 12345678 | 密码 |
Operation_Type | String | Read | 操作类型 |
Tower_crane | String | Tower_crane1 | 设备型号 |
- 请求示例:
http://192.168.199.152:3001/Repair_Data?Username=12345678&Password=12345678&Operation_Type=Read&Tower_crane=Tower_crane1
- JSON返回示例:
[{
"Operation_Success": "yes",
"Operation_Type": "Read",
"Sever_Work": "yes",
"Data": [{
"Tower_crane": "Tower_crane1",
"Operator": "李四",
"Repair_Data": "正常",
"Repair_Result": "正常运行",
"Time": "10"
}]
}]
c、添加设备维护记录
- 接口地址:/Repair_Data
- 方式和返回:GET JSON
- 请求参数:
名称 | 类型 | 举例 | 说明 |
---|---|---|---|
Username | String | 12345678 | 账号 |
Password | String | 12345678 | 密码 |
Operation_Type | String | Write | 操作类型 |
Tower_crane | String | Tower_crane1 | 设备型号 |
Operator | String | 李四 | 操作员 |
Repair_Result | String | 正常 | 维修结果 |
Repair_Data | String | 更换塔吊部件 | 维修数据 |
- 请求示例:
http://192.168.199.152:3001/No_Equipment_Check?Username=12345678&Password=12345678&Operation_Type=Write&Tower_crane=Tower_crane1&Operator=李四&Check_Result=正常&Check_Equipment= Tower_crane1&Time=20190101
- JSON返回示例:
[ {
"Success" : "yes",
"Type_APP" : "Write",
"Sever_Work" : "yes"
} ]
4、实时数据接口
a、通信协议:
- MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议)
b、MQTT:
- 一个基于客户端-服务器的消息发布/订阅传输协议。
c、优点:
-
使用发布/订阅消息模式,提供一对多的消息发布,解除应用程序耦合。
-
对负载内容屏蔽的消息传输。
-
使用TCP/IP提供网络连接: 主流的MQTT是基于TCP连接进行数据推送的,但是同样有基于UDP的版本,叫做MQTT-SN。这两种版本由于基于不同的连接方式,优缺点自然也就各有不同了。
-
有三种消息发布服务质量:“至多一次”,消息发布完全依赖底层TCP/IP网络。会发生消息丢失或重复。这一级别可用于如下情况,环境传感器数据,丢失一次读记录无所谓,因为不久后还会有第二次发送。这一种方式主要普通APP的推送,倘若你的智能设备在消息推送时未联网,推送过去没收到,再次联网也就收不到了。“至少一次”,确保消息到达,但消息重复可能会发生。“只有一次”,确保消息到达一次。在一些要求比较严格的计费系统中,可以使用此级别。在计费系统中,消息重复或丢失会导致不正确的结果。这种最高质量的消息发布服务还可以用于即时通讯类的APP的推送,确保用户收到且只会收到一次。
-
小型传输,开销很小(固定长度的头部是2字节),协议交换最小化,以降低网络流量。
这就是为什么在介绍里说它非常适合"在物联网领域,传感器与服务器的通信,信息的收集",要知道嵌入式设备的运算能力和带宽都相对薄弱,使用这种协议来传递消息再适合不过了。 -
使用Last Will和Testament特性通知有关各方客户端异常中断的机制。Last Will:即遗言机制,用于通知同一主题下的其他设备发送遗言的设备已经断开了连接。Testament:遗嘱机制,功能类似于Last Will。
d、MQTT协议实现方式
实现MQTT协议需要客户端和服务器端通讯完成,在通讯过程中,MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。
MQTT传输的消息分为:主题(Topic)和负载(payload)两部分:
- Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload)。
- payload,可以理解为消息的内容,是指订阅者具体要使用的内容。
e、网络传输与应用消息
– MQTT服务器以称为"消息代理"(Broker),可以是一个应用程序或一台设备。它是位于消息发布者和订阅者之间,它可以:
a、接受来自客户的网络连接
b、接受客户发布的应用信息
c、处理来自客户端的订阅和退订请求
d、向订阅的客户转发应用程序消息
f、MQTT接口
- IP地址:192.168.199.183
- 端口:1883
- 主题(Topic):/test/one
- 心跳间隔(Keeplive): 300s
- 负载(payload):
属性 | 解释 |
Tcnumber: | 塔机编号(设备编码) 索引 |
Datatype : | 数据类型 |
TCManufacturer: | 塔机制造商 |
TCModel: | 塔机型号 (设备规格) |
TCheigh: | 塔机臂长 |
nld: | 额定载重量 |
ODTEMP: | 户外温度 |
WS: | 风速 |
onTime: | 开机时间 |
TCRunTime: | 工作时间 |
RttDeg: | 回转角度 |
amplitude: | 变幅 |
hoist: | 起升 |
hookHt: | 吊钩高度 |
LiftWt: | 起吊重量 |
pow: | 当前功率 |
moment: | 力矩 |
erp: | 塔机错误代码 |
ert: | 变频器错误代码 |
PCL_IN: | PLC输入状态 |
PCL_OUT: | PLC输出状态 |
logindate : | 最近登录时间 default:默认值 |
- 测试数据一
{
"Tcnumber": "1",
"Datatype" : "2",
"TCManufacturer": "3",
"TCModel": "4",
"TCheigh": "5",
"nld": "6",
"ODTEMP": "7",
"WS": "8",
"onTime": "2018-12-20T02:46:20.214Z",
"TCRunTime": "2018-12-20T02:46:20.214Z",
"RttDeg": "11",
"amplitude":"12",
"hoist": "13",
"hookHt":"14",
"LiftWt": "15",
"pow":"16",
"moment":"17",
"erp":"18",
"ert": "19",
"PCL_IN":"20",
"PCL_OUT":"21",
"logindate" :"2018-12-20T02:46:20.214Z"
}
- 测试数据二
{
"Tcnumber" : 1123,
"Datatype" : "char",
"TCManufacturer" : "华工",
"TCModel" : "重型",
"TCheigh" : 40,
"nld" : 50000,
"ODTEMP" : 11,
"WS" : 30,
"onTime" :"2018-12-20T02:46:20.214Z",
"TCRunTime" : "2018-12-20T02:46:20.214Z",
"RttDeg" : 23,
"amplitude" : 35,
"hoist" : 60,
"hookHt" : 50,
"LiftWt" : 50,
"pow" : 5000,
"moment" : 20,
"erp" : 301,
"ert" : 301,
"PCL_IN" : 0,
"PCL_OUT" : 1,
"logindate" : "2018-12-20T02:46:20.214Z",
}
五、Android 项目导入
1、使用AS导入项目(注意是导入工程)
- File --> New -->Import Project
- 选择相应的项目工程
- 完成加载即可运行
2、关于Android 源码
- 在源代码内部重要的部分都已经加以注释,这里就不展开了。
六、总结
1、关于界面的问题
- 本项目因为与服务器同时进行开发,所以后台给的API 存在部分的冗余。
- 在设备的详细信息界面,没有实现实时数据上传。需要后续继续完善。
2、关于程序设计
- 本项目只是部分使用了MVC、MVP的设计模式,但是也只是少部分,在某些模块代码仍存在代码冗余问题。需要后续改进。
3、建议
- 建议后期迭代加入路由事件总线,降低程序的耦合性。