|
- using BPASmartClient.Helper;
- using BPASmartClient.IoT;
- 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
- {
- /// <summary>
- /// DataV客户端
- /// </summary>
- public class DataVReport
- {
- #region 外部调用
- /// <summary>
- /// 初始化IOT连接
- /// </summary>
- public bool Initialize(string url,string clientId,string deviceId,ref string message)
- {
- if(string.IsNullOrEmpty(url))return false;
- DeviceTable device;
- if (!CreateLinks(url,clientId,deviceId, out device))
- {
- message += $"客户端{clientId}设备{deviceId}阿里云上没有该设备。";
- return false;
- }
- IOT_Subscribe(BroadcastTopic);//订阅广播主题
- if (DatavDeviceClient.IsConnected) message += $"设备{device.devicename} {device.remark}阿里云连接成功.";
- else message += $"设备{device.devicename} {device.remark}阿里云连接失败.不能上报业务信息";
- return DatavDeviceClient.IsConnected;
- }
-
- /// <summary>
- /// 获取连接状态
- /// </summary>
- public bool GetIsConnected()
- {
- try
- {
- if (DatavDeviceClient == null || !DatavDeviceClient.IsConnected)
- return false;
- else return true;
- }
- catch (Exception ex)
- {
- return false;
- throw;
- }
- }
-
- /// <summary>
- /// 断开连接
- /// </summary>
- public void Disconnect()
- {
- if (DatavDeviceClient != null)
- {
- DatavDeviceClient.Disconnect();
- }
- }
-
- /// <summary>
- /// 发布消息
- /// </summary>
- /// <param name="topic"></param>
- /// <param name="message"></param>
- public void IOT_Publish(string topic, string message)
- {
- var id = DatavDeviceClient.Publish(topic, Encoding.UTF8.GetBytes(message));
- }
-
- /// <summary>
- /// 订阅主题
- /// </summary>
- /// <param name="topic"></param>
- public void IOT_Subscribe(string topic)
- {
- if (SubTopicList.Contains(topic))
- {
- SubTopicList.Add(topic);
- }
- DatavDeviceClient.Subscribe(new string[] { topic }, new byte[] { 0 });
- }
- #endregion
-
- #region 私有函数
- /// <summary>
- /// 设置变量
- /// </summary>
- /// <param name="_ProductKey"></param>
- /// <param name="_DeviceName"></param>
- /// <param name="_DeviceSecret"></param>
- /// <param name="_RegionId"></param>
- 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";
- }
-
- /// <summary>
- /// 创建连接
- /// </summary>
- private bool CreateLinks(string url, string clientId, string deviceId, out DeviceTable device)
- {
- try
- {
- string json = HttpRequestHelper.HttpGetRequest($"{url}/api/Device/Query?clientId={clientId}&deviceId={deviceId}");
- JsonMsg<List<DeviceTable>> jsonMsg = Tools.JsonToObjectTools<JsonMsg<List<DeviceTable>>>(json);
- if (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 _clientId = host.AddressList.FirstOrDefault(
- ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).ToString();
- string t = Convert.ToString(DateTimeOffset.Now.ToUnixTimeMilliseconds());
- string signmethod = "hmacmd5";
-
- Dictionary<string, string> dict = new Dictionary<string, string>();
- 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;
- }
- }
-
- /// <summary>
- /// MQTT创建连接
- /// </summary>
- /// <param name="targetServer"></param>
- /// <param name="mqttClientId"></param>
- /// <param name="mqttUserName"></param>
- /// <param name="mqttPassword"></param>
- 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;
- }
-
- /// <summary>
- /// MQTT 断开事件
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private static void Client_ConnectionClosed(object sender, EventArgs e)
- {
- // 尝试重连
- _TryContinueConnect();
- }
-
- /// <summary>
- /// 订阅数据接收
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private static void Client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
- {
- string topic = e.Topic;
- string message = Encoding.UTF8.GetString(e.Message);
- if (DataVMessageAction != null)
- {
- DataVMessageAction.Invoke(topic, message);
- }
- }
-
- /// <summary>
- /// 自动重连主体
- /// </summary>
- private static 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;
- #endregion
-
- #region 公有变量
- /// <summary>
- /// 设备消息数据回调
- /// </summary>
- public static Action<string, string> DataVMessageAction { get; set; }
- /// <summary>
- /// 重连事件
- /// </summary>
- public static Action<string> UnConnectMqtt { get; set; }
- /// <summary>
- /// 客户端
- /// </summary>
- public static MqttClient DatavDeviceClient { get; set; }
- /// <summary>
- /// 当前设备
- /// </summary>
- public DeviceTable deviceTable { get; set; }
- #endregion
-
- #region 发布或订阅主题或URL地址
- /// <summary>
- /// 属性发布消息主题
- /// </summary>
- public static string PubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
- /// <summary>
- /// 属性接收消息主题
- /// </summary>
- public static string SubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
- /// <summary>
- /// 自定义发布消息主题
- /// </summary>
- public static string UserPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/update";
- /// <summary>
- /// 自定义接收消息主题
- /// </summary>
- public static string UserSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/get";
- /// <summary>
- /// 告警订阅主题
- /// </summary>
- public static string AlarmSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/AlarmMessage";
- /// <summary>
- /// 日志订阅主题
- /// </summary>
- public static string LogsSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ExceptionLogs";
- /// <summary>
- /// 上下线订阅主题
- /// </summary>
- public static string HeartbeatSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/HeartbeatAndState";
- /// <summary>
- /// 属性状态主题
- /// </summary>
- public static string TargetStatusSubTopic = "/" + ProductKey + "/" + DeviceName + "/user/TargetStatus";
- /// <summary>
- /// 大屏展示发布主题
- /// </summary>
- public static string ScreenShowPubTopic = "/" + ProductKey + "/" + DeviceName + "/user/ScreenShow";
- /// <summary>
- /// 广播主题
- /// </summary>
- public static string BroadcastTopic = "/broadcast/" + "grgpECHSL7q" + "/" + DeviceName + "_SetDevice";
- /// <summary>
- /// 订阅主题集合
- /// </summary>
- public static List<string> SubTopicList = new List<string>();
- #endregion
- }
-
- /// <summary>
- /// Iot 设备上报
- /// </summary>
- public class IotSignUtils
- {
- public static string sign(Dictionary<string, string> 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();
- }
- }
- }
|