Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

511 řádky
19 KiB

  1. using DataVAPI.Model;
  2. using DataVAPI.Tool.API请求;
  3. using Newtonsoft.Json;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Net.Sockets;
  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 DataVAPI.Tool.IOT
  15. {
  16. /// <summary>
  17. /// add fengyoufu
  18. /// 黑菠萝科技有限公司
  19. /// IOT设备上报消息类
  20. /// </summary>
  21. public class IOTDevServer
  22. {
  23. #region 私有IOT连接变量
  24. private static string ProductKey = "grgpECHSL7q";
  25. private static string DeviceName = "hbldev";
  26. private static string DeviceSecret = "4ec120de0c866199183b22e2e3135aeb";
  27. private static string RegionId = "cn-shanghai";
  28. private static string mqttUserName = string.Empty;
  29. private static string mqttPassword = string.Empty;
  30. private static string mqttClientId = string.Empty;
  31. private static string targetServer = string.Empty;
  32. #endregion
  33. #region 公有变量
  34. /// <summary>
  35. /// 设备消息数据回调
  36. /// </summary>
  37. public static Action<string, string> DevIOTAction { get; set; }
  38. /// <summary>
  39. /// 重连事件
  40. /// </summary>
  41. public static Action<string> UNConnectMqtt { get; set; }
  42. /// <summary>
  43. /// 客户端
  44. /// </summary>
  45. public static MqttClient client { get; set; }
  46. #endregion
  47. #region 发布或订阅主题或URL地址
  48. /// <summary>
  49. /// API 服务
  50. /// </summary>
  51. private static string APIurl = "http://124.222.238.75:6002";
  52. /// <summary>
  53. /// 属性发布消息主题
  54. /// </summary>
  55. public static string PubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
  56. /// <summary>
  57. /// 属性接收消息主题
  58. /// </summary>
  59. public static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
  60. /// <summary>
  61. /// 自定义发布消息主题
  62. /// </summary>
  63. public static string UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
  64. /// <summary>
  65. /// 自定义接收消息主题
  66. /// </summary>
  67. public static string UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
  68. /// <summary>
  69. /// 告警订阅主题
  70. /// </summary>
  71. public static string AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
  72. /// <summary>
  73. /// 日志订阅主题
  74. /// </summary>
  75. public static string LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
  76. /// <summary>
  77. /// 上下线订阅主题
  78. /// </summary>
  79. public static string HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
  80. /// <summary>
  81. /// 属性状态主题
  82. /// </summary>
  83. public static string TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
  84. /// <summary>
  85. /// 大屏展示发布主题
  86. /// </summary>
  87. public static string ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
  88. /// <summary>
  89. /// 广播主题
  90. /// </summary>
  91. public static string BroadcastTopic = "/broadcast/" + "grgpECHSL7q" + "/" + DeviceName + "_SetDevice";
  92. /// <summary>
  93. /// 订阅主题集合
  94. /// </summary>
  95. public static List<string> SubTopicList = new List<string>();
  96. #endregion
  97. #region 单例模式
  98. private static IOTDevServer iot = null;
  99. public static IOTDevServer GetInstance()
  100. {
  101. if (iot == null) { iot = new IOTDevServer(); }
  102. return iot;
  103. }
  104. #endregion
  105. #region 公共调用阿里云连接或检测
  106. /// <summary>
  107. /// 设置URL
  108. /// </summary>
  109. /// <param name="url"></param>
  110. public void SetUrl(string url = "http://124.222.238.75:6002")
  111. {
  112. APIurl = url;
  113. }
  114. /// <summary>
  115. /// 设置变量
  116. /// </summary>
  117. /// <param name="_ProductKey"></param>
  118. /// <param name="_DeviceName"></param>
  119. /// <param name="_DeviceSecret"></param>
  120. /// <param name="_RegionId"></param>
  121. public void Set(string _ProductKey, string _DeviceName, string _DeviceSecret, string _RegionId = "cn-shanghai")
  122. {
  123. ProductKey = _ProductKey;
  124. DeviceName = _DeviceName;
  125. DeviceSecret = _DeviceSecret;
  126. RegionId = _RegionId;
  127. PubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/post";
  128. SubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/set";
  129. UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
  130. UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
  131. BroadcastTopic = "/broadcast/" + ProductKey + "/" + DeviceName + "_SetDevice";
  132. AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
  133. LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
  134. HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
  135. TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
  136. ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
  137. }
  138. /// <summary>
  139. /// 创建连接
  140. /// </summary>
  141. /// <returns></returns>
  142. public bool CreateLinks(int ClientId, out DeviceTable device)
  143. {
  144. try
  145. {
  146. //http://localhost:9092/api/Device/Query?chid=2
  147. string json = HttpRequestHelper.HttpGetRequest($"{APIurl}/api/Device/Query?clientId={ClientId}");
  148. JsonMsg<List<DeviceTable>> jsonMsg = Tools.JsonToObjectTools<JsonMsg<List<DeviceTable>>>(json);
  149. if (jsonMsg.obj != null && jsonMsg.obj.data!=null)
  150. {
  151. device = jsonMsg.obj.data.FirstOrDefault();
  152. if (device == null) return false;
  153. Set(device.productkey, device.devicename, device.devicesecret);
  154. IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
  155. string clientId = host.AddressList.FirstOrDefault(
  156. ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
  157. string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
  158. string signmethod = "hmacmd5";
  159. Dictionary<string, string> dict = new Dictionary<string, string>();
  160. dict.Add("productKey", ProductKey);
  161. dict.Add("deviceName", DeviceName);
  162. dict.Add("clientId", clientId);
  163. dict.Add("timestamp", t);
  164. mqttUserName = DeviceName + "&" + ProductKey;
  165. mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
  166. mqttClientId = clientId + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
  167. targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
  168. ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
  169. return true;
  170. }
  171. else
  172. {
  173. device = null;
  174. return false;
  175. }
  176. }
  177. catch (Exception ex)
  178. {
  179. device = null;
  180. return false;
  181. }
  182. }
  183. public bool CreateLinks(string key, string name, string secret)
  184. {
  185. try
  186. {
  187. Set(key, name, secret);
  188. IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
  189. string clientId = host.AddressList.FirstOrDefault(
  190. ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
  191. string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
  192. string signmethod = "hmacmd5";
  193. Dictionary<string, string> dict = new Dictionary<string, string>();
  194. dict.Add("productKey", ProductKey);
  195. dict.Add("deviceName", DeviceName);
  196. dict.Add("clientId", clientId);
  197. dict.Add("timestamp", t);
  198. mqttUserName = DeviceName + "&" + ProductKey;
  199. mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod);
  200. mqttClientId = clientId + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|";
  201. targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com";
  202. ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword);
  203. return true;
  204. }
  205. catch (Exception ex)
  206. {
  207. return false;
  208. }
  209. }
  210. /// <summary>
  211. /// 获取连接状态
  212. /// </summary>
  213. public bool GetIsConnected()
  214. {
  215. try
  216. {
  217. if (client == null || !client.IsConnected)
  218. return false;
  219. else return true;
  220. }
  221. catch (Exception ex)
  222. {
  223. return false;
  224. throw;
  225. }
  226. }
  227. /// <summary>
  228. /// 断开连接
  229. /// </summary>
  230. public void Disconnect()
  231. {
  232. if (client != null)
  233. {
  234. client.Disconnect();
  235. }
  236. }
  237. #endregion
  238. #region 公共发布或订阅函数
  239. /// <summary>
  240. /// 发布消息
  241. /// </summary>
  242. /// <param name="topic"></param>
  243. /// <param name="message"></param>
  244. public void IOT_Publish(string topic, string message)
  245. {
  246. var id = client.Publish(topic, Encoding.UTF8.GetBytes(message));
  247. }
  248. /// <summary>
  249. /// 订阅主题
  250. /// </summary>
  251. /// <param name="topic"></param>
  252. public void IOT_Subscribe(string topic)
  253. {
  254. if (SubTopicList.Contains(topic))
  255. {
  256. SubTopicList.Add(topic);
  257. }
  258. client.Subscribe(new string[] { topic }, new byte[] { 0 });
  259. }
  260. #endregion
  261. #region 私有函数
  262. /// <summary>
  263. /// mQTT创建连接
  264. /// </summary>
  265. /// <param name="targetServer"></param>
  266. /// <param name="mqttClientId"></param>
  267. /// <param name="mqttUserName"></param>
  268. /// <param name="mqttPassword"></param>
  269. private void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword)
  270. {
  271. client = new MqttClient(targetServer);
  272. client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
  273. client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
  274. client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
  275. client.ConnectionClosed += Client_ConnectionClosed;
  276. }
  277. /// <summary>
  278. /// MQTT 断开事件
  279. /// </summary>
  280. /// <param name="sender"></param>
  281. /// <param name="e"></param>
  282. private static void Client_ConnectionClosed(object sender, EventArgs e)
  283. {
  284. // 尝试重连
  285. _TryContinueConnect();
  286. }
  287. /// <summary>
  288. /// 订阅数据接收
  289. /// </summary>
  290. /// <param name="sender"></param>
  291. /// <param name="e"></param>
  292. private static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
  293. {
  294. string topic = e.Topic;
  295. string message = Encoding.UTF8.GetString(e.Message);
  296. if (DevIOTAction != null)
  297. {
  298. DevIOTAction.Invoke(topic, message);
  299. }
  300. }
  301. /// <summary>
  302. /// 自动重连主体
  303. /// </summary>
  304. private static void _TryContinueConnect()
  305. {
  306. Thread retryThread = new Thread(new ThreadStart(delegate
  307. {
  308. while (client == null || !client.IsConnected)
  309. {
  310. if (client.IsConnected) break;
  311. if (client == null)
  312. {
  313. client = new MqttClient(targetServer);
  314. client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1;
  315. client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
  316. client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived;
  317. client.ConnectionClosed += Client_ConnectionClosed;
  318. if (client.IsConnected)
  319. {
  320. SubTopicList.ForEach(par =>
  321. {
  322. client.Subscribe(new string[] { par }, new byte[] { 0 });
  323. });
  324. }
  325. Thread.Sleep(3000);
  326. continue;
  327. }
  328. try
  329. {
  330. client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60);
  331. if (client.IsConnected)
  332. {
  333. SubTopicList.ForEach(par =>
  334. {
  335. client.Subscribe(new string[] { par }, new byte[] { 0 });
  336. });
  337. UNConnectMqtt?.Invoke("重新连接阿里云MQTT成功!");
  338. }
  339. }
  340. catch (Exception ce)
  341. {
  342. UNConnectMqtt?.Invoke("重新连接阿里云MQTT失败!");
  343. }
  344. // 如果还没连接不符合结束条件则睡2秒
  345. if (!client.IsConnected)
  346. {
  347. Thread.Sleep(2000);
  348. }
  349. }
  350. }));
  351. retryThread.Start();
  352. }
  353. #endregion
  354. }
  355. /// <summary>
  356. /// Iot 设备上报
  357. /// </summary>
  358. public class IotSignUtils
  359. {
  360. public static string sign(Dictionary<string, string> param,
  361. string deviceSecret, string signMethod)
  362. {
  363. string[] sortedKey = param.Keys.ToArray();
  364. Array.Sort(sortedKey);
  365. StringBuilder builder = new StringBuilder();
  366. foreach (var i in sortedKey)
  367. {
  368. builder.Append(i).Append(param[i]);
  369. }
  370. byte[] key = Encoding.UTF8.GetBytes(deviceSecret);
  371. byte[] signContent = Encoding.UTF8.GetBytes(builder.ToString());
  372. //这里根据signMethod动态调整,本例子硬编码了: 'hmacmd5'
  373. var hmac = new HMACMD5(key);
  374. byte[] hashBytes = hmac.ComputeHash(signContent);
  375. StringBuilder signBuilder = new StringBuilder();
  376. foreach (byte b in hashBytes)
  377. signBuilder.AppendFormat("{0:x2}", b);
  378. return signBuilder.ToString();
  379. }
  380. }
  381. /// <summary>
  382. /// 工具
  383. /// </summary>
  384. public class Tools
  385. {
  386. /// <summary>
  387. /// 对象Json序列
  388. /// </summary>
  389. /// <typeparam name="T">对象类型</typeparam>
  390. /// <param name="obj">对象实例</param>
  391. /// <returns></returns>
  392. public static string JsonConvertTools<T>(T obj)
  393. {
  394. string strvalue = JsonConvert.SerializeObject(obj);
  395. return strvalue;
  396. }
  397. /// <summary>
  398. /// 对象反Json序列
  399. /// </summary>
  400. /// <typeparam name="T">对象类型</typeparam>
  401. /// <param name="jsonstring">对象序列化json字符串</param>
  402. /// <returns>返回对象实例</returns>
  403. public static T JsonToObjectTools<T>(string jsonstring)
  404. {
  405. T obj = JsonConvert.DeserializeObject<T>(jsonstring);
  406. return obj;
  407. }
  408. /// <summary>
  409. /// DateTime --> long
  410. /// </summary>
  411. /// <param name="dt"></param>
  412. /// <returns></returns>
  413. public static long ConvertDateTimeToLong(DateTime dt)
  414. {
  415. DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
  416. TimeSpan toNow = dt.Subtract(dtStart);
  417. long timeStamp = toNow.Ticks;
  418. timeStamp = long.Parse(timeStamp.ToString().Substring(0, timeStamp.ToString().Length - 4));
  419. return timeStamp;
  420. }
  421. /// <summary>
  422. /// long --> DateTime
  423. /// </summary>
  424. /// <param name="d"></param>
  425. /// <returns></returns>
  426. public static DateTime ConvertLongToDateTime(long d)
  427. {
  428. DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1));
  429. long lTime = long.Parse(d + "0000");
  430. TimeSpan toNow = new TimeSpan(lTime);
  431. DateTime dtResult = dtStart.Add(toNow);
  432. return dtResult;
  433. }
  434. /// <summary>
  435. /// 获取IP 地址
  436. /// </summary>
  437. /// <returns></returns>
  438. public static string GetLocalIp()
  439. {
  440. //得到本机名
  441. string hostname = Dns.GetHostName();
  442. //解析主机名称或IP地址的system.net.iphostentry实例。
  443. IPHostEntry localhost = Dns.GetHostEntry(hostname);
  444. if (localhost != null)
  445. {
  446. foreach (IPAddress item in localhost.AddressList)
  447. {
  448. //判断是否是内网IPv4地址
  449. if (item.AddressFamily == AddressFamily.InterNetwork)
  450. {
  451. return item.MapToIPv4().ToString();
  452. }
  453. }
  454. }
  455. return "192.168.1.124";
  456. }
  457. /// <summary>
  458. /// 获取某个对象中的属性值
  459. /// </summary>
  460. /// <param name="info"></param>
  461. /// <param name="field"></param>
  462. /// <returns></returns>
  463. public static object GetPropertyValue(object info, string field)
  464. {
  465. if (info == null) return null;
  466. Type t = info.GetType();
  467. IEnumerable<System.Reflection.PropertyInfo> property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi;
  468. return property.First().GetValue(info, null);
  469. }
  470. }
  471. }