终端一体化运控平台
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

DataVReport.cs 19 KiB

2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
2年前
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. using BPA.Message.IOT;
  2. using BPASmartClient.Helper;
  3. using BPASmartClient.IoT;
  4. using BPASmartClient.IoT.Model;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Net;
  9. using System.Security.Cryptography;
  10. using System.Text;
  11. using System.Threading;
  12. using uPLibrary.Networking.M2Mqtt;
  13. using uPLibrary.Networking.M2Mqtt.Messages;
  14. namespace BPASmartDatavDeviceClient.IoT
  15. {
  16. /// <summary>
  17. /// DataV客户端
  18. /// </summary>
  19. public class DataVReport
  20. {
  21. #region 外部调用
  22. /// <summary>
  23. /// 初始化IOT连接
  24. /// </summary>
  25. public bool Initialize(string url, string _clientId, string _deviceId, ref string message)
  26. {
  27. if (string.IsNullOrEmpty(url)) return false;
  28. deviceId = _deviceId;
  29. if (!CreateLinks(url, _clientId, out deviceTable, _deviceId))
  30. {
  31. message += $"客户端{_clientId}设备{_deviceId}阿里云上没有该设备。";
  32. return false;
  33. }
  34. IOT_Subscribe(BroadcastTopic);//订阅广播主题
  35. IOT_Subscribe(FileUpLoadReplyTopic);
  36. IOT_Subscribe(FileUpLoadSendReplyTopic);
  37. IOT_Subscribe(CancelFileUpLoadSendTopic);
  38. if (!DatavDeviceClient.IsConnected) message += $"客户端:【{_clientId}】,设备名称{deviceTable.devicename}阿里云连接失败.不能上报业务信息";
  39. return DatavDeviceClient.IsConnected;
  40. }
  41. /// <summary>
  42. /// 初始化IOT连接
  43. /// </summary>
  44. public bool InitializeNo(string _productkey, string _devicename, string _devicesecret, ref string message)
  45. {
  46. try
  47. {
  48. if (deviceTable == null) deviceTable = new DeviceTable();
  49. deviceTable.devicename = _devicename;
  50. SetValue(_productkey, _devicename, _devicesecret);
  51. IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
  52. string _clientIp = host.AddressList.FirstOrDefault(
  53. ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
  54. string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
  55. string signmethod = "hmacmd5";
  56. Dictionary<string, string> dict = new Dictionary<string, string>();
  57. dict.Add("productKey", ProductKey);
  58. dict.Add("deviceName", DeviceName);
  59. dict.Add("clientId", _clientIp);
  60. dict.Add("timestamp", t);
  61. mqttUserName = DeviceName + "&" + ProductKey;
  62. mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
  63. mqttClientId = _clientIp + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
  64. targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
  65. ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
  66. }
  67. catch (Exception ex)
  68. {
  69. message += $"阿里云{_devicename}连接失败,{ex.Message}";
  70. return false;
  71. }
  72. IOT_Subscribe(BroadcastTopic);//订阅广播主题
  73. IOT_Subscribe(FileUpLoadReplyTopic);
  74. IOT_Subscribe(FileUpLoadSendReplyTopic);
  75. IOT_Subscribe(CancelFileUpLoadSendTopic);
  76. if (!DatavDeviceClient.IsConnected) message += $"客户端:【】,设备名称{deviceTable.devicename}阿里云连接失败.不能上报业务信息";
  77. return DatavDeviceClient.IsConnected;
  78. }
  79. /// <summary>
  80. /// 获取连接状态
  81. /// </summary>
  82. public bool GetIsConnected()
  83. {
  84. try
  85. {
  86. if (DatavDeviceClient == null || !DatavDeviceClient.IsConnected)
  87. return false;
  88. else return true;
  89. }
  90. catch (Exception ex)
  91. {
  92. return false;
  93. throw;
  94. }
  95. }
  96. /// <summary>
  97. /// 断开连接
  98. /// </summary>
  99. public void Disconnect()
  100. {
  101. if (DatavDeviceClient != null)
  102. {
  103. DatavDeviceClient.Disconnect();
  104. }
  105. }
  106. /// <summary>
  107. /// 发布消息
  108. /// </summary>
  109. /// <param name="topic"></param>
  110. /// <param name="message"></param>
  111. public void IOT_Publish(string topic, string message)
  112. {
  113. var id = DatavDeviceClient.Publish(topic, Encoding.UTF8.GetBytes(message));
  114. }
  115. public void IOT_Publish(string topic, byte[] message)
  116. {
  117. var id = DatavDeviceClient.Publish(topic, message);
  118. }
  119. /// <summary>
  120. /// 订阅主题
  121. /// </summary>
  122. /// <param name="topic"></param>
  123. public void IOT_Subscribe(string topic)
  124. {
  125. if (SubTopicList.Contains(topic))
  126. {
  127. SubTopicList.Add(topic);
  128. }
  129. DatavDeviceClient.Subscribe(new string[] { topic }, new byte[] { 0 });
  130. }
  131. public void Chkin_Up()
  132. {
  133. OSS_Helper ss = new OSS_Helper();
  134. string objectName = "Project/aa.bak";
  135. string downloadFilename = @"\\aa.bak";
  136. //记录进度的文件路径
  137. string checkpointDir = @"D:\checkin\";
  138. //ss.Multipar_tUp(objectName, downloadFilename);
  139. ss.chkin_Up(objectName, downloadFilename, checkpointDir);
  140. }
  141. #endregion
  142. #region 私有函数
  143. /// <summary>
  144. /// 设置变量
  145. /// </summary>
  146. /// <param name="_ProductKey"></param>
  147. /// <param name="_DeviceName"></param>
  148. /// <param name="_DeviceSecret"></param>
  149. /// <param name="_RegionId"></param>
  150. private void SetValue(string _ProductKey, string _DeviceName, string _DeviceSecret, string _RegionId = "cn-shanghai")
  151. {
  152. ProductKey = _ProductKey;
  153. DeviceName = _DeviceName;
  154. DeviceSecret = _DeviceSecret;
  155. RegionId = _RegionId;
  156. PubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/post";
  157. SubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/set";
  158. UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
  159. UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
  160. BroadcastTopic = "/broadcast/" + ProductKey + "/" + DeviceName + "_SetDevice";
  161. AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
  162. LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
  163. HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
  164. TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
  165. ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
  166. FileUpLoadTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init";
  167. FileUpLoadReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init_reply";
  168. FileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send";
  169. FileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send_reply";
  170. CancelFileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel";
  171. CancelFileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel_reply";
  172. }
  173. /// <summary>
  174. /// 创建连接
  175. /// </summary>
  176. private bool CreateLinks(string url, string clientId, out DeviceTable device, string deviceId = "")
  177. {
  178. try
  179. {
  180. string json = string.Empty;
  181. if (string.IsNullOrEmpty(deviceId))
  182. json = HttpRequestHelper.HttpGetRequest($"{url}/api/Device/Query?clientId={clientId}", 1000);
  183. else
  184. json = HttpRequestHelper.HttpGetRequest($"{url}/api/Device/Query?clientId={clientId}&deviceId={deviceId}");
  185. JsonMsg<List<DeviceTable>> jsonMsg = Tools.JsonToObjectTools<JsonMsg<List<DeviceTable>>>(json);
  186. if (jsonMsg.obj != null && jsonMsg.obj.data != null)
  187. {
  188. device = jsonMsg.obj.data.FirstOrDefault();
  189. if (device == null) return false;
  190. SetValue(device.productkey, device.devicename, device.devicesecret);
  191. IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
  192. string _clientIp = host.AddressList.FirstOrDefault(
  193. ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
  194. string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
  195. string signmethod = "hmacmd5";
  196. Dictionary<string, string> dict = new Dictionary<string, string>();
  197. dict.Add("productKey", ProductKey);
  198. dict.Add("deviceName", DeviceName);
  199. dict.Add("clientId", _clientIp);
  200. dict.Add("timestamp", t);
  201. mqttUserName = DeviceName + "&" + ProductKey;
  202. mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
  203. mqttClientId = _clientIp + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
  204. targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
  205. ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
  206. return true;
  207. }
  208. else
  209. {
  210. device = null;
  211. return false;
  212. }
  213. }
  214. catch (Exception ex)
  215. {
  216. device = null;
  217. return false;
  218. }
  219. }
  220. /// <summary>
  221. /// MQTT创建连接
  222. /// </summary>
  223. /// <param name="targetServer"></param>
  224. /// <param name="mqttClientId"></param>
  225. /// <param name="mqttUserName"></param>
  226. /// <param name="mqttPassword"></param>
  227. private void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword)
  228. {
  229. DatavDeviceClient = new MqttClient(targetServer);
  230. DatavDeviceClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
  231. DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
  232. DatavDeviceClient.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
  233. DatavDeviceClient.ConnectionClosed += Client_ConnectionClosed;
  234. }
  235. /// <summary>
  236. /// MQTT 断开事件
  237. /// </summary>
  238. /// <param name="sender"></param>
  239. /// <param name="e"></param>
  240. private void Client_ConnectionClosed(object sender, EventArgs e)
  241. {
  242. // 尝试重连
  243. _TryContinueConnect();
  244. }
  245. /// <summary>
  246. /// 订阅数据接收
  247. /// </summary>
  248. /// <param name="sender"></param>
  249. /// <param name="e"></param>
  250. private void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
  251. {
  252. string topic = e.Topic;
  253. string message = Encoding.UTF8.GetString(e.Message);
  254. if (DataVMessageAction != null)
  255. {
  256. DataVMessageAction.Invoke(deviceId, topic, message);
  257. }
  258. }
  259. /// <summary>
  260. /// 自动重连主体
  261. /// </summary>
  262. private void _TryContinueConnect()
  263. {
  264. Thread retryThread = new Thread(new ThreadStart(delegate
  265. {
  266. while (DatavDeviceClient == null || !DatavDeviceClient.IsConnected)
  267. {
  268. if (DatavDeviceClient.IsConnected) break;
  269. if (DatavDeviceClient == null)
  270. {
  271. DatavDeviceClient = new MqttClient(targetServer);
  272. DatavDeviceClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
  273. DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
  274. DatavDeviceClient.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
  275. DatavDeviceClient.ConnectionClosed += Client_ConnectionClosed;
  276. if (DatavDeviceClient.IsConnected)
  277. {
  278. SubTopicList?.ForEach(par => { DatavDeviceClient.Subscribe(new string[] { par }, new byte[] { 0 }); });
  279. }
  280. Thread.Sleep(3000);
  281. continue;
  282. }
  283. try
  284. {
  285. DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
  286. if (DatavDeviceClient.IsConnected)
  287. {
  288. SubTopicList?.ForEach(par => { DatavDeviceClient.Subscribe(new string[] { par }, new byte[] { 0 }); });
  289. UnConnectMqtt?.Invoke("重新连接阿里云MQTT成功!");
  290. }
  291. }
  292. catch (Exception ce)
  293. {
  294. UnConnectMqtt?.Invoke("重新连接阿里云MQTT失败!");
  295. }
  296. // 如果还没连接不符合结束条件则睡2秒
  297. if (!DatavDeviceClient.IsConnected)
  298. {
  299. Thread.Sleep(2000);
  300. }
  301. }
  302. }));
  303. retryThread.Start();
  304. }
  305. #endregion
  306. #region 私有IOT连接变量
  307. private static string ProductKey = "grgpECHSL7q";
  308. private static string DeviceName = "hbldev";
  309. private static string DeviceSecret = "4ec120de0c866199183b22e2e3135aeb";
  310. private static string RegionId = "cn-shanghai";
  311. private static string mqttUserName = string.Empty;
  312. private static string mqttPassword = string.Empty;
  313. private static string mqttClientId = string.Empty;
  314. private static string targetServer = string.Empty;
  315. private static string deviceId = string.Empty;
  316. #endregion
  317. #region 公有变量
  318. /// <summary>
  319. /// 设备消息数据回调
  320. /// </summary>
  321. public Action<string, string, string> DataVMessageAction { get; set; }
  322. /// <summary>
  323. /// 重连事件
  324. /// </summary>
  325. public static Action<string> UnConnectMqtt { get; set; }
  326. /// <summary>
  327. /// 客户端
  328. /// </summary>
  329. public static MqttClient DatavDeviceClient { get; set; }
  330. /// <summary>
  331. /// 当前设备
  332. /// </summary>
  333. public DeviceTable deviceTable = new DeviceTable();
  334. #endregion
  335. #region 发布或订阅主题或URL地址
  336. /// <summary>
  337. /// 属性发布消息主题
  338. /// </summary>
  339. public string PubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
  340. /// <summary>
  341. /// 属性接收消息主题
  342. /// </summary>
  343. public static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
  344. /// <summary>
  345. /// 自定义发布消息主题
  346. /// </summary>
  347. public static string UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
  348. /// <summary>
  349. /// 自定义接收消息主题
  350. /// </summary>
  351. public static string UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
  352. /// <summary>
  353. /// 告警订阅主题
  354. /// </summary>
  355. public static string AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
  356. /// <summary>
  357. /// 日志订阅主题
  358. /// </summary>
  359. public static string LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
  360. /// <summary>
  361. /// 上下线订阅主题
  362. /// </summary>
  363. public static string HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
  364. /// <summary>
  365. /// 属性状态主题
  366. /// </summary>
  367. public static string TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
  368. /// <summary>
  369. /// 大屏展示发布主题
  370. /// </summary>
  371. public static string ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
  372. /// <summary>
  373. /// 广播主题
  374. /// </summary>
  375. public string BroadcastTopic = "/broadcast/" + "grgpECHSL7q" + "/" + DeviceName + "_SetDevice";
  376. /// <summary>
  377. /// 文件上传请求Topic
  378. /// </summary>
  379. public string FileUpLoadTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init";
  380. /// <summary>
  381. /// 文件上传请求响应Topic
  382. /// </summary>
  383. public string FileUpLoadReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init_reply";
  384. /// <summary>
  385. /// 文件发送Topic
  386. /// </summary>
  387. public string FileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send";
  388. /// <summary>
  389. /// 文件发送响应Topic
  390. /// </summary>
  391. public string FileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send_reply";
  392. /// <summary>
  393. /// 取消文件发送Topic
  394. /// </summary>
  395. public string CancelFileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel";
  396. /// <summary>
  397. /// 取消文件发送响应Topic
  398. /// </summary>
  399. public string CancelFileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel_reply";
  400. /// <summary>
  401. /// 订阅主题集合
  402. /// </summary>
  403. public static List<string> SubTopicList = new List<string>();
  404. #endregion
  405. }
  406. /// <summary>
  407. /// Iot 设备上报
  408. /// </summary>
  409. public class IotSignUtils
  410. {
  411. public static string sign(Dictionary<string, string> param,
  412. string deviceSecret, string signMethod)
  413. {
  414. string[] sortedKey = param.Keys.ToArray();
  415. Array.Sort(sortedKey);
  416. StringBuilder builder = new StringBuilder();
  417. foreach (var i in sortedKey)
  418. {
  419. builder.Append(i).Append(param[i]);
  420. }
  421. byte[] key = Encoding.UTF8.GetBytes(deviceSecret);
  422. byte[] signContent = Encoding.UTF8.GetBytes(builder.ToString());
  423. //这里根据signMethod动态调整,本例子硬编码了: 'hmacmd5'
  424. var hmac = new HMACMD5(key);
  425. byte[] hashBytes = hmac.ComputeHash(signContent);
  426. StringBuilder signBuilder = new StringBuilder();
  427. foreach (byte b in hashBytes)
  428. signBuilder.AppendFormat("{0:x2}", b);
  429. return signBuilder.ToString();
  430. }
  431. }
  432. }