wxr
2022-08-17 d6578b10542226650e263815dea75e598a7090f9
tcp状态更新,iOS扫描
4个文件已添加
28个文件已修改
1807 ■■■■ 已修改文件
DLL/IOS/HDL.Shared.IOS.ScanQRCode.dll 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_Android/Assets/Language.ini 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_Android/Assets/Phone/Public/IotCheckIcon.png 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_Android/Assets/Phone/Public/IotCheckOnIcon.png 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_Android/HDL-ON_Android.csproj 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_Android/Properties/AndroidManifest.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_iOS/HDL-ON_iOS.csproj 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_iOS/Info.plist 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_iOS/Resources/Language.ini 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL-ON_iOS/Scan.cs 101 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/Common/ImageUtlis.cs 68 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/Common/R.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/DriverLayer/A_Protocol_Common.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/DriverLayer/Control.cs 135 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/DriverLayer/Control_Tcp.cs 811 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/DriverLayer/Control_TcpClient.cs 178 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/DriverLayer/Control_TcpServer.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/DriverLayer/UdpSocket.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/DAL/Server/HttpServerRequest.cs 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/Entity/Function/Scene.cs 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/Entity/Integratedbrand/IntegratedBrand.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/HDL_ON.projitems 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/MainPage.cs 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/2-Classification/ClassificaitionPublicBLL.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/2-Classification/FunctionControlZone.cs 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/Iot_AuthorizedPage.cs 114 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/Iot_BrandFunctionListPage.cs 125 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/Iot_BrandListPage.cs 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/iot_BindTipPage.cs 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/4-PersonalCenter/PersonalDataPageBLL.cs 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/4-PersonalCenter/ResetAccountPassword/ResetPasswordPage.cs 74 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
HDL_ON/UI/UI2/FuntionControlView/1ContorlPage/CacControlPage.cs 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
DLL/IOS/HDL.Shared.IOS.ScanQRCode.dll
Binary files differ
HDL-ON_Android/Assets/Language.ini
@@ -546,6 +546,7 @@
558=Someone is sitting
559=Bind a third-party account
560=Bound
561=Original password
@@ -1751,6 +1752,7 @@
558=有人坐着
559=绑定第三方账号
560=已绑定
561=原密码
 
@@ -2935,6 +2937,7 @@
558=Someone is sitting
559=Bind a third-party account
560=Bound
561=Original password
2532=Visitor Invitation Record
@@ -4130,6 +4133,7 @@
558=Someone is sitting
559=Bind a third-party account
560=Bound
561=Original password
2532=Visitor Invitation Record
HDL-ON_Android/Assets/Phone/Public/IotCheckIcon.png
HDL-ON_Android/Assets/Phone/Public/IotCheckOnIcon.png
HDL-ON_Android/HDL-ON_Android.csproj
@@ -260,6 +260,8 @@
    <AndroidAsset Include="Assets\Phone\FunctionIcon\Icon\HomeIcon\sensormegahealth.png" />
    <AndroidAsset Include="Assets\Phone\Public\Iot_agreement_icon.png" />
    <AndroidAsset Include="Assets\Phone\Public\LinkIotIcon.png" />
    <AndroidAsset Include="Assets\Phone\Public\IotCheckIcon.png" />
    <AndroidAsset Include="Assets\Phone\Public\IotCheckOnIcon.png" />
  </ItemGroup>
  <ItemGroup>
    <AndroidResource Include="Resources\values\colors.xml" />
HDL-ON_Android/Properties/AndroidManifest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.6.0" package="com.hdl.onpro" xmlns:tools="http://schemas.android.com/tools" android:versionCode="202208031">
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionName="1.6.0" package="com.hdl.onpro" xmlns:tools="http://schemas.android.com/tools" android:versionCode="202208151">
    <uses-sdk android:minSdkVersion="26" android:targetSdkVersion="29" />
    <!--友盟-->
    <!--<uses-sdk android:minSdkVersion="8"></uses-sdk>-->
HDL-ON_iOS/HDL-ON_iOS.csproj
@@ -114,6 +114,9 @@
        <Reference Include="Shared.IOS.HDLFVSDK">
          <HintPath>..\DLL\IOS\Shared.IOS.HDLFVSDK.dll</HintPath>
        </Reference>
        <Reference Include="HDL.Shared.IOS.ScanQRCode">
          <HintPath>..\DLL\IOS\HDL.Shared.IOS.ScanQRCode.dll</HintPath>
        </Reference>
    </ItemGroup>
    <ItemGroup>
      <PackageReference Include="Newtonsoft.Json">
HDL-ON_iOS/Info.plist
@@ -100,9 +100,9 @@
    <key>UIStatusBarStyle</key>
    <string>UIStatusBarStyleLightContent</string>
    <key>CFBundleShortVersionString</key>
    <string>1.5.902207251</string>
    <string>1.6.002208151</string>
    <key>CFBundleVersion</key>
    <string>1.5.907251</string>
    <string>1.6.008151</string>
    <key>NSLocationWhenInUseUsageDescription</key>
    <string>Use geographic location to provide services such as weather</string>
    <key>NSAppleMusicUsageDescription</key>
HDL-ON_iOS/Resources/Language.ini
@@ -544,6 +544,9 @@
556=Someone is running
557=Someone is standing
558=Someone is sitting
559=Bind a third-party account
560=Bound
561=Original password
@@ -1747,6 +1750,9 @@
556=有人在跑
557=有人站着
558=有人坐着
559=绑定第三方账号
560=已绑定
561=原密码
 
@@ -2929,6 +2935,9 @@
556=Someone is running
557=Someone is standing
558=Someone is sitting
559=Bind a third-party account
560=Bound
561=Original password
2532=Visitor Invitation Record
@@ -4122,6 +4131,10 @@
556=Someone is running
557=Someone is standing
558=Someone is sitting
559=Bind a third-party account
560=Bound
561=Original password
2532=Visitor Invitation Record
2533=Visitor management
HDL-ON_iOS/Scan.cs
@@ -2,7 +2,7 @@
using HDL_ON_iOS;
using Shared;
using ZXing.Mobile;
using HDL.Shared.IOS.ScanQRCode;
namespace HDL_ON
{
    public class Scan
@@ -27,51 +27,78 @@
        }
        static MobileBarcodeScanner scanner;
        public async void OpenScan(Action<string> action)
        void ScanResult(string result)
        {
            string cancel = "取消";
            string flashText = "";
            string titleText = "二维码扫描";
            if (Language.CurrentLanguage != "Chinese")
            {
                cancel = "Cancel";
                flashText = "";
                titleText = "Scan";
            }
            if (scanner == null)
            {
                var mZXingOverlayView = new ZXingOverlayView(cancel, flashText, titleText);
                scanner = new MobileBarcodeScanner(AppDelegate.rootViewController) { FlashButtonText = flashText, TopText = titleText, BottomText = "", CancelButtonText = cancel };
                scanner.UseCustomOverlay = true;
                scanner.CustomOverlay = mZXingOverlayView;
                var bOn = false;
                mZXingOverlayView.OnCancel += () =>
                {
                    scanner?.Cancel();
                };
                mZXingOverlayView.OnTorch += () =>
                {
                    bOn = !bOn;
                    scanner?.Torch(bOn);
                };
            }
            var result = await scanner.Scan();
            if (result != null)
            {
                action?.Invoke(result.Text);
                action?.Invoke(result);
            }
            else
            {
                action?.Invoke(null);
                Console.WriteLine("二维码返回值为null");
            }
        }
        static MobileBarcodeScanner scanner;
        Action<string> action;
        public void OpenScan(Action<string> action)
        {
            this.action = action;
            string cancel = "取消";
            //string flashText = "";
            string titleText = "二维码扫描";
            if (Language.CurrentLanguage != "Chinese")
            {
                cancel = "Cancel";
                //flashText = "";
                titleText = "Scan";
            }
            var d1 = new HDLQRCodeScanFinish(ScanResult);
            HDL.Shared.IOS.ScanQRCode.HDLScanQRCodeSDK.SharedInstance().ScanQRCodeWith(cancel, titleText, d1);
            //if (scanner == null)
            //{
            //    var mZXingOverlayView = new ZXingOverlayView(cancel, flashText, titleText);
            //    scanner = new MobileBarcodeScanner(AppDelegate.rootViewController) { FlashButtonText = flashText, TopText = titleText, BottomText = "", CancelButtonText = cancel };
            //    scanner.UseCustomOverlay = true;
            //    scanner.CustomOverlay = mZXingOverlayView;
            //    var bOn = false;
            //    mZXingOverlayView.OnCancel += () =>
            //    {
            //        scanner?.Cancel();
            //    };
            //    mZXingOverlayView.OnTorch += () =>
            //    {
            //        bOn = !bOn;
            //        scanner?.Torch(bOn);
            //    };
            //}
            //var result = await scanner.Scan();
            //if (result != null)
            //{
            //    action?.Invoke(result.Text);
            //}
            //else
            //{
            //    action?.Invoke(null);
            //    Console.WriteLine("二维码返回值为null");
            //}
        }
        public static byte[] BytesFromText(string text, int width = 300, int height = 300)
HDL_ON/Common/ImageUtlis.cs
@@ -4,6 +4,8 @@
using System.IO;
using HDL_ON.Common;
using System.Collections.Generic;
using System.Text;
using System.Security.Cryptography;
namespace HDL_ON
{
@@ -179,19 +181,26 @@
        /// </summary>
        public byte[] GetImageDownloadUrl(string imageKey)
        {
            var requestJson = HttpUtil.GetSignRequestJson(new GetImageUrlObj()
            if (imageKey.StartsWith("https:"))
            {
                imageKey = imageKey,
            });
            var revertObj = HttpUtil.RequestHttpsPostFroHome(NewAPI.API_POST_GetImageUrl, requestJson);
            if (revertObj.Code == StateCode.SUCCESS)
                return HttpUtil.HttpsDownload(imageKey);
            }
            else
            {
                if (revertObj.Data != null)
                var requestJson = HttpUtil.GetSignRequestJson(new GetImageUrlObj()
                {
                    if (!string.IsNullOrEmpty(revertObj.Data.ToString()))
                    imageKey = imageKey,
                });
                var revertObj = HttpUtil.RequestHttpsPostFroHome(NewAPI.API_POST_GetImageUrl, requestJson);
                if (revertObj.Code == StateCode.SUCCESS)
                {
                    if (revertObj.Data != null)
                    {
                        var url = revertObj.Data.ToString();
                        return HttpUtil.HttpsDownload(url);
                        if (!string.IsNullOrEmpty(revertObj.Data.ToString()))
                        {
                            var url = revertObj.Data.ToString();
                            return HttpUtil.HttpsDownload(url);
                        }
                    }
                }
            }
@@ -294,6 +303,34 @@
            }
        }
        string strKey = "abcdefgh";//注意:这里的密钥sKey必须能转为8个byte,即输入密钥为8半角个字符或者4个全角字符或者4个汉字的字符串
        string strIV = "ijklmnop";
        // 加密
        private string Encrypt(string _strQ)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(_strQ);
            MemoryStream ms = new MemoryStream();
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(ms, des.CreateEncryptor(Encoding.UTF8.GetBytes(strKey), Encoding.UTF8.GetBytes(strIV)), CryptoStreamMode.Write);
            encStream.Write(buffer, 0, buffer.Length);
            encStream.FlushFinalBlock();
            return Convert.ToBase64String(ms.ToArray());
        }
        // 解密
        private string Decrypt(string _strQ)
        {
            byte[] buffer = Convert.FromBase64String(_strQ);
            MemoryStream ms = new MemoryStream();
            DESCryptoServiceProvider des = new DESCryptoServiceProvider();
            CryptoStream encStream = new CryptoStream(ms, des.CreateDecryptor(Encoding.UTF8.GetBytes(strKey), Encoding.UTF8.GetBytes(strIV)), CryptoStreamMode.Write);
            encStream.Write(buffer, 0, buffer.Length);
            encStream.FlushFinalBlock();
            return Encoding.UTF8.GetString(ms.ToArray());
        }
        /// <summary>
        /// 2020-12-03
        /// 检测加载图片
@@ -306,6 +343,13 @@
        {
            try
            {
                var imageUrl = imageKey;
                if (imageUrl.StartsWith("http"))
                {
                    imageKey = Encrypt(imageKey);
                }
                //1.本地默认图库图片,直接加载本地
                if (imageKey.Contains("Classification/Room/Roombg") || imageKey.Contains("Intelligence/Gallery/scenebg"))
                {
@@ -333,7 +377,7 @@
                        //2.2 本地没缓存,开启线程云端下载然后缓存
                        System.Threading.Tasks.Task.Run(() =>
                        {
                            byte[] imageBytes = GetImageDownloadUrl(imageKey);
                            byte[] imageBytes = GetImageDownloadUrl(imageUrl);
                            if (imageBytes != null)
                            {
                                WriteFileByBytes(imageKey, imageBytes);
@@ -343,14 +387,14 @@
                                    if (frameLayout != null)
                                    {
                                        frameLayout.BackgroundImagePath = imageKey;
                                        //Utlis.WriteLine("imageKey 加载云端下载图片成功");
                                        Utlis.WriteLine("imageKey 加载云端下载图片成功");
                                    }
                                });
                            }
                            else
                            {
                                //2.4 下载是否,是否使用默认图片
                                //Utlis.WriteLine("imageKey 加载云端图片失败");
                                Utlis.WriteLine("imageKey 加载云端图片失败");
                            }
                        });
                    }
HDL_ON/Common/R.cs
@@ -5,6 +5,10 @@
    public static class StringId
    {
        /// <summary>
        /// 原密码
        /// </summary>
        public const int OriginalPassword = 561;
        /// <summary>
        /// 已绑定
        /// </summary>
        public const int Bound = 560;
HDL_ON/DAL/DriverLayer/A_Protocol_Common.cs
@@ -196,6 +196,16 @@
                return $"/user/{Control.Ins.GatewayId}/custom/security/list/get";
            }
        }
        /// <summary>
        /// 心跳包
        /// </summary>
        public string HeartBeat
        {
            get
            {
                return $"/user/{Control.Ins.GatewayId}/custom/gateway/heartbeat";
            }
        }
        #region 门锁
        public string OneKeyUnlock
HDL_ON/DAL/DriverLayer/Control.cs
@@ -4,26 +4,12 @@
using HDL_ON.DAL.Server;
using HDL_ON.Entity;
using HDL_ON.UI;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Shared;
namespace HDL_ON.DriverLayer
{
    /// <summary>
    /// 通讯方式
    /// </summary>
    public enum CommunicationMode
    {
        none,
        /// <summary>
        /// 本地udp
        /// </summary>
        local_BusUdp,
        /// <summary>
        /// 本地tcp客户端
        /// </summary>
        tcp_local_client,
    }
    public class Control
    {
@@ -43,6 +29,11 @@
        /// 记录接收到的消息,方便zb的工程师调试他们的设备
        /// </summary>
        public List<string> MsgInfoList = new List<string>();
        /// <summary>
        /// 本地tcp客户端连接是否成功
        /// 是否登录网关成功
        /// </summary>
        public bool LocalTcpClientLogin = false;
        int _msg_id = 1;
        /// <summary>
@@ -200,11 +191,6 @@
        public Control_Udp myUdp1 = null;
        /// <summary>
        /// 通讯方式
        /// </summary>
        public CommunicationMode communicationMode;
        /// <summary>
        /// 打开tcp服务端
        /// </summary>
        public void OpenTcpServer()
@@ -297,6 +283,38 @@
            }
        }
        private System.Threading.Thread loginGatewayThread;
        /// <summary>
        /// 登录网关
        /// </summary>
        public void LoginGateway()
        {
            if(loginGatewayThread== null)
            {
                loginGatewayThread = new System.Threading.Thread(() => {
                    while (true)
                    {
                        if (Ins.GatewayOnline_Local && myTcpClient.isConnected && LocalTcpClientLogin)
                        {
                            var sendData = new { clientType = "app", version = "1.0" };
                            var sendJob = new { id = Control.Ins.msg_id.ToString(), time_stamp = Utlis.GetTimestamp(), objects = sendData };
                            var bodyString = JsonConvert.SerializeObject(sendJob);
                            var sendBytes = ConvertSendBodyData($"/user/{GatewayId}/custom/gateway/login", bodyString);
                            Ins.myTcpClient.SendMessage(sendBytes);
                        }
                        System.Threading.Thread.Sleep(2000);
                    }
                });
            }
        }
        /// <summary>
        /// 场景控制入口
        /// </summary>
@@ -342,15 +360,6 @@
                }
            }
        }
        /// <summary>
        /// 安防控制
        /// </summary>
        public void ControlArm()
        {
            DAL.Server.HttpServerRequest httpServer = new DAL.Server.HttpServerRequest();
            //var pack = httpServer.GetSecurityAlarmLogList
        }
        /// <summary>
        /// 发送命令
@@ -903,6 +912,12 @@
                //}
                receiveObj.BodyDataString = res[1];
                if(receiveObj.Topic == CommunicationTopic.ct.HeartBeat)
                {
                    return null;
                }
                //2021-09-23 过滤不需要解密的主题 目前搜索网关主题不加密
                if (receiveObj.Topic != CommunicationTopic.SearchLoaclGatewayReply)
                {
@@ -943,6 +958,21 @@
                    }
                }
                try
                {
                    var idMsg = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponsePack>(res[1]);
                    var hasProcess = hasItBeenProcessed(idMsg.id);
                    if (hasProcess)
                    {
                        return null;
                    }
                    MainPage.Log($"处理局域网数据id:{idMsg.id}");
                }
                catch (Exception ex)
                {
                    MainPage.Log($"解析局域网数据异常{ex.Message}");
                }
                if (receiveObj.Topic == CommunicationTopic.SearchLoaclGatewayReply || receiveObj.Topic == CommunicationTopic.GatewayBroadcast)
                {
@@ -975,17 +1005,22 @@
                        //2021-09-23 新增获取当前网关是否本地加密
                        Ins.IsLocalEncrypt = device.isLocalEncrypt;
                        //MainPage.Log("网关本地加密状态:" + device.local_encrypt.ToString());
                        OpenTcpClent();
                        LoginGateway();
                    }
                }
                else if (receiveObj.Topic == CommunicationTopic.ct.ReadStatus + "_reply" ||
                    receiveObj.Topic == CommunicationTopic.ct.ControlFunctionTopic + "_reply" ||
                    receiveObj.Topic == CommunicationTopic.ct.GatewayUpStatus ||
                    receiveObj.Topic.Contains( CommunicationTopic.ct.GatewayUpSortTopic))
                    receiveObj.Topic.Contains(CommunicationTopic.ct.GatewayUpSortTopic))
                {
                    //TODO 暂时不传正确的数据上去,如果后面要优化前面这些代码
                    UpdataFunctionStatus(receiveObj.BodyDataString, null);
                }
                else if (receiveObj.Topic == CommunicationTopic.ct.ControlSeurity +"_reply"
                else if (receiveObj.Topic == CommunicationTopic.ct.ControlSeurity + "_reply"
                    || receiveObj.Topic == CommunicationTopic.ct.ReadSecurityStatus + "_reply"
                    || receiveObj.Topic == CommunicationTopic.ct.SecurityStatusUp)
                {
@@ -993,7 +1028,8 @@
                    {
                        MainPage.Log($"局域网安防信息: {receiveObj.Topic}  : 内容: {res[1]}");
                        var tt = "";
                        lock (tt) {
                        lock (tt)
                        {
                            var temp = Newtonsoft.Json.JsonConvert.DeserializeObject<SecurityStatusObj>(receiveObj.BodyDataString);
                            if (temp != null)
                            {
@@ -1012,8 +1048,16 @@
                            }
                        }
                    }
                    catch (Exception ex){
                    catch (Exception ex)
                    {
                        MainPage.Log($"安防局域网异常:{ex.Message}");
                    }
                }
                else if (receiveObj.Topic == $"/user/{GatewayId}/custom/gateway/login_reply") {
                    var temp = Newtonsoft.Json.JsonConvert.DeserializeObject<JObject>(receiveObj.BodyDataString);
                    if (temp.GetValue("objects").ToString().Contains("success"))
                    {
                        LocalTcpClientLogin = true;
                    }
                }
                else
@@ -1025,6 +1069,29 @@
            return receiveObj;
        }
        private List<string> processedDataList = new List<string>();
        /// <summary>
        /// 是否已经处理过数据
        /// </summary>
        /// <returns></returns>
        private bool hasItBeenProcessed(string msgId)
        {
            if (processedDataList.Contains(msgId))
            {
                return true;
            }
            else
            {
                if(processedDataList.Count> 50)
                {
                    processedDataList.RemoveAt(0);
                }
                return false;
            }
        }
        /// <summary>
        /// 更新设备状态
        /// A协议数据
HDL_ON/DAL/DriverLayer/Control_Tcp.cs
New file
@@ -0,0 +1,811 @@
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Timers;
using HDL_ON;
using HDL_ON.Entity;
using HDL_ON.UI;
namespace HDL_ON.DriverLayer
{
    /// <summary>
    /// link网关本地链接逻辑
    /// </summary>
    public class Control_Tcp
    {
        #region ■ 变量声明___________________________
        /// <summary>
        /// link网关链接逻辑
        /// </summary>
        private static Control_Tcp m_Current = null;
        /// <summary>
        /// link网关链接逻辑
        /// </summary>
        public static Control_Tcp Current
        {
            get
            {
                if (m_Current == null)
                {
                    m_Current = new Control_Tcp();
                }
                return m_Current;
            }
        }
        /// <summary>
        /// Link网关tcp接收回调,理论上它不会处理zigbee的上报(第一个参数是网关的mac,第二个参数是接收的数据)
        /// </summary>
        private Action<string, string, string> tcpReceiveEvent = null;
        /// <summary>
        /// Tcp客户端连接池
        /// </summary>
        private List<TcpConnectData> listTcpClient = new List<TcpConnectData>();
        /// <summary>
        /// 是否搜索网关
        /// </summary>
        private bool isSearchGateway = false;
        #endregion
        #region ■ 搜索Link网关_______________________
//        /// <summary>
//        /// 搜索Link网关
//        /// </summary>
//        /// <param name="resultEvent">搜索到网关的回调函数,-1:异常了 1:收到一个A网关</param>
//        /// <param name="searchTime">搜索时间(秒)</param>
//        /// <param name="connectLocalOnly">当搜索到网关时,是否只连接本地的(不能瞎连其他的网关,但是网关搜索界面特殊)</param>
//        public void SearchLinkGateway(Action<int, AGatewayInfo> resultEvent, int searchTime, bool connectLocalOnly)
//        {
//            this.isSearchGateway = true;
//            //算了,在这里启动远程连接吧,反正也就执行一次
//            HdlLinkCloudConnectLogic.Current.StartCloudMqttConnection();
//            var listGateway = HdlLinkGatewayLogic.Current.GetAllLocalGateway();
//            var dicGateway = new Dictionary<string, ZigBee.Device.LinkGateway>();
//            foreach (var gw in listGateway)
//            {
//                //获取本地全部的A网关的mac
//                dicGateway[gw.GwMac] = gw;
//            }
//            //重复检测
//            var listCheck = new HashSet<string>();
//            var sendData = "Topic:/user/all/custom/gateway/search\r\n";
//            var dic = new Dictionary<string, string>();
//            dic["id"] = HdlGatewayResourse.AGatewayLinkFlage;
//            dic["time_stamp"] = HdlHttpLogic.Current.GetTimestamp().PadRight(13, '0');
//            var bodyData = Newtonsoft.Json.JsonConvert.SerializeObject(dic);
//            sendData += "Length:" + bodyData.Length + "\r\n\r\n";
//            sendData += bodyData;
//            //初始化udp
//            var udpLogic = new HdlUdpLogic();
//            if (udpLogic.InitUdp("239.0.168.188", 8585) == false)
//            {
//                //关闭udp
//                udpLogic.CloseUdp();
//                resultEvent?.Invoke(-1, null);
//                return;
//            }
//            HDL_ON.DriverLayer.Control.Ins.OpenUdp(8585);
//            //接收事件
//            Action<System.Net.IPEndPoint, string> actionEvent = (ipPoint, result) =>
//            {
//                //处理搜索A网关时,网关回复的数据
//                try
//                {
//                    /////
//                    System.Net.IPAddress s = ipPoint.Address;
//                    MainPage.Log("TcpClient->SearchLinkGateway", $"{s}==网关搜索本地回复,数据内容{result}");
//                    //检验A协议网关主题(如果检验是指定主题,则返回负载数据,否则返回null)
//                    var resultData = HdlLinkGatewaySendLogic.Current.CheckLinkGatewayTopic("/user/all/custom/gateway/search_reply", result);
//                    if (resultData == null) { return; }
//                    //调用回调函数
//                    var info = Newtonsoft.Json.JsonConvert.DeserializeObject<AGatewayInfo>(resultData);
//                    if (info == null)
//                    {
//                        //数据异常,退出
//                        return;
//                    }
//                    if (!(string.IsNullOrEmpty(info.HomeId) == true || info.HomeId == Common.Config.Instance.HomeId))
//                    {
//                        //网关已经绑定其他住宅,退出
//                        return;
//                    }
//                    ///tcp连接目标设备的ip
//                    info.Ip_address = ipPoint.Address.ToString();
//                    //搜索到的这个网关,是否是存在在本地了的
//                    if (dicGateway.ContainsKey(info.Device_mac) == true)
//                    {
//                        var gateWay = dicGateway[info.Device_mac];
//                        //如果搜索得到本地存在的网关,则使用本地通信
//                        gateWay.OnlineStatu = 1;
//                        gateWay.isLocalEncrypt = info.isLocalEncrypt;
//                        gateWay.Master = info.Master;
//                        //gateWay.Slaver_list1 = info.Slaver_list1;
//                        gateWay.Oid = info.Oid;
//                        gateWay.InGatewayHomeId = info.HomeId;
//                        info.IsBindGateway = true;
//                        Common.Config.Instance.Home.NowHomeOnlineStatu = "1";
//                    }
//                    //搜索到的网关,建立链接
//                    if (connectLocalOnly == false || info.IsBindGateway == true)
//                    {
//                        this.ConnectLocalLinkGateway(info.Device_mac, info.Ip_address, info.GatewayId, info.isLocalEncrypt);
//                    }
//                    else
//                    {
//                        //获取连接对象
//                        var connectObj = this.GetConnectObject(info.Device_mac, false);
//                        if (connectObj != null)
//                        {
//                            //如果有这个对象, 则替换一下它的网关id
//                            connectObj.GatewayId = info.GatewayId;
//                            connectObj.localEncrypt = info.isLocalEncrypt;
//                            return;
//                        }
//                    }
//                    if (listCheck.Contains(info.Device_mac) == true)
//                    {
//                        //已经处理过了
//                        return;
//                    }
//                    listCheck.Add(info.Device_mac);
//#if DEBUG
//                    Console.WriteLine($"搜索网关捕抓到网关:{info.Device_mac}");
//#endif
//                    //info
//                    //回调函数
//                    resultEvent?.Invoke(1, info);
//                }
//                catch (Exception e)
//                {
//                    string str = e.Message;
//                }
//            };
//            udpLogic.ReceviceEvent += actionEvent;
//            var dateTime = System.DateTime.Now.AddSeconds(searchTime);
//            while (this.isSearchGateway && System.DateTime.Now < dateTime)
//            {
//                udpLogic.SendData(sendData, "239.0.168.188", 8585);
//                udpLogic.SendData(sendData, "255.255.255.255", 8585);
//                System.Threading.Thread.Sleep(1000);
//            }
//            udpLogic.ReceviceEvent -= actionEvent;
//            //别关那么快
//            System.Threading.Thread.Sleep(300);
//            this.isSearchGateway = false;
//            //关闭udp
//            udpLogic.CloseUdp();
//        }
//        /// <summary>
//        /// 停止搜索Link网关
//        /// </summary>
//        public void StopSearchLinkGateway()
//        {
//            this.isSearchGateway = false;
//        }
        #endregion
        #region ■ 链接本地Link网关___________________
        /// <summary>
        /// 链接Link网关
        /// </summary>
        /// <param name="i_mac">网关mac</param>
        /// <param name="i_ipAdrr">网关ip</param>
        /// <param name="i_gwId">网关Id</param>
        /// <param name="isBinded">该tcp所指向的网关,是否是当前住宅所绑定的</param>
        /// <returns></returns>
        public void ConnectLocalLinkGateway(string i_mac, string i_ipAdrr, string i_gwId, bool localEncrypt)
        {
            if (i_mac == string.Empty || i_ipAdrr == string.Empty)
            {
                return;
            }
            var connectData = new TcpConnectData();
            connectData.GatewayId = i_gwId;
            connectData.GatewayIp = i_ipAdrr;
            connectData.GatewayMac = i_mac;
            connectData.localEncrypt = localEncrypt;
            lock (this.listTcpClient)
            {
                //找到当前网关的连接
                if (this.listTcpClient.Find((v) => v.GatewayMac == i_mac) != null)
                {
                    return;
                }
                this.listTcpClient.Add(connectData);
            }
            try
            {
                //TCP连接
                connectData.tcpClient = new Communication.TcpClient(i_ipAdrr, 8586);
                connectData.tcpClient.Connect();
                connectData.tcpClient.ReadFormSocket();
                connectData.tcpClient.ExitEvent += (s, e) =>
                {
                    StopConnectLinkGateway(connectData);
                };
                connectData.tcpClient.ReceiveBytesAction += (topic, bytes, socket) =>
                {
                    managerLinkGatewayData(topic, bytes, socket);
                };
            }
            catch
            {
#if DEBUG
                //HdlMessageLogic.Current.ShowMassage(ShowMsgType.Tip, i_ipAdrr + "Tcp链接不了");
#endif
                StopConnectLinkGateway(connectData);
            }
        }
        public TcpConnectData GetConnectObjectBySocket(Socket socket)
        {
            lock (listTcpClient)
            {
                var tcpConnectData = listTcpClient.Find(tcd => tcd.tcpClient._socket == socket);
                return tcpConnectData;
            }
        }
        /// <summary>
        /// 断开全部的Link网关连接
        /// </summary>
        public void StopAllConnectLinkGateway()
        {
            var listTemp = new List<TcpConnectData>();
            for (int i = 0; i < this.listTcpClient.Count; i++)
            {
                //创另外一个对象出来,是有作用的
                listTemp.Add(this.listTcpClient[i]);
            }
            foreach (var data in listTemp)
            {
                //断开指定的link网关连接
                this.StopConnectLinkGateway(data);
            }
            //清空缓存
            this.listTcpClient.Clear();
        }
        /// <summary>
        /// 断开指定的link网关连接
        /// </summary>
        /// <param name="mac">需要断开连接的网关mac</param>
        public void StopConnectLinkGateway(string mac)
        {
            var tempGateway = listTcpClient.Find((v) => v.GatewayMac == mac);
            if (tempGateway != null)
            {
                //断开指定的link网关连接
                this.StopConnectLinkGateway(tempGateway);
            }
        }
        /// <summary>
        /// 断开指定的link网关连接
        /// </summary>
        /// <param name="connectData">连接数据</param>
        private void StopConnectLinkGateway(TcpConnectData connectData)
        {
            lock (listTcpClient)
            {
                this.listTcpClient.Remove(connectData);
                connectData.tcpClient.Dispose();
            }
        }
        #endregion
        #region ■ 发送数据到Link网关_________________
        /// <summary>
        /// 发送数据到本地Link网关
        /// </summary>
        /// <param name="connectData">链接信息</param>
        /// <param name="sendData">发送的数据</param>
        /// <returns></returns>
        private void DoSendDataToLinkGateway(TcpConnectData connectData, string sendData)
        {
#if DEBUG
            MainPage.Log(DateTime.Now + ":TcpClient->DoSendDataToLinkGateway", $"本地发送数据,Data:{sendData}");
#endif
            byte[] byteData;
            //44bytes 加密数据 AES加密 base64密文
            ////目前默认都是加密载荷
            //byteData = this.AesEncryptPayload(byteData, Config.Instance.Home.localSecret);
            //解密负载数据(因为写密钥给网关一定明文,因为那时网关还没有密钥)
            if (connectData.localEncrypt)
            {
                var headerAndBody = sendData.Split("\r\n\r\n");
                string topic = headerAndBody[0].Split("\r\n")[0];
                //加密载荷
                var byteBody = this.AesEncryptPayload(System.Text.Encoding.UTF8.GetBytes(headerAndBody[1]), DB_ResidenceData.Instance.CurrentRegion.localSecret);
                var header = System.Text.Encoding.UTF8.GetBytes($"{topic}\r\nLength:{byteBody.Length}\r\n" + "\r\n");
                byteData = new byte[header.Length + byteBody.Length];
                System.Array.Copy(header, 0, byteData, 0, header.Length);
                ///参数(源文件,取源文件索引值,存储器,存放位置,源文件长度)
                System.Array.Copy(byteBody, 0, byteData, header.Length, byteBody.Length);
            }
            else
            {
                byteData = Encoding.UTF8.GetBytes(sendData);
            }
            //byteData = Encoding.UTF8.GetBytes(sendData);
            //将数据写入网络流
            connectData.tcpClient?.CommSend(byteData, byteData.Length);
        }
        #endregion
        #region ■ 处理Link网关的数据_________________
        /// <summary>
        /// 处理接收本地Link网关的数据(返回值 0:还不存在完成的数据  1:已经存在完成的数据)
        /// </summary>
        /// <param name="listByte">数据</param>
        private void managerLinkGatewayData(string topic, byte[] bytes, Socket socket)
        {
            try
            {
                var arryTopic = topic.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries);
                if (arryTopic.Length < 2)
                {
                    //非正规主题
                    return;
                }
                var connectData = this.GetConnectObjectBySocket(socket);
                if (connectData == null)
                {
                    return;
                }
                string gatewayMac = connectData.GatewayMac;
                string gatewayId = connectData.GatewayId;
                ///解密负载数据
                if (connectData.localEncrypt == true)
                {
                    var tempBytes = bytes;
                    bytes = this.AesDecryptPayload(bytes, DB_ResidenceData.Instance.CurrentRegion.localSecret);
                    if (bytes == null)
                    {
                        bytes = tempBytes;
                    }
                }
                /////目前网关默认都是加密的
                //bytes = this.AesDecryptPayload(bytes, Config.Instance.Home.localSecret);
                var bodyData = System.Text.Encoding.UTF8.GetString(bytes);
                MainPage.Log(DateTime.Now + ":Control_Tcp->本地接收数据", $"Topic:{topic}\r\nData:{bodyData}");
                if (topic.Contains("thing/property/up") == true)
                {
                    //这个是Link设备的状态上报,别整,只要zigbee的
                    var temp = Newtonsoft.Json.JsonConvert.DeserializeObject<AlinkFunctionStatusObj>(bodyData);
                    return;
                }
            }
            catch (Exception e)
            {
            }
        }
        #endregion
        #region ■ 结构体_____________________________
        /// <summary>
        /// Tcp连接信息
        /// </summary>
        public class TcpConnectData
        {
            /// <summary>
            /// 网关的mac(主键使用)
            /// </summary>
            public string GatewayMac = string.Empty;
            /// <summary>
            /// 网关ip
            /// </summary>
            public string GatewayIp = string.Empty;
            /// <summary>
            /// 网关Id(不是云端的那个)
            /// </summary>
            public string GatewayId = string.Empty;
            //
            public Communication.TcpClient tcpClient;
            /// <summary>
            /// 本地是否加密
            /// </summary>
            public bool localEncrypt;
        }
        #endregion
        #region ■ 加密以及解密_______________________
        /// <summary>
        /// 加密负载为二进制流(Link专用)
        /// </summary>
        /// <param name="toEncryptArray"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private byte[] AesEncryptPayload(byte[] toEncryptArray, string key)
        {
            //加密密钥为空
            if (key == string.Empty)
            {
                return toEncryptArray;
            }
            try
            {
                if (string.IsNullOrEmpty(key)) return toEncryptArray;
                //配置AES加密Key(密钥、向量、模式、填充)
                var rm = new System.Security.Cryptography.RijndaelManaged
                {
                    Key = Encoding.UTF8.GetBytes(key),
                    IV = Encoding.UTF8.GetBytes(key),
                    Mode = System.Security.Cryptography.CipherMode.CBC,
                    Padding = System.Security.Cryptography.PaddingMode.PKCS7
                };
                //创建AES加密器对象
                var cTransform = rm.CreateEncryptor();
                //使用AES将明文流转成密文字节数组
                return cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
            }
            catch
            {
                return null;
            }
        }
        /// <summary>
        /// 采用Aes解密负载数据(Link专用)
        /// </summary>
        /// <param name="toEncryptArray"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        private byte[] AesDecryptPayload(byte[] toEncryptArray, string key)
        {
            //解密密钥为空
            if (key == string.Empty)
            {
                return toEncryptArray;
            }
            try
            {
                //配置AES加密Key(密钥、向量、模式、填充)
                var rm = new System.Security.Cryptography.RijndaelManaged
                {
                    Key = Encoding.UTF8.GetBytes(key),
                    IV = Encoding.UTF8.GetBytes(key),
                    Mode = System.Security.Cryptography.CipherMode.CBC,
                    Padding = System.Security.Cryptography.PaddingMode.PKCS7
                };
                //创建AES解密器对象
                var cTransform = rm.CreateDecryptor();
                //使用AES将密文流转成明文的字节数组
                return cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
            }
            catch
            {
                return null;
            }
        }
        #endregion
    }
}
namespace Communication
{
    //TCP客户端实现
    public class TcpClient
    {
        private const int MAX_RECONNECT_TIMES = 3;  //断线重连尝试次数
        //soket对象及参数
        public Socket _socket;
        private string host;
        private int port;
        private bool reconnect;
        private bool run = true;
        private int ConnecteFailedCount { get; set; }
        public int ReconnectStatistics { get; private set; }
        private static uint _keepAliveTime = 5000;      //无数据交互持续时间(ms)
        private static uint _keepAliveInterval = 500;   //发送探测包间隔(ms)
        //重连失败事件
        public event EventHandler ExitEvent;
        public Action<string, byte[], Socket> ReceiveBytesAction;
        //构造函数
        public TcpClient(string host, int port)
        {
            this.host = host;
            this.port = port;
            reconnect = false;
            ConnecteFailedCount = 0;
        }
        //连接
        public void Connect()
        {
            byteList = new List<byte>(1024 * 5);
            _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
                ProtocolType.Tcp);
            _socket.Connect(host, port);
            MainPage.Log("TcpClient->Reconnect", $"连接成功,IP:{host}");
            ConnecteFailedCount = MAX_RECONNECT_TIMES;
            //设置KeepAlive
            _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
            byte[] optionValue = new byte[12];
            BitConverter.GetBytes(1).CopyTo(optionValue, 0);
            BitConverter.GetBytes(_keepAliveTime).CopyTo(optionValue, 4);
            BitConverter.GetBytes(_keepAliveInterval).CopyTo(optionValue, 8);
            _socket.IOControl(IOControlCode.KeepAliveValues, optionValue, null);
        }
        //重连
        public bool Reconnect()
        {
            ReconnectStatistics++;
            reconnect = false;
            close();
            try
            {
                MainPage.Log("TcpClient->Reconnect", $"重新开始连接,IP:{host}");
                Connect();
            }
            catch (Exception e)
            {
                ConnecteFailedCount--;
                if (ConnecteFailedCount > 0)
                {
                    //Console.WriteLine("重试次数剩余{0}",ConnecteFailedCount);
                    reconnect = true;
                    return true;
                }
                else
                {
                    //重连失败事件
                    return false;
                }
            }
            return true;
        }
        /// <summary>
        /// 关闭
        /// </summary>
        private void close()
        {
            try
            {
                MainPage.Log("TcpClient->Close", $"Socket 关闭,IP:{host}");
                _socket.Close();
            }
            catch { }
        }
        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            run = false;
            close();
        }
        //发送数据接收实现,断线重连
        public int CommSend(byte[] buffer, int size)
        {
            int sendSize = 0;
            try
            {
                if (_socket.Connected)
                {
                    sendSize = _socket.Send(buffer, size, SocketFlags.None);
                }
            }
            catch (Exception e)
            {
                MainPage.Log("TcpClient->CommSend", $"发送失败,Data:{System.Text.Encoding.UTF8.GetString(buffer)} Exception:{e.Message}");
                ReconnectStatistics++;
                reconnect = true;
            }
            return sendSize;
        }
        List<byte> byteList = new List<byte>();
        //接收数据线程,使用阻塞方式接收数据
        public void ReadFormSocket()
        {
            new System.Threading.Thread(() =>
            {
                int count;
                byte[] byteBuffer = new byte[2048];
                while (run)
                {
                    try
                    {
                        try
                        {
                            count = _socket.Receive(byteBuffer, SocketFlags.None);
                            for (int i = 0; i < count; i++)
                            {
                                byteList.Add(byteBuffer[i]);
                            }
                        }
                        catch (Exception e)
                        {
                            count = 0;
                        }
                        //网络断开Receive返回0
                        if (count == 0 || reconnect == true)
                        {
                            if (run)
                            {
                                //重连次数用尽,退出
                                if (Reconnect() == false)
                                {
                                    //通知其它功能释放及删除当前对象
                                    ExitEvent?.Invoke(null, new EventArgs());
                                    break;
                                }
                            }
                            else
                            {
                                ExitEvent?.Invoke(null, new EventArgs());
                            }
                        }
                        else
                        {
                            while (true)
                            {
                                var bytes = byteList.ToArray();
                                var topMsgs = System.Text.Encoding.UTF8.GetString(bytes).Split("\r\n");
                                var lenght = getLenght(topMsgs);
                                if (lenght <= 0)
                                {
                                    //头部数据还没有接收完成
                                    break;
                                }
                                //是否已经获取完整所有的数据
                                var data = new byte[lenght];
                                int index = getDataIndex(byteList);
                                if (byteList.Count < index + lenght)
                                {
                                    //当前数据还没有接收完成
                                    break;
                                }
                                //复制出body数据
                                System.Array.Copy(bytes, index, data, 0, data.Length);
                                //保留剩余的数据,以次用
                                byteList.Clear();
                                for (int i = index + lenght; i < bytes.Length; i++)
                                {
                                    byteList.Add(bytes[i]);
                                }
                                var topic = getTopic(topMsgs);
                                ReceiveBytesAction?.Invoke(topic, data, _socket);
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        MainPage.Log("TcpClient->ReadFormSocket", $"Exception:{e.Message}");
                    }
                }
            })
            {
                IsBackground = true
            }.Start();
        }
        /// <summary>
        /// 获取内容长度
        /// </summary>
        /// <param name="topMsgs"></param>
        /// <returns></returns>
        int getLenght(string[] topMsgs)
        {
            for (int i = 0; i < topMsgs.Length; i++)
            {
                string topMsg = topMsgs[i].Trim();
                if (topMsg.StartsWith("Length:"))
                {
                    return int.Parse(topMsg.Replace("Length:", ""));
                }
            }
            //找不到长度
            return -1;
        }
        /// <summary>
        /// 获取主题
        /// </summary>
        /// <param name="topMsgs"></param>
        /// <returns></returns>
        private string getTopic(string[] topMsgs)
        {
            for (int i = 0; i < topMsgs.Length; i++)
            {
                var topMsg = topMsgs[i].Trim();
                if (topMsg.StartsWith("Topic:"))
                {
                    return topMsg.Replace("Topic:", "");
                }
            }
            //找不到主题
            return null;
        }
        /**
         * 获取数据的开始位置
         * @param arrayList 接收到的所有数据
         * @return 数据位的开始索引
         */
        int getDataIndex(List<byte> arrayList)
        {
            var r = (byte)'\r';
            var n = (byte)'\n';
            for (int i = 0; i < arrayList.Count; i++)
            {
                //找出数据内容前面的两个换行
                if (3 <= i && arrayList[i - 3] == r && arrayList[i - 2] == n && arrayList[i - 1] == r && arrayList[i] == n)
                {
                    //剩余的数据
                    return i + 1;
                }
            }
            return -1;
        }
    }
}
HDL_ON/DAL/DriverLayer/Control_TcpClient.cs
@@ -1,7 +1,11 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
using HDL_ON.Entity;
using Newtonsoft.Json;
namespace HDL_ON.DriverLayer
{
@@ -18,6 +22,16 @@
        public Action<string> ReceiveEvent;
        /// <summary>
        /// 连接次数
        /// </summary>
        private int reconnectIndex = 0;
        /// <summary>
        /// 是否连接成功
        /// </summary>
        public bool isConnected = false;
        /// <summary>
        /// 构造函数
        /// </summary>
        public Control_TcpClient(string serverIp)
@@ -26,18 +40,22 @@
        }
        //TCP连接
        public bool Connect(int _port = 8586)
        private bool ConnectToTcp( )
        {
            if (string.IsNullOrEmpty(_ip) || _port == 0)
            if (string.IsNullOrEmpty(_ip) )
            {
                return false;
            }
            _tcpClient = new TcpClient();
            if (_tcpClient == null)
            {
                _tcpClient = new TcpClient();
            }
            try
            {
                _tcpClient.Connect(IPAddress.Parse(_ip), _port);
                _tcpClient.Connect(IPAddress.Parse(_ip), 8586);
                Task.Run(new Action(ReceiveMessage));//开启线程,不停接收消息
                MainPage.Log($"打开tcp client{_ip}:{_port}");
                MainPage.Log($"打开tcp client{_ip}:8586");
                isConnected = true;
            }
            catch (Exception e)
            {
@@ -46,6 +64,53 @@
            }
            return true;//返回连接状态
        }
        /// <summary>
        /// 连接tcp线程
        /// </summary>
        private Thread connectThread;
        /// <summary>
        /// 连接线程
        /// </summary>
        public void Connect()
        {
            if(connectThread == null)
            {
                connectThread = new Thread(() => {
                    while (Control.Ins.GatewayOnline_Local)
                    {
                        if (_tcpClient == null)
                        {
                            ConnectToTcp();
                        }
                        else
                        {
                            if (!_tcpClient.Connected)
                            {
                                try
                                {
                                    //_tcpClient.ReceiveTimeout =
                                    _tcpClient.Connect(IPAddress.Parse(_ip), 8586);
                                    Task.Run(new Action(ReceiveMessage));//开启线程,不停接收消息
                                }
                                catch (Exception ex)
                                {
                                    MainPage.Log($"tcp重连异常:{ex.Message}");
                                    _tcpClient.Close();
                                    _tcpClient = null;
                                }
                            }
                        }
                        Thread.Sleep(1000);
                    }
                });
                connectThread.Start();
            }
        }
        /// <summary>
        /// 关闭连接
        /// </summary>
@@ -65,67 +130,76 @@
        /// <param name="bytes">需要发送的字节</param>
        public void SendMessage(byte[] bytes)
        {
            NetworkStream networkStream = _tcpClient.GetStream();
            if (networkStream.CanWrite)
            if (_tcpClient.GetStream().CanWrite)
            {
                networkStream.Write(bytes, 0, bytes.Length);
                _tcpClient.GetStream().Write(bytes, 0, bytes.Length);
            }
            //networkStream.Close();
        }
        /// <summary>
        /// 获取列表数据回调方法
        /// 心跳包线程
        /// </summary>
        public Action<string> GetListResponseAction;
        private Thread heartBeatThread;
        private DateTime heartBeatTime;
        public void HeartBeat()
        {
            if(heartBeatThread == null)
            {
                heartBeatThread = new Thread(() => {
                    if(_tcpClient.Connected&&10 *1000 <(System.DateTime.Now - heartBeatTime).TotalMilliseconds)
                    {
                        var sendBytes = Control.Ins.ConvertSendBodyData(CommunicationTopic.ct.HeartBeat, "");
                        SendMessage(sendBytes);
                    }
                    Thread.Sleep(100);
                });
                heartBeatThread.Start();
            }
        }
        /// <summary>
        /// 接收数据线程
        /// </summary>
        private Thread receiveThread;
        //接收消息
        public void ReceiveMessage()
        {
            NetworkStream networkStream = _tcpClient.GetStream();
            while (true)
            if(receiveThread == null)
            {
                // 定义一个2M的缓存区;
                byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                int size = networkStream.Read(arrMsgRec, 0, arrMsgRec.Length);
                var tcpDataString = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, arrMsgRec.Length);
                if (!string.IsNullOrEmpty(tcpDataString))
                {
                    ReceiveEvent?.Invoke(tcpDataString);
                }
                receiveThread = new Thread(() => {
                    while (true)
                    {
                        if(_tcpClient == null)
                        {
                            receiveThread.Abort();
                            receiveThread = null;
                            return;
                        }
                        if (!_tcpClient.Connected)
                        {
                            MainPage.Log("tcp客户端断开了连接...");
                            receiveThread.Abort();
                            receiveThread = null;
                            isConnected = false;
                            return;
                        }
                //// 将接受到的数据存入到输入  arrMsgRec中;
                //int length = -1;
                //try
                //{
                //    length = socketClient.Receive(arrMsgRec); // 接收数据,并返回数据的长度;
                //}
                //catch (Exception ex)
                //{
                //    MainPage.Log($"tcpListener  error 1 :  {ex.Message}");
                        // 定义一个2M的缓存区;
                        byte[] arrMsgRec = new byte[1024 * 1024 * 2];
                        int size = _tcpClient.GetStream().Read(arrMsgRec, 0, arrMsgRec.Length);
                        var tcpDataString = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, arrMsgRec.Length);
                //    Flag_Receive = false;
                //    // 从通信线程集合中删除被中断连接的通信线程对象;
                //    string keystr = socketClient.RemoteEndPoint.ToString();
                //    dic_ClientSocket.Remove(keystr);//删除客户端字典中该socket
                //    dic_ClientThread[keystr].Abort();//关闭线程
                //    dic_ClientThread.Remove(keystr);//删除字典中该线程
                //    tcpClient = null;
                //    socketClient = null;
                //    break;
                //}
                //byte[] buf = new byte[length];
                //Array.Copy(arrMsgRec, buf, length);
                //lock (tcpClient.m_Buffer)
                //{
                //    var tcpDataString = System.Text.Encoding.UTF8.GetString(arrMsgRec, 0, length);
                //    if (!string.IsNullOrEmpty(tcpDataString))
                //    {
                //        ReceiveEvent?.Invoke(tcpDataString);
                //    }
                        if (!string.IsNullOrEmpty(tcpDataString))
                        {
                            MainPage.Log($"局域网tcp数据接收");
                            Control.Ins.ConvertReceiveData(arrMsgRec, null);
                //    MainPage.Log($"接收服务端数据:{tcpDataString}");
                //}
                        }
                    }
                });
                //receiveThread.IsBackground = true;
                receiveThread.Start();
            }
        }
HDL_ON/DAL/DriverLayer/Control_TcpServer.cs
@@ -183,7 +183,7 @@
        {
            MainPage.Log($"0001 tcpDataString:\r\n {tcpBodyDataString}");
            var tcpDataObj = Control.Ins.AnalysisReceiveData(tcpBodyDataString, null);
            if (tcpDataObj.BodyDataString == null)
            if (tcpDataObj==null || tcpDataObj.BodyDataString == null)
            {
                return;
            }
HDL_ON/DAL/DriverLayer/UdpSocket.cs
@@ -138,6 +138,7 @@
                //mqtt连接数据读取  A协议网络设备信息读取回复 处理
                if (((IPEndPoint)packet.RemoteEndPoint).Port == 8585)
                {
                    MainPage.Log($"局域网udp信息");
                    Control.Ins.ConvertReceiveData(bytes, ((IPEndPoint)packet.RemoteEndPoint).Address.ToString());
                }
                else if (((IPEndPoint)packet.RemoteEndPoint).Port == 6000)//处理bus 6000端口的数据
HDL_ON/DAL/Server/HttpServerRequest.cs
@@ -340,6 +340,20 @@
            var requestJson = HttpUtil.GetSignRequestJson(requestObj);
            return HttpUtil.RequestHttpsPost(NewAPI.API_POST_Member_ForgetPwd, requestJson);
        }
        /// <summary>
        /// 修改密码
        /// </summary>
        /// <param name="loginPwd"></param>
        /// <param name="loginNewPwd"></param>
        /// <returns></returns>
        public ResponsePackNew UpdataPassword(string loginPwd,string loginNewPwd)
        {
            Dictionary<string, object> d = new Dictionary<string, object>();
            d.Add("loginPwd", loginPwd);
            d.Add("loginNewPwd", loginNewPwd);
            var requestJson = HttpUtil.GetSignRequestJson(d);
            return HttpUtil.RequestHttpsPost(NewAPI.API_POST_Update_Pwd, requestJson);
        }
        /// <summary>
        /// 验证验证码
@@ -2682,10 +2696,10 @@
        /// 设置第三方设备绑定的住宅
        /// </summary>
        /// <returns></returns>
        public ResponsePackNew Set3tyIotFunctionToHouse(string deviceId,string homeId, string companyId)
        public ResponsePackNew Set3tyIotFunctionToHouse(List<string> deviceIds,string homeId, string companyId)
        {
            Dictionary<string, object> d = new Dictionary<string, object>();
            d.Add("deviceId", deviceId);
            d.Add("deviceIds", deviceIds);
            d.Add("homeId", homeId);
            d.Add("companyId", companyId);
            var requestJson = HttpUtil.GetSignRequestJson(d);
HDL_ON/Entity/Function/Scene.cs
@@ -124,10 +124,7 @@
                    {
                        return sceneImageInfo.defaultIconName;
                    }
                    else
                    {
                        return "Intelligence/Gallery/scenebg1.png";
                    }
                    return image;
                }
            }
            set
HDL_ON/Entity/Integratedbrand/IntegratedBrand.cs
@@ -74,7 +74,7 @@
        /// <summary>
        /// 图片url
        /// </summary>
        public string authrBandIconUrl;
        public string authBrandIconUrl;
        /// <summary>
        /// 认证授权地址
        /// </summary>
HDL_ON/HDL_ON.projitems
@@ -512,6 +512,7 @@
    <Compile Include="$(MSBuildThisFileDirectory)UI\UI2\4-PersonalCenter\AddFunction\Iot_BrandFunctionListPage.cs" />
    <Compile Include="$(MSBuildThisFileDirectory)UI\UI2\4-PersonalCenter\AddFunction\Iot_AuthorizedPage.cs" />
    <Compile Include="$(MSBuildThisFileDirectory)UI\UI2\4-PersonalCenter\AddFunction\Iot_SupportSpkListPage.cs" />
    <Compile Include="$(MSBuildThisFileDirectory)DAL\DriverLayer\Control_Tcp.cs" />
  </ItemGroup>
  <ItemGroup>
    <Folder Include="$(MSBuildThisFileDirectory)Entity\Device\" />
HDL_ON/UI/MainPage.cs
@@ -465,6 +465,17 @@
        }
        /// <summary>
        /// 自定义日志输出
        /// </summary>
        public static void Log(string tag,string msg)
        {
#if DEBUG
            Console.WriteLine($"{tag}-->{msg}");
#endif
        }
    }
}
HDL_ON/UI/UI2/2-Classification/ClassificaitionPublicBLL.cs
@@ -17,14 +17,14 @@
        /// <param name="updataFunction"></param>
        public void UpdataStates(Function updataFunction, FrameLayout view, VerticalScrolViewLayout scrolView, Room room = null)
        {
            if (view == null || scrolView == null || updataFunction == null)
            {
                return;
            }
            Application.RunOnMainThread((() =>
            {
                try
                {
                    if (view == null || scrolView == null || updataFunction == null)
                    {
                        return;
                    }
                    if (!scrolView.ScrollEnabled)
                    {
                        return;
HDL_ON/UI/UI2/2-Classification/FunctionControlZone.cs
@@ -185,7 +185,7 @@
            {
                var btnHumidityIcon = new Button()
                {
                    X = Application.GetRealWidth(51),
                    X = Application.GetRealWidth(110),
                    Y = Application.GetRealHeight(66),
                    Width = Application.GetMinRealAverage(16),
                    Height = Application.GetMinRealAverage(16),
@@ -194,7 +194,7 @@
                bodyDiv.AddChidren(btnHumidityIcon);
                var btnHumidityValues = new TextButton()
                {
                    X = Application.GetRealWidth(70),
                    X = Application.GetRealWidth(130),
                    Y = Application.GetRealHeight(64),
                    Height = Application.GetRealHeight(18),
                    TextColor = 0xFF161616,
@@ -208,7 +208,7 @@
                Button btnTempIcon = new Button()
                {
                    X = Application.GetRealWidth(110),
                    X = Application.GetRealWidth(51),
                    Y = Application.GetRealHeight(66),
                    Width = Application.GetMinRealAverage(17),
                    Height = Application.GetMinRealAverage(17),
@@ -218,7 +218,7 @@
                var btnTempValues = new TextButton()
                {
                    X = Application.GetRealWidth(130),
                    X = Application.GetRealWidth(70),
                    Y = Application.GetRealHeight(64),
                    Height = Application.GetRealHeight(18),
                    TextColor = 0xFF161616,
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/Iot_AuthorizedPage.cs
@@ -2,6 +2,7 @@
using Shared;
using HDL_ON.Entity;
using HDL_ON.DAL.Server;
using HDL_ON.UI.CSS;
namespace HDL_ON.UI
{
@@ -32,9 +33,99 @@
                UnsubscribeAsync3tyIotbind();
                Application.RunOnMainThread(() =>
                {
                    http.Search3tyIotDevice(brand_Iot.companyId);
                    //http.Search3tyIotDevice(brand_Iot.companyId);
                    boudedAction?.Invoke();
                    dd.Close();
                    {
                        Dialog dialog = new Dialog()
                        {
                            BackgroundColor = CSS_Color.DialogTransparentColor1,
                        };
                        FrameLayout contentView = new FrameLayout()
                        {
                            Gravity = Gravity.Center,
                            Width = Application.GetRealWidth(305),
                            Height = Application.GetRealHeight(180),
                            BackgroundColor = CSS.CSS_Color.MainBackgroundColor,
                            BorderColor = 0x00000000,
                            BorderWidth = 0,
                            Radius = (uint)Application.GetMinRealAverage(10),
                        };
                        dialog.AddChidren(contentView);
                        Button btnTitle = new Button()
                        {
                            Gravity = Gravity.CenterHorizontal,
                            Y = Application.GetRealHeight(10),
                            Height = Application.GetRealHeight(38),
                            TextAlignment = TextAlignment.Center,
                            IsBold = true,
                            TextColor = 0xFF222222,
                            TextSize = CSS_FontSize.SubheadingFontSize,
                            TextID = StringId.Tip
                        };
                        contentView.AddChidren(btnTitle);
                        Button btnMsg = new Button()
                        {
                            Gravity = Gravity.CenterHorizontal,
                            Height = Application.GetRealHeight(70),
                            Y = Application.GetRealHeight(55),
                            TextAlignment = TextAlignment.TopCenter,
                            TextColor = CSS_Color.FirstLevelTitleColor,
                            TextSize = CSS_FontSize.SubheadingFontSize,
                            Padding = new Padding(0, Application.GetRealWidth(16), 0, Application.GetRealWidth(16)),
                            Text = "账户绑定成功,您可以继续完成设备关联操作",
                            IsMoreLines = true,
                        };
                        contentView.AddChidren(btnMsg);
                        if(Language.CurrentLanguage != "Chinese")
                        {
                            btnMsg.Text = "Account binding is successful.You can continue to complete the device association operation";
                        }
                        Button btnLine = new Button()
                        {
                            Y = Application.GetRealHeight(125),
                            Height = Application.GetRealHeight(1),
                            BackgroundColor = CSS.CSS_Color.DividingLineColor,
                        };
                        contentView.AddChidren(btnLine);
                        Button btnConfirm = new Button()
                        {
                            Y = btnLine.Bottom,
                            Height = Application.GetRealHeight(55),
                            TextAlignment = TextAlignment.Center,
                            TextColor = CSS_Color.MainColor,
                            TextSize = CSS_FontSize.SubheadingFontSize,
                            SelectedTextColor = CSS_Color.MainBackgroundColor,
                            SelectedBackgroundColor = CSS_Color.MainColor,
                            TextID = StringId.Confirm,
                        };
                        btnConfirm.SetCornerWithSameRadius(Application.GetMinRealAverage(10), HDLUtils.RectCornerBottomLeft);
                        btnConfirm.SetCornerWithSameRadius(Application.GetMinRealAverage(10), HDLUtils.RectCornerBottomRight);
                        contentView.AddChidren(btnConfirm);
                        dialog.Show();
                        btnConfirm.MouseDownEventHandler += (sender, e) =>
                        {
                            btnConfirm.IsSelected = true;
                        };
                        btnConfirm.MouseUpEventHandler += (sender, e) =>
                        {
                            dialog.Close();
                        };
                    }
                });
            };
            SubscribeAsync3tyIotbind();
@@ -79,17 +170,16 @@
            })
            { IsBackground = true }.Start();
        }
        /// <summary>
        /// 搜索第三方设备
        /// </summary>
        private void SearchDevice()
        {
            var pack = http.Search3tyIotDevice(brand_Iot.companyId);
            if(pack!= null)
            {
            }
        }
        ///// <summary>
        ///// 搜索第三方设备
        ///// </summary>
        //private void SearchDevice()
        //{
        //    var pack = http.Search3tyIotDevice(brand_Iot.companyId);
        //    if(pack!= null)
        //    {
        //    }
        //}
        /// <summary>
        /// 获取第三方功能列表
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/Iot_BrandFunctionListPage.cs
@@ -12,6 +12,7 @@
        FrameLayout contentView;
        FrameLayout optionView;
        IntegratedBrand_Iot brand_Iot;
@@ -61,11 +62,15 @@
                TextColor = CSS_Color.FirstLevelTitleColor,
                Padding = new Padding(12,  Application.GetRealWidth(16), 12, Application.GetRealWidth(16)),
                TextSize = CSS_FontSize.TextFontSize,
                Text = "默认将第三方品牌的设备全部关联到On Pro上,您也可以通过下方的开关按键,进行选择性关联。",
                Text = "*您可以将第三方品牌的设备关联到On Pro您当前的住宅上。",
                IsMoreLines = true,
                TextAlignment = TextAlignment.CenterLeft,
            };
            bodyView.AddChidren(btnTipText);
            if (Language.CurrentLanguage != "Chinese")
            {
                btnTipText.Text = "*You can associate third-party branded devices with on Pro's current home.";
            }
            contentView = new FrameLayout()
            {
@@ -82,6 +87,11 @@
            {
                try
                {
                    var pack0 = http.Search3tyIotDevice(brand_Iot.companyId);
                    if(pack0 != null)
                    {
                    }
                    var pack = http.Get3tyIotDeviceFunctionList(brand_Iot.companyId);
                    if (pack != null)
                    {
@@ -104,6 +114,54 @@
                    });
                }
            }) { IsBackground = true }.Start();
            optionView = new FrameLayout()
            {
                Y = Application.GetRealHeight(667 - 80),
                Height = Application.GetRealHeight(90),
                Radius = (uint)Application.GetRealWidth(22),
                Visible = false,
            };
            bodyView.AddChidren(optionView);
            var btnComfirm = new Button()
            {
                Gravity = Gravity.CenterHorizontal,
                Y = Application.GetRealHeight(14),
                Width = Application.GetRealWidth(164),
                Height = Application.GetRealHeight(44),
                TextAlignment = TextAlignment.Center,
                BackgroundColor = CSS_Color.MainColor,
                TextColor = CSS_Color.MainBackgroundColor,
                TextSize = CSS_FontSize.SubheadingFontSize,
                TextID = StringId.Confirm,
                Radius = (uint)Application.GetRealHeight(22)
            };
            optionView.AddChidren(btnComfirm);
            btnComfirm.MouseUpEventHandler = (sender, e) => {
                var pack = http.Set3tyIotFunctionToHouse(optionList, DB_ResidenceData.Instance.CurrentRegion.id, brand_Iot.companyId);
                if (pack != null)
                {
                    if (pack.Code == StateCode.SUCCESS)
                    {
                        btnComfirm.Visible = false;
                    }
                }
                //var pack = http.Set3tyIotFunctionToHouse(function.deviceId, "0", brand_Iot.companyId);
                //if (pack != null)
                //{
                //    if (pack.Code == StateCode.SUCCESS)
                //    {
                //        btnName.IsSelected = btnIcon.IsSelected = btnCheckIcon.IsSelected = false;
                //    }
                //}
            };
        }
@@ -163,11 +221,11 @@
                    var btnbg = new Button()
                    {
                        UnSelectedImagePath = "Collection/Functionbg.png",
                        SelectedImagePath = "Collection/FunctionOnbg.png",
                        SelectedImagePath = "Collection/Functionbg.png",
                        Tag = function.sid
                    };
                    functionView.AddChidren(btnbg);
                    LoadDeviceFunctionDiv(functionView, function,btnbg);
                    LoadDeviceFunctionDiv(functionView, function);
                    index++;
                
@@ -188,6 +246,10 @@
                        Text = "没有任何设备"
                    };
                    view.AddChidren(btnNoCollectionTip);
                    if (Language.CurrentLanguage != "Chinese")
                    {
                        btnNoCollectionTip.Text = "No equipment";
                    }
                }
            }
            catch (Exception ex)
@@ -196,16 +258,34 @@
            deviceFunctionView.AddChidren(new Button { Height = Application.GetRealHeight(30) });
            #endregion
            deviceFunctionView.AddChidren(new Button {
                Height = Application.GetRealHeight(90),
            });
        }
        /// <summary>
        /// 加载功能控制卡片
        /// </summary>
        void LoadDeviceFunctionDiv(FrameLayout view, Function function,Button btnBg)
        void LoadDeviceFunctionDiv(FrameLayout view, Function function)
        {
            try
            {
                var btnCheckIcon = new Button()
                {
                    X = Application.GetRealWidth(22),
                    Y = Application.GetRealHeight(16),
                    Width = Application.GetRealWidth(21),
                    Height = Application.GetRealWidth(21),
                    UnSelectedImagePath = "Public/IotCheckIcon.png",
                    SelectedImagePath = "Public/IotCheckOnIcon.png",
                };
                view.AddChidren(btnCheckIcon);
                Button btnIcon;
                btnIcon = new Button()
                {
@@ -237,39 +317,32 @@
                Button btnClick = new Button();
                view.AddChidren(btnClick);
                btnClick.MouseUpEventHandler = (sender, e) => {
                    function.collect = !function.collect;
                    if (function.collect)
                    btnCheckIcon.IsSelected = function.collect = !function.collect;
                    if (optionList.Contains(function.deviceId))
                    {
                        var pack = http.Set3tyIotFunctionToHouse(function.deviceId, DB_ResidenceData.Instance.CurrentRegion.id,brand_Iot.companyId);
                        if (pack != null)
                        {
                            if(pack.Code == StateCode.SUCCESS)
                            {
                                btnName.IsSelected = btnIcon.IsSelected = btnBg.IsSelected = true;
                            }
                        }
                        optionList.Remove(function.deviceId);
                    }
                    else
                    {
                        btnName.IsSelected = btnIcon.IsSelected = btnBg.IsSelected = false;
                        var pack = http.Set3tyIotFunctionToHouse(function.deviceId, "0", brand_Iot.companyId);
                        if (pack != null)
                        {
                            if (pack.Code == StateCode.SUCCESS)
                            {
                                btnName.IsSelected = btnIcon.IsSelected = btnBg.IsSelected = false;
                            }
                        }
                        optionList.Add(function.deviceId);
                    }
                    optionView.Visible = true;
                };
                if (function.homeId == DB_ResidenceData.Instance.CurrentRegion.id )
                {
                    btnCheckIcon.IsSelected = true;
                    optionList.Add(function.deviceId);
                }
            }
            catch (Exception ex)
            {
                MainPage.Log("homepage LoadControlView error : " + ex.Message);
            }
        }
        /// <summary>
        /// 记录需要操作的列表
        /// </summary>
        private List<string> optionList = new List<string>();
        void NotListTipView()
@@ -312,7 +385,7 @@
                BorderWidth = 0,
                Text = "查看设备支持范围"
            };
            contentView.AddChidren(btnAdd);
            //contentView.AddChidren(btnAdd);
            btnAdd.MouseUpEventHandler = (sender, e) =>
            {
                //var page = new AddThirdPartyBrandListpage(brandList);
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/Iot_BrandListPage.cs
@@ -55,7 +55,12 @@
                TextAlignment = TextAlignment.CenterLeft,
            };
            bodyView.AddChidren(btnTipText);
            if (Language.CurrentLanguage != "Chinese")
            {
                btnTipText.Text = "Synchronize your devices on the third-party platform to on Pro for control by binding the third-party platform account to the cloud connection";
            }
            contentView = new VerticalScrolViewLayout()
            {
                Y = Application.GetRealHeight(150),
@@ -76,7 +81,7 @@
        }
        /// <summary>
        /// 获取绑定列表
        /// 获取列表
        /// </summary>
        void GetBindList()
        {
@@ -197,9 +202,8 @@
                };
                row.AddChidren(btnName);
                //下载第三方品牌icon
                ImageUtlis.Current.Load3tyBrandIconImages(brand.brandName, brand.authrBandIconUrl, btnIcon);
                btnName.MouseUpEventHandler = (sender, e) => {
                ImageUtlis.Current.Load3tyBrandIconImages(brand.brandName, brand.authBrandIconUrl, btnIcon);
                EventHandler<MouseEventArgs> eventHandler =  (sender, e) => {
                    if (brand.hasAuthorization)
                    {
                        Action unboundAction = () =>
@@ -231,6 +235,11 @@
                        MainPage.BasePageView.PageIndex = MainPage.BasePageView.ChildrenCount - 1;
                    }
                };
                btnRight.MouseUpEventHandler = eventHandler;
                row.MouseUpEventHandler = eventHandler;
                btnName.MouseUpEventHandler = eventHandler;
                btnBindTip.MouseUpEventHandler = eventHandler;
            }
        }
HDL_ON/UI/UI2/4-PersonalCenter/AddFunction/iot_BindTipPage.cs
@@ -27,8 +27,7 @@
        public void LoadPage(IntegratedBrand_Iot brand_Iot)
        {
            new TopViewDiv(bodyView, Language.StringByID(StringId.Bind3thIotAccount)).LoadTopView(CSS_Color.MainBackgroundColor);
            new TopViewDiv(bodyView, brand_Iot.brandName).LoadTopView(CSS_Color.MainBackgroundColor);
            bodyView.BackgroundColor = CSS_Color.MainBackgroundColor;
@@ -63,6 +62,10 @@
                Text = "关于账号绑定的声明"
            };
            contentView.AddChidren(btnTipTitle);
            if (Language.CurrentLanguage != "Chinese")
            {
                btnTipTitle.Text = "Statement on account binding";
            }
            var btnTipText = new Button()
            {
@@ -87,6 +90,16 @@
"如需终止以上信息的收集与处理,您可以在“我的”> “绑定第三方账户”>“解除”"
            };
            contentView.AddChidren(btnTipText);
            if (Language.CurrentLanguage != "Chinese")
            {
                btnTipText.Text = $"account binding brand: {brand_Iot.brandName} (hereinafter referred to as the third party brand)" + "\r\n" + "\r\n" +
"After you bind the account of the third-party brand, you will authorize 'on Pro' to use your account of the third-party to jointly manage the device. On Pro will also automatically synchronize the device you added in the third-party brand." + "\r\n" + "\r\n" +
"To realize the device control function, this application will obtain the following data from a third party:" + "\r\n" + "\r\n" +
"1. List of some devices added on the third-party brand for intelligent control in on Pro;" + "\r\n" + "\r\n" +
"2. Equipment and network information, including equipment identifier, MAC address and equipment serial number, is used to identify the currently working equipment and perform equipment control functions." + "\r\n" + "\r\n" +
"If you do not agree with our collection of the above information, you will not be able to manage third-party branded devices." + "\r\n" + "\r\n" +
"To terminate the collection and processing of the above information, you can click my > bind third party account > cancel";
            }
            var optionView = new FrameLayout()
@@ -110,7 +123,7 @@
                TextAlignment = TextAlignment.Center,
                TextColor = CSS_Color.MainColor,
                TextSize = CSS_FontSize.SubheadingFontSize,
                Text = "返回",
                TextID= StringId.fanhui,
                Radius = (uint)Application.GetRealHeight(22)
            };
            optionView.AddChidren(btnCannel);
@@ -133,6 +146,10 @@
                Radius = (uint)Application.GetRealHeight(22)
            };
            optionView.AddChidren(btnComfirm);
            if (Language.CurrentLanguage != "Chinese")
            {
                btnComfirm.Text = "Consent authorization";
            }
            if (!brand_Iot.hasAuthorization)
@@ -151,8 +168,8 @@
                        MainPage.BasePageView.PageIndex = MainPage.BasePageView.ChildrenCount - 1;
                    };
                    var page = new Iot_AuthorizedPage(brand_Iot,action);
                    page.LoadView();
                    var page2 = new Iot_AuthorizedPage(brand_Iot,action);
                    page2.LoadView();
@@ -161,6 +178,10 @@
            else
            {
                btnComfirm.Text = "解除授权";
                if (Language.CurrentLanguage != "Chinese")
                {
                    btnComfirm.Text = "Cancel authorization";
                }
                btnComfirm.MouseUpEventHandler = (sender, e) =>
                {
                    Dialog dialog = new Dialog()
@@ -168,7 +189,7 @@
                        BackgroundColor = CSS_Color.DialogTransparentColor1,
                    };
                    FrameLayout contentView = new FrameLayout()
                    FrameLayout contentView2 = new FrameLayout()
                    {
                        Gravity = Gravity.Center,
                        Width = Application.GetRealWidth(305),
@@ -178,7 +199,7 @@
                        BorderWidth = 0,
                        Radius = (uint)Application.GetMinRealAverage(10),
                    };
                    dialog.AddChidren(contentView);
                    dialog.AddChidren(contentView2);
                    Button btnMsg = new Button()
                    {
@@ -192,7 +213,11 @@
                        Text = "撤销授权后,该品牌关联在On Pro中的设备将全部被解绑,相关使用信息合设备值也将失效",
                        IsMoreLines = true,
                    };
                    contentView.AddChidren(btnMsg);
                    contentView2.AddChidren(btnMsg);
                    if (Language.CurrentLanguage != "Chinese")
                    {
                        btnMsg.Text = "After the authorization is revoked, all the devices associated with the brand in on Pro will be unbound, and the relevant use information and device value will also become invalid";
                    }
                    Button btnLine = new Button()
                    {
@@ -200,7 +225,7 @@
                        Height = Application.GetRealHeight(1),
                        BackgroundColor = CSS.CSS_Color.DividingLineColor,
                    };
                    contentView.AddChidren(btnLine);
                    contentView2.AddChidren(btnLine);
                    Button btnConfirm = new Button()
                    {
@@ -213,17 +238,21 @@
                        SelectedBackgroundColor = CSS_Color.MainColor,
                        Text = "确定撤回授权",
                    };
                    if (Language.CurrentLanguage != "Chinese")
                    {
                        btnConfirm.Text = "Confirm to withdraw authorization";
                    }
                    btnConfirm.SetCornerWithSameRadius(Application.GetMinRealAverage(10), HDLUtils.RectCornerBottomLeft);
                    btnConfirm.SetCornerWithSameRadius(Application.GetMinRealAverage(10), HDLUtils.RectCornerBottomRight);
                    contentView.AddChidren(btnConfirm);
                    contentView2.AddChidren(btnConfirm);
                    dialog.Show();
                    btnConfirm.MouseDownEventHandler += (sender, e) =>
                    btnConfirm.MouseDownEventHandler += (sender2, e2) =>
                    {
                        btnConfirm.IsSelected = true;
                    };
                    btnConfirm.MouseUpEventHandler += (sender, e) =>
                    btnConfirm.MouseUpEventHandler += (sender2, e2) =>
                    {
                        var http = new HttpServerRequest();
                        var waitPage = new Loading();
@@ -251,7 +280,14 @@
                                else
                                {
                                    dialog.Close();
                                    new Alert("", "操作失败", "").Show();
                                    if (Language.CurrentLanguage != "Chinese")
                                    {
                                        new Alert("", "Operation failed", "").Show();
                                    }
                                    else
                                    {
                                        new Alert("", "操作失败", "").Show();
                                    }
                                }
                            }
                            catch { }
HDL_ON/UI/UI2/4-PersonalCenter/PersonalDataPageBLL.cs
@@ -544,10 +544,16 @@
        {
            EventHandler<MouseEventArgs> eventHandler = (sender, e) =>
            {
                var page = new ResetPasswordOptionPage();
                MainPage.BasePageView.AddChidren(page);
                page.LoadPage();
                //var page = new ResetPasswordOptionPage();
                //MainPage.BasePageView.AddChidren(page);
                //page.LoadPage();
                //MainPage.BasePageView.PageIndex = MainPage.BasePageView.ChildrenCount - 1;
                var vcp = new ResetPasswordPage();
                MainPage.BasePageView.AddChidren(vcp);
                vcp.LoadPage();
                MainPage.BasePageView.PageIndex = MainPage.BasePageView.ChildrenCount - 1;
            };
            btnResetPasswordRight.MouseUpEventHandler = eventHandler;
            btnResetPasswordText.MouseUpEventHandler = eventHandler;
HDL_ON/UI/UI2/4-PersonalCenter/ResetAccountPassword/ResetPasswordPage.cs
@@ -23,6 +23,11 @@
        #region 控件View
        /// <summary>
        /// 原密码文本框
        /// </summary>
        EditText etOldPwd;
        /// <summary>
        /// 密码文本框
        /// </summary>
        EditText etPassword;
@@ -64,10 +69,45 @@
            new TopViewDiv(bodyView, Language.StringByID(StringId.ModifyPassword)).LoadTopView(backAction);
            #region 原密码
            FrameLayout oldPwdView = new FrameLayout()
            {
                Y = Application.GetRealHeight(64),
                Height = Application.GetRealHeight(50),
                BackgroundColor = CSS_Color.MainBackgroundColor,
            };
            bodyView.AddChidren(oldPwdView);
            Button btnOldPwdTitle = new Button()
            {
                X = Application.GetRealWidth(16),
                Width = Application.GetRealWidth(180),
                TextColor = CSS_Color.FirstLevelTitleColor,
                TextSize = CSS_FontSize.SubheadingFontSize,
                TextAlignment = TextAlignment.CenterLeft,
                Text = Language.StringByID(StringId.OriginalPassword) + ":"
            };
            oldPwdView.AddChidren(btnOldPwdTitle);
            etOldPwd = new EditText()
            {
                Width = Application.GetRealWidth(359),
                TextColor = CSS_Color.PromptingColor1,
                TextSize = CSS_FontSize.TextFontSize,
                SecureTextEntry = true,
                TextAlignment = TextAlignment.CenterRight,
                Foucs = true
            };
            oldPwdView.AddChidren(etOldPwd);
            oldPwdView.AddChidren(new LineView(oldPwdView.Height));
            #endregion
            #region 新密码
            FrameLayout rowView = new FrameLayout()
            {
                Y = Application.GetRealHeight(64),
                Y = oldPwdView.Bottom ,
                Height = Application.GetRealHeight(50),
                BackgroundColor = CSS_Color.MainBackgroundColor,
            };
@@ -156,24 +196,24 @@
    public partial class ResetPasswordPage
    {
        /// <summary>
        /// 指定关闭页面个数
        /// </summary>
        /// <param name="countPage"></param>
        void ClosePageWithCount(int countPage)
        {
            //关闭多少个页面
            for (int i = 0; i < countPage; i++)
            {
                MainPage.BasePageView.GetChildren(MainPage.BasePageView.ChildrenCount - 1).RemoveFromParent();
            }
        }
        ///// <summary>
        ///// 指定关闭页面个数
        ///// </summary>
        ///// <param name="countPage"></param>
        //void ClosePageWithCount(int countPage)
        //{
        //    //关闭多少个页面
        //    for (int i = 0; i < countPage; i++)
        //    {
        //        MainPage.BasePageView.GetChildren(MainPage.BasePageView.ChildrenCount - 1).RemoveFromParent();
        //    }
        //}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="password"></param>
        void ResetPassword(string password)
        void ResetPassword(string oldPwd, string password)
        {
            //校验密码是否符合要求
@@ -211,13 +251,13 @@
                try
                {
                    // 忘记密码
                    var resultObj = new HttpServerRequest().ForgetPassword(account, password, verCode, isPhone);
                    var resultObj = new HttpServerRequest().UpdataPassword(oldPwd, password);
                    if (resultObj.Code == StateCode.SUCCESS)
                    {
                        Application.RunOnMainThread(() =>
                        {
                            Utlis.ShowTip(Language.StringByID(StringId.PasswordChangeSuccessfully));
                            ClosePageWithCount(2);
                            this.RemoveFromParent();
                        });
                    }
                    else
@@ -252,7 +292,7 @@
            {
                if (btnReset.IsSelected)
                {
                    ResetPassword(etPassword.Text.ToString());
                    ResetPassword(etOldPwd.Text.Trim().ToString(), etPassword.Text.ToString());
                }
            };
        }
HDL_ON/UI/UI2/FuntionControlView/1ContorlPage/CacControlPage.cs
@@ -102,6 +102,7 @@
            this.RefreshNowDeviceStatuMemory(this.device);
            //刷新界面状态
            this.RefreshFormStatu();
            controlTime = DateTime.Now;
            //读取状态
            new System.Threading.Thread(() =>
            {
@@ -109,7 +110,7 @@
                {
                    if (controlTime == DateTime.MinValue)
                    {
                    }
                    else if (controlTime.AddSeconds(2) < DateTime.Now)
                    {
@@ -176,7 +177,6 @@
            temp = (int)Convert.ToDouble(device.GetAttrState(FunctionAttributeKey.SetTemp).Replace(",", "."));
            if (temp <= 0)
            {
                //默认值改成16,2022年06月10日10:03:19 成甫要求的
                temp = 16;
                device.SetAttrState(FunctionAttributeKey.SetTemp, temp.ToString());
            }
@@ -683,10 +683,12 @@
                {
                    //btnIndoorTemp.Text = Language.StringByID(StringId.IndoorTemp) + Convert.ToInt32(Convert.ToDouble(device.GetAttrState(FunctionAttributeKey.RoomTemp).Replace(",", "."))) + "°C"
                    //                    + Language.StringByID(StringId.Humidity) + Convert.ToInt32(Convert.ToDouble(device.GetAttrState("room_humidity").Replace(", ", "."))) + "%";
                    btnTempValues.Text = Convert.ToInt32(Convert.ToDouble(device.GetAttrState(FunctionAttributeKey.RoomTemp).Replace(",", "."))) + "°C";
                    btnHumidityValues.Text = Convert.ToInt32(Convert.ToDouble(device.GetAttrState("room_humidity").Replace(", ", "."))) + "%";
                    btnTempValues.Text = Convert.ToDouble(device.GetAttrState(FunctionAttributeKey.RoomTemp).Replace(",", ".")) + "°C";
                    btnHumidityValues.Text = Convert.ToDouble(device.GetAttrState("room_humidity").Replace(", ", ".")) + "%";
                    btnMode.UnSelectedImagePath = acFunction.GetModeIconPath(device.GetAttrState(FunctionAttributeKey.Mode));
                    btnModeText.Text = acFunction.GetModeAttrText(device.GetAttrState(FunctionAttributeKey.Mode));
                    temp = Convert.ToInt32(Convert.ToDouble(device.GetAttrState(FunctionAttributeKey.SetTemp).Replace(",", ".")));