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

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