using BPA.Message.IOT; using BPA.Helper; using BPASmartClient.IoT; using BPASmartClient.IoT.Model; using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Security.Cryptography; using System.Text; using System.Threading; using uPLibrary.Networking.M2Mqtt; using uPLibrary.Networking.M2Mqtt.Messages; namespace BPASmartDatavDeviceClient.IoT { /// /// DataV客户端 /// public class DataVReport { #region 外部调用 /// /// 初始化IOT连接 /// public bool Initialize(string url, string _clientId, string _deviceId, ref string message) { if (string.IsNullOrEmpty(url)) return false; deviceId = _deviceId; if (!CreateLinks(url, _clientId, out deviceTable, _deviceId)) { message += $"客户端{_clientId}设备{_deviceId}阿里云上没有该设备。"; return false; } IOT_Subscribe(BroadcastTopic);//订阅广播主题 IOT_Subscribe(FileUpLoadReplyTopic); IOT_Subscribe(FileUpLoadSendReplyTopic); IOT_Subscribe(CancelFileUpLoadSendTopic); if (!DatavDeviceClient.IsConnected) message += $"客户端:【{_clientId}】,设备名称{deviceTable.devicename}阿里云连接失败.不能上报业务信息"; return DatavDeviceClient.IsConnected; } /// /// 初始化IOT连接 /// public bool InitializeNo(string _productkey, string _devicename, string _devicesecret, ref string message) { try { if (deviceTable == null) deviceTable = new DeviceTable(); deviceTable.devicename = _devicename; SetValue(_productkey, _devicename, _devicesecret); IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); string _clientIp = host.AddressList.FirstOrDefault( ip => ip.AddressFamily == System.Net.Sockets.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", _clientIp); dict.Add("timestamp", t); mqttUserName = DeviceName + "&" + ProductKey; mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod); mqttClientId = _clientIp + "|securemode=3,signmethod=" + signmethod + ",timestamp=" + t + "|"; targetServer = ProductKey + ".iot-as-mqtt." + RegionId + ".aliyuncs.com"; ConnectMqtt(targetServer, mqttClientId, mqttUserName, mqttPassword); } catch (Exception ex) { message += $"阿里云{_devicename}连接失败,{ex.Message}"; return false; } IOT_Subscribe(BroadcastTopic);//订阅广播主题 IOT_Subscribe(FileUpLoadReplyTopic); IOT_Subscribe(FileUpLoadSendReplyTopic); IOT_Subscribe(CancelFileUpLoadSendTopic); if (!DatavDeviceClient.IsConnected) message += $"客户端:【】,设备名称{deviceTable.devicename}阿里云连接失败.不能上报业务信息"; return DatavDeviceClient.IsConnected; } /// /// 获取连接状态 /// public bool GetIsConnected() { try { if (DatavDeviceClient == null || !DatavDeviceClient.IsConnected) return false; else return true; } catch (Exception ex) { return false; throw; } } /// /// 断开连接 /// public void Disconnect() { if (DatavDeviceClient != null) { DatavDeviceClient.Disconnect(); } } /// /// 发布消息 /// /// /// public void IOT_Publish(string topic, string message) { var id = DatavDeviceClient.Publish(topic, Encoding.UTF8.GetBytes(message)); } public void IOT_Publish(string topic, byte[] message) { var id = DatavDeviceClient.Publish(topic, message); } /// /// 订阅主题 /// /// public void IOT_Subscribe(string topic) { if (SubTopicList.Contains(topic)) { SubTopicList.Add(topic); } DatavDeviceClient.Subscribe(new string[] { topic }, new byte[] { 0 }); } public void Chkin_Up() { OSS_Helper ss = new OSS_Helper(); string objectName = "Project/aa.bak"; string downloadFilename = @"\\aa.bak"; //记录进度的文件路径 string checkpointDir = @"D:\checkin\"; //ss.Multipar_tUp(objectName, downloadFilename); ss.chkin_Up(objectName, downloadFilename, checkpointDir); } #endregion #region 私有函数 /// /// 设置变量 /// /// /// /// /// private void SetValue(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"; FileUpLoadTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init"; FileUpLoadReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init_reply"; FileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send"; FileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send_reply"; CancelFileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel"; CancelFileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel_reply"; } /// /// 创建连接 /// private bool CreateLinks(string url, string clientId, out DeviceTable device, string deviceId = "") { try { string json = string.Empty; if (string.IsNullOrEmpty(deviceId)) //json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}", 1000); json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}"); else //json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}&deviceId={deviceId}"); json = APIHelper.GetInstance.GetRequest($"{url}/api/Device/Query?clientId={clientId}&deviceId={deviceId}"); JsonMsg> jsonMsg = Tools.JsonToObjectTools>>(json); if (jsonMsg != null && jsonMsg.obj != null && jsonMsg.obj.data != null) { device = jsonMsg.obj.data.FirstOrDefault(); if (device == null) return false; SetValue(device.productkey, device.devicename, device.devicesecret); IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName()); string _clientIp = host.AddressList.FirstOrDefault( ip => ip.AddressFamily == System.Net.Sockets.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", _clientIp); dict.Add("timestamp", t); mqttUserName = DeviceName + "&" + ProductKey; mqttPassword = IotSignUtils.sign(dict, DeviceSecret, signmethod); mqttClientId = _clientIp + "|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; } } /// /// MQTT创建连接 /// /// /// /// /// private void ConnectMqtt(string targetServer, string mqttClientId, string mqttUserName, string mqttPassword) { DatavDeviceClient = new MqttClient(targetServer); DatavDeviceClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1; DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60); DatavDeviceClient.MqttMsgPublishReceived += Client_MqttMsgPublishReceived; DatavDeviceClient.ConnectionClosed += Client_ConnectionClosed; } /// /// MQTT 断开事件 /// /// /// private void Client_ConnectionClosed(object sender, EventArgs e) { // 尝试重连 _TryContinueConnect(); } /// /// 订阅数据接收 /// /// /// private void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e) { string topic = e.Topic; string message = Encoding.UTF8.GetString(e.Message); if (DataVMessageAction != null) { DataVMessageAction.Invoke(deviceId, topic, message); } } /// /// 自动重连主体 /// private void _TryContinueConnect() { Thread retryThread = new Thread(new ThreadStart(delegate { while (DatavDeviceClient == null || !DatavDeviceClient.IsConnected) { if (DatavDeviceClient.IsConnected) break; if (DatavDeviceClient == null) { DatavDeviceClient = new MqttClient(targetServer); DatavDeviceClient.ProtocolVersion = MqttProtocolVersion.Version_3_1_1; DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60); DatavDeviceClient.MqttMsgPublishReceived += Client_MqttMsgPublishReceived; DatavDeviceClient.ConnectionClosed += Client_ConnectionClosed; if (DatavDeviceClient.IsConnected) { SubTopicList?.ForEach(par => { DatavDeviceClient.Subscribe(new string[] { par }, new byte[] { 0 }); }); } Thread.Sleep(3000); continue; } try { DatavDeviceClient.Connect(mqttClientId, mqttUserName, mqttPassword, false, 60); if (DatavDeviceClient.IsConnected) { SubTopicList?.ForEach(par => { DatavDeviceClient.Subscribe(new string[] { par }, new byte[] { 0 }); }); UnConnectMqtt?.Invoke("重新连接阿里云MQTT成功!"); } } catch (Exception ce) { UnConnectMqtt?.Invoke("重新连接阿里云MQTT失败!"); } // 如果还没连接不符合结束条件则睡2秒 if (!DatavDeviceClient.IsConnected) { Thread.Sleep(2000); } } })); retryThread.Start(); } #endregion #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; private static string deviceId = string.Empty; #endregion #region 公有变量 /// /// 设备消息数据回调 /// public Action DataVMessageAction { get; set; } /// /// 重连事件 /// public static Action UnConnectMqtt { get; set; } /// /// 客户端 /// public static MqttClient DatavDeviceClient { get; set; } /// /// 当前设备 /// public DeviceTable deviceTable = new DeviceTable(); #endregion #region 发布或订阅主题或URL地址 /// /// 属性发布消息主题 /// public 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 string BroadcastTopic = "/broadcast/" + "grgpECHSL7q" + "/" + DeviceName + "_SetDevice"; /// /// 文件上传请求Topic /// public string FileUpLoadTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init"; /// /// 文件上传请求响应Topic /// public string FileUpLoadReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/init_reply"; /// /// 文件发送Topic /// public string FileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send"; /// /// 文件发送响应Topic /// public string FileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/send_reply"; /// /// 取消文件发送Topic /// public string CancelFileUpLoadSendTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel"; /// /// 取消文件发送响应Topic /// public string CancelFileUpLoadSendReplyTopic = $"/sys/{ProductKey}/{DeviceName}/thing/file/upload/mqtt/cancel_reply"; /// /// 订阅主题集合 /// public static List SubTopicList = new List(); #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(); } } }