You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

IOTDevServer.cs 19 KiB

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