终端一体化运控平台
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

466 lignes
19 KiB

  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. }