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

IOTDevServer.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年前
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年前
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. }