黄学彪
2019-11-25 160785587667cc0d927f85e44c139ec9dde13a9e
ZigbeeApp/Shared/Phone/ZigBee/Device/ZbGateway.cs
@@ -8,10 +8,11 @@
using System.Net.Sockets;
using System.Net;
using Newtonsoft.Json.Linq;
using MQTTnet.Core.Client;
using MQTTnet;
using Shared.Common;
using Shared.Phone.UserView;
using MQTTnet.Client;
using System.Threading.Tasks;
namespace ZigBee.Device
{
@@ -25,6 +26,8 @@
        {
            this.Type = DeviceType.ZbGateway;
        }
        #region 网关特殊信息处理
        /// <summary>
@@ -52,16 +55,10 @@
        }
        /// <summary>
        /// 远程网关
        /// 是否使用远程连接模式
        /// </summary>
        /// <value><c>true</c> if is remote; otherwise, <c>false</c>.</value>
        public static bool IsRemote
        {
            get
            {
                return ZigBee.Device.ZbGateway.RemoteMqttClient != null && ZigBee.Device.ZbGateway.RemoteMqttClient.IsConnected;
            }
        }
        public static bool IsRemote;
        /// <summary>
        /// 网关保存路径
@@ -589,8 +586,22 @@
                DebugPrintLog("GwReName_Actions 启动" + System.DateTime.Now.ToString());
                try
                {
                    //账号ID
                    string accountId = string.Empty;
                    if (homeId != string.Empty)
                    {
                        if (Shared.Phone.UserCenter.UserCenterResourse.UserInfo.AuthorityNo == 1)
                        {
                            //主账号
                            accountId = Config.Instance.Guid;
                        }
                        else
                        {
                            accountId = Config.Instance.Home.MainUserDistributedMark;
                        }
                    }
                    var jObject = new JObject { { "Cluster_ID", 0 }, { "Command", 82 } };
                    var data = new JObject { { "HomeId", homeId } };
                    var data = new JObject { { "HomeId", homeId }, { "AccountId", accountId } };
                    jObject.Add("Data", data);
                    Send("GwSetHomeId", jObject.ToString());
                }
@@ -3077,15 +3088,12 @@
        /// <summary>
        /// 局域网的MQTT
        /// </summary>
        IMqttClient mqttClient;
        IMqttClient localMqttClient = new MqttFactory().CreateMqttClient();
        bool localMqttIsConnecting;
        /// <summary>
        /// 手机标识
        /// </summary>
        static Guid currentGuid = Guid.NewGuid();
        /// <summary>
        /// 局域网的MQTT是否正在连接
        /// </summary>
        object mqttIsConnecting = false.ToString();
        public async System.Threading.Tasks.Task StartLocalMqtt(string brokerName)
        {
@@ -3093,40 +3101,46 @@
            {
                try
                {
                    lock (mqttIsConnecting)
                    lock (localMqttClient)
                    {
                        if (mqttIsConnecting.ToString() == true.ToString() || brokerName == null)
                        if (localMqttIsConnecting
                        || !Shared.Common.Config.Instance.IsLogin
                        || Shared.Common.Config.Instance.HomeId == ""
                        || localMqttClient.IsConnected)
                        {
                            return;
                        }
                        mqttIsConnecting = true.ToString();
                        if (mqttClient == null)
                        //表示后面将进行连接
                        localMqttIsConnecting = true;
                        //(3)当[连接Mqtt成功后]或者[Mqtt转发数据给网关成功后],处理接收到数据包响应时在mqttClient_ApplicationMessageReceived这个方法处理
                        if (localMqttClient.ApplicationMessageReceivedHandler == null)
                        {
                            //(2)创建Mqtt客户端
                            mqttClient = new MqttClientFactory().CreateMqttClient();
                            //(3)当[连接Mqtt成功后]或者[Mqtt转发数据给网关成功后],处理接收到数据包响应时在mqttClient_ApplicationMessageReceived这个方法处理
                            mqttClient.ApplicationMessageReceived += (sender, e) =>
                            {
                                if (mqttClient == null || !mqttClient.IsConnected)
                            localMqttClient.UseApplicationMessageReceivedHandler((e) =>
                                {
                                    return;
                                }
                                mqttClient_MqttMsgPublishReceived(sender, e);
                            };
                            mqttClient.Disconnected += (sender, e) =>
                                    if (!localMqttClient.IsConnected)
                                    {
                                        return;
                                    }
                                    mqttClient_MqttMsgPublishReceived(e);
                                });
                        }
                        if (localMqttClient.DisconnectedHandler == null)
                        {
                            localMqttClient.UseDisconnectedHandler((e) =>
                            {
                                IsEncry = false;
#if DEBUG
                                DebugPrintLog($" 本地连接断开_网关IP:{brokerName}_网关是否加:{IsEncry}_{System.DateTime.Now.ToString()}");
#endif
                            };
                            mqttClient.Connected += async (sender, e) =>
                                DebugPrintLog($" 本地连接断开_网关IP:{brokerName}_网关是否加:{IsEncry}");
                            });
                        }
                        if (localMqttClient.ConnectedHandler == null)
                        {
                            localMqttClient.UseConnectedHandler(async (e) =>
                            {
#if DEBUG
                                DebugPrintLog($" 本地连接成功_网关IP:{brokerName}_网关是否加:{IsEncry}_当前密码:{Password}_{System.DateTime.Now.ToString()}");
#endif
                                DebugPrintLog($" 本地连接成功_网关IP:{brokerName}_网关是否加:{IsEncry}_当前密码:{Password}");
                                IsRemote = false;
                                if (PubKey != null)
                                {
                                    var rsaString = ZigBee.Common.SecuritySet.RSAEncrypt(PubKey, Password);
@@ -3142,57 +3156,133 @@
                                }
                                Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.WIFI);
                                System.Console.WriteLine($"当前是网关Wi-Fi在通讯_{System.DateTime.Now.ToString()}");
                            };
                        }
                        if (RemoteMqttClient != null && RemoteMqttClient.IsConnected == true)
                        {
                            RemoteMqttClient?.DisconnectAsync();
                            System.Console.WriteLine($"收到局域网网关,远程连接主动断开_{System.DateTime.Now.ToString()}");
                            RemoteMqttClient = null;
                        }
                        if (mqttClient.IsConnected)
                        {
                            return;
                            });
                        }
                    }
                    //(1)连接到Mqtt客户端连接参数
                    var connectCloudMqttClientOptions = new MqttClientTcpOptions
                    {
                        Server = brokerName,    //ip地址
                        ClientId = currentGuid.ToString(),
                        CleanSession = true,// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
                        KeepAlivePeriod = new TimeSpan(0, 5, 0),//设置心跳时间(最大值,2^16-1 = 65535秒 = 18小时。最小值可以为0,表示客户端不断开。一般设为几分钟,比如微信心跳周期为300秒。)
                        DefaultCommunicationTimeout = new TimeSpan(0, 0, 100),//设置超时时间
                    };
                    await mqttClient.ConnectAsync(connectCloudMqttClientOptions);
                    var options = new MQTTnet.Client.Options.MqttClientOptionsBuilder()
                                   .WithClientId(currentGuid.ToString())
               .WithTcpServer(brokerName, 1883)
               .WithKeepAlivePeriod(TimeSpan.FromSeconds(20))
               .WithCleanSession()
               .WithCredentials("", "")
               .Build();
                    await localMqttClient.ConnectAsync(options, CancellationToken.None);
                }
                catch (Exception ex)
                {
#if DEBUG
                    DebugPrintLog($"局域网通讯连接出异常:{ex.Message}");
#endif
                }
                finally
                {
                    mqttIsConnecting = false.ToString();
                    localMqttIsConnecting = false;
                }
            });
        }
        class GateWayBaseInfomation
        {
            //public string GatewayUniqueId;//"Emq网关1",   <!-- 网关Mac -->
            public bool MqttOnlineStatus;//: true,  <!-- 网关在云端Emq是否在线 -->
            public string AesKey;// : "a5d8da8a-ddea-48",  <!-- 与此网关在云端Emq通信时,负载加解的16位Aes密钥 -->
            public string MacMark;//: "61eaa0ea-4812-4a7a-86d6-3098c61e64ed"   <!-- 网关对应的唯一码 -->
        }
        /// <summary>
        /// 当前有帐号下所有的网关列表及信息
        /// </summary>
        static Dictionary<string, GateWayBaseInfomation> GateWayBaseInfomations = new Dictionary<string, GateWayBaseInfomation> { };
        /// <summary>
        /// 获取当前帐号所有的网关信息
        /// </summary>
        /// <returns></returns>
        static async System.Threading.Tasks.Task initGateWayBaseInfomation()
        {
            string loginToken = Config.Instance.Token;
            if (Config.Instance.Home.IsOthreShare == true)
            {
                //获取成员的特殊Token
                var pra = new
                {
                    CommonPage.RequestVersion,
                    LoginAccessToken = Config.Instance.Token,
                    MainAccountId = Config.Instance.Home.MainUserDistributedMark,
                    SharedHid = Config.Instance.Home.Id
                };
                var listNotShow = new List<string>() { "NotSetAgain" };
                var resultData = await Shared.Phone.UserCenter.UserCenterLogic.GetByteResponseDataByRequestHttps("App/GetSharedHomeApiControl", false, pra, listNotShow);
                if (resultData == null)
                {
                    return;
                }
                var revertObj = Newtonsoft.Json.JsonConvert.DeserializeObject<Shared.Common.ResponseEntity.ResponsePack>(Encoding.UTF8.GetString(resultData));
                //分享链接
                var info = Newtonsoft.Json.JsonConvert.DeserializeObject<Shared.Phone.UserCenter.MemberAdministratorResult>(revertObj.ResponseData.ToString());
                loginToken = info.RequestToken;
            }
            try
            {
                //设置访问接口的参数
                var pra2 = new Shared.Phone.UserCenter.GetGatewayPra();
                pra2.IsOtherAccountCtrl = Config.Instance.Home.IsOthreShare;
                pra2.ReqDto.PageSetting.Page = 1;
                pra2.ReqDto.PageSetting.PageSize = 20;
                pra2.ReqDto.LoginAccessToken = loginToken;
                var bytes = System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(pra2));
                var result = await CommonPage.Instance.DoRequestZigbeeHttpsInterface("https://global.hdlcontrol.com/HangZhouHdlCloudApi/App/GetSingleHomeGatewayPagger", bytes, loginToken);
                if (result != null)
                {
                    var jobject = Newtonsoft.Json.Linq.JObject.Parse(Encoding.UTF8.GetString(result));
                    var statuCode = jobject["StateCode"].ToString();
                    if (statuCode != "Success")
                    {
                        //Log出力
                        Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(-1, "接口访问失败★:App/GetSingleHomeGatewayPagger " + statuCode);
                        //序列化对象
                        var requestJson = Newtonsoft.Json.JsonConvert.SerializeObject(pra2);
                        Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(-1, "参数:\r\n" + requestJson);
                    }
                    var responseData = jobject["ResponseData"];
                    if (responseData != null)
                    {
                        if (responseData["PageData"] != null)
                        {
                            var list = JArray.Parse(responseData["PageData"].ToString());
                            foreach (var v in list)
                            {
                                GateWayBaseInfomations[v["GatewayUniqueId"].ToString()] = new GateWayBaseInfomation { AesKey = v["AesKey"].ToString(), MacMark = v["MacMark"].ToString(), MqttOnlineStatus = bool.Parse(v["MqttOnlineStatus"].ToString()) };
                                //if (RemoteMqttClient.IsConnected)
                                {
                                    await RemoteMqttClient.SubscribeAsync($"/ZigbeeGateWayToClient/{v["MacMark"].ToString()}/#", MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce);
                                }
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Shared.Phone.UserCenter.HdlLogLogic.Current.WriteLog(ex);
            }
        }
        /// <summary>
        /// 外网的MQTT是否正在连接
        /// </summary>
        static bool remoteMqttIsConnecting; static bool IsLoginAgain;
        static bool remoteMqttIsConnecting;
        static bool IsLoginAgain;
        /// <summary>
        /// 远程MqttClient
        /// </summary>
        public static IMqttClient RemoteMqttClient;
        public static IMqttClient RemoteMqttClient= new MqttFactory().CreateMqttClient();
        private int IsLogin = 0;
        [Newtonsoft.Json.JsonIgnore]
        static Action actionTemp;
        /// <summary>
        /// 启动远程Mqtt
        /// </summary>
@@ -3204,136 +3294,143 @@
            {
                try
                {
                    if (!Shared.Common.Config.Instance.IsLogin) {
                        return;
                    }
                    if (remoteMqttIsConnecting || Shared.Common.Config.Instance.HomeId == "")
                    lock (RemoteMqttClient)
                    {
                        return;
                    }
                    remoteMqttIsConnecting = true;
                        if (remoteMqttIsConnecting
                        || !Shared.Common.Config.Instance.IsLogin
                        || Shared.Common.Config.Instance.HomeId == ""
                        || RemoteMqttClient.IsConnected)
                        {
                            return;
                        }
                    var url = Shared.Common.Config.Instance.ZigbeeMqttBrokerLoadSubDomain;//.Replace("6688","6689");
                    if (string.IsNullOrEmpty(url) || !url.StartsWith("tcp://") || url.Split(':').Length != 3)
                    {
                        remoteMqttIsConnecting = false;
                        return;
                    }
                    if (RemoteMqttClient == null)
                    {
                        //(2)创建Mqtt客户端
                        RemoteMqttClient = new MqttClientFactory().CreateMqttClient();
                        //表示后面将进行连接
                        remoteMqttIsConnecting = true;
                        #region 初始化远程Mqtt
                        //(3)当[连接云端的Mqtt成功后]或者[以及后面App通过云端Mqtt转发数据给网关成功后],处理接收到云端数据包响应时在mqttServerClient_ApplicationMessageReceived这个方法处理
                        RemoteMqttClient.ApplicationMessageReceived += (sender, e) =>
                        if (RemoteMqttClient.ApplicationMessageReceivedHandler == null)
                        {
                            if (RemoteMqttClient == null || !RemoteMqttClient.IsConnected)
                            RemoteMqttClient.UseApplicationMessageReceivedHandler((e) =>
                            {
                                return;
                            }
                            mqttRemoteClient_MqttMsgPublishReceived(sender, e);
                        };
                        RemoteMqttClient.Disconnected += (sender, e) =>
                                if (!RemoteMqttClient.IsConnected || !IsRemote)
                                {
                                    return;
                                }
                                mqttRemoteClient_MqttMsgPublishReceived(e);
                            });
                        }
                        if (RemoteMqttClient.DisconnectedHandler == null)
                        {
#if DEBUG
                            DebugPrintLog($"远程连接断开_{System.DateTime.Now.ToString()}");
#endif
                        };
                        RemoteMqttClient.Connected += async (sender, e) =>
                        {
#if DEBUG
                            DebugPrintLog($"远程连接成功_{System.DateTime.Now.ToString()}");
#endif
                            Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.Remote);
                            //没有主网关时主动读取,获取主网关信息
                            var gateWayList = GateWayList.FindAll(obj => obj.getGatewayBaseInfo.HomeId == Shared.Common.Config.Instance.HomeId);
                            if (gateWayList.Find(obj => obj.getGatewayBaseInfo.IsMainGateWay == true) == null)
                            RemoteMqttClient.UseDisconnectedHandler((e) =>
                            {
                                DebugPrintLog($"远程连接断开");
                            });
                        }
                        if (RemoteMqttClient.ConnectedHandler == null)
                        {
                            RemoteMqttClient.UseConnectedHandler(async (e) =>
                            {
                                if (gateWayList.Count == 1)
                                DebugPrintLog($"远程连接成功");
                                await initGateWayBaseInfomation();
                                Shared.Phone.UserCenter.HdlGatewayLogic.Current.CheckGatewayByConnectChanged(Shared.Phone.UserCenter.GatewayConnectMode.Remote);
                                //没有主网关时主动读取,获取主网关信息
                                var gateWayList = GateWayList.FindAll(obj => obj.getGatewayBaseInfo.HomeId == Shared.Common.Config.Instance.HomeId);
                                if (gateWayList.Find(obj => obj.getGatewayBaseInfo.IsMainGateWay == true) == null)
                                {
                                    gateWayList[0].getGatewayBaseInfo.IsMainGateWay = true;
                                }
                                else
                                {
                                    for (int i = 0; i < gateWayList.Count; i++)
                                    if (gateWayList.Count == 1)
                                    {
                                        var gateWay = gateWayList[i];
                                        var info = await gateWay.GetZbGwInfoAsync();
                                        if (info == null || info.getGwData == null)
                                        gateWayList[0].getGatewayBaseInfo.IsMainGateWay = true;
                                    }
                                    else
                                    {
                                        for (int i = 0; i < gateWayList.Count; i++)
                                        {
                                            continue;
                                        }
                                        if (info.getGwData.IsDominant == 1)
                                        {
                                            gateWay.getGatewayBaseInfo.IsMainGateWay = true;
                                            for (int j = i + 1; j < gateWayList.Count; j++)
                                            var gateWay = gateWayList[i];
                                            var info = await gateWay.GetZbGwInfoAsync();
                                            if (info == null || info.getGwData == null)
                                            {
                                                gateWayList[j].getGatewayBaseInfo.IsMainGateWay = false;
                                                continue;
                                            }
                                            break;
                                            if (info.getGwData.IsDominant == 1)
                                            {
                                                for (int j = 0; j < gateWayList.Count; j++)
                                                {
                                                    if (gateWayList[i].getGatewayBaseInfo.gwID == info.getGwData.GwId)
                                                    {
                                                        gateWayList[i].getGatewayBaseInfo.IsMainGateWay = true;
                                                    }
                                                    else
                                                    {
                                                        gateWayList[i].getGatewayBaseInfo.IsMainGateWay = false;
                                                    }
                                                }
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                        };
                    }
                    if (RemoteMqttClient.IsConnected)
                    {
                        //当网关的连接方式改变时,检测网关,然后显示特效(可重复调用)
                        return;
                    }
                    for (int i = 0; i < GateWayList.Count; i++)
                    {
                        var gateWay = GateWayList[i];
                        try
                        {
                            gateWay.IsVirtual = true;
                            await gateWay.DisConnect("本地搜素不到网关,准备调用远程,关闭当前局域网中所有网关");
                            });
                        }
                        catch { }
                    }
                    //断开后重新链接需要重新登录获取连接的密码
                    var tempResult = await Shared.Phone.UserView.HomePage.Instance.LoginByPWDAsync(Shared.Common.Config.Instance.Account, Shared.Common.Config.Instance.Password);
                    if (tempResult != 1)
                    {
#if DEBUG
                        DebugPrintLog($"重新连接远程通讯失败,因为获取新的KEY失败");
#endif
                        return;
                        #endregion
                    }
                    //还有种情况是同一个ID 有多个设备用这个id连接(会导致中断)
                    string clientId = Shared.Common.Config.Instance.ConnectZigbeeMqttClientId;
                    string username = Shared.Common.Config.Instance.ConnectGuid;
                    string passwordRemote = Shared.Common.Config.Instance.ConnectZigbeeMqttBrokerPwd;
                    //(1)连接到云端的Mqtt客户端连接参数
                    var connectCloudMqttClientOptions = new MqttClientTcpOptions
                    {
                        Server = url.Split(':')[1].Substring("//".Length),    //114.215.173.87 先写ip吧,这个地址可能后面会换成域名
                        Port = int.Parse(url.Split(':')[2]),
                        ClientId = clientId,
                        UserName = username,//连接的用户名
                        Password = passwordRemote,//连接的密码(App登录后获取到的连接云端Mqtt密码只能连接一次成功之后不能再使用相同的密码进行连接Mqtt否则会提示用户名密码失败,连接不上云端;)
                        CleanSession = true,// 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
                        KeepAlivePeriod = new TimeSpan(0, 5, 0),//设置心跳时间(最大值,2^16-1 = 65535秒 = 18小时。最小值可以为0,表示客户端不断开。一般设为几分钟,比如微信心跳周期为300秒。)
                        DefaultCommunicationTimeout = new TimeSpan(0, 0, 100),//设置超时时间
                    };
                    //远程通讯连接,连接云端服务器
                    if (RemoteMqttClient != null)
                    try
                    {
                        await RemoteMqttClient.ConnectAsync(connectCloudMqttClientOptions);
                    }
                        var jsonData = new Dictionary<string, object> { ["RequestVersion"] = "RequestVersion", ["RequestSource"] = 0, ["LoginAccessToken"] = Config.Instance.Token, ["RequestProtocolType"] = 0 };
                        var bytes = System.Text.Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(jsonData));
                        var result = await CommonPage.Instance.DoRequestZigbeeHttpsInterface("https://global.hdlcontrol.com/HangZhouHdlCloudApi/EmqMqtt/GetConnMqttInfo", bytes, Config.Instance.Token);
                        //{
                        //"ResponseVersion": "RequestVersion1",
                        //"StateCode": "Success",
                        //"ErrorInfo": null,
                        //"ResponseData": { < !--如下信息只能使用一次,即便你连接失败!-- >
                        //   "ConnEmqDomainPort": "tcp://developer.hdlcontrol.com:1883",
                        //  "ConnEmqClientId": "ZigbeeClientTcp_33094de8-34ba-4e38-93c2-ac8da16d0e68_Zigbee",
                        //  "ConnEmqUserName": "33094de8-34ba-4e38-93c2-ac8da16d0e68",
                        //  "ConnEmqPwd": "4a265b65-d6cc-4a"
                        //}
                        //}
                        if (result != null)
                        {
                            var jobject = Newtonsoft.Json.Linq.JObject.Parse(Encoding.UTF8.GetString(result));
                            var responseData = jobject["ResponseData"];
                            if (responseData != null)
                            {
                                var connEmqDomainPort = responseData["ConnEmqDomainPort"]?.ToString();
                                var connEmqClientId = responseData["ConnEmqClientId"]?.ToString();
                                var connEmqUserName = responseData["ConnEmqUserName"]?.ToString();
                                var connEmqPwd = responseData["ConnEmqPwd"]?.ToString();
                                var connEmqDomainPorts = connEmqDomainPort.Replace("//", "").Split(':');
                                var domain = connEmqDomainPorts[1];
                                var port = connEmqDomainPorts[2];
                                var options = new MQTTnet.Client.Options.MqttClientOptionsBuilder()
                                    .WithClientId(connEmqClientId)
                .WithTcpServer(domain, int.Parse(port))
                .WithCredentials(connEmqUserName, connEmqPwd)
                .WithKeepAlivePeriod(TimeSpan.FromSeconds(20))
                .WithCleanSession()
                .Build();
                                await RemoteMqttClient.ConnectAsync(options);
                            }
                        }
                    }
                    catch { }
                    finally
                    {
                        //最终要释放连接状态
                        remoteMqttIsConnecting = false;
                    }
                }
                catch (Exception ex)
                {
#if DEBUG
                    DebugPrintLog($"远程连接通讯连接出异常:{ex.Message}");
#endif
                }
                finally
                {
                    remoteMqttIsConnecting = false;
                }
            });
        }
@@ -3345,21 +3442,26 @@
        {
            try
            {
#if DEBUG
                DebugPrintLog($"主动断开_{System.DateTime.Now.ToString()}_{s}");
#endif
                if (mqttClient != null && mqttClient.IsConnected == true)
                DebugPrintLog($"主动断开_{s}");
                if (localMqttClient.IsConnected == true)
                {
                    await mqttClient.DisconnectAsync();
                    await localMqttClient.DisconnectAsync();
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                DebugPrintLog($"断开通讯连接出异常:{ex.Message}");
#endif
            }
        }
        /// <summary>
        /// 断开远程Mqtt的链接
        /// </summary>
        public static void DisRemoteMqttClientConnect()
        {
            RemoteMqttClient.DisconnectAsync();
        }
        #endregion
        /// <summary>
@@ -3388,32 +3490,38 @@
        /// <summary>
        /// 远程发送数据格式
        /// </summary>
        async System.Threading.Tasks.Task SendRemoteMsg(string topicName, byte[] message, MQTTnet.Core.Protocol.MqttQualityOfServiceLevel qosLevel = MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, bool retain = false)
        async System.Threading.Tasks.Task SendRemoteMsg(string topicName, byte[] message, bool retain = false)
        {
            //(1)生成[用户名:密码]
            var userNameAndPwdStr = string.Concat(Shared.Common.Config.Instance.Guid, RemoteOperatorConsts.CAP_NUMBER, Shared.Common.Config.Instance.MD5PWD);
            DebugPrintLog($"userNameAndPwdStr:{userNameAndPwdStr} ");
            if (this.getGatewayBaseInfo?.gwID == null || !GateWayBaseInfomations.ContainsKey(this.getGatewayBaseInfo?.gwID))
            {
                return;
            }
            var gateWayBaseInfomation = GateWayBaseInfomations[this.getGatewayBaseInfo?.gwID];
            ////(1)生成[用户名:密码]
            //var userNameAndPwdStr = string.Concat(Shared.Common.Config.Instance.Guid, RemoteOperatorConsts.CAP_NUMBER, Shared.Common.Config.Instance.MD5PWD);
            //DebugPrintLog($"userNameAndPwdStr:{userNameAndPwdStr} ");
            //(2)将(1)转成Base64字符串,生成格式[Base64(用户名:密码)]
            var userNameAndPwdStrBaseSexFour = Convert.ToBase64String(ZigBee.Common.CommonInfo.EncodingUTF8.GetBytes(userNameAndPwdStr));
            ////(2)将(1)转成Base64字符串,生成格式[Base64(用户名:密码)]
            //var userNameAndPwdStrBaseSexFour = Convert.ToBase64String(ZigBee.Common.CommonInfo.EncodingUTF8.GetBytes(userNameAndPwdStr));
            //(3)将(2)继续生成格式[Base64(用户名:密码):Timestamp]
            var userNameAndPwdStrBaseSexFourAndTimestamp = string.Concat(userNameAndPwdStrBaseSexFour, RemoteOperatorConsts.CAP_NUMBER, CurrentTimeStamp.ToString());
            ////(3)将(2)继续生成格式[Base64(用户名:密码):Timestamp]
            //var userNameAndPwdStrBaseSexFourAndTimestamp = string.Concat(userNameAndPwdStrBaseSexFour, RemoteOperatorConsts.CAP_NUMBER, CurrentTimeStamp.ToString());
            //[Zigbee.Buspro]App/id(帐号Id)/Base64(DES[Base64(用户名:密码):Timestamp ]/网关唯一Id/转发给网关的主题/XX/XX
            //(4)生成上报主题,主题模式需要为  /ZigbeeApp/id(主子调试帐号Id)/Base64(DES[Base64(用户名:密码):Timestamp ]/网关唯一Id/topicName "000204022022"   GateWayId  000204022022
            var reportTopic = string.Format("/{0}/{1}/{2}/{3}/{4}", RemoteOperatorConsts.ZIGBEE_APP_STARTS_WITH, Shared.Common.Config.Instance.Guid, userNameAndPwdStrBaseSexFourAndTimestamp, this.getGatewayBaseInfo?.gwID, topicName);
            var aa = System.Text.Encoding.UTF8.GetString(message);
            ////[Zigbee.Buspro]App/id(帐号Id)/Base64(DES[Base64(用户名:密码):Timestamp ]/网关唯一Id/转发给网关的主题/XX/XX
            ////(4)生成上报主题,主题模式需要为  /ZigbeeApp/id(主子调试帐号Id)/Base64(DES[Base64(用户名:密码):Timestamp ]/网关唯一Id/topicName "000204022022"   GateWayId  000204022022
            //var reportTopic = string.Format("/{0}/{1}/{2}/{3}/{4}", RemoteOperatorConsts.ZIGBEE_APP_STARTS_WITH, Shared.Common.Config.Instance.Guid, userNameAndPwdStrBaseSexFourAndTimestamp, this.getGatewayBaseInfo?.gwID, topicName);
            string topicEncStr = reportTopic;
            //文件流不用加密
            topicEncStr = ZigBee.Common.SecuritySet.AesEncrypt(System.Text.Encoding.UTF8.GetBytes(topicEncStr), Shared.Common.Config.Instance.MqttKey);
            topicEncStr = topicEncStr.Replace("/", "[[$-MQTT_TILT_SYMBOL_REPLACE-$]]").Replace("+", "[[$-MQTT_PLUS_SYMBOL_REPLACE-$]]");
            message = System.Text.Encoding.UTF8.GetBytes(SecuritySet.AesEncrypt(message, Shared.Common.Config.Instance.MqttKey));
            var bb = System.Text.Encoding.UTF8.GetString(message);
            ////文件流不用加密
            //var topicEncStr = ZigBee.Common.SecuritySet.AesEncrypt(System.Text.Encoding.UTF8.GetBytes(reportTopic), gateWayBaseInfomation.AesKey);
            //topicEncStr = topicEncStr.Replace("/", "[[$-MQTT_TILT_SYMBOL_REPLACE-$]]").Replace("+", "[[$-MQTT_PLUS_SYMBOL_REPLACE-$]]");
            //message = System.Text.Encoding.UTF8.GetBytes(SecuritySet.AesEncrypt(message, gateWayBaseInfomation.AesKey));
            message = SecuritySet.AesEncryptBytes(message, gateWayBaseInfomation.AesKey);
            var topicEncStr = $"/ClientToZigbeeGateWay/{gateWayBaseInfomation.MacMark}/Common/{topicName}";
            //(6)构建Mqtt需要发布的数据包,发布给云端的MqttBroker
            await RemoteMqttClient.PublishAsync(new MQTTnet.Core.MqttApplicationMessage(topicEncStr, message, qosLevel, retain));
            if (RemoteMqttClient.IsConnected)
            {
                await RemoteMqttClient.PublishAsync(new MqttApplicationMessage { Topic = topicEncStr, Payload = message, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce });
            }
        }
        /// <summary>
@@ -3422,9 +3530,8 @@
        /// <returns></returns>
        /// <param name="topic"></param>
        /// <param name="message"></param>
        /// <param name="qosLevel"></param>
        /// <param name="retain"></param>
        public async System.Threading.Tasks.Task Send(string topic, byte[] message, MQTTnet.Core.Protocol.MqttQualityOfServiceLevel qosLevel = MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, bool retain = false)
        public async System.Threading.Tasks.Task Send(string topic, byte[] message, bool retain = false)
        {
            try
            {
@@ -3435,18 +3542,13 @@
                if (IsRemote)
                {
                    await SendRemoteMsg(topic, message, qosLevel, retain);
#if DEBUG
                    DebugPrintLog($"远程 ——发送到网关的主题:{topic}_发送到网关的数据:{System.Text.Encoding.UTF8.GetString(message)}_当前网关{CurrentGateWayId}_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");//{System.DateTime.Now.ToString()}");// DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")
#endif
                    await SendRemoteMsg(topic, message, retain);
                    DebugPrintLog($"远程——发送到网关的主题:{topic}_发送到网关的数据:{System.Text.Encoding.UTF8.GetString(message)}_当前网关{CurrentGateWayId}");//{System.DateTime.Now.ToString()}");// DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")
                }
                else
                {
#if DEBUG
                    DebugPrintLog($"局域网——发送到网关的主题:{topic}_发送到网关的数据:{System.Text.Encoding.UTF8.GetString(message)}_当前网关{CurrentGateWayId}_{System.DateTime.Now.ToString()}");
#endif
                    if (mqttClient == null || !mqttClient.IsConnected)
                    DebugPrintLog($"局域网——发送到网关的主题:{topic}_发送到网关的数据:{System.Text.Encoding.UTF8.GetString(message)}_当前网关{CurrentGateWayId}");
                    if (!localMqttClient.IsConnected)
                    {
                        await StartLocalMqtt(getGatewayBaseInfo.IpAddress);
                    }
@@ -3456,25 +3558,19 @@
                        //文件流不用加密
                        if (topic != "FileTransfer/SendFile")
                        {
                            topic = ZigBee.Common.SecuritySet.AesEncrypt(System.Text.Encoding.UTF8.GetBytes(topic), Password);
                            topic = ZigBee.Common.SecuritySet.AesEncrypt(System.Text.Encoding.UTF8.GetBytes(topic), Password);
                            topic = topic.Replace("/", "[[$-MQTT_TILT_SYMBOL_REPLACE-$]]").Replace("+", "[[$-MQTT_PLUS_SYMBOL_REPLACE-$]]");
                            message = System.Text.Encoding.UTF8.GetBytes(SecuritySet.AesEncrypt(message, password));
                            DebugPrintLog($"局域网——发送到网关的主题(秘文):{topic}_当前秘钥{Password}_发送到网关的数据(秘文):{System.Text.Encoding.UTF8.GetString(message)}_当前网关{CurrentGateWayId}_{System.DateTime.Now.ToString()}");
                        }
                        await mqttClient.PublishAsync(new MQTTnet.Core.MqttApplicationMessage(topic, message, qosLevel, retain));
                    }
                    else
                    {
                        await mqttClient.PublishAsync(new MQTTnet.Core.MqttApplicationMessage(topic, message, qosLevel, retain));
                    }
                    await localMqttClient.PublishAsync(new MqttApplicationMessage { Topic = topic, Payload = message, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, Retain = retain });
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                DebugPrintLog($"Send:{ex.Message}");
#endif
            }
        }
@@ -3484,15 +3580,14 @@
        /// <returns></returns>
        /// <param name="topic"></param>
        /// <param name="message"></param>
        /// <param name="qosLevel"></param>
        /// <param name="retain"></param>
        public async System.Threading.Tasks.Task Send(string topic, string message, MQTTnet.Core.Protocol.MqttQualityOfServiceLevel qosLevel = MQTTnet.Core.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, bool retain = false)
        public async System.Threading.Tasks.Task Send(string topic, string message, bool retain = false)
        {
            if (string.IsNullOrEmpty(message))
            {
                return;
            }
            await Send(topic, System.Text.Encoding.UTF8.GetBytes(message), qosLevel, retain);
            await Send(topic, System.Text.Encoding.UTF8.GetBytes(message), retain);
        }
@@ -3509,100 +3604,60 @@
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">E.</param>
        static void mqttRemoteClient_MqttMsgPublishReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        static void mqttRemoteClient_MqttMsgPublishReceived(MqttApplicationMessageReceivedEventArgs e)
        {
            try
            {
                var topic = e.ApplicationMessage.Topic.TrimStart('/');
                var topic = e.ApplicationMessage.Topic.TrimStart('/');
                topic = topic.Replace("[[$-MQTT_TILT_SYMBOL_REPLACE-$]]", "/").Replace("[[$-MQTT_PLUS_SYMBOL_REPLACE-$]]", "+");
                var payload = e.ApplicationMessage.Payload;
                var message = string.Empty;
                //你当前的IP及端口在云端不存在,请重新登录连接下!
                if (topic == "YouIpAndPortNoRecord")
                var topics = topic.Split("/");
                if (topics.Length < 3)
                {
                    message = System.Text.Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                }
                else if (topic == "BeingSqueezedOffline")
                {
                    //云端中的当前连接被挤下线,需要通知app
                    //全局接收网关推送的的逻辑(为了执行速度,尽可能的别加耗时的操作)
                    message = "BeingSqueezedOffline";
                    Shared.Phone.UserCenter.HdlGatewayReceiveLogic.Current.GatewayOverallMsgReceive("", topic, "", null);
                    DebugPrintLog($"被挤下线通知:{ topic}_远程返回的数据_{message}_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");//{System.DateTime.Now.ToString()}");// DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")
                    return;
                }
                //重新登录:帐号或者共享连接中的[子帐号分布式Id$Share$分布式住宅Id=XXX尚未登录,请重新登录后再连接后再进行发布操作,如果您当前是别人共享给你的连接,则请重新请求获取连接信息一下,再初始化连接再次发布远程控制即可!!
                else if (topic == "AppNoLogin")
                if (topics[0] != "ZigbeeGateWayToClient")
                {
                    message = System.Text.Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                    return;
                }
                else
                {
                    topic = topic.Replace("[[$-MQTT_TILT_SYMBOL_REPLACE-$]]", "/");
                    topic = topic.Replace("[[$-MQTT_PLUS_SYMBOL_REPLACE-$]]", "+");
                    topic = ZigBee.Common.SecuritySet.AesDecrypt(System.Text.Encoding.UTF8.GetBytes(topic), Shared.Common.Config.Instance.MqttKey).TrimStart('/'); ;
                    if (!message.EndsWith("}"))
                    {
                        message = ZigBee.Common.SecuritySet.AesDecrypt(e.ApplicationMessage.Payload, Shared.Common.Config.Instance.MqttKey);
                    }
                if (topics[2]== "NotifyGateWayInfoChagne") {
                    initGateWayBaseInfomation();
                    return;
                }
#if DEBUG
                DebugPrintLog($"远程返回的主题:{ topic}_远程返回的数据_{message}_{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");//{System.DateTime.Now.ToString()}");// DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")
#endif
                var cloudMqttResult = Newtonsoft.Json.JsonConvert.DeserializeObject<ZigBee.Common.CloudMqttResponsePack>(message);
                if (cloudMqttResult != null)
                if (topics[2] == "Common")
                {
                    if (topic == "AppConnectMqttBrokerSuccess")
                    var macMark = topics[1];
                    topic = topic.Substring(topics[0].Length + topics[1].Length + topics[2].Length + 3);
                    if (payload[0] == (byte)'{' && payload[payload.Length - 1] == (byte)'}')
                    {
                        RemoteTimeStamp = ulong.Parse(cloudMqttResult.CloudTimestamp);
                        LoginRemoteDateTime = System.DateTime.Now;
#if DEBUG
                        DebugPrintLog($"远程返回主题:{topic}_当前时间戳:_+{CurrentTimeStamp} + _+{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")}");//{System.DateTime.Now.ToString()}");// DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"   // {System.DateTime.Now.ToString()}");
#endif
                        return;
                        message = System.Text.Encoding.UTF8.GetString(payload);
                    }
                    else
                    {
                        switch (cloudMqttResult.StateCode)
                        foreach (var key in GateWayBaseInfomations.Keys)
                        {
                            case "GatewayIdNoIsYou":
                                message = cloudMqttResult.StateCode + ":" + cloudMqttResult.Info;
#if DEBUG
                                DebugPrintLog($"远程返回返回的提示内容:{message}_当前时间戳:_+{CurrentTimeStamp} + _+ {System.DateTime.Now.ToString()}");
#endif
                                return;
                            case "AppTimeOut":
                                RemoteTimeStamp = ulong.Parse(cloudMqttResult.CloudTimestamp);
                                LoginRemoteDateTime = System.DateTime.Now;
                                message = cloudMqttResult.StateCode + ":" + cloudMqttResult.Info;
#if DEBUG
                                DebugPrintLog($"远程返回返回的提示内容:{message}_当前时间戳:_+{CurrentTimeStamp} + _+ {System.DateTime.Now.ToString()}");
#endif
                                return;
                            case "AppReportSuccess":
                                RemoteTimeStamp = ulong.Parse(cloudMqttResult.CloudTimestamp);
                                LoginRemoteDateTime = System.DateTime.Now;
                                message = cloudMqttResult.StateCode + ":" + cloudMqttResult.Info;
#if DEBUG
                                DebugPrintLog($"远程返回返回的提示内容:{message}_当前时间戳:_+{CurrentTimeStamp} + _+ {System.DateTime.Now.ToString()}");
#endif
                                return;
                            case "ForwardGatewayNoOnLine":
                                message = cloudMqttResult.StateCode + ":" + cloudMqttResult.Info;
#if DEBUG
                                DebugPrintLog($"远程返回返回的提示内容:{message}_当前时间戳:_+{CurrentTimeStamp} + _+ {System.DateTime.Now.ToString()}");
#endif
                                return;
                            var value = GateWayBaseInfomations[key];
                            if (value.MacMark == macMark)
                            {
                                topic = $"{key}/{topic}";
                                message = System.Text.Encoding.UTF8.GetString(ZigBee.Common.SecuritySet.AesDecryptBytes(e.ApplicationMessage.Payload, value.AesKey));
                                break;
                            }
                        }
                    }
                }
                ReceiveMessage(topic, message, e);
                DebugPrintLog($"远程返回的主题:{ topic}_远程返回的数据_{message}");//{System.DateTime.Now.ToString()}");// DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")
                ReceiveMessage(topic, message, payload);
            }
            catch (Exception ex)
            {
#if DEBUG
                DebugPrintLog($"接收云端数据异常:{ex.Message}");
#endif
                DebugPrintLog($"接收云端数据异常:{ex.Message} ");
            }
        }
@@ -3612,11 +3667,12 @@
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">E.</param>
        void mqttClient_MqttMsgPublishReceived(object sender, MqttApplicationMessageReceivedEventArgs e)
        void mqttClient_MqttMsgPublishReceived(MqttApplicationMessageReceivedEventArgs e)
        {
            try
            {
                var topic = e.ApplicationMessage.Topic;
                var topic = e.ApplicationMessage.Topic;
                topic = topic.Replace("[[$-MQTT_TILT_SYMBOL_REPLACE-$]]", "/").Replace("[[$-MQTT_PLUS_SYMBOL_REPLACE-$]]", "+");
                var message = System.Text.Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                if (IsEncry)
@@ -3637,14 +3693,11 @@
                        message = Common.SecuritySet.AesDecrypt(e.ApplicationMessage.Payload, Password);
                    }
                }
                else
                {
                    topic = e.ApplicationMessage.Topic;
                }
#if DEBUG
                DebugPrintLog($"网关返回的主题:{topic}_网关返回的负载:{message}_{System.DateTime.Now.ToString()}");
#endif
                ReceiveMessage(topic, message, e);
                ReceiveMessage(topic, message, e.ApplicationMessage.Payload);
            }
            catch (Exception ex)
            {
@@ -3660,7 +3713,7 @@
        /// <param name="topic">Topic.</param>
        /// <param name="message">Message.</param>
        /// <param name="e">E.</param>
        static void ReceiveMessage(string topic, string message, MqttApplicationMessageReceivedEventArgs e)
        static void ReceiveMessage(string topic, string message, byte []payload)
        {
            try
            {
@@ -3683,7 +3736,7 @@
                    attrId = topic.Split('/')[5];
                }
                var gwa = ZigBee.Device.ZbGateway.GateWayList.Find(obj => obj.getGatewayBaseInfo.gwID == gatewayID);
                var gwa = GateWayList.Find(obj => obj.getGatewayBaseInfo.gwID == gatewayID);
                if (gwa == null)
                {
                    return;
@@ -3694,24 +3747,18 @@
                    gwa?.Actions(topic, message);
                }
                if (gwa.GwResDataAction != null)
                {
                    gwa.GwResDataAction(topic, message);
                }
                gwa.GwResDataAction?.Invoke(topic, message);
                gwa.CurrentGateWayId = gatewayID;
                Newtonsoft.Json.Linq.JObject jobject = new Newtonsoft.Json.Linq.JObject();
                var jobject = new Newtonsoft.Json.Linq.JObject();
                if (topic.Split('/')[0] + "/" + topic.Split('/')[1] == topic.Split('/')[0] + "/" + "FileTransfer")
                {
                    if (topic.Split('/')[2] == "DownloadFile")
                    {
                        gwa.DownloadFileConfirmAsync(e.ApplicationMessage.Payload);
                        message = System.Text.Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
                        if (gwa.FileContentAction != null)
                        {
                            gwa.FileContentAction(topic, e.ApplicationMessage.Payload);
                        }
                        DebugPrintLog($"网关返回数据流_{message}_{System.DateTime.Now.ToString()}");
                        gwa.DownloadFileConfirmAsync(payload);
                        message = System.Text.Encoding.UTF8.GetString(payload);
                        gwa.FileContentAction?.Invoke(topic, payload);
                        DebugPrintLog($"网关返回数据流_{message}");
                        return;
                    }
                }
@@ -3723,38 +3770,6 @@
                //全局接收网关推送的的逻辑(为了执行速度,尽可能的别加耗时的操作)
                Shared.Phone.UserCenter.HdlGatewayReceiveLogic.Current.GatewayOverallMsgReceive(gatewayID, topic, reportStatus, jobject);
                #region 云端通知
                var cloudMqttResult = Newtonsoft.Json.JsonConvert.DeserializeObject<ZigBee.Common.CloudMqttResponsePack>(message);
                if (cloudMqttResult != null)
                {
                    switch (cloudMqttResult.StateCode)
                    {
                        case "AppNoLogin":
                            if (gwa.CloudErrorAction != null)
                            {
                                DebugPrintLog("AppNoLogin已经通知");
                                gwa.CloudErrorAction("AppNoLogin", "登录过期,请重新登录");
                            }
                            //全局接收网关推送的的逻辑(为了执行速度,尽可能的别加耗时的操作)
                            Shared.Phone.UserCenter.HdlGatewayReceiveLogic.Current.GatewayOverallMsgReceive(gatewayID, "AppNoLogin", reportStatus, jobject);
                            break;
                        case "AppTimeOut":
                            if (gwa.CloudErrorAction != null)
                            {
                                DebugPrintLog("AppTimeOut已经通知");
                                gwa.CloudErrorAction("AppTimeOut", "从云端获取数据超时,请重新获取");
                            }
                            break;
                        case "ForwardGatewayNoOnLine":
                            if (gwa.CloudErrorAction != null)
                            {
                                DebugPrintLog("ForwardGatewayNoOnLine已经通知");
                                gwa.CloudErrorAction("ForwardGatewayNoOnLine", "当前操作的网关不在线");
                            }
                            break;
                    }
                }
                #endregion
                #region 远程,主网关上报通知
                if (IsRemote)
                {