JLChen
2020-03-16 30d5375178a275abd2019f2e5ce0eab1dfa51e0e
Crabtree/SmartHome/UI/SimpleControl/MqttCommon.cs
@@ -21,6 +21,7 @@
        static string checkGatewayTopicBase64 = "";
        static RemoteMACInfo CurRemoteMACInfo = null;
        static MqttInfo mMqttInfo = null;
        public static bool IsGatewayOnline = true;
        /// <summary>
        /// 手机标识
@@ -44,6 +45,7 @@
        static MqttCommon ()
        {
            InitMqtt ();
            InitCheckGateway ();
        }
        /// <summary>
@@ -54,11 +56,13 @@
        {
            new System.Threading.Thread (async () => {
                while (true) {
                    System.Threading.Thread.Sleep (100);
                    if (!CommonPage.IsRemote) continue;
                    try {
                        System.Threading.Thread.Sleep (100);
                        if (!CommonPage.IsRemote) continue;
                    await StartCloudMqtt ();
                    await CheckingSubscribeTopics ();
                        await StartCloudMqtt ();
                        await CheckingSubscribeTopics ();
                    } catch { }
                }
            }) { IsBackground = true }.Start ();
@@ -97,7 +101,15 @@
                        QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce
                    };
                    var topicFilters = new TopicFilter [] { topicFilterCommon, topicFilterGateWayInfoChange, topicFilterNotifySqueeze };
                    //网关掉线主题
                    var topicFilterNotifyGateWayOffline = new TopicFilter () {
                        Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyGateWayOffline",
                        QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce
                    };
                    var topicFilters = new TopicFilter [] { topicFilterCommon, topicFilterGateWayInfoChange, topicFilterNotifySqueeze, topicFilterNotifyGateWayOffline };
                    var result = await RemoteMqttClient.SubscribeAsync (topicFilters);
                    if (result.Items [0].ResultCode == MQTTnet.Client.Subscribing.MqttClientSubscribeResultCode.GrantedQoS2) {
                        isSubscribeTopicSuccess = true;
@@ -110,21 +122,26 @@
        /// <summary>
        /// 断开远程Mqtt的链接
        /// <summary>
        /// 断开远程Mqtt的链接
        /// </summary>
        public static async System.Threading.Tasks.Task DisConnectRemoteMqttClient (string s = "")
        {
            try {
                if (remoteIsConnected) {
                    remoteIsConnected = false;
                    System.Console.WriteLine ($"============>MqttRemote主动断开_{s}");
                    //await RemoteMqttClient.DisconnectAsync(new MQTTnet.Client.Disconnecting.MqttClientDisconnectOptions { }, CancellationToken.None);
        public static async System.Threading.Tasks.Task DisConnectRemoteMqttClient (string s = "")
        {
            try {
                if (remoteIsConnected) {
                    remoteIsConnected = false;
                    System.Console.WriteLine ($"============>MqttRemote主动断开_{s}");
                    //await RemoteMqttClient.DisconnectAsync(new MQTTnet.Client.Disconnecting.MqttClientDisconnectOptions { }, CancellationToken.None);
                    await RemoteMqttClient.DisconnectAsync ();
                }
                    if (CommonPage.IsRemote) {
                        Utlis.ShowAppLinkStatus (AppLinkStatus.CloudUnlink);
                    }
                    System.Console.WriteLine ($"============>MqttRemoteDisConnectRemoteMqttClient");
                }
            } catch (Exception e) {
                System.Console.WriteLine ($"============>MqttRemote断开通讯连接出异常:{e.Message}");
            }
                System.Console.WriteLine ($"============>MqttRemote断开通讯连接出异常:{e.Message}");
            }
        }
        static DateTime dateTime = DateTime.MinValue;
@@ -178,55 +195,26 @@
                                    //2020-01-11 修改订阅主题地址
                                    if (aesDecryptTopic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyBusGateWayInfoChange") {//网关上线,需要更新aeskey                                                                                                                     //----第二步:读取账号下面的网关列表
                                        await ReceiveNotifyBusGateWayInfoChange ();
                                    } else if (aesDecryptTopic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyGateWayOffline") {//网关掉线                                                                                                                    //----第二步:读取账号下面的网关列表
                                        ReceiveNotifyGateWayOffline ();
                                    } else if (aesDecryptTopic == $"/BusGateWayToClient/{mMqttInfo.connEmqClientId}/Push/NotifySqueeze") {//订阅挤下线问题
                                        await ReceiveNotifySqueezeAsync (aesDecryptPayload);
                                    }else if (aesDecryptTopic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/Common/CheckGateway") {
                                        MainPage.WiFiStatus = "CrabtreeAdd/CloudUnlink.png";
                                        // = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/OldON";
                                        var ss = CommonPage.MyEncodingUTF8.GetString (aesDecryptPayload);
                                        var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponsePack> (ss);
                                        if (obj == null) {
                                            return;
                                        }
                                        switch (obj.StateCode) {
                                        case "HDLUdpDataForwardServerMqttClientNoOnLine":
                                        case "NoOnline":
                                        case "NetworkAnomaly"://不在线
                                            MainPage.AddTip ("Gateway offline");
                                            //Application.RunOnMainThread (() => {
                                            //    Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
                                            //});
                                            break;
                                        case "NoRecord"://MAC不正确
                                            MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.MACError));
                                            //Application.RunOnMainThread (() => {
                                            //    Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
                                            //});
                                            break;
                                        case "Success":
                                            MainPage.AddTip (UserConfig.Instance.CurrentRegion.Name + ":" + Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LinkSuccess));
                                            MainPage.WiFiStatus = "CrabtreeAdd/CloudLink.png";
                                            break;
                                        default:
                                            MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LinkLoser));
                                            //Application.RunOnMainThread (() => {
                                            //    Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
                                            //});
                                            break;
                                        }
                                        Application.RunOnMainThread (() => {
                                            UserMiddle.btnLinkStatus.UnSelectedImagePath = MainPage.WiFiStatus;
                                        });
                                        ReceiveCheckGatewayTopic ();
                                    } else {
                                        SetGatewayOnlineResetCheck ();
                                        if (!string.IsNullOrEmpty (mqttEncryptKey)) {
                                            aesDecryptPayload = Shared.Securitys.EncryptionService.AesDecryptPayload (e.ApplicationMessage.Payload, mqttEncryptKey);
                                        }
                                        var packet = new Packet ();
                                        packet.IsLocal = false;
                                        packet.Bytes = aesDecryptPayload;
                                        packet.Manager ();
                                    }
                                    var packet = new Packet ();
                                    packet.IsLocal = false;
                                    packet.Bytes = aesDecryptPayload;
                                    packet.Manager ();
                                } catch { }
                            });
                        }
@@ -250,20 +238,38 @@
                        }
                        if (RemoteMqttClient.ConnectedHandler == null) {
                            RemoteMqttClient.UseConnectedHandler (async (e) => {
                                IfNeedReadAllDeviceStatus = true;
                                Shared.SimpleControl.Phone.UserMiddle.ReadAllDeviceStatus ();
                                System.Console.WriteLine ($"============>Mqtt远程连接成功");
                                if (CommonPage.IsRemote) {
                                    Utlis.ShowAppLinkStatus (AppLinkStatus.CloudLink);
                                }
                                if (CurRemoteMACInfo != null) {
                                    if (CurRemoteMACInfo.isValid == "InValid") {
                                    IsGatewayOnline = CurRemoteMACInfo.isValid != "InValid";
                                    if (!IsGatewayOnline) {
                                        //网关不在线
                                        if (CommonPage.IsRemote) {
                                            Utlis.ShowAppLinkStatus (AppLinkStatus.CloudOffline);
                                        }
                                        MainPage.AddTip ("Remote failed,gateway offline");
                                    } else {
                                        //网关在线
                                        //重新一次所有设备状态
                                        IfNeedReadAllDeviceStatus = false;
                                        Shared.SimpleControl.Phone.UserMiddle.ReadAllDeviceStatus ();
                                        //
                                        MqttRemoteSend (new byte [] { 0 }, 3);
                                    }
                                    //if (CurRemoteMACInfo.isValid == "InValid") {
                                    //    MainPage.AddTip ("Remote failed,gateway offline");
                                    //} else {
                                    //    MqttRemoteSend (new byte [] { 0 }, 3);
                                    //}
                                }
                            });
                        }
@@ -361,6 +367,7 @@
                await DisConnectRemoteMqttClient ("StartRemoteMqtt");
                await RemoteMqttClient.ConnectAsync (options1);
                remoteIsConnected = true;
                IsDisConnectingWithSendCatch = false;
                //await MqttRemoteSend (new byte [] { 0 }, 1);
                //await MqttRemoteSend (new byte [] { 0 }, 2);
                //await MqttRemoteSend (new byte [] { 0 }, 4);
@@ -368,67 +375,112 @@
            }
        }
        ///// <summary>
        /////
        ///// </summary>
        ///// <param name="message">附加数据包</param>
        ///// <param name="optionType">操作类型:0=网关控制;1=订阅网关数据;2=订阅网关上线数据;3=订阅网关是否在线主题  4=订阅挤下线主题 </param>
        ///// <returns></returns>
        //public static async Task MqttRemoteSend (byte [] message, int optionType = 0)
        //{
        //    try {
        //        if (!remoteIsConnected) {
        //            System.Console.WriteLine ($"============>Mqtt 未连接 取消发送");
        //            return;
        //        }
        //        var topicName = @"/" + MainPage.LoginUser.AccountString.ToLower () + @"/" + UserConfig.Instance.GatewayMAC.Replace (".", "") + @"/" + currentGuid;
        //        switch (optionType) {
        //        case 0:
        //            var messageSend = message;
        //            if (string.IsNullOrEmpty (mqttEncryptKey)) {
        //                topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/OldON";
        //            } else {
        //                topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/NewON";
        //                messageSend = Shared.Securitys.EncryptionService.AesEncryptPayload (message, mqttEncryptKey);
        //            }
        //            //base64加密
        //            var m = new MqttApplicationMessage { Topic = topicName, Payload = messageSend, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce };
        //            //if (remoteIsConnected) {
        //            try {
        //                RemoteMqttClient.PublishAsync (m);
        //            } catch (Exception e) {
        //                //await DisConnectRemoteMqttClient (e.Message);
        //                //await StartCloudMqtt ();
        //                //if (remoteIsConnected) {
        //                //    RemoteMqttClient.PublishAsync (m);
        //                //}
        //            }
        //            //}
        //            break;
        //        case 3:
        //            topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/CheckGateway";
        //            var m1 = new MqttApplicationMessage { Topic = topicName, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce };
        //            try {
        //                Console.WriteLine ("CheckGateway");
        //                RemoteMqttClient.PublishAsync (m1);
        //            } catch (Exception e) {
        //                Console.WriteLine ($"CheckGateway Fail:{e.Message}");
        //                //await DisConnectRemoteMqttClient (e.Message);
        //                //await StartCloudMqtt ();
        //            }
        //            break;
        //        }
        //    } catch (Exception e) {
        //    }
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="message">附加数据包</param>
        /// <param name="optionType">操作类型:0=网关控制;1=订阅网关数据;2=订阅网关上线数据;3=订阅网关是否在线主题  4=订阅挤下线主题 </param>
        /// <param name="optionType">操作类型:0=网关控制;1=订阅网关数据;2=订阅网关上线数据</param>
        /// <returns></returns>
        public static async Task MqttRemoteSend (byte [] message, int optionType = 0)
        {
            try {
                if (!remoteIsConnected) {
                    System.Console.WriteLine ($"============>Mqtt 未连接 取消发送");
                    return;
                }
                //if (!remoteIsConnected) {
                //    System.Console.WriteLine ($"============>Mqtt 未连接 取消发送");
                //    return;
                //}
                var topicName = @"/" + MainPage.LoginUser.AccountString.ToLower () + @"/" + UserConfig.Instance.GatewayMAC.Replace (".", "") + @"/" + currentGuid;
                string topicName;
                switch (optionType) {
                case 0:
                    var messageSend = message;
                    if (string.IsNullOrEmpty (mqttEncryptKey)) {
                        topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/OldON";
                    } else {
                        topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/NewON";
                        messageSend = Shared.Securitys.EncryptionService.AesEncryptPayload (message, mqttEncryptKey);
                    topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/ON";
                    if (!string.IsNullOrEmpty (mqttEncryptKey)) {
                        message = Shared.Securitys.EncryptionService.AesEncryptPayload (message, mqttEncryptKey);
                    }
                    //base64加密
                    var m = new MqttApplicationMessage { Topic = topicName, Payload = messageSend, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce };
                    //if (remoteIsConnected) {
                    try {
                         RemoteMqttClient.PublishAsync (m);
                    } catch (Exception e) {
                        //await DisConnectRemoteMqttClient (e.Message);
                        //await StartCloudMqtt ();
                        //if (remoteIsConnected) {
                        //    RemoteMqttClient.PublishAsync (m);
                        //}
                    }
                    //}
                    await RemoteMqttClient.PublishAsync (new MqttApplicationMessage { Topic = topicName, Payload = message, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce });
                    break;
                case 3:
                    topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/CheckGateway";
                    var m1 = new MqttApplicationMessage { Topic = topicName, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce };
                    try {
                        Console.WriteLine ("CheckGateway");
                         RemoteMqttClient.PublishAsync (m1);
                    } catch (Exception e) {
                        Console.WriteLine ($"CheckGateway Fail:{e.Message}");
                        //await DisConnectRemoteMqttClient (e.Message);
                        //await StartCloudMqtt ();
                    }
                    //Console.WriteLine ("CheckGateway");
                    await RemoteMqttClient.PublishAsync (new MqttApplicationMessage { Topic = topicName, Retain = false, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce });
                    break;
                }
            } catch (Exception e) {
                // System.Console.WriteLine ($"============>Mqtt MqttRemoteSend catch");
                 if (!IsDisConnectingWithSendCatch) {
                    IsDisConnectingWithSendCatch = true;
                    await DisConnectRemoteMqttClient ("MqttRemoteSendCatch");
                }
            }
        }
        /// <summary>
        /// SendCatch 后执行一次断开操作
        /// </summary>
        static bool IsDisConnectingWithSendCatch = false;
        /// <summary>
        /// 分享住宅 获取当前住宅网关信息并且连接MQTT 或者刷新  
@@ -488,12 +540,28 @@
           
        }
        /// <summary>
        /// 是否需要读取一次所有设备状态
        /// </summary>
        static bool IfNeedReadAllDeviceStatus = true;
        /// <summary>
        /// 收到网关上线消息
        /// </summary>
        static async Task ReceiveNotifyBusGateWayInfoChange ()
        {
            System.Console.WriteLine ("============>Mqtt 网关上线");
            SetGatewayOnlineResetCheck ();
            if (CommonPage.IsRemote) {
//#if DEBUG
                MainPage.AddTip ("Gateway login online");
//#endif
                if (IfNeedReadAllDeviceStatus) {
                    IfNeedReadAllDeviceStatus = false;
                    Shared.SimpleControl.Phone.UserMiddle.ReadAllDeviceStatus ();
                }
            }
            //当前住宅不是分享来
            if (!UserConfig.Instance.CurrentRegion.IsOthreShare) {
@@ -513,6 +581,139 @@
            }
        }
        /// <summary>
        /// 收到网关掉线信息
        /// </summary>
        static void ReceiveNotifyGateWayOffline ()
        {
            System.Console.WriteLine ("============>Mqtt GateWayOffline");
            IsGatewayOnline = false;
            if (CommonPage.IsRemote) {
                Utlis.ShowAppLinkStatus (AppLinkStatus.CloudOffline);
                MainPage.AddTip ("Remote failed,gateway offline");
                //if (MainPage.WiFiStatus != "CrabtreeAdd/CloudUnlink.png") {
                //    Utlis.ShowAppLinkStatus (AppLinkStatus.CloudUnlink);
                //}
            }
        }
        static int CheckGatewayCount = 0;
        static DateTime mCheckGatewayTime;
        /// <summary>
        /// 设置网关在线标志,并重置CheckGateway参数
        /// </summary>
        static void SetGatewayOnlineResetCheck ()
        {
            IsGatewayOnline = true;
            mCheckGatewayTime = DateTime.Now;
            CheckGatewayCount = 0;
            if (CommonPage.IsRemote) {
                if (MainPage.WiFiStatus != "CrabtreeAdd/CloudLink.png") {
                    Utlis.ShowAppLinkStatus (AppLinkStatus.CloudLink);
                }
            }
        }
        //static void TipGatewayOffline () {
        //}
        /// <summary>
        /// 定时检测网关是否在线
        /// 1.线程休眠间隔5s
        /// 2.发送CheckGateway间隔为9S,收到主题刷新该时间,重置发送次数
        /// 3.发送次数到达3次以上,则判定网关为离线状态
        /// </summary>
        /// <returns></returns>
        static void InitCheckGateway ()
        {
            new System.Threading.Thread (async () => {
                while (true) {
                    try {
                        if (CommonPage.IsRemote && remoteIsConnected) {
                            if (CheckGatewayCount >= 3) {
                                //连续3次没回复,判定网关超时
                                if (MainPage.WiFiStatus == "CrabtreeAdd/CloudLink.png") {
                                    IsGatewayOnline = false;
                                    Utlis.ShowAppLinkStatus (AppLinkStatus.CloudOffline);
                                    MainPage.AddTip ("Gateway offline!");
                                }
                            }
                            if (mCheckGatewayTime.AddSeconds (10).Ticks <= System.DateTime.Now.Ticks) {
                                mCheckGatewayTime = DateTime.Now;
                                //CheckGateway
                                MqttRemoteSend (new byte [] { }, 3);
                                CheckGatewayCount++;
#if DEBUG
                                Console.WriteLine ("CheckGateway");
#endif
                            }
                        }
                        System.Threading.Thread.Sleep (5500);
                    } catch { }
                }
            }) { IsBackground = true }.Start ();
        }
        /// <summary>
        /// 收到CheckGateway主题
        /// </summary>
        static void ReceiveCheckGatewayTopic () {
            //System.Console.WriteLine ("============>Mqtt CheckGateway网关回复");
            SetGatewayOnlineResetCheck ();
            //旧网关方法
            //MainPage.WiFiStatus = "CrabtreeAdd/CloudUnlink.png";
            //// = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/OldON";
            //var ss = CommonPage.MyEncodingUTF8.GetString (aesDecryptPayload);
            //var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponsePack> (ss);
            //if (obj == null) {
            //    return;
            //}
            //switch (obj.StateCode) {
            //case "HDLUdpDataForwardServerMqttClientNoOnLine":
            //case "NoOnline":
            //case "NetworkAnomaly"://不在线
            //    MainPage.AddTip ("Gateway offline");
            //    //Application.RunOnMainThread (() => {
            //    //    Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
            //    //});
            //    break;
            //case "NoRecord"://MAC不正确
            //    MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.MACError));
            //    //Application.RunOnMainThread (() => {
            //    //    Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
            //    //});
            //    break;
            //case "Success":
            //    MainPage.AddTip (UserConfig.Instance.CurrentRegion.Name + ":" + Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LinkSuccess));
            //    MainPage.WiFiStatus = "CrabtreeAdd/CloudLink.png";
            //    break;
            //default:
            //    MainPage.AddTip (Language.StringByID (Shared.SimpleControl.R.MyInternationalizationString.LinkLoser));
            //    //Application.RunOnMainThread (() => {
            //    //    Shared.SimpleControl.Phone.UserMiddle.LinkStatusTip.BackgroundColor = SkinStyle.Current.DelColor;
            //    //});
            //    break;
            //}
            //Application.RunOnMainThread (() => {
            //    UserMiddle.btnLinkStatus.UnSelectedImagePath = MainPage.WiFiStatus;
            //});
        }
        /// <summary>
        /// 收到挤下线推送