using BPA.Helper; using BPASmartClient.IoT; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; using System.Threading; using uPLibrary.Networking.M2Mqtt; using uPLibrary.Networking.M2Mqtt.Messages; namespace DataVAPI.Tool.IOT { /// /// add fengyoufu /// 黑菠萝科技有限公司 /// IOT设备上报消息类 /// public class IOTDevServer { #region 私有IOT连接变量 private static string ProductKey = "grgpECHSL7q"; private static string DeviceName = "hbldev"; private static string DeviceSecret = "4ec120de0c866199183b22e2e3135aeb"; private static string RegionId = "cn-shanghai"; private static string mqttUserName = string.Empty; private static string mqttPassword = string.Empty; private static string mqttClientId = string.Empty; private static string targetServer = string.Empty; #endregion #region 公有变量 /// /// 设备消息数据回调 /// public static Action DevIOTAction { get; set; } /// /// 重连事件 /// public static Action UNConnectMqtt { get; set; } /// /// 客户端 /// public static MqttClient client { get; set; } #endregion #region 发布或订阅主题或URL地址 /// /// API 服务 /// private static string APIurl = "http://124.222.238.75:6002"; /// /// 属性发布消息主题 /// public static string PubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update"; /// /// 属性接收消息主题 /// public static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get"; /// /// 自定义发布消息主题 /// public static string UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update"; /// /// 自定义接收消息主题 /// public static string UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get"; /// /// 告警订阅主题 /// public static string AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage"; /// /// 日志订阅主题 /// public static string LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs"; /// /// 上下线订阅主题 /// public static string HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState"; /// /// 属性状态主题 /// public static string TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus"; /// /// 大屏展示发布主题 /// public static string ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow"; /// /// 广播主题 /// public static string BroadcastTopic = "/broadcast/" + "grgpECHSL7q" + "/" + DeviceName + "_SetDevice"; /// /// 订阅主题集合 /// public static List SubTopicList = new List(); #endregion #region 单例模式 private static IOTDevServer iot = null; public static IOTDevServer GetInstance() { if (iot == null) { iot = new IOTDevServer(); } return iot; } #endregion #region 公共调用阿里云连接或检测 /// /// 设置URL /// /// public void SetUrl(string url = "http://124.222.238.75:6002") { APIurl = url; } /// /// 设置变量 /// /// /// /// /// public void Set(string _ProductKey, string _DeviceName, string _DeviceSecret, string _RegionId = "cn-shanghai") { ProductKey = _ProductKey; DeviceName = _DeviceName; DeviceSecret = _DeviceSecret; RegionId = _RegionId; PubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/post"; SubTopic = "/sys/" + ProductKey + "/" + DeviceName + "/thing/event/property/set"; UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update"; UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get"; BroadcastTopic = "/broadcast/" + ProductKey + "/" + DeviceName + "_SetDevice"; AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage"; LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs"; HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState"; TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus"; ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow"; } /// /// 创建连接 /// /// public bool CreateLinks(int ClientId, out DeviceTable device) { try { //http://localhost:9092/api/Device/Query?chid=2 //string json = APIHelper.GetInstance.GetRequest($"{APIurl}/api/Device/Query?clientId={ClientId}"); string json = APIHelper.GetInstance.GetRequest($"{APIurl}/api/Device/Query?clientId={ClientId}"); JsonMsg> jsonMsg = Tools.JsonToObjectTools>>(json); if (jsonMsg.obj != null && jsonMsg.obj.data != null) { device = jsonMsg.obj.data.FirstOrDefault(); if (device == null) return false; Set(device.productkey, device.devicename, device.devicesecret); IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); string clientId = host.AddressList.FirstOrDefault( ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString(); string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds()); string signmethod = "hmacmd5"; Dictionary dict = new Dictionary(); dict.Add("productKey", ProductKey); dict.Add("deviceName", DeviceName); dict.Add("clientId", clientId); dict.Add("timestamp", t); mqttUserName = DeviceName + "&" + ProductKey; mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod); mqttClientId = clientId + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|"; targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com"; ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword); return true; } else { device = null; return false; } } catch (Exception ex) { device = null; return false; } } /// /// 获取连接状态 /// public bool GetIsConnected() { try { if (client == null || !client.IsConnected) return false; else return true; } catch (Exception ex) { return false; throw; } } /// /// 断开连接 /// public void Disconnect() { if (client != null) { client.Disconnect(); } } #endregion #region 公共发布或订阅函数 /// /// 发布消息 /// /// /// public void IOT_Publish(string topic, string message) { var id = client.Publish(topic, Encoding.UTF8.GetBytes(message)); } /// /// 订阅主题 /// /// public void IOT_Subscribe(string topic) { if (SubTopicList.Contains(topic)) { SubTopicList.Add(topic); } client.Subscribe(new string[] { topic }, new byte[] { 0 }); } #endregion #region 私有函数 /// /// mQTT创建连接 /// /// /// /// /// private void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword) { client = new MqttClient(targetServer); client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1; client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60); client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived; client.ConnectionClosed += Client_ConnectionClosed; } /// /// MQTT 断开事件 /// /// /// private static void Client_ConnectionClosed(object sender, EventArgs e) { // 尝试重连 _TryContinueConnect(); } /// /// 订阅数据接收 /// /// /// private static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e) { string topic = e.Topic; string message = Encoding.UTF8.GetString(e.Message); if (DevIOTAction != null) { DevIOTAction.Invoke(topic, message); } } /// /// 自动重连主体 /// private static void _TryContinueConnect() { Thread retryThread = new Thread(new ThreadStart(delegate { while (client == null || !client.IsConnected) { if (client.IsConnected) break; if (client == null) { client = new MqttClient(targetServer); client.ProtocolVersion = MqttProtocolVersion.Version_3_1_1; client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60); client.MqttMsgPublishReceived += Client_MqttMsgPublishReceived; client.ConnectionClosed += Client_ConnectionClosed; if (client.IsConnected) { SubTopicList.ForEach(par => { client.Subscribe(new string[] { par }, new byte[] { 0 }); }); } Thread.Sleep(3000); continue; } try { client.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60); if (client.IsConnected) { SubTopicList.ForEach(par => { client.Subscribe(new string[] { par }, new byte[] { 0 }); }); UNConnectMqtt?.Invoke("重新连接阿里云MQTT成功!"); } } catch (Exception ce) { UNConnectMqtt?.Invoke("重新连接阿里云MQTT失败!"); } // 如果还没连接不符合结束条件则睡2秒 if (!client.IsConnected) { Thread.Sleep(2000); } } })); retryThread.Start(); } #endregion } /// /// Iot 设备上报 /// public class IotSignUtils { public static string sign(Dictionary param, string deviceSecret, string signMethod) { string[] sortedKey = param.Keys.ToArray(); Array.Sort(sortedKey); StringBuilder builder = new StringBuilder(); foreach (var i in sortedKey) { builder.Append(i).Append(param[i]); } byte[] key = Encoding.UTF8.GetBytes(deviceSecret); byte[] signContent = Encoding.UTF8.GetBytes(builder.ToString()); //这里根据signMethod动态调整,本例子硬编码了: 'hmacmd5' var hmac = new HMACMD5(key); byte[] hashBytes = hmac.ComputeHash(signContent); StringBuilder signBuilder = new StringBuilder(); foreach (byte b in hashBytes) signBuilder.AppendFormat("{0:x2}", b); return signBuilder.ToString(); } } /// /// 工具 /// public class Tools { /// /// 对象Json序列 /// /// 对象类型 /// 对象实例 /// public static string JsonConvertTools(T obj) { string strvalue = JsonConvert.SerializeObject(obj); return strvalue; } /// /// 对象反Json序列 /// /// 对象类型 /// 对象序列化json字符串 /// 返回对象实例 public static T JsonToObjectTools(string jsonstring) { T obj = JsonConvert.DeserializeObject(jsonstring); return obj; } /// /// DateTime --> long /// /// /// public static long ConvertDateTimeToLong(DateTime dt) { DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); TimeSpan toNow = dt.Subtract(dtStart); long timeStamp = toNow.Ticks; timeStamp = long.Parse(timeStamp.ToString().Substring(0, timeStamp.ToString().Length - 4)); return timeStamp; } /// /// long --> DateTime /// /// /// public static DateTime ConvertLongToDateTime(long d) { DateTime dtStart = TimeZone.CurrentTimeZone.ToLocalTime(new DateTime(1970, 1, 1)); long lTime = long.Parse(d + "0000"); TimeSpan toNow = new TimeSpan(lTime); DateTime dtResult = dtStart.Add(toNow); return dtResult; } /// /// 获取IP 地址 /// /// public static string GetLocalIp() { //得到本机名 string hostname = Dns.GetHostName(); //解析主机名称或IP地址的system.net.iphostentry实例。 IPHostEntry localhost = Dns.GetHostEntry(hostname); if (localhost != null) { foreach (IPAddress item in localhost.AddressList) { //判断是否是内网IPv4地址 if (item.AddressFamily == AddressFamily.InterNetwork) { return item.MapToIPv4().ToString(); } } } return "192.168.1.124"; } /// /// Http下载文件 /// public static string HttpDownloadFile(string url, string path) { // 设置参数 HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest; //发送请求并获取相应回应数据 HttpWebResponse response = request.GetResponse() as HttpWebResponse; //直到request.GetResponse()程序才开始向目标网页发送Post请求 Stream responseStream = response.GetResponseStream(); //创建本地文件写入流 Stream stream = new FileStream(path, FileMode.Create); byte[] bArr = new byte[1024]; int size = responseStream.Read(bArr, 0, (int)bArr.Length); while (size > 0) { stream.Write(bArr, 0, size); size = responseStream.Read(bArr, 0, (int)bArr.Length); } stream.Close(); responseStream.Close(); return path; } } }