From 134209ad70f82051da3ce63471df0cc8f778e57d Mon Sep 17 00:00:00 2001
From: panlili2024 <14743743+panlili2024@user.noreply.gitee.com>
Date: 星期三, 05 三月 2025 14:30:19 +0800
Subject: [PATCH] 增加source屏扫码绑定住宅接口

---
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLLinkConfig.java                   |   22 
 HDLSDK/app/src/main/AndroidManifest.xml                                                          |    5 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/EventType.java                        |   27 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java                       |   32 
 HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/MainActivity.java                                   |  146 +
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindAuthEvent.java                    |   37 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCode.java                         |   65 +
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudApi.java                      |   16 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java                   |    4 
 HDLSDK_DEMO/app/src/main/AndroidManifest.xml                                                     |    5 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/HdlLoginInterceptor.java  |  281 ++++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/socket/SocketBoot.java                              |    2 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/ThreadUtils.java              |  319 +++++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BaseEvent.java                        |   12 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/GlobalBroadcastManager.java |   35 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QrCodeView.java                     |  141 ++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/DeviceUtils.java                     |  377 +++++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcast.java         |   58 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/RenameThreadFactory.java      |   48 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudController.java               |   84 +
 HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java                                                 |   16 
 HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java                                  |  106 +
 HDLSDK_DEMO/app/src/main/res/layout/activity_source_bind.xml                                     |   27 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListListener.java     |   15 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcastAction.java   |   17 
 HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.1.aar                                                      |    0 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/HDLCloudBroadcast.java      |  119 +
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/CloudCode.java                        |   59 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/SibichiListener.java         |   14 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java            |   20 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/SPKey.java                           |   19 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLLink.java                                |   69 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/GatewayInfo.java                 |  177 ++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/AiLoginInfo.java                 |  163 ++
 HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java                             |  106 +
 HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/App.java                                            |   16 
 HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java                                  |    2 
 HDLSDK_DEMO/app/build.gradle                                                                     |    7 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLCloudConfig.java                  |  150 ++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/MainThreadExecutor.java       |  152 ++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/EncryptInterceptor.java   |    5 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindHomeService.java                  |  184 ++
 HDLSDK/hdl-connect/build.gradle                                                                  |    8 
 HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java                             |    2 
 HDLSDK/app/src/main/res/layout/activity_source_bind.xml                                          |   27 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/response/BindInfoBean.java             |  338 +++++
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListener.java         |   11 
 HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCodeUtils.java                    |   71 +
 HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java                                        |  146 +
 49 files changed, 3,612 insertions(+), 150 deletions(-)

diff --git a/HDLSDK/app/src/main/AndroidManifest.xml b/HDLSDK/app/src/main/AndroidManifest.xml
index 490bf4e..fd83be6 100644
--- a/HDLSDK/app/src/main/AndroidManifest.xml
+++ b/HDLSDK/app/src/main/AndroidManifest.xml
@@ -36,6 +36,11 @@
             android:exported="false"
             android:windowSoftInputMode="adjustPan|stateHidden" />
 
+        <activity
+            android:name=".SourceBindActivity"
+            android:exported="false"
+            android:windowSoftInputMode="adjustPan|stateHidden" />
+
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java
index 5e35853..284a4e9 100644
--- a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/App.java
@@ -1,13 +1,11 @@
 package com.hdl.hdlsdk;
 
 import android.app.Application;
-import android.util.Log;
 
 import com.hdl.sdk.common.HDLSdk;
-import com.hdl.sdk.common.event.EventListener;
-import com.hdl.sdk.common.utils.LogUtils;
 import com.hdl.sdk.connect.HDLLink;
-import com.hdl.sdk.connect.bean.LinkResponse;
+import com.hdl.sdk.connect.cloud.broadcast.GlobalBroadcastManager;
+import com.hdl.sdk.sourceos.OsManager;
 
 /**
  * Created by Tong on 2021/10/8.
@@ -15,6 +13,7 @@
 public class App extends Application {
 
     private String deviceStatusUpdateTopic;
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -23,6 +22,15 @@
         //鎺у埗SDK鏃ュ織鎵撳嵃
         HDLSdk.getInstance().setLogEnabled(true);
 
+        //source绯荤粺鎺ュ彛鍒濆鍖�
+        OsManager.init(this);
+
+        //appkey:ryfElI3tVOT
+        //appsecret:AKIn7s1A2YnNvAZRtL8FQxzp0R2KUpIY
+        HDLLink.getInstance().initCloud(this, "ryfElI3tVOT", "AKIn7s1A2YnNvAZRtL8FQxzp0R2KUpIY");
+
+        //娉ㄥ唽鍏ㄥ眬骞挎挱,鍒锋柊token
+        GlobalBroadcastManager.registerGlobalBroadcast(this);
     }
 
     @Override
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
index 0a79a1c..5f8e69d 100644
--- a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
@@ -35,6 +35,7 @@
 import com.hdl.sdk.common.exception.HDLLinkException;
 import com.hdl.sdk.common.utils.IdUtils;
 import com.hdl.sdk.common.utils.LogUtils;
+import com.hdl.sdk.common.utils.SPUtils;
 import com.hdl.sdk.common.utils.gson.GsonConvert;
 import com.hdl.sdk.connect.HDLLink;
 import com.hdl.sdk.connect.bean.LinkResponse;
@@ -44,6 +45,7 @@
 import com.hdl.sdk.connect.bean.request.ListSidRequest;
 import com.hdl.sdk.connect.bean.request.ListUploadRequest;
 import com.hdl.sdk.connect.bean.response.BaseLocalResponse;
+import com.hdl.sdk.connect.bean.response.BindInfoBean;
 import com.hdl.sdk.connect.bean.response.GatewaySearchBean;
 import com.hdl.sdk.connect.bean.response.UpdateInfo;
 import com.hdl.sdk.connect.callback.HDLLinkCallBack;
@@ -51,8 +53,13 @@
 import com.hdl.sdk.connect.cloud.CallBackListener;
 import com.hdl.sdk.connect.cloud.CheckAppVersionListener;
 import com.hdl.sdk.connect.cloud.HDLException;
+import com.hdl.sdk.connect.cloud.bean.GatewayInfo;
+import com.hdl.sdk.connect.cloud.listener.GatewayListener;
+import com.hdl.sdk.connect.cloud.listener.SibichiListener;
+import com.hdl.sdk.connect.cloud.bean.AiLoginInfo;
 import com.hdl.sdk.connect.config.HDLLinkConfig;
 import com.hdl.sdk.connect.socket.HDLAuthSocket;
+import com.hdl.sdk.sourceos.utils.SPKey;
 
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
@@ -79,21 +86,12 @@
     private List<SceneBean> sceneList = new ArrayList<>();
     private List<SceneDetailBean> sceneDetailList = new ArrayList<>();
     private List<SceneDetailBean> roomSceneList = new ArrayList<>();
+    private GatewayInfo gatewayInfo;
 
     void applyDeviceSecret() {
         tv.setText("寮�濮嬬敵璇疯澶囧瘑閽�...");
         responseTv.setText("");
 
-//        //姝e紡鏈嶅姟鍣�
-//        String appKey = "i8hR07jzrIS";//appkey
-//        String appSecret = "BmnJ8RWTtaVEBk24zPPF4UMwfYu0lAWU";//appsecret
-
-        //娴嬭瘯鏈嶅姟鍣�
-        String appKey = "FcRyUJlLJFF";
-        String appSecret = "wz8wn75ABidx8vXcFGUotqhwFkTaYvvJ";
-
-//        String appKey = "L2OZliZRxHc";
-//        String appSecret = "aCIWSvJDOukXfx3kivsKW11x9xdR3IbV";
         String supplier = "JINMAOYUN";//鍘傚晢
 //        String mac = "AA00000000000100";//璁惧鍞竴MAC鍦板潃
         String mac = editText.getText().toString();
@@ -103,8 +101,8 @@
             Toast.makeText(this, "mac涓嶈兘涓虹┖锛�", Toast.LENGTH_SHORT).show();
             return;
         }
-
-        HDLLink.getInstance().applyDeviceSecret(this, appKey, appSecret, supplier, mac, spk, new CallBackListener() {
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().applyDeviceSecret(supplier, mac, spk, new CallBackListener() {
             @Override
             public void onError(HDLException e) {
                 tv.setText("鐢宠澶辫触");
@@ -126,13 +124,10 @@
         tv.setText("寮�濮嬫娴嬫洿鏂�...");
         responseTv.setText("");
 
-//        //姝e紡鏈嶅姟鍣�
-        String appKey = "i8hR07jzrIS";//appkey
-        String appSecret = "BmnJ8RWTtaVEBk24zPPF4UMwfYu0lAWU";//appsecret
-
         String appCode = "1697150870315999233";//appCode
 
-        HDLLink.getInstance().checkAppVersion(this, appKey, appSecret, getAppVersionName(this), appCode, new CheckAppVersionListener() {
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().checkAppVersion(getAppVersionName(this), appCode, new CheckAppVersionListener() {
             @Override
             public void onSuccess(UpdateInfo info) {
                 tv.setText("鏈夋柊鏇存柊");
@@ -142,6 +137,60 @@
             @Override
             public void onError(HDLException e) {
                 tv.setText("妫�娴嬫洿鏂板け璐�");
+                responseTv.setText(e.getMsg());
+            }
+        });
+
+    }
+
+    void getSibichiToken() {
+        tv.setText("鑾峰彇鎬濆繀椹皌oken...");
+        responseTv.setText("");
+
+        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+        String clientId = "4ED634B5A7AD97A770A52AC00FF43805";//鎬濆繀椹癱lientId
+
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().getSibichiToken(bindInfoBean.getHomeId(), clientId, new SibichiListener() {
+            @Override
+            public void onSuccess(AiLoginInfo info) {
+                tv.setText("鎬濆繀椹皌oken");
+                responseTv.setText(info.toString());
+            }
+
+            @Override
+            public void onError(HDLException e) {
+                tv.setText("鑾峰彇鎬濆繀椹皌oken澶辫触");
+                responseTv.setText(e.getMsg());
+            }
+        });
+
+    }
+
+    void syncMainGateway() {
+        tv.setText("鑾峰彇涓荤綉鍏充俊鎭�...");
+        responseTv.setText("");
+
+        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+        if (bindInfoBean == null) {
+            Toast.makeText(this, "璇峰厛鎵爜缁戝畾浣忓畢锛�", Toast.LENGTH_SHORT).show();
+            return;
+        }
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().syncMainGateway(bindInfoBean.getHomeId(), new GatewayListener() {
+            @Override
+            public void onSuccess(GatewayInfo info) {
+                tv.setText("鑾峰彇涓荤綉鍏充俊鎭�");
+                responseTv.setText(info.toString());
+                if (info != null) {
+                    HDLLinkConfig.getInstance().setGatewayId(info.getGatewayId());
+                    //HDLLinkConfig.getInstance().setIpAddress(info.ip);
+                }
+            }
+
+            @Override
+            public void onError(HDLException e) {
+                tv.setText("鑾峰彇涓荤綉鍏充俊鎭け璐�");
                 responseTv.setText(e.getMsg());
             }
         });
@@ -180,7 +229,7 @@
 
         selectnetwork();
         checkIfCertified();
-        initDeviceInfo();//鍒濆鍖�
+        //initDeviceInfo();//涓嶈蛋浠庢満鍏ョ綉鐨勬柟寮忎笉闇�瑕佸垵濮嬪寲
         registerAllTopicsListener();
         HDLLink.getInstance().setDeleteNetworkListener(new DeleteNetworkListener() {
             @Override
@@ -226,6 +275,9 @@
         beans.add(new DemoBean("鑾峰彇鎴块棿鍦烘櫙鍒楄〃"));
         beans.add(new DemoBean("鑾峰彇鑷姩鍖栧垪琛�"));
         beans.add(new DemoBean("饩冨姩鍖栧惎饨ょ饨�"));
+        beans.add(new DemoBean("鐢熸垚浜岀淮鐮佺粦瀹氫綇瀹�"));
+        beans.add(new DemoBean("鑾峰彇鎬濆繀椹皌oken"));
+        beans.add(new DemoBean("鑾峰彇缃戝叧淇℃伅"));
         demoAdapter = new DemoAdapter(beans);
         rv.setAdapter(demoAdapter);
 
@@ -313,6 +365,18 @@
                     case 19:
                         //饩冨姩鍖栧惎饨ょ饨�
                         editEnableLogic();
+                        break;
+                    case 20:
+                        //鐢熸垚浜岀淮鐮佺粦瀹氫綇瀹�
+                        startSourceBindActivity();
+                        break;
+                    case 21:
+                        //鑾峰彇鎬濆繀椹皌oken
+                        getSibichiToken();
+                        break;
+                    case 22:
+                        //鑾峰彇缃戝叧淇℃伅
+                        syncMainGateway();
                         break;
                 }
             }
@@ -418,6 +482,20 @@
 
     }
 
+    void initLink() {
+        //step1:鍏堢敓鎴愪簩缁寸爜锛岀敤onpro鎵爜缁戝畾浣忓畢鑾峰彇浣忓畢淇℃伅
+        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+        if (bindInfoBean != null) {
+            HDLLinkConfig.getInstance().setHomeId(bindInfoBean.getHomeId());
+            HDLLinkConfig.getInstance().setLocalSecret(bindInfoBean.getLocalSecret());
+
+        }
+        //step2锛氬啀鑾峰彇缃戝叧淇℃伅
+        if (gatewayInfo != null) {
+            HDLLinkConfig.getInstance().setGatewayId(gatewayInfo.getGatewayId());//褰撳墠涓荤綉鍏砳d
+        }
+    }
+
     /**
      * 鍏ョ綉璁よ瘉
      */
@@ -425,15 +503,9 @@
         tv.setText("寮�濮嬪叆缃戣璇�...");
         //璁よ瘉鎻愪氦鍙傛暟鍑嗗
 
-//        娴嬭瘯鏈嶅姟
-//        String spkStr = "ir.module";//浜у搧spk
-//        String macStr = "AA000000000000AF";//璁惧鍞竴MAC鍦板潃
-//        String secret = "44b360eb74b7ba64";//閫氳繃spk鍜宮ac鎻愪氦浜戠璁よ瘉鍚庡垎閰嶇殑secret
-
-//        姝e紡鏈嶅姟鍣�
+        //姝e紡鏈嶅姟鍣�
         String spkStr = "screen.mirror";//浜у搧spk
         String macStr = "f2c5d8bad48f";//璁惧鍞竴MAC鍦板潃
-//        String secret = "e186beeb7974998e";//閫氳繃spk鍜宮ac鎻愪氦浜戠璁よ瘉鍚庡垎閰嶇殑secret
 
         String mac_key = stringToMD5(stringToMD5(macStr + secret));
         String versionString = "HDL_V1.0.1";//
@@ -560,7 +632,12 @@
         tv.setText("璁惧鍔熻兘灞炴�ц鍙�");
         responseTv.setText("");
         List<String> sids = new ArrayList<>();
-        sids.add(testLightSid);
+        if (devicesList.size() != 0) {
+            sids.add(devicesList.get(0).getSid());
+        } else {
+            sids.add(testLightSid);
+        }
+
         HDLLink.getInstance().getFunctionAttribute(sids, new HDLLinkCallBack() {
             @Override
             public void onSuccess(String msg) {
@@ -582,7 +659,11 @@
         tv.setText("璇诲彇鐘舵�佷腑...");
         responseTv.setText("");
         List<String> list = new ArrayList<>();
-        list.add(testLightSid);//瑕佽鍙栬澶囩殑sid
+        if (devicesList.size() != 0) {
+            list.add(devicesList.get(0).getSid());
+        } else {
+            list.add(testLightSid);//瑕佽鍙栬澶囩殑sid
+        }
         HDLLink.getInstance().propertyRead(list, new HDLLinkCallBack() {
             @Override
             public void onSuccess(String data) {
@@ -608,7 +689,11 @@
         isOn = !isOn;
         List<DeviceControlRequest> requestList = new ArrayList<>();
         DeviceControlRequest request = new DeviceControlRequest();
-        request.setSid(testLightSid);
+        if (devicesList.size() != 0) {
+            request.setSid(devicesList.get(0).getSid());
+        } else {
+            request.setSid(testLightSid);//瑕佽鍙栬澶囩殑sid
+        }
         List<DeviceControlRequest.StatusBean> statusBeanList = new ArrayList<>();
         DeviceControlRequest.StatusBean bean = new DeviceControlRequest.StatusBean();
         bean.setKey("on_off");
@@ -905,6 +990,11 @@
         startActivity(intent);
     }
 
+    void startSourceBindActivity() {
+        Intent intent = new Intent(this, SourceBindActivity.class);
+        startActivity(intent);
+    }
+
     /**
      * TCP鍙戦�� 鍙彂涓�娆★紝涓嶇洃鍚洖澶嶏紝涓嶉噸鍙�
      */
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java
new file mode 100644
index 0000000..6be92a1
--- /dev/null
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java
@@ -0,0 +1,106 @@
+package com.hdl.hdlsdk;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.connect.bean.response.BindInfoBean;
+import com.hdl.sdk.connect.config.HDLLinkConfig;
+import com.hdl.sdk.sourceos.bind.BaseEvent;
+import com.hdl.sdk.sourceos.bind.BindAuthEvent;
+import com.hdl.sdk.sourceos.bind.BindHomeService;
+import com.hdl.sdk.sourceos.bind.EventType;
+import com.hdl.sdk.sourceos.qrcode.QRCode;
+import com.hdl.sdk.sourceos.qrcode.QrCodeView;
+import com.hdl.sdk.sourceos.utils.SPKey;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+public class SourceBindActivity extends AppCompatActivity {
+
+    private static final String TAG = "SourceBindActivity";
+    private QrCodeView qrcodeView;
+    private TextView responseTv;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_source_bind);
+        registerEventBus();
+        initView();
+    }
+
+    @SuppressLint("WrongConstant")
+    private void initView() {
+        qrcodeView = findViewById(R.id.qrcode_view);
+        responseTv = findViewById(R.id.response_tv);
+        createBindQRCodeInfo();
+    }
+
+    private void createBindQRCodeInfo() {
+        final String time = String.valueOf(System.currentTimeMillis());
+        String info = QRCode.createBindQRCodeInfo(time);
+        qrcodeView.setContent(info);
+
+        //寮�濮嬭疆璇�
+        BindHomeService.getInstance().startQuery(time);
+    }
+
+    /**
+     * 缁戝畾鎴愬姛閫氱煡浜嬩欢
+     *
+     * @param event
+     */
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    public void onEventMessage(BaseEvent event) {
+        switch (event.getEventType()) {
+            case EventType.ON_PLUS_BINDING_TYPE:
+                if (event instanceof BindAuthEvent) {
+                    int action = ((BindAuthEvent) event).getAction();
+                    if (action == BindAuthEvent.ON_PLUS_BINDING_SUCCEED_ACTION) {
+                        //on+缁戝畾鎴愬姛
+                        Toast.makeText(this, "缁戝畾鎴愬姛", Toast.LENGTH_SHORT).show();
+                        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+                        responseTv.setText(bindInfoBean.toString());
+
+                        if (bindInfoBean != null) {
+                            HDLLinkConfig.getInstance().setHomeId(bindInfoBean.getHomeId());
+                            HDLLinkConfig.getInstance().setLocalSecret(bindInfoBean.getLocalSecret());
+                        }
+                    } else if (action == BindAuthEvent.ON_PLUS_BINDING_TIMEOUT_ACTION) {
+                        //on+缁戝畾瓒呮椂
+                        Toast.makeText(this, "缁戝畾瓒呮椂", Toast.LENGTH_SHORT).show();
+                    } else if (action == BindAuthEvent.ON_PLUS_BINDING_ERROR_ACTION) {
+                        //缃戠粶閿欒
+                        //Toast.makeText(this, "缃戠粶寮傚父", Toast.LENGTH_SHORT).show();
+                    }
+                }
+                break;
+        }
+    }
+
+    protected void unregisterEventBus() {
+        if (EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().unregister(this);
+        }
+    }
+
+    protected void registerEventBus() {
+        if (!EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().register(this);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterEventBus();
+        BindHomeService.getInstance().stopQuery();
+    }
+}
\ No newline at end of file
diff --git a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java
index ed08f82..4f2266a 100644
--- a/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java
+++ b/HDLSDK/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java
@@ -78,8 +78,6 @@
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REBOOT, Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST);
         }
-        //绯荤粺鎺ュ彛鍒濆鍖�
-        OsManager.init(SourceTestActivity.this);
 
         OsManager.addEventListener(eventListener);
 
diff --git a/HDLSDK/app/src/main/res/layout/activity_source_bind.xml b/HDLSDK/app/src/main/res/layout/activity_source_bind.xml
new file mode 100644
index 0000000..8454510
--- /dev/null
+++ b/HDLSDK/app/src/main/res/layout/activity_source_bind.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".SourceBindActivity">
+
+    <com.hdl.sdk.sourceos.qrcode.QrCodeView
+        android:id="@+id/qrcode_view"
+        android:layout_width="125dp"
+        android:layout_height="125dp"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:layout_marginStart="28dp"
+        android:layout_marginTop="28dp"
+        android:padding="3dp" />
+
+    <TextView
+        android:id="@+id/response_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="3dp"
+        android:layout_marginTop="28dp" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/HDLSDK/hdl-connect/build.gradle b/HDLSDK/hdl-connect/build.gradle
index e30fa87..94c2a47 100644
--- a/HDLSDK/hdl-connect/build.gradle
+++ b/HDLSDK/hdl-connect/build.gradle
@@ -8,8 +8,8 @@
     defaultConfig {
         minSdkVersion rootProject.minSdkVersion
         targetSdkVersion rootProject.targetSdkVersion
-        versionCode 8
-        versionName "1.2.0"
+        versionCode 9
+        versionName "1.2.1"
 
         consumerProguardFiles "consumer-rules.pro"
     }
@@ -34,4 +34,8 @@
     api files('libs/hdlSDK_V1.0.7.jar')
 
     api 'com.google.code.gson:gson:2.8.8'
+    //浜岀淮鐮�
+    api 'com.google.zxing:core:3.4.1'
+    //浜嬩欢鎬荤嚎
+    api 'org.greenrobot:eventbus:3.2.0'
 }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLLink.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLLink.java
index 0e30ae9..b89fe9e 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLLink.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/HDLLink.java
@@ -17,8 +17,9 @@
 import com.hdl.sdk.connect.cloud.CheckAppVersionListener;
 import com.hdl.sdk.connect.cloud.HdlCloudApi;
 import com.hdl.sdk.connect.cloud.HdlCloudController;
-import com.hdl.sdk.connect.cloud.interceptor.EncryptInterceptor;
-import com.hdl.sdk.connect.cloud.interceptor.SmartHeaderInterceptor;
+import com.hdl.sdk.connect.cloud.listener.GatewayListener;
+import com.hdl.sdk.connect.cloud.listener.SibichiListener;
+import com.hdl.sdk.connect.config.HDLCloudConfig;
 import com.hdl.sdk.connect.config.HDLLinkConfig;
 import com.hdl.sdk.connect.socket.HDLAuthSocket;
 import com.hdl.sdk.connect.socket.HDLSocket;
@@ -164,51 +165,59 @@
      * @param spk      璁惧spk
      * @param callBack 缁撴灉鍥炶皟
      */
-    public void applyDeviceSecret(Context context, String appKey, String appSecret, String supplier, String mac, String spk, CallBackListener callBack) {
+    public void applyDeviceSecret(String supplier, String mac, String spk, CallBackListener callBack) {
         LogUtils.i("鐢宠璁惧瀵嗛挜");
-        HxHttpConfig.getInstance().init(context, HdlCloudApi.BASE_CHINA_URL)
-                .addInterceptor(
-                        new EncryptInterceptor(),
-                        new SmartHeaderInterceptor());
-        this.appKey = appKey;
-        this.appSecret = appSecret;
-
-        HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
-        httpLoggingInterceptor.level(HttpLoggingInterceptor.Level.BODY);
-
-        HxHttpConfig.getInstance()
-                //.addInterceptor(new HttpCacheInterceptor())
-                .addInterceptor(httpLoggingInterceptor).ignoreSSL();
-
         HdlCloudController.applyDeviceSecret(supplier, mac, spk, callBack);
     }
 
     /**
      * 妫�娴嬫洿鏂�
      *
-     * @param appKey      appKey
-     * @param appSecret   appSecret
      * @param versionCode 褰撳墠鐗堟湰
      * @param appCode     appCode
      * @param listener    缁撴灉鍥炶皟
      */
-    public void checkAppVersion(Context context, String appKey, String appSecret, String versionCode, String appCode, CheckAppVersionListener listener) {
+    public void checkAppVersion(String versionCode, String appCode, CheckAppVersionListener listener) {
         LogUtils.i("妫�娴嬫洿鏂�");
-        HxHttpConfig.getInstance().init(context, HdlCloudApi.BASE_CHINA_URL)
-                .addInterceptor(
-                        new EncryptInterceptor(),
-                        new SmartHeaderInterceptor());
-        this.appKey = appKey;
-        this.appSecret = appSecret;
+        HdlCloudController.checkAppVersion(versionCode, appCode, listener);
+    }
+
+    /**
+     * 鍒濆鍖栦簯绔�
+     */
+    public void initCloud(Context context, String appKey, String appSecret) {
+
+        HDLCloudConfig.getInstance().init(context, appKey, appSecret, HdlCloudApi.BASE_CHINA_URL);
+
+        HxHttpConfig.getInstance().ignoreSSL();
 
         HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
         httpLoggingInterceptor.level(HttpLoggingInterceptor.Level.BODY);
+        HxHttpConfig.getInstance().addInterceptor(httpLoggingInterceptor);
 
-        HxHttpConfig.getInstance()
-                //.addInterceptor(new HttpCacheInterceptor())
-                .addInterceptor(httpLoggingInterceptor).ignoreSSL();
+    }
 
-        HdlCloudController.checkAppVersion(versionCode, appCode, listener);
+    /**
+     * 鑾峰彇鎬濆繀椹皌oken
+     *
+     * @param homeId   homeId
+     * @param clientId clientId
+     * @param listener 缁撴灉鍥炶皟
+     */
+    public void getSibichiToken(String homeId, String clientId, SibichiListener listener) {
+        LogUtils.i("鑾峰彇鎬濆繀椹皌oken");
+        HdlCloudController.getSibichiToken(homeId, clientId, listener);
+    }
+
+    /**
+     * 鑾峰彇涓荤綉鍏充俊鎭�
+     *
+     * @param homeId   homeId
+     * @param listener 缁撴灉鍥炶皟
+     */
+    public void syncMainGateway(String homeId, GatewayListener listener) {
+        LogUtils.i("鑾峰彇涓荤綉鍏充俊鎭�");
+        HdlCloudController.syncMainGateway(homeId, listener);
     }
 
     /**
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/response/BindInfoBean.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/response/BindInfoBean.java
new file mode 100644
index 0000000..8b7aab2
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/bean/response/BindInfoBean.java
@@ -0,0 +1,338 @@
+package com.hdl.sdk.connect.bean.response;
+
+import android.text.TextUtils;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/11/14.
+ * on+鎵爜缁戝畾
+ */
+public class BindInfoBean implements Serializable {
+
+    private String homeId;
+    private String homeName;
+    private String token;
+    private String expiresIn;
+    private Long expiration;
+    private String refreshToken;
+    private String refreshExpiresIn;
+    private Long refreshExpiration;
+    //绀惧尯缂栧彿
+    private String communityCode;
+    private String communityId;
+
+    private String houseCode;
+
+    private String groupName;
+    //鏈�/鍖� 鍙�
+    private String groupNum;
+
+    private String buildName;
+    //妤兼爧鍙�
+    private String buildNum;
+    //妤煎眰鍙�
+    private String floorNum;
+    private String floorName;
+
+    private String houseNo;
+    //鍗曞厓鍚嶇О
+    private String unitName;
+    //鍗曞厓鍙�
+    private String unitNum;
+    private String localSecret;
+    //灏忓尯缁村害 鏈湴瀵嗛挜
+    private String communityLocalSecret;
+    //璁惧鍒嗘満鍙�
+    private String deviceNumber;
+
+    //椤圭洰绫诲瀷
+    private String projectType;
+
+    private String userId;
+
+    //绌洪棿缂栧彿 鐢ㄤ簬璺熼棬鍙f満閫氳锛屼笉鍖呭惈鍒嗘満鍙�
+    public String getHomeId() {
+        return homeId;
+    }
+
+    public void setHomeId(String homeId) {
+        this.homeId = homeId;
+
+    }
+
+    public String getHomeName() {
+        return homeName;
+    }
+
+    public void setHomeName(String homeName) {
+        this.homeName = homeName;
+    }
+
+    public String getToken() {
+        return token;
+    }
+
+    public void setToken(String token) {
+        this.token = token;
+    }
+
+    public String getExpiresIn() {
+        return expiresIn;
+    }
+
+    public void setExpiresIn(String expiresIn) {
+        this.expiresIn = expiresIn;
+    }
+
+    public Long getExpiration() {
+        return expiration;
+    }
+
+    public void setExpiration(Long expiration) {
+        this.expiration = expiration;
+    }
+
+    public String getRefreshToken() {
+        return refreshToken;
+    }
+
+    public void setRefreshToken(String refreshToken) {
+        this.refreshToken = refreshToken;
+    }
+
+    public String getRefreshExpiresIn() {
+        return refreshExpiresIn;
+    }
+
+    public void setRefreshExpiresIn(String refreshExpiresIn) {
+        this.refreshExpiresIn = refreshExpiresIn;
+    }
+
+    public Long getRefreshExpiration() {
+        return refreshExpiration;
+    }
+
+    public void setRefreshExpiration(Long refreshExpiration) {
+        this.refreshExpiration = refreshExpiration;
+    }
+
+    public String getCommunityCode() {
+        return communityCode;
+    }
+
+    public void setCommunityCode(String communityCode) {
+        this.communityCode = communityCode;
+    }
+
+    public String getCommunityId() {
+        return communityId;
+    }
+
+    public void setCommunityId(String communityId) {
+        this.communityId = communityId;
+    }
+
+
+    public String getHouseCode() {
+        return houseCode;
+    }
+
+    public void setHouseCode(String houseCode) {
+        this.houseCode = houseCode;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public void setGroupName(String groupName) {
+        this.groupName = groupName;
+    }
+
+    public String getGroupNum() {
+        return groupNum;
+    }
+
+    public void setGroupNum(String groupNum) {
+        this.groupNum = groupNum;
+    }
+
+    public String getBuildName() {
+        return buildName;
+    }
+
+    public void setBuildName(String buildName) {
+        this.buildName = buildName;
+    }
+
+    public String getBuildNum() {
+        return buildNum;
+    }
+
+    public void setBuildNum(String buildNum) {
+        this.buildNum = buildNum;
+    }
+
+    public String getHouseNo() {
+        return houseNo;
+    }
+
+    public void setHouseNo(String houseNo) {
+        this.houseNo = houseNo;
+    }
+
+    public String getUnitName() {
+        return unitName;
+    }
+
+    public void setUnitName(String unitName) {
+        this.unitName = unitName;
+    }
+
+    public String getUnitNum() {
+        return unitNum;
+    }
+
+    public void setUnitNum(String unitNum) {
+        this.unitNum = unitNum;
+    }
+
+    public String getLocalSecret() {
+        return localSecret;
+    }
+
+    public void setLocalSecret(String localSecret) {
+        this.localSecret = localSecret;
+    }
+
+    public String getCommunityLocalSecret() {
+        return communityLocalSecret;
+    }
+
+    public void setCommunityLocalSecret(String communityLocalSecret) {
+        this.communityLocalSecret = communityLocalSecret;
+    }
+
+    public String getDeviceNumber() {
+        return deviceNumber;
+    }
+
+    public void setDeviceNumber(String deviceNumber) {
+        this.deviceNumber = deviceNumber;
+    }
+
+    public String getUserId() {
+        return userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getFloorNum() {
+        return floorNum;
+    }
+
+    public void setFloorNum(String floorNum) {
+        this.floorNum = floorNum;
+    }
+
+    public String getFloorName() {
+        return floorName;
+    }
+
+    public void setFloorName(String floorName) {
+        this.floorName = floorName;
+    }
+
+
+    public String getProjectType() {
+        return projectType;
+    }
+
+    public void setProjectType(String projectType) {
+        this.projectType = projectType;
+    }
+
+    /**
+     * @return 绌洪棿缂栧彿锛屾病鏈夊垎鏈哄彿
+     */
+    public String getSpaceCode() {
+        return generateSpaceCode();
+    }
+
+    /**
+     * 鐢熸垚绌洪棿缂栧彿
+     */
+    public String generateSpaceCode() {
+        StringBuilder builder = new StringBuilder();
+        //鏈�/鍖� 鍙�
+        if (!TextUtils.isEmpty(groupNum)) {
+            builder.append("-").append(groupNum);
+        }
+        //妤兼爧鍙�
+        if (!TextUtils.isEmpty(buildNum)) {
+            builder.append("-").append(buildNum);
+        }
+        //鍗曞厓鍙�
+        if (!TextUtils.isEmpty(unitNum)) {
+            builder.append("-").append(unitNum);
+        }
+        //妤煎眰鍙�
+        if (!TextUtils.isEmpty(floorNum)) {
+            builder.append("-").append(floorNum);
+        }
+        //闂ㄧ墝鍙�
+        if (!TextUtils.isEmpty(houseNo)) {
+            builder.append("-").append(houseNo);
+        }
+
+        /*//鍒嗘満鍙� 鑲畾寰楁湁
+        if (TextUtils.isEmpty(deviceNumber)) {
+            //绌虹殑璇濓紝鐢ㄥ敮涓�鐮佸惂
+            Log.i("info", "鍒嗘満鍙蜂负绌猴細鐢ㄥ敮涓�鐮�");
+            deviceNumber = DeviceUtils.getUniqueCode();
+        }
+        builder.append("~").append(deviceNumber);*/
+
+
+        String code = builder.toString();
+        int index = code.indexOf("-");
+        if (index != -1) {
+            code = code.substring(index + 1);
+        }
+        return code;
+    }
+
+    @Override
+    public String toString() {
+        return "BindInfoBean{" +
+                "homeId='" + homeId + '\'' +
+                ", homeName='" + homeName + '\'' +
+                ", token='" + token + '\'' +
+                ", expiresIn='" + expiresIn + '\'' +
+                ", expiration=" + expiration +
+                ", refreshToken='" + refreshToken + '\'' +
+                ", refreshExpiresIn='" + refreshExpiresIn + '\'' +
+                ", refreshExpiration=" + refreshExpiration +
+                ", communityCode='" + communityCode + '\'' +
+                ", communityId='" + communityId + '\'' +
+                ", houseCode='" + houseCode + '\'' +
+                ", groupName='" + groupName + '\'' +
+                ", groupNum='" + groupNum + '\'' +
+                ", buildName='" + buildName + '\'' +
+                ", buildNum='" + buildNum + '\'' +
+                ", floorNum='" + floorNum + '\'' +
+                ", floorName='" + floorName + '\'' +
+                ", houseNo='" + houseNo + '\'' +
+                ", unitName='" + unitName + '\'' +
+                ", unitNum='" + unitNum + '\'' +
+                ", localSecret='" + localSecret + '\'' +
+                ", communityLocalSecret='" + communityLocalSecret + '\'' +
+                ", deviceNumber='" + deviceNumber + '\'' +
+                ", projectType='" + projectType + '\'' +
+                ", userId='" + userId + '\'' +
+                '}';
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/CloudCode.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/CloudCode.java
new file mode 100644
index 0000000..7bbe496
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/CloudCode.java
@@ -0,0 +1,59 @@
+package com.hdl.sdk.connect.cloud;
+
+/**
+ * Created by Tong on 2021/11/2.
+ */
+public @interface CloudCode {
+
+    //鎴愬姛
+    int SUCCEED = 0;
+
+    //绯荤粺绻佸繖
+    int SYSTEM_BUSY = 1;
+
+    //绯荤粺缁存姢 2
+
+    //鏈嶅姟寮傚父 3
+
+    //绛惧悕閿欒 4
+
+    //鍙傛暟寮傚父 5
+
+    //token瓒呮椂
+    int TOKEN_TIMEOUT = 10001;
+    //10002 閲嶆柊鐧诲綍
+    int RE_LOGIN = 10002;
+    //token涓嶅悎娉�
+    int TOKEN_NOT_STANDARD = 10003;
+    //缂哄皯token鍙傛暟
+    int NO_TOKEN = 10004;
+    //鐢ㄦ埛鍚嶆垨鑰呭瘑鐮侀敊璇� 10008
+    //鐢ㄦ埛宸茶绂佺敤 10009
+    //10010	鐢ㄦ埛涓嶅瓨鍦�
+    //10012	鐢ㄦ埛宸插瓨鍦紝涓嶈兘閲嶅娉ㄥ唽
+    //10404	浣忓畢鍞竴鏍囪瘑涓嶅瓨鍦�
+    //10506	缃戝叧涓嶅瓨鍦�
+    //10805	璁惧涓嶅瓨鍦�
+    //12005	搴旂敤涓嶅瓨鍦�
+    //20000	鎺у埗澶辫触
+    //20001	缃戝叧绂荤嚎
+    //20002	璁惧绂荤嚎
+    //20101	spk涓嶆敮鎸佽鍔熻兘灞炴��
+    //20102	spk涓嶆敮鎸佽鍔熻兘灞炴�у��
+
+    //10009 鐢ㄦ埛
+
+    //10401 浣忓畢浜や粯浜�
+
+    //10041 锛� RefreshToken 鏁版嵁閿欒
+    //10042 锛� RefreshToken 杩囨湡
+    //10043 锛� RefreshToken 瑙f瀽閿欒
+
+
+    // 10003 锛� 涓嶅悎娉曠殑token锛岃璁ょ湡姣斿token鐨勭鍚�
+    // 10004 锛� 缂哄皯token鍙傛暟
+    // 10006 锛� 瑙f瀽鐢ㄦ埛韬唤閿欒锛岃閲嶆柊鐧诲綍
+    // 10009 锛�
+
+    //125102鎬濆繀椹版巿鏉�
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudApi.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudApi.java
index a32f225..3968fd2 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudApi.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudApi.java
@@ -7,10 +7,13 @@
 public class HdlCloudApi {
 
     //姝e紡鐜
-//    public static final String BASE_CHINA_URL = "https://china-gateway.hdlcontrol.com";
+    public static final String BASE_CHINA_URL = "https://china-gateway.hdlcontrol.com";
 
     //娴嬭瘯鐜
-    public static final String BASE_CHINA_URL = "https://test-gz.hdlcontrol.com";
+//    public static final String BASE_CHINA_URL = "https://test-gz.hdlcontrol.com";
+
+    //鐧婚檰鍒锋柊token
+    public static final String LOGIN = "/smart-footstone/member/oauth/login";
 
     //鐢宠璁惧瀵嗛挜(鏍规嵁璁惧MAC)
     public static final String APPLY_DEVICE_SECRET = "/smart-open/third/device/authByMac";
@@ -18,4 +21,13 @@
     //妫�鏌pp鏄惁鏇存柊
     public static final String CHECK_APP_VERSION_URL = "/basis-footstone/app/appVersion/check";
 
+    //鑾峰彇鎬濆繀椹皌oken
+    public static final String GET_SIBICHI_TOKEN = "/smart-footstone/thirdToken/aiSpeechToken";
+
+    //楠岃瘉鏄惁on+鏄惁缁戝畾source
+    public static final String IS_BIND_URL = "/home-wisdom/source/screen/home/isBind";
+
+    //鑾峰彇缃戝叧鍒楄〃
+    public static final String GET_GATEWAY_LIST = "/home-wisdom/app/gateway/getGatewayList";
+
 }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudController.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudController.java
index 8f05dcf..b47fd7c 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudController.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/HdlCloudController.java
@@ -1,7 +1,15 @@
 package com.hdl.sdk.connect.cloud;
 
 import com.hdl.hdlhttp.HxHttp;
+import com.hdl.hdlhttp.HxHttpBuilder;
 import com.hdl.sdk.connect.bean.response.UpdateInfo;
+import com.hdl.sdk.connect.cloud.bean.AiLoginInfo;
+import com.hdl.sdk.connect.cloud.bean.GatewayInfo;
+import com.hdl.sdk.connect.cloud.listener.GatewayListListener;
+import com.hdl.sdk.connect.cloud.listener.GatewayListener;
+import com.hdl.sdk.connect.cloud.listener.SibichiListener;
+
+import java.util.List;
 
 import io.reactivex.rxjava3.disposables.Disposable;
 
@@ -62,4 +70,80 @@
                 });
     }
 
+    /**
+     * 鑾峰彇鎬濆繀椹皌oken
+     *
+     * @return
+     */
+    public static Disposable getSibichiToken(String homeId, String clientId, SibichiListener listener) {
+        return HxHttp.builder()
+                .url(HdlCloudApi.GET_SIBICHI_TOKEN)
+                .params("homeId", homeId)
+                .params("clientId", clientId)
+                .build()
+                .post()
+                .subscribeWith(new HDLResponse<AiLoginInfo>() {
+                    @Override
+                    public void onResponse(AiLoginInfo response) {
+                        listener.onSuccess(response);
+                    }
+
+                    @Override
+                    public void onFailure(HDLException e) {
+                        listener.onError(e);
+                    }
+                });
+    }
+
+    /**
+     * 鑾峰彇涓荤綉鍏�
+     */
+    public static Disposable syncMainGateway(String homeId, GatewayListener listener) {
+        return syncGatewayList(homeId, new GatewayListListener() {
+            @Override
+            public void onSuccess(List<GatewayInfo> info) {
+                if (listener != null) {
+                    if (info == null || info.isEmpty()) {
+                        listener.onError(new HDLException(-5000, "鎼滅储缃戝叧澶辫触"));
+                    } else {
+                        listener.onSuccess(info.get(0));
+                    }
+                }
+
+            }
+
+            @Override
+            public void onError(HDLException e) {
+                if (listener != null) {
+                    listener.onError(e);
+                }
+            }
+        });
+    }
+
+    /**
+     * 鍚屾鑾峰彇缃戝叧鍒楄〃
+     */
+    public static Disposable syncGatewayList(String homeId, GatewayListListener listener) {
+        HxHttpBuilder httpBuilder = HxHttp.builder()
+                .params("homeId", homeId)
+                .url(HdlCloudApi.GET_GATEWAY_LIST);
+        return httpBuilder.build().post().subscribeWith(new HDLResponse<List<GatewayInfo>>() {
+            @Override
+            public void onResponse(List<GatewayInfo> response) {
+                if (listener != null) {
+                    listener.onSuccess(response);
+                }
+            }
+
+            @Override
+            public void onFailure(HDLException e) {
+                if (listener != null) {
+                    listener.onError(e);
+                }
+            }
+        });
+    }
+
+
 }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/AiLoginInfo.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/AiLoginInfo.java
new file mode 100644
index 0000000..bb6dbd4
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/AiLoginInfo.java
@@ -0,0 +1,163 @@
+package com.hdl.sdk.connect.cloud.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2024/12/10.
+ * 鎬濆繀椹�
+ */
+public class AiLoginInfo implements Serializable {
+    private String accessToken;
+    private long expiration;
+    private String refreshToken;
+    private long refreshExpiration;
+    private String headerPrefix;
+    private String name;
+    private String account;
+    private String userPhone;
+    private String tenantId;
+    private String userId;
+    private String role;
+    private Integer expiresIn;
+
+    /**
+     * 鎺ュ彛楠岃瘉token
+     */
+    public String getAccessToken() {
+        return accessToken == null ? "" : accessToken;
+    }
+
+    public void setAccessToken(String accessToken) {
+        this.accessToken = accessToken;
+    }
+
+    /**
+     * token杩囨湡鏃堕棿鎴�
+     */
+    public long getExpiration() {
+        return expiration;
+    }
+
+    public void setExpiration(long expiration) {
+        this.expiration = expiration;
+    }
+
+    /**
+     * refreshToken杩囨湡鏃堕棿鎴�
+     */
+    public long getRefreshExpiration() {
+        return refreshExpiration;
+    }
+
+    public void setRefreshExpiration(long refreshExpiration) {
+        this.refreshExpiration = refreshExpiration;
+    }
+
+    /**
+     * 鍒锋柊token闇�瑕佷娇鐢�
+     */
+    public String getRefreshToken() {
+        return refreshToken == null ? "" : refreshToken;
+    }
+
+    public void setRefreshToken(String refreshToken) {
+        this.refreshToken = refreshToken;
+    }
+
+    /**
+     * token绫诲瀷
+     */
+    public String getHeaderPrefix() {
+        return headerPrefix == null ? "" : headerPrefix;
+    }
+
+    public void setHeaderPrefix(String headerPrefix) {
+        this.headerPrefix = headerPrefix;
+    }
+
+    /**
+     * 鐢ㄦ埛鐪熷疄濮撳悕锛堟病鏈夎璇佹埧灞嬫儏鍐典笅寤鸿浣跨敤account锛�
+     */
+    public String getName() {
+        return name == null ? "" : name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * 鐧诲綍璐﹀彿
+     */
+    public String getAccount() {
+        return account == null ? "" : account;
+    }
+
+    public void setAccount(String account) {
+        this.account = account;
+    }
+
+    /**
+     * 鐢ㄦ埛鎵嬫満鍙风爜 鑰佺増鏈娇鐢ㄩ偖绠辨敞鍐屼細娌℃湁
+     */
+    public String getUserPhone() {
+        return userPhone == null ? "" : userPhone;
+    }
+
+    public void setUserPhone(String userPhone) {
+        this.userPhone = userPhone;
+    }
+
+    public String getTenantId() {
+        return tenantId == null ? "" : tenantId;
+    }
+
+    public void setTenantId(String tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    public String getUserId() {
+        return userId == null ? "" : userId;
+    }
+
+    public void setUserId(String userId) {
+        this.userId = userId;
+    }
+
+    public String getRole() {
+        return role == null ? "" : role;
+    }
+
+    public void setRole(String role) {
+        this.role = role;
+    }
+
+    public Integer getExpiresIn() {
+        return expiresIn;
+    }
+
+    public void setExpiresIn(Integer expiresIn) {
+        this.expiresIn = expiresIn;
+    }
+
+    @Override
+    public String toString() {
+        return "AiLoginInfo{" +
+                "accessToken='" + accessToken + '\'' +
+                ", expiration=" + expiration +
+                ", refreshToken='" + refreshToken + '\'' +
+                ", refreshExpiration=" + refreshExpiration +
+                ", headerPrefix='" + headerPrefix + '\'' +
+                ", name='" + name + '\'' +
+                ", account='" + account + '\'' +
+                ", userPhone='" + userPhone + '\'' +
+                ", tenantId='" + tenantId + '\'' +
+                ", userId='" + userId + '\'' +
+                ", role='" + role + '\'' +
+                ", expiresIn=" + expiresIn +
+                '}';
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/GatewayInfo.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/GatewayInfo.java
new file mode 100644
index 0000000..bce7c54
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/bean/GatewayInfo.java
@@ -0,0 +1,177 @@
+package com.hdl.sdk.connect.cloud.bean;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/12/7.
+ * 缃戝叧淇℃伅
+ */
+public class GatewayInfo implements Serializable {
+
+    private String gatewayId;
+    private String aesKey;
+    private Integer deviceId;
+    private Integer encryptionType;
+    private String gatewayType;
+    private String groupName;
+    private String homeId;
+    private String mac;
+    private String primaryKey;
+    private String projectName;
+    private Integer subnetId;
+    private String userName;
+    private String gatewayStatus;
+    private String modifyTime;
+    private String localSecret;
+    private String lastHeartbeatTime;
+
+    public String getGatewayId() {
+        return gatewayId;
+    }
+
+    public void setGatewayId(String gatewayId) {
+        this.gatewayId = gatewayId;
+    }
+
+    public String getAesKey() {
+        return aesKey;
+    }
+
+    public void setAesKey(String aesKey) {
+        this.aesKey = aesKey;
+    }
+
+    public Integer getDeviceId() {
+        return deviceId;
+    }
+
+    public void setDeviceId(Integer deviceId) {
+        this.deviceId = deviceId;
+    }
+
+    public Integer getEncryptionType() {
+        return encryptionType;
+    }
+
+    public void setEncryptionType(Integer encryptionType) {
+        this.encryptionType = encryptionType;
+    }
+
+    public String getGatewayType() {
+        return gatewayType;
+    }
+
+    public void setGatewayType(String gatewayType) {
+        this.gatewayType = gatewayType;
+    }
+
+    public String getGroupName() {
+        return groupName;
+    }
+
+    public void setGroupName(String groupName) {
+        this.groupName = groupName;
+    }
+
+    public String getHomeId() {
+        return homeId;
+    }
+
+    public void setHomeId(String homeId) {
+        this.homeId = homeId;
+    }
+
+    public String getMac() {
+        return mac;
+    }
+
+    public void setMac(String mac) {
+        this.mac = mac;
+    }
+
+    public String getPrimaryKey() {
+        return primaryKey;
+    }
+
+    public void setPrimaryKey(String primaryKey) {
+        this.primaryKey = primaryKey;
+    }
+
+    public String getProjectName() {
+        return projectName;
+    }
+
+    public void setProjectName(String projectName) {
+        this.projectName = projectName;
+    }
+
+    public Integer getSubnetId() {
+        return subnetId;
+    }
+
+    public void setSubnetId(Integer subnetId) {
+        this.subnetId = subnetId;
+    }
+
+    public String getUserName() {
+        return userName;
+    }
+
+    public void setUserName(String userName) {
+        this.userName = userName;
+    }
+
+    public String getGatewayStatus() {
+        return gatewayStatus;
+    }
+
+    public void setGatewayStatus(String gatewayStatus) {
+        this.gatewayStatus = gatewayStatus;
+    }
+
+    public String getModifyTime() {
+        return modifyTime;
+    }
+
+    public void setModifyTime(String modifyTime) {
+        this.modifyTime = modifyTime;
+    }
+
+    public String getLocalSecret() {
+        return localSecret;
+    }
+
+    public void setLocalSecret(String localSecret) {
+        this.localSecret = localSecret;
+    }
+
+    public String getLastHeartbeatTime() {
+        return lastHeartbeatTime;
+    }
+
+    public void setLastHeartbeatTime(String lastHeartbeatTime) {
+        this.lastHeartbeatTime = lastHeartbeatTime;
+    }
+
+    @Override
+    public String toString() {
+        return "GatewayInfo{" +
+                "gatewayId='" + gatewayId + '\'' +
+                ", aesKey='" + aesKey + '\'' +
+                ", deviceId=" + deviceId +
+                ", encryptionType=" + encryptionType +
+                ", gatewayType='" + gatewayType + '\'' +
+                ", groupName='" + groupName + '\'' +
+                ", homeId='" + homeId + '\'' +
+                ", mac='" + mac + '\'' +
+                ", primaryKey='" + primaryKey + '\'' +
+                ", projectName='" + projectName + '\'' +
+                ", subnetId=" + subnetId +
+                ", userName='" + userName + '\'' +
+                ", gatewayStatus='" + gatewayStatus + '\'' +
+                ", modifyTime='" + modifyTime + '\'' +
+                ", localSecret='" + localSecret + '\'' +
+                ", lastHeartbeatTime='" + lastHeartbeatTime + '\'' +
+                '}';
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcast.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcast.java
new file mode 100644
index 0000000..87a50d2
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcast.java
@@ -0,0 +1,58 @@
+package com.hdl.sdk.connect.cloud.broadcast;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.text.TextUtils;
+
+/**
+ * Created by Tong on 2021/11/9.
+ * 缃戠粶璇锋眰骞挎挱
+ * 闇�瑕佸簲鐢ㄥ眰娉ㄥ唽
+ */
+public abstract class CloudBroadcast extends BroadcastReceiver {
+
+    public static final String KEY_API_CODE = "key_api_code";
+    public static final String KEY_API_MESSAGE = "key_api_message";
+
+    @Override
+    public final void onReceive(Context context, Intent intent) {
+        if (intent == null) return;
+        String action = intent.getAction();
+        if (action != null && !TextUtils.isEmpty(action)) {
+            switch (action) {
+                case CloudBroadcastAction.REFRESH_TOKEN_INVALID_ACTION:
+                    onLogOut();
+                    break;
+                case CloudBroadcastAction.API_ERROR_ACTION:
+                    try {
+                        final String message = intent.getStringExtra(KEY_API_MESSAGE);
+                        final int code = intent.getIntExtra(KEY_API_CODE, -1);
+                        onOtherError(code, message);
+                    } catch (Exception e) {
+                        onOtherError(-1, e.getMessage());
+                    }
+                    break;
+            }
+        }
+    }
+
+    /**
+     * 鐧诲綍澶辨晥
+     */
+    public void onLogOut() {
+        //浼氶绻佹敹鍒�
+    }
+
+
+    /**
+     * 娑堟伅
+     *
+     * @param code    code
+     * @param message 娑堟伅
+     */
+    public void onOtherError(int code, String message) {
+
+    }
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcastAction.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcastAction.java
new file mode 100644
index 0000000..1559f56
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/CloudBroadcastAction.java
@@ -0,0 +1,17 @@
+package com.hdl.sdk.connect.cloud.broadcast;
+
+/**
+ * Created by Tong on 2021/11/8.
+ */
+public class CloudBroadcastAction {
+
+    //token鍒锋柊浜�
+    public static final String REFRESH_TOKEN_ACTION = "hdl.cloud.broadcast.action.REFRESH_TOKEN";
+
+    //鍒锋柊token澶辨晥浜�
+    public static final String REFRESH_TOKEN_INVALID_ACTION = "hdl.cloud.broadcast.action.REFRESH_TOKEN_INVALID";
+
+    //闈�0涓斾笉鏄埛鏂皌oken锛宔rror
+    public static final String API_ERROR_ACTION = "hdl.cloud.broadcast.action.Api_Error";
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/GlobalBroadcastManager.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/GlobalBroadcastManager.java
new file mode 100644
index 0000000..5698611
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/GlobalBroadcastManager.java
@@ -0,0 +1,35 @@
+package com.hdl.sdk.connect.cloud.broadcast;
+
+import android.app.Application;
+import android.content.IntentFilter;
+
+
+/**
+ * Created by Tong on 2023/05/06.
+ * 闇�瑕佹敞鍐屽叏灞�骞挎挱浠g爜鏀捐繖閲�
+ */
+public class GlobalBroadcastManager {
+
+
+    /**
+     * 娉ㄥ唽鍏ㄥ眬骞挎挱
+     */
+    public static void registerGlobalBroadcast(Application app) {
+        registerCloudBroadcast(app);
+    }
+
+
+    /**
+     * 娉ㄥ唽鎺ュ彛杩斿洖鐨勫箍鎾�
+     */
+    private static void registerCloudBroadcast(Application application) {
+
+        HDLCloudBroadcast hdlCloudBroadcast = new HDLCloudBroadcast();
+        IntentFilter filter = new IntentFilter();
+
+        filter.addAction(CloudBroadcastAction.REFRESH_TOKEN_INVALID_ACTION);
+        filter.addAction(CloudBroadcastAction.REFRESH_TOKEN_ACTION);
+        application.registerReceiver(hdlCloudBroadcast, filter);
+    }
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/HDLCloudBroadcast.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/HDLCloudBroadcast.java
new file mode 100644
index 0000000..0450362
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/broadcast/HDLCloudBroadcast.java
@@ -0,0 +1,119 @@
+package com.hdl.sdk.connect.cloud.broadcast;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.hdl.sdk.connect.bean.response.BindInfoBean;
+import com.hdl.sdk.connect.cloud.HDLException;
+import com.hdl.sdk.connect.cloud.HDLResponse;
+import com.hdl.sdk.connect.config.HDLCloudConfig;
+import com.hdl.sdk.sourceos.bind.BindHomeService;
+import com.hdl.sdk.sourceos.qrcode.QRCode;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * Created by Tong on 2022/2/12.
+ * token澶辨晥澶勭悊
+ */
+public class HDLCloudBroadcast extends CloudBroadcast {
+
+    private final ExecutorService service = Executors.newSingleThreadExecutor();
+
+    private volatile Future<?> mBindTokenTask;
+
+    private static final String TAG = HDLCloudBroadcast.class.getSimpleName();
+
+    /**
+     * 鐧诲綍澶辨晥浜�
+     */
+    @Override
+    public void onLogOut() {
+        super.onLogOut();
+        refreshBindingToken();
+    }
+
+
+    /**
+     * 鍒锋柊缁戝畾Token
+     */
+    public void refreshBindingToken() {
+        Log.e(TAG, "refreshBindingToken");
+        if (mBindTokenTask != null) {
+            try {
+                mBindTokenTask.cancel(true);
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+        final String code = QRCode.getBindQRCode();
+        if (!TextUtils.isEmpty(code)) {
+            String[] split = code.split("_");
+            if (split.length == 3) {
+                try {
+                    mBindTokenTask = service.submit(new Runnable() {
+                        @Override
+                        public void run() {
+                            try {
+                                try {
+                                    //闃叉棰戠箒浼戠湢10绉�
+                                    Thread.sleep(10 * 1000);
+                                } catch (Exception e) {
+                                    e.printStackTrace();
+                                }
+
+
+                                BindHomeService.isBind(split[0], split[1], split[2], new HDLResponse<BindInfoBean>() {
+                                    @Override
+                                    public void onResponse(BindInfoBean response) {
+                                        if (response != null) {
+                                            HDLCloudConfig.getInstance().setToken(response.getToken());
+                                            HDLCloudConfig.getInstance().setRefreshToken(response.getRefreshToken());
+                                        }
+                                        Log.e(TAG, "refreshBindingToken---> succeed");
+                                    }
+
+                                    @Override
+                                    public void onFailure(HDLException e) {
+                                        Log.e(TAG, "refreshBindingToken error---> " + e);
+                                        /*if (e instanceof ApiException) {
+                                            if (e.getCode() != CloudCode.NO_TOKEN) {
+
+                                            }
+
+                                        }*/
+                                    }
+                                });
+
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    });
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+
+
+            }
+        }
+
+
+    }
+
+    @Override
+    public void onOtherError(int code, String message) {
+        super.onOtherError(code, message);
+
+        Log.d(TAG, "onOtherError: code" + code + "," + message);
+
+        if (code == 125102 || code == 10401) {
+            //鎬濆繀椹板け鏁堜簡锛� 浣忓畢鍜屽綋鍓嶇敤鎴蜂笉鍖归厤
+            Log.d(TAG, "onOtherError: 鎬濆繀椹板け鏁堜簡");
+
+            refreshBindingToken();
+        }
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/EncryptInterceptor.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/EncryptInterceptor.java
index 9a83b75..691ba75 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/EncryptInterceptor.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/EncryptInterceptor.java
@@ -12,6 +12,7 @@
 import com.hdl.sdk.connect.HDLLink;
 import com.hdl.sdk.connect.cloud.GsonUtils;
 import com.hdl.sdk.connect.cloud.MD5Utils;
+import com.hdl.sdk.connect.config.HDLCloudConfig;
 
 import java.io.IOException;
 import java.net.URLDecoder;
@@ -57,8 +58,8 @@
      */
     private Request encrypt(Request request) {
         final String timestamp = String.valueOf(System.currentTimeMillis());
-        final String appKey = HDLLink.getInstance().getAppKey();
-        final String appSecret = HDLLink.getInstance().getAppSecret();
+        final String appKey = HDLCloudConfig.getInstance().getAppKey();
+        final String appSecret = HDLCloudConfig.getInstance().getAppSecret();
         final JsonObject json = getBodyJson(request);
         if (json != null) {
             json.addProperty("appKey", appKey);
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/HdlLoginInterceptor.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/HdlLoginInterceptor.java
new file mode 100644
index 0000000..f36b6c2
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/interceptor/HdlLoginInterceptor.java
@@ -0,0 +1,281 @@
+package com.hdl.sdk.connect.cloud.interceptor;
+
+import android.content.Intent;
+import android.text.TextUtils;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.hdl.hdlhttp.HxHttpConfig;
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.connect.cloud.CloudCode;
+import com.hdl.sdk.connect.cloud.HdlCloudApi;
+import com.hdl.sdk.connect.cloud.broadcast.CloudBroadcast;
+import com.hdl.sdk.connect.cloud.broadcast.CloudBroadcastAction;
+import com.hdl.sdk.connect.config.HDLCloudConfig;
+import com.hdl.sdk.sourceos.utils.SPKey;
+
+import java.io.IOException;
+import java.nio.charset.Charset;
+
+import okhttp3.Headers;
+import okhttp3.Interceptor;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import okio.Buffer;
+import okio.BufferedSource;
+
+/**
+ * Created by Tong on 2021/11/2.
+ */
+public class HdlLoginInterceptor implements Interceptor {
+
+    @NonNull
+    @Override
+    public Response intercept(@NonNull Chain chain) throws IOException {
+        Request request = chain.request();
+        if (!isRefreshTokenHeader(request.headers())) {
+            String token = HDLCloudConfig.getInstance().getToken();
+            if (!TextUtils.isEmpty(token)) {
+                Request processRequest = addToken(request, token);
+                Response processResponse = chain.proceed(processRequest);
+                return disposeToken(chain, processRequest, processResponse);
+            } else {
+                //娌℃湁缂撳瓨token澶勭悊
+                Response response = chain.proceed(request);
+                //鏄惁闇�瑕乼oken锛岄渶瑕佸垯骞挎挱
+                ResponseBody responseBody = response.body();
+                if (401 == response.code() || 402 == response.code() || 403 == response.code()) {
+                    //缃戠粶鏍¢獙寮傚父锛岄渶瑕乼oken
+                    final Intent intent = new Intent();
+                    intent.setAction(CloudBroadcastAction.REFRESH_TOKEN_INVALID_ACTION);
+                    sendBroadcast(intent);
+
+                } else if (responseBody != null && response.isSuccessful()) {
+                    try {
+                        MediaType mediaType = responseBody.contentType();
+                        if (mediaType != null) {
+                            String type = mediaType.toString();
+
+                            //json绫诲瀷鎵嶅鐞�
+                            if (!TextUtils.isEmpty(type) && type.contains("json")) {
+
+                                BufferedSource source = responseBody.source();
+
+                                source.request(Long.MAX_VALUE);
+
+                                Buffer buffer = source.getBuffer().clone();
+                                String respString = buffer.readString(Charset.defaultCharset());
+                                JsonObject object = JsonParser.parseString(respString).getAsJsonObject();
+                                int code = object.get("code").getAsInt();
+                                if (isTokenLoseByCode(code)) {
+                                    //token澶辨晥浜�,闇�瑕乼oken
+                                    final Intent intent = new Intent();
+                                    intent.setAction(CloudBroadcastAction.REFRESH_TOKEN_INVALID_ACTION);
+                                    sendBroadcast(intent);
+                                }
+                            }
+
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+
+                }
+
+                return response;
+            }
+        }
+        return chain.proceed(request);
+    }
+
+    @NonNull
+    private Response disposeToken(Chain chain, Request request, Response response) {
+        try {
+            if (401 == response.code() || 402 == response.code() || 403 == response.code()) {
+                final String token = refreshToken();
+                if (!TextUtils.isEmpty(token)) {
+                    return chain.proceed(addToken(request, token));
+                }
+                //缃戠粶寮傚父涓嶉渶瑕侀噸缃畉oken
+
+            } else if (response.isSuccessful()) {
+                ResponseBody responseBody = response.body();
+                if (responseBody != null) {
+                    MediaType mediaType = responseBody.contentType();
+                    if (mediaType != null) {
+                        String type = mediaType.toString();
+                        //json绫诲瀷鎵嶅鐞�
+                        if (!TextUtils.isEmpty(type) && type.contains("json")) {
+                            BufferedSource source = responseBody.source();
+                            source.request(Long.MAX_VALUE);
+                            Buffer buffer = source.getBuffer().clone();
+                            String respString = buffer.readString(Charset.defaultCharset());
+                            JsonObject object = JsonParser.parseString(respString).getAsJsonObject();
+
+                            int code = -1;
+                            try {
+                                if (object != null) {
+                                    code = object.get("code").getAsInt();
+                                }
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                            String message = "";
+                            try {
+                                if (object != null && object.has("message")) {
+                                    message = object.get("message").getAsString();
+                                    if (TextUtils.isEmpty(message)) {
+                                        message = "";
+                                    }
+                                }
+
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+
+                            if (isTokenLoseByCode(code)) {
+                                //鍒锋柊token
+                                final String token = refreshToken();
+                                if (!TextUtils.isEmpty(token)) {
+                                    Response newResponse = chain.proceed(addToken(request, token));
+
+                                    //token鏇存柊浜�
+                                    final Intent intent = new Intent();
+                                    intent.setAction(CloudBroadcastAction.REFRESH_TOKEN_ACTION);
+                                    sendBroadcast(intent);
+
+                                    return newResponse;
+                                } else {
+                                    //娓呯┖token
+                                    HDLCloudConfig.getInstance().setToken("");
+                                    HDLCloudConfig.getInstance().setRefreshToken("");
+
+                                    //token鍒锋柊澶辫触锛岄�氱煡token澶辨晥浜�
+                                    final Intent intent = new Intent();
+                                    intent.setAction(CloudBroadcastAction.REFRESH_TOKEN_INVALID_ACTION);
+                                    sendBroadcast(intent);
+                                }
+                            } else {
+                                try {
+                                    //鍏朵粬寮傚父鎯呭喌
+                                    final Intent intent = new Intent();
+                                    intent.setAction(CloudBroadcastAction.API_ERROR_ACTION);
+                                    intent.putExtra(CloudBroadcast.KEY_API_CODE, code);
+                                    intent.putExtra(CloudBroadcast.KEY_API_MESSAGE, message);
+                                    sendBroadcast(intent);
+                                } catch (Exception e) {
+                                    e.printStackTrace();
+                                }
+                            }
+                            buffer.clear();
+                        }
+                    }
+
+                }
+
+            }
+
+        } catch (Exception e) {
+            Log.d("HDL===>", "disposeToken: 澶辫触," + e);
+        }
+        return response;
+    }
+
+
+    /**
+     * 鏍规嵁code鍒ゆ柇token鏄惁澶辨晥
+     *
+     * @param code 涓氬姟code
+     * @return ture 澶辨晥
+     */
+    private boolean isTokenLoseByCode(int code) {
+        return CloudCode.TOKEN_TIMEOUT == code ||
+                CloudCode.TOKEN_NOT_STANDARD == code ||
+                CloudCode.NO_TOKEN == code;
+    }
+
+
+    /**
+     * 鏄惁瀛樺湪鍒锋柊澶�
+     */
+    private boolean isRefreshTokenHeader(Headers headers) {
+        String signHeader = headers.get(SmartHeader.REFRESH_TOKEN_HEADER);
+        return !TextUtils.isEmpty(signHeader);
+    }
+
+    private Request addToken(Request request, String token) {
+        return request.newBuilder()
+                .removeHeader("Authorization")
+                .build()
+                .newBuilder()
+                .method(request.method(), request.body())
+                .addHeader("Authorization", HDLCloudConfig.getInstance().getTokenHeaderPrefix() + token)
+                .build();
+    }
+
+    /**
+     * 鎷︽埅鍣‥ncryptInterceptor浼氬鐞嗗姞瀵�
+     *
+     * @return token
+     */
+    private String refreshToken() {
+        final String cacheRefreshToken = SPUtils.getString(SPKey.REFRESH_TOKEN);
+        if (TextUtils.isEmpty(cacheRefreshToken)) {
+            return null;
+        }
+        final OkHttpClient client = HxHttpConfig.getInstance().getClient();
+
+        Request.Builder builder = new Request.Builder();
+
+        final JsonObject json = new JsonObject();
+        json.addProperty("refreshToken", cacheRefreshToken);
+        json.addProperty("grantType", "refresh_token");
+
+        final RequestBody requestBody = RequestBody.create(json.toString(), MediaType.parse("application/json;charset=UTF-8"));
+        builder.post(requestBody);
+        builder.url(HDLCloudConfig.getInstance().getBaseUrl() + HdlCloudApi.LOGIN);
+        builder.addHeader(SmartHeader.REFRESH_TOKEN_HEADER, "0");
+        try {
+            Response response = client.newCall(builder.build()).execute();
+            if (response.isSuccessful()) {
+                ResponseBody responseBody = response.body();
+                if (responseBody != null) {
+                    BufferedSource source = responseBody.source();
+                    source.request(Long.MAX_VALUE);
+                    Buffer buffer = source.getBuffer().clone();
+                    String respString = buffer.readString(Charset.defaultCharset());
+
+                    JsonObject object = JsonParser.parseString(respString).getAsJsonObject();
+                    JsonObject dataJson = object.get("data").getAsJsonObject();
+                    String accessToken = dataJson.get("accessToken").getAsString();
+                    String refreshToken = dataJson.get("refreshToken").getAsString();
+                    if (!TextUtils.isEmpty(accessToken)) {
+                        HDLCloudConfig.getInstance().setToken(accessToken);
+                    }
+                    if (!TextUtils.isEmpty(refreshToken)) {
+                        HDLCloudConfig.getInstance().setRefreshToken(refreshToken);
+                    }
+                    return accessToken;
+
+                }
+            } else {
+                Log.d("OKHTTP===>", "refreshToken: 澶辫触浜�");
+            }
+        } catch (Exception ignored) {
+            Log.d("OKHTTP===>", "refreshToken: 澶辫触,寮傚父");
+        }
+        return "";
+    }
+
+
+    private void sendBroadcast(Intent intent) {
+        HDLCloudConfig.getInstance().getContext().sendBroadcast(intent);
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListListener.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListListener.java
new file mode 100644
index 0000000..d8b31ae
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListListener.java
@@ -0,0 +1,15 @@
+package com.hdl.sdk.connect.cloud.listener;
+
+import com.hdl.sdk.connect.cloud.BaseCallBack;
+import com.hdl.sdk.connect.cloud.bean.GatewayInfo;
+
+import java.util.List;
+
+/**
+ * Created by Tong on 2021/12/7.
+ * 缃戝叧鍒楄〃
+ */
+public interface GatewayListListener extends BaseCallBack {
+    void onSuccess(List<GatewayInfo> info);
+}
+
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListener.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListener.java
new file mode 100644
index 0000000..ec1d8ec
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/GatewayListener.java
@@ -0,0 +1,11 @@
+package com.hdl.sdk.connect.cloud.listener;
+
+import com.hdl.sdk.connect.cloud.BaseCallBack;
+import com.hdl.sdk.connect.cloud.bean.GatewayInfo;
+
+/**
+ * Created by Tong on 2021/12/7.
+ */
+public interface GatewayListener extends BaseCallBack {
+    void onSuccess(GatewayInfo info);
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/SibichiListener.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/SibichiListener.java
new file mode 100644
index 0000000..1522d9d
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/cloud/listener/SibichiListener.java
@@ -0,0 +1,14 @@
+package com.hdl.sdk.connect.cloud.listener;
+
+
+import com.hdl.sdk.connect.cloud.BaseCallBack;
+import com.hdl.sdk.connect.cloud.bean.AiLoginInfo;
+
+/**
+ * Created by Zoro
+ * Created on 2021/11/26
+ * description:
+ */
+public interface SibichiListener extends BaseCallBack {
+    void onSuccess(AiLoginInfo info);
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLCloudConfig.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLCloudConfig.java
new file mode 100644
index 0000000..178433e
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLCloudConfig.java
@@ -0,0 +1,150 @@
+package com.hdl.sdk.connect.config;
+
+import android.content.Context;
+import android.text.TextUtils;
+
+import com.hdl.hdlhttp.HxHttpConfig;
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.connect.cloud.interceptor.EncryptInterceptor;
+import com.hdl.sdk.connect.cloud.interceptor.HdlLoginInterceptor;
+import com.hdl.sdk.connect.cloud.interceptor.SmartHeaderInterceptor;
+import com.hdl.sdk.sourceos.utils.SPKey;
+
+import okhttp3.Interceptor;
+import okhttp3.logging.HttpLoggingInterceptor;
+
+/**
+ * Created by panlili on 2025/3/4
+ * description:
+ */
+public class HDLCloudConfig {
+
+    private String mBaseUrl;
+
+    private String mDefBaseUrl;
+
+    private String mLanguage;
+
+    private static final String DEF_TOKEN_HEADER_PREFIX = "Bearer ";
+
+    private HDLCloudConfig() {
+    }
+
+    private static class SingletonInstance {
+        private static final HDLCloudConfig INSTANCE = new HDLCloudConfig();
+    }
+
+    public static HDLCloudConfig getInstance() {
+        return SingletonInstance.INSTANCE;
+    }
+
+    private Context context;
+
+    private String appKey, appSecret;
+
+    private String token, refreshToken;
+
+    private String tokenHeaderPrefix = DEF_TOKEN_HEADER_PREFIX;
+
+    public Context getContext() {
+        return context;
+    }
+
+    public void init(Context context, String appKey, String appSecret, String url) {
+        this.context = context;
+        HxHttpConfig.getInstance().init(context, url)
+                .addInterceptor(
+                        new HdlLoginInterceptor(),
+                        new EncryptInterceptor(),
+                        new SmartHeaderInterceptor());
+        this.mBaseUrl = url;
+        this.mDefBaseUrl = url;
+        this.appKey = appKey;
+        this.appSecret = appSecret;
+        setBaseUrl(url);
+    }
+
+    public void addInterceptor(Interceptor... interceptors) {
+        HxHttpConfig.getInstance().addInterceptor(interceptors);
+    }
+
+
+    public String getBaseUrl() {
+        if (TextUtils.isEmpty(mBaseUrl)) {
+            mBaseUrl = SPUtils.getString(SPKey.BASE_URL, "");
+        }
+        return mBaseUrl;
+    }
+
+    public void setBaseUrl(String mBaseUrl) {
+        this.mBaseUrl = mBaseUrl;
+        HxHttpConfig.getInstance().init(context,mBaseUrl);
+        SPUtils.put(SPKey.BASE_URL, mBaseUrl);
+    }
+
+    public String getDefBaseUrl() {
+        return mDefBaseUrl;
+    }
+
+    public void setDefBaseUrl(String mDefBaseUrl) {
+        this.mDefBaseUrl = mDefBaseUrl;
+    }
+
+    public String getAppKey() {
+        return appKey;
+    }
+
+    public void setAppKey(String appKey) {
+        this.appKey = appKey;
+    }
+
+    public String getAppSecret() {
+        return appSecret;
+    }
+
+    public void setAppSecret(String appSecret) {
+        this.appSecret = appSecret;
+    }
+
+    public synchronized String getToken() {
+        if (TextUtils.isEmpty(token)) {
+            token = SPUtils.getString(SPKey.TOKEN);
+        }
+        return token;
+
+    }
+
+    public synchronized void setToken(String token) {
+        this.token = token;
+        SPUtils.put(SPKey.TOKEN, token);
+    }
+
+    public synchronized String getRefreshToken() {
+        if (TextUtils.isEmpty(refreshToken)) {
+            refreshToken = SPUtils.getString(SPKey.REFRESH_TOKEN);
+        }
+        return refreshToken;
+    }
+
+    public synchronized void setRefreshToken(String refreshToken) {
+        this.refreshToken = refreshToken;
+        SPUtils.put(SPKey.REFRESH_TOKEN, refreshToken);
+    }
+
+    public String getTokenHeaderPrefix() {
+        return tokenHeaderPrefix;
+    }
+
+    public void setTokenHeaderPrefix(String tokenHeaderPrefix) {
+        this.tokenHeaderPrefix = tokenHeaderPrefix;
+    }
+
+
+    public String getLanguage() {
+        return mLanguage;
+    }
+
+    public void setLanguage(String mLanguage) {
+        this.mLanguage = mLanguage;
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLLinkConfig.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLLinkConfig.java
index 006fd97..892b6e6 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLLinkConfig.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/config/HDLLinkConfig.java
@@ -21,7 +21,7 @@
     private static final String AUTHENTICATE_IS_LS_KEY = "auth_isls_key";
     public static final String AUTHENTICATE_IS_DEVICEINFO_KEY = "auth_deviceinfo_key";
 
-    public static final String GATEWAY_REMOTEINFO_KEY="gateway_remoteinfo_key";
+    public static final String GATEWAY_REMOTEINFO_KEY = "gateway_remoteinfo_key";
     private static final String GATEWAY_PARENTOID_KEY = "gateway_parentoiid_key";
 
     private String localSecret;//鏈湴鍔犲瘑瀵嗛挜
@@ -39,9 +39,9 @@
     /**
      * instance
      */
-    private  static final HDLLinkConfig instance=new HDLLinkConfig();
-    private HDLLinkConfig()
-    {
+    private static final HDLLinkConfig instance = new HDLLinkConfig();
+
+    private HDLLinkConfig() {
         loadConfig();
     }
 
@@ -50,7 +50,7 @@
      *
      * @return AuthenticateConfig
      */
-    public static  HDLLinkConfig getInstance() {
+    public static HDLLinkConfig getInstance() {
 //        if (instance == null) {
 //            synchronized (HDLLinkConfig.class) {
 //                if (instance == null) {
@@ -69,7 +69,7 @@
         this.gatewayId = "";
         this.ipAddress = "";
         this.localSecret = "";
-        this.homeId="";
+        this.homeId = "";
         SPUtils.remove(AUTHENTICATE_LS_KEY);
         SPUtils.remove(AUTHENTICATE_GATEWAYID_KEY);
         SPUtils.remove(AUTHENTICATE_IPADDRESS_KEY);
@@ -138,14 +138,16 @@
     public String getGatewayId() {
         return gatewayId;
     }
+
     public void setGatewayId(String gatewayId) {
-        this.gatewayId=gatewayId;
+        this.gatewayId = gatewayId;
     }
 
     public String getIpAddress() {
         return ipAddress;
     }
-    public void setIpAddress(String ipAddress){
+
+    public void setIpAddress(String ipAddress) {
         this.ipAddress = ipAddress;
     }
 
@@ -209,8 +211,8 @@
 
     public AuthenticateRequest.AuthenticateDeviceInfoBean getDeviceInfoBean() {
         AuthenticateRequest.AuthenticateDeviceInfoBean infoBean = (AuthenticateRequest.AuthenticateDeviceInfoBean) SPUtils.getSerializableEntity(AUTHENTICATE_IS_DEVICEINFO_KEY);
-        if(infoBean==null){
-            infoBean= new AuthenticateRequest.AuthenticateDeviceInfoBean();
+        if (infoBean == null) {
+            infoBean = new AuthenticateRequest.AuthenticateDeviceInfoBean();
         }
         return infoBean;
     }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java
index 1cf5c5c..38438d9 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/protocol/LinkMessageDecoder.java
@@ -3,39 +3,19 @@
 
 import android.os.Build;
 import android.text.TextUtils;
-import android.util.Log;
 
 import androidx.annotation.RequiresApi;
 
-import com.google.gson.reflect.TypeToken;
-import com.hdl.sdk.common.config.TopicConstant;
 import com.hdl.sdk.common.event.EventDispatcher;
-import com.hdl.sdk.common.exception.HDLLinkException;
-import com.hdl.sdk.common.utils.ByteUtils;
 import com.hdl.sdk.common.utils.LogUtils;
-import com.hdl.sdk.common.utils.SPUtils;
-import com.hdl.sdk.common.utils.gson.GsonConvert;
-import com.hdl.sdk.connect.HDLLink;
 import com.hdl.sdk.connect.bean.LinkResponse;
-import com.hdl.sdk.connect.bean.request.AuthenticateRequest;
-import com.hdl.sdk.connect.bean.response.DeviceDeleteResponse;
-import com.hdl.sdk.connect.bean.response.DeviceInfoResponse;
-import com.hdl.sdk.connect.callback.HDLLinkCallBack;
 import com.hdl.sdk.connect.config.HDLLinkConfig;
-import com.hdl.sdk.connect.socket.HDLAuthSocket;
-import com.hdl.sdk.connect.socket.HDLSocket;
 import com.hdl.sdk.connect.utils.AesUtil;
 import com.hdl.sdk.connect.utils.ByteBufferUtils;
 import com.hdl.sdk.socket.codec.ByteToMessageDecoder;
 
 import java.nio.ByteBuffer;
 import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.List;
-
-import android.util.Base64;
-
-import kotlin.ParameterName;
 
 /**
  * Created by Tong on 2021/9/22.
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java
index 950e4aa..3f277dc 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLAuthSocket.java
@@ -585,7 +585,7 @@
         if (broadcast) {
             ip = IpUtils.getBroadcastAddress();
         }
-        HdlSocketHelper.sendUdp(getUdpBoot(), ip, UDP_PORT, message,"", 1, new HdlSocketHelper.HdlSocketListener() {
+        HdlSocketHelper.sendUdp(getUdpBoot(), ip, UDP_PORT, message, "", 1, new HdlSocketHelper.HdlSocketListener() {
                     @Override
                     public void onSucceed(Object msg) {
                         if (callBack == null) return;
@@ -703,6 +703,8 @@
                                     HDLLinkConfig.getInstance().setCurrentGateway(searchBean);//璁剧疆褰撳墠缃戝叧
                                     if (mSearchGatewayCallBack != null) {
                                         mSearchGatewayCallBack.onSuccess(searchBean);
+                                        HDLSocket.getInstance().isBroadcast = true;
+                                        HDLSocket.getInstance().getTcp();
                                     }
                                 }
                             }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java
index 0149de2..2147f3e 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/connect/socket/HDLSocket.java
@@ -46,6 +46,7 @@
 import com.hdl.sdk.socket.listener.ConnectStatusListener;
 import com.hdl.sdk.socket.listener.SendListener;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.ScheduledExecutorService;
@@ -480,25 +481,30 @@
                 @Override
                 public void heartbeat() {
 
-                    if (HDLLinkConfig.getInstance().getDeviceInfoBean() == null || HDLLinkConfig.getInstance().getDeviceInfoBean().getOID() == null) {
-                        LogUtils.i("DeviceInfoBean涓虹┖锛岄渶瑕佽缃墠鑳芥甯稿績璺�");
-                        return;
-                    }
-
                     String time = String.valueOf(System.currentTimeMillis());
                     JsonObject jsonObject = new JsonObject();
                     jsonObject.addProperty("id", IdUtils.getUUId());
                     jsonObject.addProperty("time_stamp", time);
+                    if (HDLLinkConfig.getInstance().getDeviceInfoBean().getOID() == null) {
+                        //涓嶈蛋浠庢満鍏ョ綉锛岄�氳繃gatewayId鍙戦��
+                        if (HDLLinkConfig.getInstance().getGatewayId() == null) {
+                            return;
+                        }
+                        String topic = String.format(TopicConstant.HEARTBEAT, HDLLinkConfig.getInstance().getGatewayId());
+                        LinkRequest message = new LinkRequest(topic,
+                                jsonObject.toString());
+                        sendMsg(message.getSendBytes(), null, null, null);
 
-                    if (HDLLinkConfig.getInstance().getRequestBean() != null) {
-                        jsonObject.addProperty("mac", HDLLinkConfig.getInstance().getRequestBean().getMAC());
+                    } else {
+                        if (HDLLinkConfig.getInstance().getRequestBean() != null) {
+                            jsonObject.addProperty("mac", HDLLinkConfig.getInstance().getRequestBean().getMAC());
+                        }
+                        //璧颁粠鏈哄叆缃戯紝閫氳繃oid鍙戦��
+                        String topic = String.format(TopicConstant.HEARTBEAT, HDLLinkConfig.getInstance().getDeviceInfoBean().getOID());
+                        LinkRequest message = new LinkRequest(topic,
+                                jsonObject.toString());
+                        sendMsg(message.getSendBytes(), null, null, null);
                     }
-
-                    String topic = String.format(TopicConstant.HEARTBEAT, HDLLinkConfig.getInstance().getDeviceInfoBean().getOID());
-
-                    LinkRequest message = new LinkRequest(topic,
-                            jsonObject.toString());
-                    sendMsg(message.getSendBytes(), null, null, null);
                 }
             });
         }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/socket/SocketBoot.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/socket/SocketBoot.java
index 3a1647c..1c609b4 100644
--- a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/socket/SocketBoot.java
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/socket/SocketBoot.java
@@ -179,7 +179,7 @@
                 public void run() {
                     while (true) {
                         try {
-//                            LogUtils.i("initConnectThread: connected=" + connected + " isBroadcast=" + HDLSocket.getInstance().isBroadcast);
+                            LogUtils.i("initConnectThread: connected=" + connected + " isBroadcast=" + HDLSocket.getInstance().isBroadcast);
                             if (!connected && HDLSocket.getInstance().isBroadcast) {
                                 reconect();
                             }
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BaseEvent.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BaseEvent.java
new file mode 100644
index 0000000..dfa538f
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BaseEvent.java
@@ -0,0 +1,12 @@
+package com.hdl.sdk.sourceos.bind;
+
+import java.io.Serializable;
+
+/**
+ * Created by Tong on 2021/11/12.
+ */
+public interface BaseEvent extends Serializable {
+
+    @EventType
+    String getEventType();
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindAuthEvent.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindAuthEvent.java
new file mode 100644
index 0000000..6ea2666
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindAuthEvent.java
@@ -0,0 +1,37 @@
+package com.hdl.sdk.sourceos.bind;
+
+/**
+ * Created by Tong on 2022/3/23.
+ * 鎵爜缁戝畾浜嬩欢
+ */
+public class BindAuthEvent implements BaseEvent {
+
+
+    //on+缁戝畾鎴愬姛
+    public static final int ON_PLUS_BINDING_SUCCEED_ACTION = 0;
+
+    //on+缁戝畾瓒呮椂
+    public static final int ON_PLUS_BINDING_TIMEOUT_ACTION = 1;
+
+    //缃戠粶寮傚父
+    public static final int ON_PLUS_BINDING_ERROR_ACTION = 2;
+
+    private int action;
+
+    public BindAuthEvent(int action) {
+        this.action = action;
+    }
+
+    @Override
+    public String getEventType() {
+        return EventType.ON_PLUS_BINDING_TYPE;
+    }
+
+    public int getAction() {
+        return action;
+    }
+
+    public void setAction(int action) {
+        this.action = action;
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindHomeService.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindHomeService.java
new file mode 100644
index 0000000..00a2397
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/BindHomeService.java
@@ -0,0 +1,184 @@
+package com.hdl.sdk.sourceos.bind;
+
+import android.text.TextUtils;
+
+import com.hdl.hdlhttp.HxHttp;
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.connect.bean.response.BindInfoBean;
+import com.hdl.sdk.connect.cloud.HDLException;
+import com.hdl.sdk.connect.cloud.HDLResponse;
+import com.hdl.sdk.connect.cloud.HdlCloudApi;
+import com.hdl.sdk.connect.config.HDLCloudConfig;
+import com.hdl.sdk.connect.config.HDLLinkConfig;
+import com.hdl.sdk.sourceos.Rk3566Manager;
+import com.hdl.sdk.sourceos.qrcode.QRCode;
+import com.hdl.sdk.sourceos.utils.DeviceUtils;
+import com.hdl.sdk.sourceos.utils.SPKey;
+import com.hdl.sdk.sourceos.utils.thread.ThreadUtils;
+
+import org.greenrobot.eventbus.EventBus;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import io.reactivex.rxjava3.disposables.CompositeDisposable;
+import io.reactivex.rxjava3.disposables.Disposable;
+
+/**
+ * Created by Tong on 2021/11/11.
+ * on+鏄惁缁戝畾
+ * 1銆佺粦瀹氭垚鍔熼渶瑕佹煡璇綇瀹呬俊鎭�
+ * 2銆佹壂鐮�3鍒嗛挓瓒呮椂
+ */
+public class BindHomeService {
+
+    private ScheduledExecutorService queryThread;
+
+    private final CompositeDisposable compositeDisposable = new CompositeDisposable();
+
+    //鏈�澶ф椂闂�
+    private static final long MAX_TIME = 3 * 60 * 1000;
+
+    //涓婁竴娆℃墽琛屾椂闂�
+    private final AtomicLong lastTime = new AtomicLong(0);
+
+    private BindHomeService() {
+    }
+
+    private static class SingletonInstance {
+        private static final BindHomeService INSTANCE = new BindHomeService();
+    }
+
+    public static BindHomeService getInstance() {
+        return SingletonInstance.INSTANCE;
+    }
+
+    /**
+     * 杞鏄惁缁戝畾
+     *
+     * @param timestamp 鏃堕棿鎴�
+     */
+    public void startQuery(String timestamp) {
+        stopQuery();
+        lastTime.set(System.currentTimeMillis());
+        String packageName = Rk3566Manager.getInstance().getContext().getPackageName();
+        String unique = DeviceUtils.getUniqueCode();
+        queryThread = ThreadUtils.newScheduledThreadPool(1);
+        queryThread.scheduleWithFixedDelay(new Runnable() {
+            @Override
+            public void run() {
+                long timeMillis = System.currentTimeMillis();
+                if (timeMillis - lastTime.get() < MAX_TIME) {
+                    compositeDisposable.add(isBind(packageName, unique, timestamp));
+                } else {
+                    //瓒呮椂浜�
+                    EventBus.getDefault().post(new BindAuthEvent(BindAuthEvent.ON_PLUS_BINDING_TIMEOUT_ACTION));
+                    stopQuery();
+                }
+
+            }
+        }, 0L, 800L, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 鍋滄鏌ヨ
+     */
+    public void stopQuery() {
+        lastTime.set(0);
+        if (queryThread != null && !queryThread.isShutdown()) {
+            queryThread.shutdownNow();
+        }
+        if (!compositeDisposable.isDisposed()) {
+            compositeDisposable.dispose();
+        }
+    }
+
+
+    /**
+     * 閫氳繃淇濆瓨鐨刢ode鏌ヨ鏄惁缁戝畾
+     *
+     * @param bindCode 淇濆瓨鐨刢ode鏌ヨ鏄惁缁戝畾
+     * @return
+     */
+    public static Disposable isBindByCode(String bindCode) {
+        if (TextUtils.isEmpty(bindCode)) return null;
+        String[] code = bindCode.split("_");
+        if (code.length < 3) {
+            return null;
+        }
+        String packageName = code[0];
+        String unique = code[1];
+        String timestamp = code[2];
+        return isBind(packageName, unique, timestamp);
+    }
+
+    public static Disposable isBind(String timestamp) {
+        String packageName = Rk3566Manager.getInstance().getContext().getPackageName();
+        String unique = DeviceUtils.getUniqueCode();
+        return isBind(packageName, unique, timestamp);
+    }
+
+    /**
+     * @param timestamp   鏃堕棿鎴�
+     * @param packageName 鍖呭悕
+     * @param unique      搴忓垪鍙�
+     * @return
+     */
+    public static Disposable isBind(String packageName, String unique, String timestamp) {
+        return isBind(packageName, unique, timestamp, new HDLResponse<BindInfoBean>() {
+            @Override
+            public void onResponse(BindInfoBean response) {
+                handleBind(response, timestamp);
+            }
+
+            @Override
+            public void onFailure(HDLException e) {
+                //缃戠粶寮傚父銆佹垨鑰呮帴鍙f姤閿�
+                EventBus.getDefault().post(new BindAuthEvent(BindAuthEvent.ON_PLUS_BINDING_ERROR_ACTION));
+            }
+        });
+    }
+
+
+    /**
+     * @param timestamp   鏃堕棿鎴�
+     * @param packageName 鍖呭悕
+     * @param unique      搴忓垪鍙�
+     * @return
+     */
+    public static Disposable isBind(String packageName, String unique, String timestamp, HDLResponse<BindInfoBean> response) {
+        return HxHttp.builder()
+                .url(HdlCloudApi.IS_BIND_URL)
+                .params("packageName", packageName)
+                .params("unique", unique)
+                .params("qrcodeTimestamp", timestamp)
+                .build()
+                .executePost()
+                .subscribeWith(response);
+    }
+
+
+    /**
+     * 澶勭悊缁戝畾
+     *
+     * @param response  杩斿洖
+     * @param timestamp 鏃堕棿鎴�
+     */
+    private static void handleBind(BindInfoBean response, String timestamp) {
+        if (!TextUtils.isEmpty(response.getHomeId())) {
+
+            SPUtils.saveSerializableEntity(SPKey.BIND_HOME_INFO, response);
+            SPUtils.put(SPKey.BIND_CODE, QRCode.createBindQRCodeInfo(timestamp));
+
+            HDLCloudConfig.getInstance().setToken(response.getToken());
+            HDLCloudConfig.getInstance().setRefreshToken(response.getRefreshToken());
+
+            EventBus.getDefault().post(new BindAuthEvent(BindAuthEvent.ON_PLUS_BINDING_SUCCEED_ACTION));
+
+            getInstance().stopQuery();
+        }
+    }
+
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/EventType.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/EventType.java
new file mode 100644
index 0000000..1005838
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/bind/EventType.java
@@ -0,0 +1,27 @@
+package com.hdl.sdk.sourceos.bind;
+
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import androidx.annotation.StringDef;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Created by Tong on 2021/11/8.
+ */
+@StringDef({
+        EventType.TEST_TYPE,
+        EventType.ON_PLUS_BINDING_TYPE
+
+})
+@Retention(SOURCE)
+public @interface EventType {
+
+    //娴嬭瘯鏁版嵁
+    String TEST_TYPE = "event_test_type";
+
+    //on+缁戝畾鎴愬姛
+    String ON_PLUS_BINDING_TYPE = "event_on_plus_binding_type";
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCode.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCode.java
new file mode 100644
index 0000000..e964e4e
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCode.java
@@ -0,0 +1,65 @@
+package com.hdl.sdk.sourceos.qrcode;
+
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.sourceos.Rk3566Manager;
+import com.hdl.sdk.sourceos.utils.DeviceUtils;
+import com.hdl.sdk.sourceos.utils.SPKey;
+
+/**
+ * Created by Tong on 2021/11/8.
+ */
+public class QRCode {
+
+    private static final String SOURCE_SCHEME = "source";
+    //缁戝畾source
+    private static final String BIND_HOST = "bind";
+
+
+
+    /**
+     * @return source://bind/鍖呭悕_搴忓垪鍙穇鏃堕棿鎴�
+     */
+    public static String getBindQRCodeInfo() {
+        return SPUtils.getString(SPKey.BIND_CODE);
+    }
+
+    /**
+     * @return 鍖呭悕_搴忓垪鍙穇鏃堕棿鎴�
+     */
+    public static String getBindQRCode(String code) {
+        if (!TextUtils.isEmpty(code)) {
+            Uri uri = Uri.parse(code);
+            return uri.getLastPathSegment();
+        }
+        return null;
+    }
+
+    /**
+     * @return 鍖呭悕_搴忓垪鍙穇鏃堕棿鎴�
+     */
+    public static String getBindQRCode() {
+        String info = QRCode.getBindQRCodeInfo();
+        return getBindQRCode(info);
+    }
+
+    /**
+     * 搴忓垪鍙穉ndroid10 浼氳幏鍙栦笉鍒�
+     *
+     * @return 鑾峰彇缁戝畾浜岀淮鐮佷俊鎭�, source://bind/鍖呭悕_搴忓垪鍙穇鏃堕棿鎴�
+     */
+    public static String createBindQRCodeInfo(String time) {
+        final String packageName = Rk3566Manager.getInstance().getContext().getPackageName();
+        final String deviceId = DeviceUtils.getUniqueCode();
+        final String builder = packageName +
+                "_" +
+                deviceId +
+                "_" +
+                time;
+        final Uri uri = new Uri.Builder().scheme(SOURCE_SCHEME).authority(BIND_HOST)
+                .appendPath(builder).build();
+        return uri.toString();
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCodeUtils.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCodeUtils.java
new file mode 100644
index 0000000..a08c801
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QRCodeUtils.java
@@ -0,0 +1,71 @@
+package com.hdl.sdk.sourceos.qrcode;
+
+import android.graphics.Bitmap;
+import android.text.TextUtils;
+
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.WriterException;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Created by Tong on 2021/11/8.
+ * 浜岀淮鐮�
+ */
+public class QRCodeUtils {
+
+
+    /**
+     * 鐢熸垚浜岀淮鐮�
+     */
+    public static Bitmap createQRCode(String txt, int width, int height, int margin) throws WriterException {
+        Bitmap bitmap = Bitmap.createBitmap(width, height,
+                Bitmap.Config.ARGB_8888);
+        createQRCode(bitmap, txt, width, height, margin);
+        return bitmap;
+    }
+
+
+    /**
+     * 鐢熸垚浜岀淮鐮�
+     */
+    public static void createQRCode(Bitmap bitmap, String txt, int width, int height, int margin) throws WriterException {
+
+        if (TextUtils.isEmpty(txt)) {
+            return;
+        }
+
+        Map<EncodeHintType, Object> hints = new HashMap<>();
+        hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
+        hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
+        if (margin >= 0) {
+            hints.put(EncodeHintType.MARGIN, margin);
+        }
+
+
+        // 鐢熸垚浜岀淮鐭╅樀
+        BitMatrix matrix = new MultiFormatWriter().encode(txt,
+                BarcodeFormat.QR_CODE, width, height, hints);
+
+        // 浜岀淮鐭╅樀杞负涓�缁村儚绱犳暟缁�,涔熷氨鏄竴鐩存í鐫�鎺掍簡
+        int[] pixels = new int[width * height];
+        for (int y = 0; y < height; y++) {
+            for (int x = 0; x < width; x++) {
+                if (matrix.get(x, y)) {
+                    pixels[y * width + x] = 0xff000000;
+                } else {
+                    pixels[y * width + x] = 0xffffffff;
+                }
+            }
+        }
+
+        bitmap.setPixels(pixels, 0, width, 0, 0, width, height);
+    }
+
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QrCodeView.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QrCodeView.java
new file mode 100644
index 0000000..0e1f13e
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/qrcode/QrCodeView.java
@@ -0,0 +1,141 @@
+package com.hdl.sdk.sourceos.qrcode;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Created by Tong on 2021/12/2.
+ * 浜岀淮鐮乂iew
+ */
+public class QrCodeView extends View {
+
+    private static final int DEF_MARGIN = 0;
+
+    private int mWidth;
+    private int mHeight;
+    private String mContent;
+    private int mMargin = DEF_MARGIN;
+
+    private Bitmap drawBitmap;
+
+    private Canvas drawCanvas;
+
+
+    private Paint paint;
+
+    private final AtomicBoolean isDraw = new AtomicBoolean(false);
+    private DrawThread mDrawThread;
+
+    public QrCodeView(Context context) {
+        this(context, null);
+    }
+
+    public QrCodeView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public QrCodeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+        init();
+    }
+
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        super.onDraw(canvas);
+        if (drawBitmap != null) {
+            canvas.drawBitmap(drawBitmap, getPaddingLeft(), getPaddingTop(), paint);
+        }
+    }
+
+
+    @Override
+    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
+        mHeight = h - getPaddingTop() - getPaddingBottom();
+        mWidth = w - getPaddingStart() - getPaddingEnd();
+
+        if (drawBitmap == null || (drawBitmap.isRecycled() || drawBitmap.getWidth() != mWidth || drawBitmap.getHeight() != mHeight)) {
+            drawBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
+            drawCanvas = new Canvas(drawBitmap);
+            startDraw();
+        }
+    }
+
+
+    public void setContent(String content) {
+        setContent(content, DEF_MARGIN);
+    }
+
+    public void setContent(String content, @Px int margin) {
+        this.mContent = content;
+        startDraw();
+        this.mMargin = margin;
+    }
+
+    public String getContent() {
+        return mContent;
+    }
+
+    public void startDraw() {
+        if (mContent == null || isDraw.get()) return;
+        isDraw.set(true);
+        mDrawThread = new DrawThread();
+        mDrawThread.start();
+    }
+
+    private void init() {
+        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    }
+
+
+    private class DrawThread extends Thread {
+        @Override
+        public void run() {
+            while (isDraw.get())
+                try {
+                    if (drawCanvas != null) {
+
+                        drawCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
+                        int size = Math.min(mHeight, mWidth);
+                        QRCodeUtils.createQRCode(drawBitmap, mContent, size, size, mMargin);
+                        postInvalidate();
+                        isDraw.set(false);
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                } finally {
+                    if (isDraw.get()) {
+                        try {
+                            Thread.sleep(200L);
+                        } catch (Exception ignore) {
+
+                        }
+                    }
+                }
+        }
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        if (drawBitmap != null) {
+            drawBitmap.recycle();
+        }
+        isDraw.set(false);
+        if (mDrawThread != null) {
+            mDrawThread.interrupt();
+        }
+    }
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/DeviceUtils.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/DeviceUtils.java
new file mode 100644
index 0000000..23d8ea8
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/DeviceUtils.java
@@ -0,0 +1,377 @@
+package com.hdl.sdk.sourceos.utils;
+
+import static android.content.Context.WIFI_SERVICE;
+
+import android.annotation.SuppressLint;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.os.Build;
+import android.provider.Settings;
+import android.text.TextUtils;
+
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.sourceos.OsManager;
+import com.hdl.sdk.sourceos.Rk3566Manager;
+
+import java.lang.reflect.Method;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Enumeration;
+import java.util.UUID;
+
+/**
+ * Created by Tong on 2021/11/8.
+ * ACCESS_WIFI_STATE
+ */
+public class DeviceUtils {
+
+    public static final String ANDROID_DEVICE_ID_KEY = "android_device_id_key";
+
+    /**
+     * @return 鑾峰彇璁惧ID锛孉ndroid10 鍙兘鐢╱uid鐢熸垚浜�
+     */
+    public static String getUniqueDeviceId() {
+        String deviceId = SPUtils.getString(ANDROID_DEVICE_ID_KEY);
+        if (!TextUtils.isEmpty(deviceId)) {
+            return deviceId;
+        }
+        deviceId = getDeviceId();
+        SPUtils.put(ANDROID_DEVICE_ID_KEY, deviceId);
+        return deviceId;
+    }
+
+    private static String getDeviceId() {
+        String deviceId;
+        try {
+
+            deviceId = getOsMacAddress();
+            if (!TextUtils.isEmpty(deviceId)) {
+                return deviceId;
+            }
+
+            deviceId = getMacAddress();
+            if (!TextUtils.isEmpty(deviceId)) {
+                return deviceId;
+            }
+
+            /*deviceId = getIMEI();
+            if (!TextUtils.isEmpty(deviceId)) {
+                return deviceId;
+            }*/
+
+            deviceId = getAndroidId();
+            if (!TextUtils.isEmpty(deviceId)) {
+                return deviceId;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+
+        deviceId = getUUid("", "");
+        return deviceId;
+    }
+
+    /**
+     * 闇�瑕佺郴缁熸潈闄�
+     * READ_PRIVILEGED_PHONE_STATE
+     */
+    /*private static String getIMEI(Context context) {
+        try {
+            TelephonyManager tm = (TelephonyManager) context.getSystemService(Service.TELEPHONY_SERVICE);
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+                return tm.getImei();
+            } else {
+                return tm.getDeviceId();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }*/
+    private static String getAndroidId() {
+        try {
+            ContentResolver contentResolver = Rk3566Manager.getInstance().getContext().getApplicationContext().getContentResolver();
+            return Settings.System.getString(contentResolver, Settings.Secure.ANDROID_ID);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    public static String getUUid(String prefix, String id) {
+        if (id.equals("")) {
+            return prefix + UUID.randomUUID().toString().replace("-", "");
+        }
+        return prefix + UUID.nameUUIDFromBytes(id.getBytes()).toString().replace("-", "");
+    }
+
+    public static InetAddress getInetAddress() {
+        try {
+            Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
+            while (nis.hasMoreElements()) {
+                NetworkInterface ni = nis.nextElement();
+                // To prevent phone of xiaomi return "10.0.2.15"
+                if (!ni.isUp()) continue;
+                Enumeration<InetAddress> addresses = ni.getInetAddresses();
+                while (addresses.hasMoreElements()) {
+                    InetAddress inetAddress = addresses.nextElement();
+                    if (!inetAddress.isLoopbackAddress()) {
+                        String hostAddress = inetAddress.getHostAddress();
+                        if (hostAddress.indexOf(':') < 0) return inetAddress;
+                    }
+                }
+            }
+        } catch (SocketException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+
+    public static String getMacAddressByWifiInfo() {
+        try {
+            final WifiManager wifi = (WifiManager) Rk3566Manager.getInstance().getContext().getApplicationContext()
+                    .getSystemService(WIFI_SERVICE);
+            if (wifi != null) {
+                final WifiInfo info = wifi.getConnectionInfo();
+                if (info != null) {
+                    @SuppressLint({"HardwareIds", "MissingPermission"})
+                    String macAddress = info.getMacAddress();
+                    if (!TextUtils.isEmpty(macAddress)) {
+                        return macAddress;
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "02:00:00:00:00:00";
+    }
+
+    /**
+     * 浠庢湁绾跨綉鍗¤幏鍙杕ac
+     *
+     * @return 鏈夌嚎缃戝叧mac
+     */
+    private static String getMacAddressByEthInterface() {
+        try {
+            Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
+            while (nis.hasMoreElements()) {
+                NetworkInterface ni = nis.nextElement();
+                if (ni == null || !ni.getName().equalsIgnoreCase("eth0")) continue;
+                byte[] macBytes = ni.getHardwareAddress();
+                if (macBytes != null && macBytes.length > 0) {
+                    StringBuilder sb = new StringBuilder();
+                    for (byte b : macBytes) {
+                        sb.append(String.format("%02x:", b));
+                    }
+                    return sb.substring(0, sb.length() - 1);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "02:00:00:00:00:00";
+    }
+
+
+    public static String getMacAddressByNetworkInterface() {
+        try {
+            Enumeration<NetworkInterface> nis = NetworkInterface.getNetworkInterfaces();
+            while (nis.hasMoreElements()) {
+                NetworkInterface ni = nis.nextElement();
+                if (ni == null || !ni.getName().equalsIgnoreCase("wlan0")) continue;
+                byte[] macBytes = ni.getHardwareAddress();
+                if (macBytes != null && macBytes.length > 0) {
+                    StringBuilder sb = new StringBuilder();
+                    for (byte b : macBytes) {
+                        sb.append(String.format("%02x:", b));
+                    }
+                    return sb.substring(0, sb.length() - 1);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "02:00:00:00:00:00";
+    }
+
+    private static String getMacAddressByInetAddress() {
+        try {
+            InetAddress inetAddress = getInetAddress();
+            if (inetAddress != null) {
+                NetworkInterface ni = NetworkInterface.getByInetAddress(inetAddress);
+                if (ni != null) {
+                    byte[] macBytes = ni.getHardwareAddress();
+                    if (macBytes != null && macBytes.length > 0) {
+                        StringBuilder sb = new StringBuilder();
+                        for (byte b : macBytes) {
+                            sb.append(String.format("%02x:", b));
+                        }
+                        return sb.substring(0, sb.length() - 1);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "02:00:00:00:00:00";
+    }
+
+
+    private static boolean isAddressNotInExcepts(final String address, final String... excepts) {
+        if (TextUtils.isEmpty(address)) {
+            return false;
+        }
+        if ("02:00:00:00:00:00".equals(address)) {
+            return false;
+        }
+        if (excepts == null || excepts.length == 0) {
+            return true;
+        }
+        for (String filter : excepts) {
+            if (filter != null && filter.equals(address)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    public static String getMacAddress(final String... excepts) {
+
+        String macAddress = getMacAddressByEthInterface();
+        if (isAddressNotInExcepts(macAddress, excepts)) {
+            return macAddress;
+        }
+
+        macAddress = getMacAddressByNetworkInterface();
+        if (isAddressNotInExcepts(macAddress, excepts)) {
+            return macAddress;
+        }
+        macAddress = getMacAddressByInetAddress();
+        if (isAddressNotInExcepts(macAddress, excepts)) {
+            return macAddress;
+        }
+        macAddress = getMacAddressByWifiInfo();
+        if (isAddressNotInExcepts(macAddress, excepts)) {
+            return macAddress;
+        }
+        return "";
+    }
+
+    /**
+     * 鑾峰彇璁惧鐨勫浐浠剁郴缁熺増鏈�
+     *
+     * @return
+     */
+    public static String getBuilderNumberDisplay() {
+        return Build.DISPLAY;
+    }
+
+    /**
+     * 璁惧鍚�
+     **/
+    public static String getDeviceName() {
+        return Build.DEVICE;
+    }
+
+    /**
+     * 鑾峰彇鎵嬫満Android 鐗堟湰
+     *
+     * @return
+     */
+    public static String getDeviceAndroidVersion() {
+        return Build.VERSION.RELEASE;
+    }
+
+//    /**
+//     * 鑾峰彇璁惧搴忓垪鍙�
+//     *
+//     * @return the serial of device
+//     */
+//    @SuppressLint("HardwareIds")
+//    public static String getDeviceSerial() {
+//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+//            try {
+//                return Build.getSerial();
+//            } catch (SecurityException e) {
+//                e.printStackTrace();
+//                return "";
+//            }
+//        }
+//        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? Build.getSerial() : Build.SERIAL;
+//    }
+
+    /**
+     * 鑾峰彇鎵嬫満搴忓垪鍙�
+     *
+     * @return 鎵嬫満搴忓垪鍙�
+     */
+    @SuppressLint({"NewApi", "MissingPermission"})
+    public static String getSerialNumber() {
+        String serial = "";
+        try {
+            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.N) {//8.0+
+                serial = Build.getSerial();
+            } else {//8.0-
+                Class<?> c = Class.forName("android.os.SystemProperties");
+                Method get = c.getMethod("get", String.class);
+                serial = (String) get.invoke(c, "ro.serialno");
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return serial;
+    }
+
+    /**
+     * 鑾峰彇APP鐗堟湰
+     *
+     * @param context
+     * @return
+     */
+    public static String getAppVersionName(Context context) {
+        String versionName = "0";
+        try {
+            PackageManager packageManager = context.getPackageManager();
+            PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), 0);
+            versionName = packageInfo.versionName;
+            if (TextUtils.isEmpty(versionName)) {
+                versionName = "0";
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return versionName;
+    }
+
+    /**
+     * 浠庣郴缁焌pi涓幏鍙杕ac
+     *
+     * @return
+     */
+    private static String getOsMacAddress() {
+        String macAddress = OsManager.getEthMacAddress();
+        if (isAddressNotInExcepts(macAddress)) {
+            return macAddress;
+        }
+        return null;
+    }
+
+
+    /**
+     * 鑾峰彇鍞竴鐮�
+     */
+    public static String getUniqueCode() {
+        return getUniqueDeviceId().replaceAll(":", "");
+    }
+
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/SPKey.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/SPKey.java
new file mode 100644
index 0000000..d76e7b3
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/SPKey.java
@@ -0,0 +1,19 @@
+package com.hdl.sdk.sourceos.utils;
+
+/**
+ * Created by panlili on 2025/3/4
+ * description:
+ */
+public class SPKey {
+
+    // 缁戝畾鐮� source://bind/鍖呭悕_搴忓垪鍙穇鏃堕棿鎴�
+    public static final String BIND_CODE = "bind_qr_code_info";
+
+    public static final String BASE_URL = "base_url";
+    public static final String TOKEN = "cloud_storage_token";
+
+    public static final String REFRESH_TOKEN = "cloud_storage_refresh_token";
+
+    public static final String BIND_HOME_INFO = "bind_home_info";
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/MainThreadExecutor.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/MainThreadExecutor.java
new file mode 100644
index 0000000..e848f9e
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/MainThreadExecutor.java
@@ -0,0 +1,152 @@
+package com.hdl.sdk.sourceos.utils.thread;
+
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+import androidx.annotation.NonNull;
+
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.concurrent.Executor;
+
+
+/**
+ * Created by Tong on 2023/01/03.
+ */
+public class MainThreadExecutor implements Executor {
+
+    private final LinkedList<Runnable> mQueue = new LinkedList<>();
+
+    private final IdleHandlerImpl mHandler = new IdleHandlerImpl(Looper.getMainLooper());
+
+    private final Handler mainHandler = new Handler(Looper.getMainLooper());
+
+    private MessageQueue mMessageQueue;
+
+    private MainThreadExecutor() {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
+            mMessageQueue = Looper.getMainLooper().getQueue();
+        } else {
+            try {
+                Method getQueue = Looper.class.getDeclaredMethod("getQueue");
+                mMessageQueue = (MessageQueue) getQueue.invoke(Looper.getMainLooper());
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static class SingletonInstance {
+        private static final MainThreadExecutor INSTANCE = new MainThreadExecutor();
+    }
+
+    public static MainThreadExecutor getInstance() {
+        return SingletonInstance.INSTANCE;
+    }
+
+
+    private class IdleHandlerImpl extends Handler implements MessageQueue.IdleHandler {
+
+        public IdleHandlerImpl(@NonNull Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            Runnable r;
+            synchronized (mQueue) {
+                if (mQueue.size() == 0) {
+                    return;
+                }
+                r = mQueue.removeFirst();
+            }
+            r.run();
+            synchronized (mQueue) {
+                scheduleNextLocked();
+            }
+        }
+
+        @Override
+        public boolean queueIdle() {
+            handleMessage(null);
+            //ture鎵ц澶氭锛宖alse鎵ц涓�娆�
+            return false;
+        }
+    }
+
+    private static class IdleRunnable implements Runnable {
+        Runnable mRunnable;
+
+        IdleRunnable(Runnable r) {
+            mRunnable = r;
+        }
+
+        public void run() {
+            mRunnable.run();
+        }
+    }
+
+
+    @Override
+    public void execute(Runnable command) {
+        if (Looper.getMainLooper() == Looper.myLooper()) {
+            command.run();
+        } else {
+            mainHandler.post(command);
+        }
+    }
+
+
+    public void post(Runnable runnable) {
+        synchronized (mQueue) {
+            mQueue.add(runnable);
+            if (mQueue.size() == 1) {
+                scheduleNextLocked();
+            }
+        }
+    }
+
+    public void postIdle(final Runnable runnable) {
+        post(new IdleRunnable(runnable));
+    }
+
+    public void postIdle(final Runnable runnable, long delayMillis) {
+        mHandler.postDelayed(runnable, delayMillis);
+    }
+
+    public void cancelAll() {
+        synchronized (mQueue) {
+            mQueue.clear();
+        }
+    }
+
+    public void flush() {
+        LinkedList<Runnable> queue;
+        synchronized (mQueue) {
+            queue = new LinkedList<>(mQueue);
+            mQueue.clear();
+        }
+        for (Runnable r : queue) {
+            r.run();
+        }
+    }
+
+    private void scheduleNextLocked() {
+        if (mQueue.size() > 0) {
+            Runnable peek = mQueue.getFirst();
+            if (peek instanceof IdleRunnable) {
+                if (mMessageQueue != null) {
+                    mMessageQueue.addIdleHandler(mHandler);
+                }
+
+            } else {
+                mHandler.sendEmptyMessage(1);
+            }
+        }
+    }
+
+
+}
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/RenameThreadFactory.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/RenameThreadFactory.java
new file mode 100644
index 0000000..0c862b9
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/RenameThreadFactory.java
@@ -0,0 +1,48 @@
+package com.hdl.sdk.sourceos.utils.thread;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Created by Tong on 2023/05/09.
+ */
+public abstract class RenameThreadFactory implements ThreadFactory {
+
+    private static final AtomicInteger poolNumber = new AtomicInteger(1);
+    private final ThreadGroup group;
+    private final AtomicInteger threadNumber = new AtomicInteger(1);
+
+    public abstract String getName(int poolNumber, int threadNumber);
+
+    private Thread.UncaughtExceptionHandler exceptionHandler;
+
+    public RenameThreadFactory() {
+        SecurityManager s = System.getSecurityManager();
+        this.group = s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+    }
+
+
+    public RenameThreadFactory(Thread.UncaughtExceptionHandler exceptionHandler) {
+        this.exceptionHandler = exceptionHandler;
+        SecurityManager s = System.getSecurityManager();
+        this.group = s != null ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+    }
+
+    public Thread newThread(Runnable r) {
+        Thread t = new Thread(this.group, r, this.getName(poolNumber.getAndIncrement(), this.threadNumber.getAndIncrement()), 0L);
+        if (t.isDaemon()) {
+            t.setDaemon(false);
+        }
+
+        if (t.getPriority() != Thread.NORM_PRIORITY) {
+            t.setPriority(Thread.NORM_PRIORITY);
+        }
+        if (exceptionHandler != null) {
+            t.setUncaughtExceptionHandler(exceptionHandler);
+        }
+
+
+        return t;
+    }
+}
+
diff --git a/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/ThreadUtils.java b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/ThreadUtils.java
new file mode 100644
index 0000000..b5f833b
--- /dev/null
+++ b/HDLSDK/hdl-connect/src/main/java/com/hdl/sdk/sourceos/utils/thread/ThreadUtils.java
@@ -0,0 +1,319 @@
+package com.hdl.sdk.sourceos.utils.thread;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.util.ArrayMap;
+
+import java.util.Timer;
+import java.util.TimerTask;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.RejectedExecutionHandler;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Created by Tong on 2021/10/21.
+ */
+public class ThreadUtils {
+
+    private static final Handler uiHandler = new Handler(Looper.getMainLooper());
+
+    private static final ArrayMap<Integer, ExecutorService> mThreadPools = new ArrayMap<>();
+
+    //鍚庡彴澶勭悊绾跨▼姹�
+    private static final int IO_TYPE = 0;
+
+    //鍒嗗彂绾跨▼姹�
+    private static final int DISPENSE_TYPE = 1;
+
+    private static final Timer TIMER = new Timer();
+
+    //cpu 鏈�澶х嚎绋嬪绾抽噺
+    private static final int coreSize = Runtime.getRuntime().availableProcessors() + 1;
+    private static final int maxCoreSize = 2 * Runtime.getRuntime().availableProcessors() + 1;
+
+
+    private volatile static ThreadUtils INSTANCE = null;
+
+    private ThreadUtils() {
+    }
+
+    public static ThreadUtils getInstance() {
+        if (INSTANCE == null) {
+            synchronized (ThreadUtils.class) {
+                if (INSTANCE == null) {
+                    INSTANCE = new ThreadUtils();
+                }
+            }
+        }
+        return INSTANCE;
+    }
+
+
+    /**
+     * @return 鍗曠嚎绋嬶紝鏃犻檺闀垮害闃熷垪锛屼細鍦ㄨ皟鐢ㄧ嚎绋嬫墽琛岋紝棰戠箒鐢ㄥ埌杩欎釜绾跨▼璇存槑骞跺彂瓒呯骇澶�
+     */
+    private ExecutorService getSingleThread() {
+        if (!mThreadPools.isEmpty() && mThreadPools.containsKey(DISPENSE_TYPE)) {
+            ExecutorService thread = mThreadPools.get(DISPENSE_TYPE);
+            if (thread != null && !thread.isShutdown()) {
+                return thread;
+            }
+        }
+        final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(1, 1, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(), new RenameThreadFactory() {
+
+            @Override
+            public String getName(int poolNumber, int threadNumber) {
+                return "app_dispense_" + poolNumber + "_" + threadNumber;
+            }
+        }, new ThreadPoolExecutor.DiscardPolicy());
+
+        poolExecutor.allowCoreThreadTimeOut(true);
+
+        mThreadPools.put(DISPENSE_TYPE, poolExecutor);
+        return poolExecutor;
+    }
+
+    /**
+     * 缁存姢 cpu 鏈�澶х嚎绋嬪绾抽噺+闃熷垪1024 鐢ㄥ畬鍦ㄥ崟绾跨▼璋冪敤
+     */
+    private ExecutorService getIOThread() {
+        if (!mThreadPools.isEmpty() && mThreadPools.containsKey(IO_TYPE)) {
+            ExecutorService thread = mThreadPools.get(IO_TYPE);
+            if (thread != null && !thread.isShutdown()) {
+                return thread;
+            }
+        }
+        final ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(coreSize, coreSize, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>(1024), new RenameThreadFactory() {
+            @Override
+            public String getName(int poolNumber, int threadNumber) {
+                return "app_io_" + poolNumber + "_" + threadNumber;
+            }
+            //婊′簡锛屽氨浣跨敤澶囦唤绾跨▼姹狅紝浼歰om锛屼娇鐢╰ask浼氭崟鎶撳紓甯�
+        }, new BackgroundRunsPolicy());
+
+        poolExecutor.allowCoreThreadTimeOut(true);
+
+        mThreadPools.put(IO_TYPE, poolExecutor);
+        return poolExecutor;
+    }
+
+
+    /**
+     * 绾跨▼鏁伴噺鍥哄畾鐨勭嚎绋嬫睜
+     */
+    public static ExecutorService newFixedThreadPool(int size) {
+        if (size == 0 || coreSize < size) {
+            return Executors.newFixedThreadPool(coreSize);
+        }
+        return Executors.newFixedThreadPool(size);
+    }
+
+    /**
+     * 瀹氭椂浠诲姟绾跨▼姹�
+     */
+    public static ScheduledExecutorService newScheduledThreadPool(int size) {
+        if (size == 0 || coreSize < size) {
+            return Executors.newScheduledThreadPool(coreSize);
+        }
+        return Executors.newScheduledThreadPool(size);
+    }
+
+
+    /**
+     * 鍒囨崲鍥炰富绾跨▼
+     */
+    public static void runOnUiThread(Runnable run) {
+        if (Looper.getMainLooper() == Looper.myLooper()) {
+            try {
+                run.run();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        } else {
+            try {
+                uiHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        try {
+                            run.run();
+                        } catch (Exception e) {
+                            e.printStackTrace();
+                        }
+                    }
+                });
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+    }
+
+    /**
+     * 寤舵椂鏇存柊Ui
+     */
+    public static void runOnUiThreadDelay(Runnable run, long delayMillis) {
+        uiHandler.postDelayed(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    run.run();
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }, delayMillis);
+    }
+
+
+    /**
+     * 鍚庡彴鑰楁椂浠诲姟
+     */
+    public static void runAsyncThread(Runnable run) {
+        try {
+            getInstance().getIOThread().execute(new Runnable() {
+                @Override
+                public void run() {
+                    try {
+                        run.run();
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+                }
+            });
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    /**
+     * 鍒犻櫎鍚庡彴浠诲姟
+     */
+    public static void removeTask(Task task) {
+        if (task == null) {
+            return;
+        }
+        try {
+            task.cancel();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+
+    }
+
+
+    /**
+     * 鏈変紤鐪�
+     * 鍚庡彴鑰楁椂寤惰繜浠诲姟
+     */
+    public static void runAsyncThread(Runnable run, long time) {
+        try {
+            final TimerTask timerTask = new TimerTask() {
+                @Override
+                public void run() {
+                    try {
+                        ExecutorService thread = getInstance().getIOThread();
+                        if (!thread.isShutdown()) {
+                            thread.execute(run);
+                        }
+                    } catch (Exception e) {
+                        e.printStackTrace();
+                    }
+
+                }
+            };
+            TIMER.schedule(timerTask, time);
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+
+    }
+
+    public abstract static class Task implements ITask {
+
+        private Thread thread;
+
+        public abstract void doInBackground();
+
+        private final AtomicBoolean isCancel = new AtomicBoolean();
+
+        public Task() {
+            isCancel.set(false);
+        }
+
+        @Override
+        public void run() {
+            thread = Thread.currentThread();
+            try {
+                if (!isCancel.get()) {
+                    doInBackground();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                onError(e);
+            }
+            thread = null;
+        }
+
+        public void cancel() {
+            try {
+                isCancel.set(true);
+                if (thread != null) {
+                    thread.interrupt();
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+
+        @Override
+        public void onError(Throwable t) {
+            t.printStackTrace();
+        }
+    }
+
+
+    public interface ITask extends Runnable {
+        void onError(Throwable t);
+    }
+
+
+    public static class BackgroundRunsPolicy implements RejectedExecutionHandler {
+
+        public BackgroundRunsPolicy() {
+        }
+
+        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
+            if (!e.isShutdown()) {
+                try {
+                    backgroundRun(r);
+                } catch (Exception e1) {
+                    if (r instanceof ITask) {
+                        ((ITask) r).onError(e1);
+                    } else {
+                        throw e1;
+                    }
+
+                }
+            }
+        }
+
+        public void backgroundRun(Runnable runnable) {
+            getInstance().getSingleThread().execute(new Runnable() {
+                @Override
+                public void run() {
+                    runnable.run();
+                }
+            });
+
+        }
+    }
+
+
+}
diff --git a/HDLSDK_DEMO/app/build.gradle b/HDLSDK_DEMO/app/build.gradle
index 5f8932c..dc145bb 100644
--- a/HDLSDK_DEMO/app/build.gradle
+++ b/HDLSDK_DEMO/app/build.gradle
@@ -39,5 +39,10 @@
 
     implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.6'
 //    implementation 'com.google.code.gson:gson:2.8.8'
-    implementation files('libs\\com.hdl.sdk-v1.2.0.aar')
+    implementation files('libs\\com.hdl.sdk-v1.2.1.aar')
+
+    //浜岀淮鐮�
+    implementation 'com.google.zxing:core:3.4.1'
+    //浜嬩欢鎬荤嚎
+    implementation 'org.greenrobot:eventbus:3.2.0'
 }
\ No newline at end of file
diff --git a/HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.0.aar b/HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.1.aar
similarity index 93%
rename from HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.0.aar
rename to HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.1.aar
index 5f340dc..4f2f890 100644
--- a/HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.0.aar
+++ b/HDLSDK_DEMO/app/libs/com.hdl.sdk-v1.2.1.aar
Binary files differ
diff --git a/HDLSDK_DEMO/app/src/main/AndroidManifest.xml b/HDLSDK_DEMO/app/src/main/AndroidManifest.xml
index 16308ba..2215aa4 100644
--- a/HDLSDK_DEMO/app/src/main/AndroidManifest.xml
+++ b/HDLSDK_DEMO/app/src/main/AndroidManifest.xml
@@ -36,6 +36,11 @@
             android:exported="false"
             android:windowSoftInputMode="adjustPan|stateHidden" />
 
+        <activity
+            android:name=".SourceBindActivity"
+            android:exported="false"
+            android:windowSoftInputMode="adjustPan|stateHidden" />
+
     </application>
 
 </manifest>
\ No newline at end of file
diff --git a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/App.java b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/App.java
index 2935d87..ebc961c 100644
--- a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/App.java
+++ b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/App.java
@@ -1,13 +1,11 @@
 package com.hdl.hdlsdk;
 
 import android.app.Application;
-import android.util.Log;
 
 import com.hdl.sdk.common.HDLSdk;
-import com.hdl.sdk.common.event.EventListener;
-import com.hdl.sdk.common.utils.LogUtils;
 import com.hdl.sdk.connect.HDLLink;
-import com.hdl.sdk.connect.bean.LinkResponse;
+import com.hdl.sdk.connect.cloud.broadcast.GlobalBroadcastManager;
+import com.hdl.sdk.sourceos.OsManager;
 
 /**
  * Created by Tong on 2021/10/8.
@@ -15,6 +13,7 @@
 public class App extends Application {
 
     private String deviceStatusUpdateTopic;
+
     @Override
     public void onCreate() {
         super.onCreate();
@@ -23,6 +22,15 @@
         //鎺у埗SDK鏃ュ織鎵撳嵃
         HDLSdk.getInstance().setLogEnabled(true);
 
+        //source绯荤粺鎺ュ彛鍒濆鍖�
+        OsManager.init(this);
+
+        //appkey:ryfElI3tVOT
+        //appsecret:AKIn7s1A2YnNvAZRtL8FQxzp0R2KUpIY
+        HDLLink.getInstance().initCloud(this, "ryfElI3tVOT", "AKIn7s1A2YnNvAZRtL8FQxzp0R2KUpIY");
+
+        //娉ㄥ唽鍏ㄥ眬骞挎挱,鍒锋柊token
+        GlobalBroadcastManager.registerGlobalBroadcast(this);
     }
 
     @Override
diff --git a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/MainActivity.java b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
index 0a79a1c..5f8e69d 100644
--- a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
+++ b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/MainActivity.java
@@ -35,6 +35,7 @@
 import com.hdl.sdk.common.exception.HDLLinkException;
 import com.hdl.sdk.common.utils.IdUtils;
 import com.hdl.sdk.common.utils.LogUtils;
+import com.hdl.sdk.common.utils.SPUtils;
 import com.hdl.sdk.common.utils.gson.GsonConvert;
 import com.hdl.sdk.connect.HDLLink;
 import com.hdl.sdk.connect.bean.LinkResponse;
@@ -44,6 +45,7 @@
 import com.hdl.sdk.connect.bean.request.ListSidRequest;
 import com.hdl.sdk.connect.bean.request.ListUploadRequest;
 import com.hdl.sdk.connect.bean.response.BaseLocalResponse;
+import com.hdl.sdk.connect.bean.response.BindInfoBean;
 import com.hdl.sdk.connect.bean.response.GatewaySearchBean;
 import com.hdl.sdk.connect.bean.response.UpdateInfo;
 import com.hdl.sdk.connect.callback.HDLLinkCallBack;
@@ -51,8 +53,13 @@
 import com.hdl.sdk.connect.cloud.CallBackListener;
 import com.hdl.sdk.connect.cloud.CheckAppVersionListener;
 import com.hdl.sdk.connect.cloud.HDLException;
+import com.hdl.sdk.connect.cloud.bean.GatewayInfo;
+import com.hdl.sdk.connect.cloud.listener.GatewayListener;
+import com.hdl.sdk.connect.cloud.listener.SibichiListener;
+import com.hdl.sdk.connect.cloud.bean.AiLoginInfo;
 import com.hdl.sdk.connect.config.HDLLinkConfig;
 import com.hdl.sdk.connect.socket.HDLAuthSocket;
+import com.hdl.sdk.sourceos.utils.SPKey;
 
 import java.io.UnsupportedEncodingException;
 import java.security.MessageDigest;
@@ -79,21 +86,12 @@
     private List<SceneBean> sceneList = new ArrayList<>();
     private List<SceneDetailBean> sceneDetailList = new ArrayList<>();
     private List<SceneDetailBean> roomSceneList = new ArrayList<>();
+    private GatewayInfo gatewayInfo;
 
     void applyDeviceSecret() {
         tv.setText("寮�濮嬬敵璇疯澶囧瘑閽�...");
         responseTv.setText("");
 
-//        //姝e紡鏈嶅姟鍣�
-//        String appKey = "i8hR07jzrIS";//appkey
-//        String appSecret = "BmnJ8RWTtaVEBk24zPPF4UMwfYu0lAWU";//appsecret
-
-        //娴嬭瘯鏈嶅姟鍣�
-        String appKey = "FcRyUJlLJFF";
-        String appSecret = "wz8wn75ABidx8vXcFGUotqhwFkTaYvvJ";
-
-//        String appKey = "L2OZliZRxHc";
-//        String appSecret = "aCIWSvJDOukXfx3kivsKW11x9xdR3IbV";
         String supplier = "JINMAOYUN";//鍘傚晢
 //        String mac = "AA00000000000100";//璁惧鍞竴MAC鍦板潃
         String mac = editText.getText().toString();
@@ -103,8 +101,8 @@
             Toast.makeText(this, "mac涓嶈兘涓虹┖锛�", Toast.LENGTH_SHORT).show();
             return;
         }
-
-        HDLLink.getInstance().applyDeviceSecret(this, appKey, appSecret, supplier, mac, spk, new CallBackListener() {
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().applyDeviceSecret(supplier, mac, spk, new CallBackListener() {
             @Override
             public void onError(HDLException e) {
                 tv.setText("鐢宠澶辫触");
@@ -126,13 +124,10 @@
         tv.setText("寮�濮嬫娴嬫洿鏂�...");
         responseTv.setText("");
 
-//        //姝e紡鏈嶅姟鍣�
-        String appKey = "i8hR07jzrIS";//appkey
-        String appSecret = "BmnJ8RWTtaVEBk24zPPF4UMwfYu0lAWU";//appsecret
-
         String appCode = "1697150870315999233";//appCode
 
-        HDLLink.getInstance().checkAppVersion(this, appKey, appSecret, getAppVersionName(this), appCode, new CheckAppVersionListener() {
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().checkAppVersion(getAppVersionName(this), appCode, new CheckAppVersionListener() {
             @Override
             public void onSuccess(UpdateInfo info) {
                 tv.setText("鏈夋柊鏇存柊");
@@ -142,6 +137,60 @@
             @Override
             public void onError(HDLException e) {
                 tv.setText("妫�娴嬫洿鏂板け璐�");
+                responseTv.setText(e.getMsg());
+            }
+        });
+
+    }
+
+    void getSibichiToken() {
+        tv.setText("鑾峰彇鎬濆繀椹皌oken...");
+        responseTv.setText("");
+
+        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+        String clientId = "4ED634B5A7AD97A770A52AC00FF43805";//鎬濆繀椹癱lientId
+
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().getSibichiToken(bindInfoBean.getHomeId(), clientId, new SibichiListener() {
+            @Override
+            public void onSuccess(AiLoginInfo info) {
+                tv.setText("鎬濆繀椹皌oken");
+                responseTv.setText(info.toString());
+            }
+
+            @Override
+            public void onError(HDLException e) {
+                tv.setText("鑾峰彇鎬濆繀椹皌oken澶辫触");
+                responseTv.setText(e.getMsg());
+            }
+        });
+
+    }
+
+    void syncMainGateway() {
+        tv.setText("鑾峰彇涓荤綉鍏充俊鎭�...");
+        responseTv.setText("");
+
+        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+        if (bindInfoBean == null) {
+            Toast.makeText(this, "璇峰厛鎵爜缁戝畾浣忓畢锛�", Toast.LENGTH_SHORT).show();
+            return;
+        }
+        //璋冪敤浜戠鎺ュ彛闇�鍒濆鍖朒DLLink.getInstance().initCloud();
+        HDLLink.getInstance().syncMainGateway(bindInfoBean.getHomeId(), new GatewayListener() {
+            @Override
+            public void onSuccess(GatewayInfo info) {
+                tv.setText("鑾峰彇涓荤綉鍏充俊鎭�");
+                responseTv.setText(info.toString());
+                if (info != null) {
+                    HDLLinkConfig.getInstance().setGatewayId(info.getGatewayId());
+                    //HDLLinkConfig.getInstance().setIpAddress(info.ip);
+                }
+            }
+
+            @Override
+            public void onError(HDLException e) {
+                tv.setText("鑾峰彇涓荤綉鍏充俊鎭け璐�");
                 responseTv.setText(e.getMsg());
             }
         });
@@ -180,7 +229,7 @@
 
         selectnetwork();
         checkIfCertified();
-        initDeviceInfo();//鍒濆鍖�
+        //initDeviceInfo();//涓嶈蛋浠庢満鍏ョ綉鐨勬柟寮忎笉闇�瑕佸垵濮嬪寲
         registerAllTopicsListener();
         HDLLink.getInstance().setDeleteNetworkListener(new DeleteNetworkListener() {
             @Override
@@ -226,6 +275,9 @@
         beans.add(new DemoBean("鑾峰彇鎴块棿鍦烘櫙鍒楄〃"));
         beans.add(new DemoBean("鑾峰彇鑷姩鍖栧垪琛�"));
         beans.add(new DemoBean("饩冨姩鍖栧惎饨ょ饨�"));
+        beans.add(new DemoBean("鐢熸垚浜岀淮鐮佺粦瀹氫綇瀹�"));
+        beans.add(new DemoBean("鑾峰彇鎬濆繀椹皌oken"));
+        beans.add(new DemoBean("鑾峰彇缃戝叧淇℃伅"));
         demoAdapter = new DemoAdapter(beans);
         rv.setAdapter(demoAdapter);
 
@@ -313,6 +365,18 @@
                     case 19:
                         //饩冨姩鍖栧惎饨ょ饨�
                         editEnableLogic();
+                        break;
+                    case 20:
+                        //鐢熸垚浜岀淮鐮佺粦瀹氫綇瀹�
+                        startSourceBindActivity();
+                        break;
+                    case 21:
+                        //鑾峰彇鎬濆繀椹皌oken
+                        getSibichiToken();
+                        break;
+                    case 22:
+                        //鑾峰彇缃戝叧淇℃伅
+                        syncMainGateway();
                         break;
                 }
             }
@@ -418,6 +482,20 @@
 
     }
 
+    void initLink() {
+        //step1:鍏堢敓鎴愪簩缁寸爜锛岀敤onpro鎵爜缁戝畾浣忓畢鑾峰彇浣忓畢淇℃伅
+        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+        if (bindInfoBean != null) {
+            HDLLinkConfig.getInstance().setHomeId(bindInfoBean.getHomeId());
+            HDLLinkConfig.getInstance().setLocalSecret(bindInfoBean.getLocalSecret());
+
+        }
+        //step2锛氬啀鑾峰彇缃戝叧淇℃伅
+        if (gatewayInfo != null) {
+            HDLLinkConfig.getInstance().setGatewayId(gatewayInfo.getGatewayId());//褰撳墠涓荤綉鍏砳d
+        }
+    }
+
     /**
      * 鍏ョ綉璁よ瘉
      */
@@ -425,15 +503,9 @@
         tv.setText("寮�濮嬪叆缃戣璇�...");
         //璁よ瘉鎻愪氦鍙傛暟鍑嗗
 
-//        娴嬭瘯鏈嶅姟
-//        String spkStr = "ir.module";//浜у搧spk
-//        String macStr = "AA000000000000AF";//璁惧鍞竴MAC鍦板潃
-//        String secret = "44b360eb74b7ba64";//閫氳繃spk鍜宮ac鎻愪氦浜戠璁よ瘉鍚庡垎閰嶇殑secret
-
-//        姝e紡鏈嶅姟鍣�
+        //姝e紡鏈嶅姟鍣�
         String spkStr = "screen.mirror";//浜у搧spk
         String macStr = "f2c5d8bad48f";//璁惧鍞竴MAC鍦板潃
-//        String secret = "e186beeb7974998e";//閫氳繃spk鍜宮ac鎻愪氦浜戠璁よ瘉鍚庡垎閰嶇殑secret
 
         String mac_key = stringToMD5(stringToMD5(macStr + secret));
         String versionString = "HDL_V1.0.1";//
@@ -560,7 +632,12 @@
         tv.setText("璁惧鍔熻兘灞炴�ц鍙�");
         responseTv.setText("");
         List<String> sids = new ArrayList<>();
-        sids.add(testLightSid);
+        if (devicesList.size() != 0) {
+            sids.add(devicesList.get(0).getSid());
+        } else {
+            sids.add(testLightSid);
+        }
+
         HDLLink.getInstance().getFunctionAttribute(sids, new HDLLinkCallBack() {
             @Override
             public void onSuccess(String msg) {
@@ -582,7 +659,11 @@
         tv.setText("璇诲彇鐘舵�佷腑...");
         responseTv.setText("");
         List<String> list = new ArrayList<>();
-        list.add(testLightSid);//瑕佽鍙栬澶囩殑sid
+        if (devicesList.size() != 0) {
+            list.add(devicesList.get(0).getSid());
+        } else {
+            list.add(testLightSid);//瑕佽鍙栬澶囩殑sid
+        }
         HDLLink.getInstance().propertyRead(list, new HDLLinkCallBack() {
             @Override
             public void onSuccess(String data) {
@@ -608,7 +689,11 @@
         isOn = !isOn;
         List<DeviceControlRequest> requestList = new ArrayList<>();
         DeviceControlRequest request = new DeviceControlRequest();
-        request.setSid(testLightSid);
+        if (devicesList.size() != 0) {
+            request.setSid(devicesList.get(0).getSid());
+        } else {
+            request.setSid(testLightSid);//瑕佽鍙栬澶囩殑sid
+        }
         List<DeviceControlRequest.StatusBean> statusBeanList = new ArrayList<>();
         DeviceControlRequest.StatusBean bean = new DeviceControlRequest.StatusBean();
         bean.setKey("on_off");
@@ -905,6 +990,11 @@
         startActivity(intent);
     }
 
+    void startSourceBindActivity() {
+        Intent intent = new Intent(this, SourceBindActivity.class);
+        startActivity(intent);
+    }
+
     /**
      * TCP鍙戦�� 鍙彂涓�娆★紝涓嶇洃鍚洖澶嶏紝涓嶉噸鍙�
      */
diff --git a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java
new file mode 100644
index 0000000..6be92a1
--- /dev/null
+++ b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceBindActivity.java
@@ -0,0 +1,106 @@
+package com.hdl.hdlsdk;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.hdl.sdk.common.utils.SPUtils;
+import com.hdl.sdk.connect.bean.response.BindInfoBean;
+import com.hdl.sdk.connect.config.HDLLinkConfig;
+import com.hdl.sdk.sourceos.bind.BaseEvent;
+import com.hdl.sdk.sourceos.bind.BindAuthEvent;
+import com.hdl.sdk.sourceos.bind.BindHomeService;
+import com.hdl.sdk.sourceos.bind.EventType;
+import com.hdl.sdk.sourceos.qrcode.QRCode;
+import com.hdl.sdk.sourceos.qrcode.QrCodeView;
+import com.hdl.sdk.sourceos.utils.SPKey;
+
+import org.greenrobot.eventbus.EventBus;
+import org.greenrobot.eventbus.Subscribe;
+import org.greenrobot.eventbus.ThreadMode;
+
+public class SourceBindActivity extends AppCompatActivity {
+
+    private static final String TAG = "SourceBindActivity";
+    private QrCodeView qrcodeView;
+    private TextView responseTv;
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_source_bind);
+        registerEventBus();
+        initView();
+    }
+
+    @SuppressLint("WrongConstant")
+    private void initView() {
+        qrcodeView = findViewById(R.id.qrcode_view);
+        responseTv = findViewById(R.id.response_tv);
+        createBindQRCodeInfo();
+    }
+
+    private void createBindQRCodeInfo() {
+        final String time = String.valueOf(System.currentTimeMillis());
+        String info = QRCode.createBindQRCodeInfo(time);
+        qrcodeView.setContent(info);
+
+        //寮�濮嬭疆璇�
+        BindHomeService.getInstance().startQuery(time);
+    }
+
+    /**
+     * 缁戝畾鎴愬姛閫氱煡浜嬩欢
+     *
+     * @param event
+     */
+    @Subscribe(threadMode = ThreadMode.MAIN)
+    public void onEventMessage(BaseEvent event) {
+        switch (event.getEventType()) {
+            case EventType.ON_PLUS_BINDING_TYPE:
+                if (event instanceof BindAuthEvent) {
+                    int action = ((BindAuthEvent) event).getAction();
+                    if (action == BindAuthEvent.ON_PLUS_BINDING_SUCCEED_ACTION) {
+                        //on+缁戝畾鎴愬姛
+                        Toast.makeText(this, "缁戝畾鎴愬姛", Toast.LENGTH_SHORT).show();
+                        BindInfoBean bindInfoBean = (BindInfoBean) SPUtils.getSerializableEntity(SPKey.BIND_HOME_INFO);
+                        responseTv.setText(bindInfoBean.toString());
+
+                        if (bindInfoBean != null) {
+                            HDLLinkConfig.getInstance().setHomeId(bindInfoBean.getHomeId());
+                            HDLLinkConfig.getInstance().setLocalSecret(bindInfoBean.getLocalSecret());
+                        }
+                    } else if (action == BindAuthEvent.ON_PLUS_BINDING_TIMEOUT_ACTION) {
+                        //on+缁戝畾瓒呮椂
+                        Toast.makeText(this, "缁戝畾瓒呮椂", Toast.LENGTH_SHORT).show();
+                    } else if (action == BindAuthEvent.ON_PLUS_BINDING_ERROR_ACTION) {
+                        //缃戠粶閿欒
+                        //Toast.makeText(this, "缃戠粶寮傚父", Toast.LENGTH_SHORT).show();
+                    }
+                }
+                break;
+        }
+    }
+
+    protected void unregisterEventBus() {
+        if (EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().unregister(this);
+        }
+    }
+
+    protected void registerEventBus() {
+        if (!EventBus.getDefault().isRegistered(this)) {
+            EventBus.getDefault().register(this);
+        }
+    }
+
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        unregisterEventBus();
+        BindHomeService.getInstance().stopQuery();
+    }
+}
\ No newline at end of file
diff --git a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java
index ed08f82..4f2266a 100644
--- a/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java
+++ b/HDLSDK_DEMO/app/src/main/java/com/hdl/hdlsdk/SourceTestActivity.java
@@ -78,8 +78,6 @@
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
             ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.REBOOT, Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSION_REQUEST);
         }
-        //绯荤粺鎺ュ彛鍒濆鍖�
-        OsManager.init(SourceTestActivity.this);
 
         OsManager.addEventListener(eventListener);
 
diff --git a/HDLSDK_DEMO/app/src/main/res/layout/activity_source_bind.xml b/HDLSDK_DEMO/app/src/main/res/layout/activity_source_bind.xml
new file mode 100644
index 0000000..8454510
--- /dev/null
+++ b/HDLSDK_DEMO/app/src/main/res/layout/activity_source_bind.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    tools:context=".SourceBindActivity">
+
+    <com.hdl.sdk.sourceos.qrcode.QrCodeView
+        android:id="@+id/qrcode_view"
+        android:layout_width="125dp"
+        android:layout_height="125dp"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:layout_marginStart="28dp"
+        android:layout_marginTop="28dp"
+        android:padding="3dp" />
+
+    <TextView
+        android:id="@+id/response_tv"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="3dp"
+        android:layout_marginTop="28dp" />
+
+</LinearLayout>
\ No newline at end of file

--
Gitblit v1.8.0