New file |
| | |
| | | using System; |
| | | using MQTTnet.Client; |
| | | using System.Threading.Tasks; |
| | | using Shared; |
| | | using MQTTnet; |
| | | using System.Text; |
| | | using HDL_ON.Entity; |
| | | |
| | | namespace HDL_ON.DAL.Net |
| | | { |
| | | public static class Mqtt_Cloud |
| | | { |
| | | static string mqttEncryptKey = ""; |
| | | static string checkGatewayTopicBase64 = ""; |
| | | static RemoteMACInfo CurRemoteMACInfo = null; |
| | | |
| | | /// <summary> |
| | | /// 手机标识 |
| | | /// </summary> |
| | | static Guid currentGuid = Guid.NewGuid(); |
| | | |
| | | /// <summary> |
| | | /// 外网的MQTT是否正在连接 |
| | | /// </summary> |
| | | /// <summary> |
| | | /// 远程MqttClient |
| | | /// </summary> |
| | | /// <summary> |
| | | /// 远程MqttClient |
| | | /// </summary> |
| | | public static IMqttClient RemoteMqttClient = new MqttFactory().CreateMqttClient(); |
| | | |
| | | static bool thisShowTip = true; |
| | | //static string mqttRequestParToken=""; |
| | | /// <summary> |
| | | /// 推送标识 |
| | | /// </summary> |
| | | static string PushSignStr = System.DateTime.Now.Ticks.ToString(); |
| | | |
| | | /// <summary> |
| | | /// 断开远程Mqtt的链接 |
| | | /// </summary> |
| | | public static async Task DisConnectRemoteMqttClient(string s = "") |
| | | { |
| | | try |
| | | { |
| | | if (remoteIsConnected) |
| | | { |
| | | remoteIsConnected = false; |
| | | MainPage.Log($"Remote主动断开_{s}"); |
| | | //await RemoteMqttClient.DisconnectAsync(new MQTTnet.Client.Disconnecting.MqttClientDisconnectOptions { }, CancellationToken.None); |
| | | await RemoteMqttClient.DisconnectAsync(); |
| | | } |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | System.Console.WriteLine($"Remote断开通讯连接出异常:{e.Message}"); |
| | | } |
| | | } |
| | | static DateTime dateTime = DateTime.MinValue; |
| | | /// <summary> |
| | | /// 外网的MQTT是否正在连接 |
| | | /// </summary> |
| | | static bool remoteMqttIsConnecting; |
| | | static bool remoteIsConnected; |
| | | |
| | | static Mqtt_Cloud() |
| | | { |
| | | InitMqtt(); |
| | | } |
| | | |
| | | public static bool IsInitMqtt = false; |
| | | |
| | | static void InitMqtt() |
| | | { |
| | | new System.Threading.Thread(async () => { |
| | | while (true) |
| | | { |
| | | try |
| | | { |
| | | System.Threading.Thread.Sleep(1000); |
| | | if (!MainPage.IsRemote) continue; |
| | | |
| | | await StartCloudMqtt(); |
| | | await SubscribeTopics(); |
| | | } |
| | | catch { } |
| | | } |
| | | }) |
| | | { IsBackground = true }.Start(); |
| | | } |
| | | |
| | | static bool isSubscribeSuccess; |
| | | static async Task SubscribeTopics() |
| | | { |
| | | if (remoteIsConnected && !isSubscribeSuccess) |
| | | { |
| | | try |
| | | { |
| | | var topicFilter1 = new TopicFilter { QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyBusGateWayInfoChange" }; |
| | | var topicFilter2 = new TopicFilter { QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce, Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/Common/#" }; |
| | | var topicFilter3 = new TopicFilter { QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.ExactlyOnce, Topic = $"/BusGateWayToClient/{CurRemoteMACInfo.clientId}/Push/NotifySqueeze" }; |
| | | var result = await RemoteMqttClient.SubscribeAsync(new TopicFilter[] { topicFilter1, topicFilter2, topicFilter3 }); |
| | | if (result.Items[0].ResultCode == MQTTnet.Client.Subscribing.MqttClientSubscribeResultCode.GrantedQoS2) |
| | | { |
| | | isSubscribeSuccess = true; |
| | | } |
| | | } |
| | | catch { } |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// 启动远程Mqtt |
| | | /// </summary> |
| | | public static async Task StartCloudMqtt() |
| | | { |
| | | //追加:没有远程连接的权限 |
| | | if (remoteMqttIsConnecting |
| | | || remoteIsConnected || !MainPage.LoginUser.IsLogin) |
| | | { |
| | | return; |
| | | } |
| | | |
| | | await Task.Factory.StartNew(async () => { |
| | | //try { |
| | | lock (RemoteMqttClient) |
| | | { |
| | | //表示后面将进行连接 |
| | | remoteMqttIsConnecting = true; |
| | | |
| | | #region 初始化远程Mqtt |
| | | //(3)当[连接云端的Mqtt成功后]或者[以及后面App通过云端Mqtt转发数据给网关成功后],处理接收到云端数据包响应时在mqttServerClient_ApplicationMessageReceived这个方法处理 |
| | | if (RemoteMqttClient.ApplicationMessageReceivedHandler == null) |
| | | { |
| | | RemoteMqttClient.UseApplicationMessageReceivedHandler((e) => { |
| | | try |
| | | { |
| | | var topic = e.ApplicationMessage.Topic; |
| | | //Console.WriteLine ("回复Topic={0}", topic); |
| | | if (topic == $"/BusGateWayToClient/{CurRemoteMACInfo.clientId}/Push/NotifySqueeze") |
| | | { |
| | | var mMes = Encoding.UTF8.GetString(e.ApplicationMessage.Payload); |
| | | //收到挤下线主题 |
| | | ReceiveNotifySqueezeAsync(mMes); |
| | | } |
| | | else if (topic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/NotifyBusGateWayInfoChange") |
| | | { |
| | | //网关上线,需要更新aeskey |
| | | //收到网关上线消息主题 |
| | | //ReceiveNotifyBusGateWayInfoChange(); |
| | | } |
| | | else if (topic == $"/BusGateWayToClient/{CurRemoteMACInfo.macMark}/Common/CheckGateway") |
| | | { |
| | | var ss = Encoding.UTF8.GetString(e.ApplicationMessage.Payload); |
| | | ReceiveCheckGateway(ss); |
| | | } |
| | | else |
| | | { |
| | | var packet = new Packet(); |
| | | |
| | | if (!string.IsNullOrEmpty(mqttEncryptKey)) |
| | | { |
| | | packet.Bytes = Shared.Securitys.EncryptionService.AesDecryptPayload(e.ApplicationMessage.Payload, mqttEncryptKey); |
| | | } |
| | | else |
| | | { |
| | | packet.Bytes = e.ApplicationMessage.Payload; |
| | | } |
| | | packet.Manager(); |
| | | } |
| | | } |
| | | catch { } |
| | | }); |
| | | } |
| | | |
| | | if (RemoteMqttClient.DisconnectedHandler == null) |
| | | { |
| | | RemoteMqttClient.UseDisconnectedHandler(async (e) => { |
| | | System.Console.WriteLine($"远程连接断开"); |
| | | isSubscribeSuccess = false; |
| | | await DisConnectRemoteMqttClient("StartRemoteMqtt.DisconnectedHandler"); |
| | | if (MainPage.IsRemote) |
| | | { |
| | | Application.RunOnMainThread(() => { |
| | | //远程连接成功 |
| | | }); |
| | | } |
| | | }); |
| | | } |
| | | if (RemoteMqttClient.ConnectedHandler == null) |
| | | { |
| | | RemoteMqttClient.UseConnectedHandler(async (e) => { |
| | | System.Console.WriteLine($"远程连接成功"); |
| | | MainPage.IsRemote = true; |
| | | Application.RunOnMainThread(() => { |
| | | //远程连接成功 |
| | | MainPage.IsRemote = true; |
| | | }); |
| | | //刷新状态 |
| | | if (CurRemoteMACInfo != null) |
| | | { |
| | | if (CurRemoteMACInfo.isValid == "InValid") |
| | | { |
| | | //远程失败 |
| | | MainPage.IsRemote = false; |
| | | } |
| | | else |
| | | { |
| | | MqttRemoteSend(new byte[] { 0 }, 3); |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | #endregion |
| | | } |
| | | |
| | | try |
| | | { |
| | | |
| | | //--第一步:获取mqtt链接参数 提交MAC 服务器自动判断是否为新网关,返回是否需要自动切换远程连接的服务器 |
| | | var mqttInfoRequestPar = new RemoteRequestParameters() |
| | | { |
| | | PlatformStr = "ON", |
| | | LoginAccessToken = MainPage.LoginUser.loginTokenString, |
| | | RequestVersion = MainPage.VersionString, |
| | | RequestProtocolType = 0, |
| | | RequestSource = 1, |
| | | HdlGatewayGatewayType = 0, |
| | | PublishPayloadJsonStr = PushSignStr, |
| | | Mac = HDL_ON.Entity.DB_ResidenceData.residenceData.residenceGatewayMAC, |
| | | }; |
| | | var jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(mqttInfoRequestPar); |
| | | var mqttInfoRequestResult = new HDL_ON.DAL.Server.HttpServerRequest().RequestMqttInfo(jsonString); |
| | | |
| | | if (mqttInfoRequestResult != null && mqttInfoRequestResult.ResponseData != null) |
| | | { |
| | | try |
| | | { |
| | | var mqttInfoRequestResult_Obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MqttInfo>(mqttInfoRequestResult.ResponseData.ToString()); |
| | | |
| | | if (mqttInfoRequestResult_Obj != null) |
| | | { |
| | | string url = mqttInfoRequestResult_Obj.connEmqDomainPort; |
| | | string clientId = mqttInfoRequestResult_Obj.connEmqClientId; |
| | | string username = mqttInfoRequestResult_Obj.connEmqUserName; |
| | | string passwordRemote = mqttInfoRequestResult_Obj.connEmqPwd; |
| | | if (mqttInfoRequestResult_Obj.AccountAllGateways != null && mqttInfoRequestResult_Obj.AccountAllGateways.Count > 0) |
| | | { |
| | | //----第二步找出是否存在匹配当前住宅的mac,存在再进行远程。 |
| | | foreach (var curRegionMac in DB_ResidenceData.residenceData.residecenInfo.homeGateways) |
| | | { |
| | | CurRemoteMACInfo = mqttInfoRequestResult_Obj.AccountAllGateways.Find((obj) => obj.mac == curRegionMac.GatewayUniqueId); |
| | | if (CurRemoteMACInfo != null) |
| | | { |
| | | break; |
| | | } |
| | | } |
| | | if (CurRemoteMACInfo != null) |
| | | { |
| | | CurRemoteMACInfo.LoginAccessToken = MainPage.LoginUser.loginTokenString; |
| | | CurRemoteMACInfo.clientId = clientId; |
| | | mqttEncryptKey = CurRemoteMACInfo.isNewBusproGateway ? CurRemoteMACInfo.aesKey : ""; |
| | | |
| | | var options1 = new MQTTnet.Client.Options.MqttClientOptionsBuilder() |
| | | .WithClientId(clientId) |
| | | .WithTcpServer(url.Split(':')[1].Substring("//".Length), int.Parse(url.Split(':')[2])) |
| | | .WithCredentials(username, passwordRemote) |
| | | .WithCleanSession() |
| | | .WithCommunicationTimeout(new TimeSpan(0, 0, 20)) |
| | | .Build(); |
| | | |
| | | await DisConnectRemoteMqttClient("StartRemoteMqtt"); |
| | | await RemoteMqttClient.ConnectAsync(options1); |
| | | remoteIsConnected = true; |
| | | IsDisConnectingWithSendCatch = false; |
| | | |
| | | } |
| | | } |
| | | |
| | | } |
| | | } |
| | | catch { } |
| | | } |
| | | |
| | | } |
| | | catch (Exception e) |
| | | { |
| | | |
| | | } |
| | | finally |
| | | { |
| | | //最终要释放连接状态 |
| | | remoteMqttIsConnecting = false; |
| | | } |
| | | |
| | | }); |
| | | } |
| | | |
| | | |
| | | |
| | | ///// <summary> |
| | | ///// 收到网关上线消息 |
| | | ///// </summary> |
| | | //static void ReceiveNotifyBusGateWayInfoChange() |
| | | //{ |
| | | // var gatewayListUrl = @"https://developer.hdlcontrol.com/Center/Center/GetGatewayPagger"; //App、Buspro软件登录后获取网关列表 http 请求 |
| | | // var gatewayListRequestPar = new RemoteRequestParameters() { Mac = CurRemoteMACInfo.mac, LoginAccessToken = MainPage.LoginUser.loginTokenString, RequestVersion = "RequestVersion1", RequestProtocolType = 0, RequestSource = 1 }; |
| | | // var gatewayListRequestResult = MainPage.RequestHttps("", Newtonsoft.Json.JsonConvert.SerializeObject(gatewayListRequestPar), false, false, gatewayListUrl); |
| | | // var gatewayListRequestResult_Obj = Newtonsoft.Json.JsonConvert.DeserializeObject<MqttRemoteInfo>(gatewayListRequestResult.ResponseData.ToString()); |
| | | // if (gatewayListRequestResult_Obj != null && gatewayListRequestResult_Obj.pageData.Count > 0) |
| | | // { |
| | | // CurRemoteMACInfo.aesKey = gatewayListRequestResult_Obj.pageData[0].aesKey; |
| | | // mqttEncryptKey = CurRemoteMACInfo.isNewBusproGateway ? CurRemoteMACInfo.aesKey : ""; |
| | | // } |
| | | //} |
| | | |
| | | /// <summary> |
| | | /// 收到挤下线推送 |
| | | /// </summary> |
| | | static void ReceiveNotifySqueezeAsync(string mMes) |
| | | { |
| | | if (mMes == PushSignStr) return;//是自己的登录推送不处理 |
| | | //断开远程连接 |
| | | MainPage.IsRemote = false; |
| | | if (!MainPage.LoginUser.IsLogin) |
| | | { |
| | | return; |
| | | } |
| | | MainPage.LoginUser.lastTime = DateTime.MinValue; |
| | | MainPage.LoginUser.SaveUserInfo(); |
| | | |
| | | string oldRegionRootPath = FileUtils.CreateRegionBackup(DB_ResidenceData.residenceData.CurReginID.ToString()); |
| | | new System.Threading.Thread(() => |
| | | { |
| | | try |
| | | { |
| | | var backuplist = FileUtils.ReadFiles(); |
| | | FileUtils.DeleteRegionFiles(oldRegionRootPath); |
| | | //移动文件 |
| | | foreach (var fileName in backuplist) |
| | | { |
| | | System.IO.FileInfo fileInfo = new System.IO.FileInfo(FileUtils.RootPath + fileName); |
| | | if (fileName == "headImage.png") |
| | | { |
| | | continue; |
| | | } |
| | | if (fileInfo.Exists) |
| | | { |
| | | fileInfo.MoveTo(oldRegionRootPath + fileName); |
| | | MainPage.Log("move file : " + fileName); |
| | | } |
| | | } |
| | | //删除本地文件 |
| | | foreach (var fileName in backuplist) |
| | | { |
| | | if (fileName == "headImage.png") |
| | | { |
| | | continue; |
| | | } |
| | | FileUtils.DeleteFile(fileName); |
| | | } |
| | | } |
| | | catch (Exception ex) |
| | | { |
| | | MainPage.Log(ex.Message); |
| | | } |
| | | finally |
| | | { |
| | | } |
| | | }) |
| | | { IsBackground = true }.Start(); |
| | | |
| | | |
| | | //删除推送数据 |
| | | DisConnectRemoteMqttClient("挤下线"); |
| | | Application.RunOnMainThread(() => |
| | | { |
| | | MainPage.GoLoginPage(MainPage.LoginUser); |
| | | }); |
| | | } |
| | | |
| | | /// <summary> |
| | | /// 收到CheckGateway主题 |
| | | /// </summary> |
| | | static void ReceiveCheckGateway(string mMes) |
| | | { |
| | | var obj = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponsePack>(mMes); |
| | | if (obj == null) |
| | | { |
| | | return; |
| | | } |
| | | switch (obj.StateCode) |
| | | { |
| | | case "HDLUdpDataForwardServerMqttClientNoOnLine": |
| | | case "NoOnline": |
| | | case "NetworkAnomaly"://不在线 |
| | | Application.RunOnMainThread(() => |
| | | { |
| | | new HDL_ON.UI.PublicAssmebly().TipMsgAutoClose(Language.StringByID(StringId.RemoteFailedGatewayOffline), true); |
| | | }); |
| | | break; |
| | | case "NoRecord"://MAC不正确 |
| | | Application.RunOnMainThread(() => { |
| | | new HDL_ON.UI.PublicAssmebly().TipMsgAutoClose(Language.StringByID(StringId.MACError), true); |
| | | }); |
| | | break; |
| | | case "Success": |
| | | break; |
| | | default: |
| | | Application.RunOnMainThread(() => { |
| | | new HDL_ON.UI.PublicAssmebly().TipMsgAutoClose(Language.StringByID(StringId.LinkLoser), true); |
| | | }); |
| | | break; |
| | | } |
| | | |
| | | } |
| | | |
| | | /// <summary> |
| | | /// |
| | | /// </summary> |
| | | /// <param name="message">附加数据包</param> |
| | | /// <param name="optionType">操作类型:0=网关控制;1=订阅网关数据;2=订阅网关上线数据</param> |
| | | /// <returns></returns> |
| | | public static async Task MqttRemoteSend(byte[] message, int optionType = 0) |
| | | { |
| | | try |
| | | { |
| | | string topicName; |
| | | switch (optionType) |
| | | { |
| | | case 0: |
| | | topicName = $"/ClientToBusGateWay/{CurRemoteMACInfo.macMark}/Common/ON"; |
| | | if (!string.IsNullOrEmpty(mqttEncryptKey)) |
| | | { |
| | | message = Shared.Securitys.EncryptionService.AesEncryptPayload(message, mqttEncryptKey); |
| | | } |
| | | 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"; |
| | | 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("SendCatch"); |
| | | } |
| | | } |
| | | } |
| | | /// <summary> |
| | | /// SendCatch 后执行一次断开操作 |
| | | /// </summary> |
| | | static bool IsDisConnectingWithSendCatch = false; |
| | | |
| | | } |
| | | } |
| | | |