All Products
Search
Document Center

IoT Platform:Connect a sub-device to IoT Platform

Last Updated:Jun 20, 2026

A sub-device does not connect to IoT Platform directly. Instead, it connects through a gateway. After a sub-device connects to a gateway, the gateway queries the topological relationship, reports the sub-device's information to IoT Platform, and then proxies the sub-device's connection to IoT Platform.

Prerequisites

Ensure you have completed the following:

Background

  • Develop a sub-device

    Because a sub-device does not connect to IoT Platform directly, you do not need to install the IoT Platform device SDK on it. The sub-device's manufacturer develops its device-side software.

  • This demo

    The DeviceTopoManager file in the java/src/main/java/com/aliyun/iot/api/common/deviceApi directory contains the code for managing topological relationships, retrieving sub-device certificates, and logging in a sub-device.

Step 1: Manage the topological relationship

After the gateway connects to IoT Platform, it must synchronize the topological relationship with IoT Platform. This allows the gateway to proxy communication between the sub-device and IoT Platform. You can view and add the topological relationship on the console or by using the sample code.

  • On the IoT Platform console, under the corresponding , view and add the topological relationship between the gateway and the sub-device.
    1. In the left-side navigation pane, choose Device Management > Devices, and find the gateway device in the list.
    2. Click Sub-device in the gateway's row to go to the sub-device management page. View the information about the gateway's sub-devices.
    3. Click Add Sub-device to add the sub-device that you created in the Create a gateway and a sub-device step.
  • Use the following sample code to query and add the topological relationship.
    • Query the topological relationship:

           /**
           * Get the topological relationship for the gateway to check if one already exists between the gateway and a sub-device.
           */
          private void getGWDeviceTopo() {
              LinkKit.getInstance().getGateway().gatewayGetSubDevices(new IConnectSendListener() {
                  @Override
                  public void onResponse(ARequest request, AResponse aResponse) {
                      ALog.i(TAG, "Successfully retrieved the topological relationship for the gateway: " + JSONObject.toJSONString(aResponse));
                      // Get the list of sub-devices.
                      try {
                          ResponseModel<List<DeviceInfo>> response = JSONObject.parseObject(aResponse.data.toString(), new TypeReference<ResponseModel<List<DeviceInfo>>>() {
                          }.getType());
                          // TODO: Process the data based on your business scenario.
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
                  }
                  @Override
                  public void onFailure(ARequest request, AError error) {
                      ALog.i(TAG, "Failed to retrieve the topological relationship for the gateway: " + JSONObject.toJSONString(error));
                  }
              });
          }
    • Add a topological relationship:
      Note
      • The next step explains how to obtain the device certificate for a sub-device.
      • After IoT Platform confirms the topological relationship between the sub-device and the gateway, the sub-device can go online and reuse the gateway's physical channel to communicate with IoT Platform.
          /**
           * Information about the sub-device for which to add the topological relationship.
           */
          private void gatewayAddSubDevice() {
              BaseInfo baseInfo1 = new BaseInfo();
              baseInfo1.productKey = "a1j7SyR****";
              baseInfo1.deviceName = "safa***";
              String deviceSecret = "7lzCJIWHmGFpZpDKbJdVucDHUz6C****";
              LinkKit.getInstance().getGateway().gatewayAddSubDevice(baseInfo1, new ISubDeviceConnectListener() {
                  @Override
                  public String getSignMethod() {
                      // The signing method to use.
                      return "hmacsha1";
                  }
                  @Override
                  public String getSignValue() {
                      // Get the signature. The user uses the deviceSecret to generate the signature.
                      Map<String, String> signMap = new HashMap<>();
                      signMap.put("productKey", baseInfo1.productKey);
                      signMap.put("deviceName", baseInfo1.deviceName);
                      //signMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
                      signMap.put("clientId", getClientId());
                      return SignUtils.hmacSign(signMap, deviceSecret);
                  }
                  @Override
                  public String getClientId() {
                      // The clientId can be any string.
                      return "id";
                  }
                  @Override
                  public Map<String, Object> getSignExtraData() {
                      return null;
                  }
                  @Override
                  public void onConnectResult(boolean isSuccess, ISubDeviceChannel iSubDeviceChannel, AError aError) {
                      // Result of the add operation.
                      if (isSuccess) {
                          // The sub-device is added. You can now proceed to log in the sub-device.
                          ALog.i(TAG, "Successfully added the topological relationship: " + JSONObject.toJSONString(iSubDeviceChannel));
                          //Log in the sub-device.
                          gatewaySubDeviceLogin();
                      } else {
                          ALog.i(TAG, "Failed to add the topological relationship: " + JSONObject.toJSONString(aError));
                      }
                  }
                  @Override
                  public void onDataPush(String s, AMessage aMessage) {
                  }
              });
          }

Step 2: Obtain sub-device certificate

After a sub-device is created, IoT Platform issues a device certificate for it. The gateway can obtain the device certificate for the sub-device by using one of the following methods.
  • Use unique-certificate-per-device authentication.

    After the sub-device is created, obtain its ProductKey, DeviceName, and DeviceSecret from the device details page on the console.

    • Define a protocol between the gateway and the sub-device that allows the gateway to discover the sub-device and obtain its device certificate. The gateway and sub-device manufacturers define this protocol.
    • Alternatively, the gateway manufacturer can provide a method to preconfigure the sub-device's certificate information on the gateway.
  • Use dynamic registration for the sub-device.

    The gateway registers the sub-device by reporting its ProductKey and DeviceName to IoT Platform. After IoT Platform validates the ProductKey and DeviceName, it dynamically issues a DeviceSecret for the sub-device.

    1. When you create a sub-device, use its serial number (SN) or MAC address as the DeviceName. After the sub-device is created, enable dynamic registration for the product.
      On the IoT Platform console, go to the Product Details page for the corresponding product and enable Dynamic Registration.
    2. When you develop the gateway, implement a protocol that allows the gateway to discover sub-devices and retrieve their model and unique identifier (SN or MAC address). You must also map the sub-device model to a ProductKey in Alibaba Cloud IoT Platform.
    3. Use the dynamic registration feature of IoT Platform to obtain the DeviceSecret for the sub-device.

    Sample code:

         /**
         * Use dynamic registration to obtain the deviceSecret for a sub-device.
         * When you create a sub-device on IoT Platform in advance, you can use its MAC address or serial number (SN) as the DeviceName.
         */
        private void gatewaySubDevicRegister() {
            List<BaseInfo> subDevices = new ArrayList<>();
            BaseInfo baseInfo1 = new BaseInfo();
            baseInfo1.productKey = "a1j7SyR***";
            baseInfo1.deviceName = "safasdf";
            subDevices.add(baseInfo1);
            LinkKit.getInstance().getGateway().gatewaySubDevicRegister(subDevices, new IConnectSendListener() {
                @Override
                public void onResponse(ARequest request, AResponse response) {
                    ALog.i(TAG, "Sub-device registered successfully: " + JSONObject.toJSONString(response));
                }
                @Override
                public void onFailure(ARequest request, AError error) {
                    ALog.i(TAG, "Failed to register the sub-device: " + JSONObject.toJSONString(error));
                }
            });
        }

    For more information about dynamic device registration, see Dynamic registration of sub-devices.

Step 3: Log in a sub-device

     /**
     * Before you call the API to log in the sub-device, make sure the topological relationship is established. After the gateway discovers a connected sub-device, it must notify IoT Platform that the sub-device is online.
     * After the sub-device is online, you can perform operations such as subscribing to topics and publishing messages.
     */
    public void gatewaySubDeviceLogin(){
        BaseInfo baseInfo1 = new BaseInfo();
        baseInfo1.productKey = "a1j7SyR****";
        baseInfo1.deviceName = "safasdf";
        LinkKit.getInstance().getGateway().gatewaySubDeviceLogin(baseInfo1, new ISubDeviceActionListener() {
            @Override
            public void onSuccess() {
                // The sub-device is logged in by proxy.
                // After the sub-device is online, you can subscribe to topics, publish messages, and delete or disable the sub-device.
                // subDevDisable(null);
                // subDevDelete(null);
            }
            @Override
            public void onFailed(AError aError) {
                ALog.d(TAG, "onFailed() called with: aError = [" + aError + "]");
            }
        });
    }
}

Appendix: Code demo

The following code demonstrates how a gateway discovers and reports sub-device information, establishes a logical channel between the sub-device and IoT Platform, and allows the sub-device to reuse the gateway's physical channel to connect to IoT Platform:

package com.aliyun.iot.api.common.deviceApi;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.aliyun.alink.dm.api.BaseInfo;
import com.aliyun.alink.dm.api.DeviceInfo;
import com.aliyun.alink.dm.api.InitResult;
import com.aliyun.alink.dm.api.SignUtils;
import com.aliyun.alink.dm.model.ResponseModel;
import com.aliyun.alink.linkkit.api.ILinkKitConnectListener;
import com.aliyun.alink.linkkit.api.IoTMqttClientConfig;
import com.aliyun.alink.linkkit.api.LinkKit;
import com.aliyun.alink.linkkit.api.LinkKitInitParams;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceActionListener;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceChannel;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceConnectListener;
import com.aliyun.alink.linksdk.channel.gateway.api.subdevice.ISubDeviceRemoveListener;
import com.aliyun.alink.linksdk.cmp.core.base.AMessage;
import com.aliyun.alink.linksdk.cmp.core.base.ARequest;
import com.aliyun.alink.linksdk.cmp.core.base.AResponse;
import com.aliyun.alink.linksdk.cmp.core.listener.IConnectSendListener;
import com.aliyun.alink.linksdk.tools.AError;
import com.aliyun.alink.linksdk.tools.ALog;
import java.util.*;
import static com.aliyun.alink.linksdk.tools.ALog.LEVEL_DEBUG;
public class DeviceTopoManager {
    private static String regionId = "cn-shanghai";
    private static final String TAG = "TOPO";
    // Gateway device
    private static String GWproductKey = "a1Bxp*********";
    private static String GWdeviceName = "XMtrv3y*************";
    private static String GWdeviceSecret = "19xJNybifnmgc*************";
    public static void main(String[] args) {
        /**
         * MQTT connection information.
         */
        DeviceTopoManager manager = new DeviceTopoManager();
        /**
         * The server-side Java HTTP client uses TLSv1.2.
         */
        System.setProperty("https.protocols", "TLSv1.2");
        manager.init();
    }
    public void init() {
        LinkKitInitParams params = new LinkKitInitParams();
        /**
         * Set MQTT initialization parameters.
         */
        IoTMqttClientConfig config = new IoTMqttClientConfig();
        config.productKey = GWproductKey;
        config.deviceName = GWdeviceName;
        config.deviceSecret = GWdeviceSecret;
        config.channelHost = GWproductKey + ".iot-as-mqtt." + regionId + ".aliyuncs.com:1883";
        /**
         * Specifies whether to receive offline messages.
         * This corresponds to the cleanSession field in MQTT.
         */
        config.receiveOfflineMsg = false;
        params.mqttClientConfig = config;
        ALog.setLevel(LEVEL_DEBUG);
        ALog.i(TAG, "mqtt connection info=" + params);
        /**
         * Set initialization parameters and pass in the device certificate of the gateway.
         */
        DeviceInfo deviceInfo = new DeviceInfo();
        deviceInfo.productKey = GWproductKey;
        deviceInfo.deviceName = GWdeviceName;
        deviceInfo.deviceSecret = GWdeviceSecret;
        params.deviceInfo = deviceInfo;
        /**Initialize the LinkKit instance and establish a connection.**/
        LinkKit.getInstance().init(params, new ILinkKitConnectListener() {
            public void onError(AError aError) {
                ALog.e(TAG, "Init Error error=" + aError);
            }
            public void onInitDone(InitResult initResult) {
                ALog.i(TAG, "onInitDone result=" + initResult);
                // Get the topological relationship for the gateway to check if one already exists between the gateway and the sub-device.
                // If a relationship exists, log in the sub-device directly.
                getGWDeviceTopo();
                // Use dynamic registration to obtain the DeviceSecret for the sub-device. If the device certificate is known, skip this step and add the topological relationship directly.
                // When you create the device on IoT Platform in advance, you can use its MAC address or serial number (SN) as the DeviceName.
                gatewaySubDevicRegister();
                // Information about the sub-device for which to add the topological relationship.
                gatewayAddSubDevice();
            }
        });
    }
    /**
     * Get the topological relationship for the gateway to check if one already exists between the gateway and a sub-device.
     */
    private void getGWDeviceTopo() {
        LinkKit.getInstance().getGateway().gatewayGetSubDevices(new IConnectSendListener() {
            @Override
            public void onResponse(ARequest request, AResponse aResponse) {
                ALog.i(TAG, "Successfully retrieved the topological relationship for the gateway: " + JSONObject.toJSONString(aResponse));
                // Get the list of sub-devices.
                try {
                    ResponseModel<List<DeviceInfo>> response = JSONObject.parseObject(aResponse.data.toString(), new TypeReference<ResponseModel<List<DeviceInfo>>>() {
                    }.getType());
                    // TODO: Process the data based on your business scenario.
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            @Override
            public void onFailure(ARequest request, AError error) {
                ALog.i(TAG, "Failed to retrieve the topological relationship for the gateway: " + JSONObject.toJSONString(error));
            }
        });
    }
    /**
     * Use dynamic registration to obtain the deviceSecret for a sub-device. If the gateway has already obtained the device certificate for the sub-device, skip this step.
     * When you create the device on IoT Platform in advance, you can use its MAC address or serial number (SN) as the DeviceName.
     */
    private void gatewaySubDevicRegister() {
        List<BaseInfo> subDevices = new ArrayList<>();
        BaseInfo baseInfo1 = new BaseInfo();
        baseInfo1.productKey = "a1j7SyR**********";
        baseInfo1.deviceName = "test123*********";
        subDevices.add(baseInfo1);
        LinkKit.getInstance().getGateway().gatewaySubDevicRegister(subDevices, new IConnectSendListener() {
            @Override
            public void onResponse(ARequest request, AResponse response) {
                ALog.i(TAG, "Sub-device registered successfully: " + JSONObject.toJSONString(response));
            }
            @Override
            public void onFailure(ARequest request, AError error) {
                ALog.i(TAG, "Failed to register the sub-device: " + JSONObject.toJSONString(error));
            }
        });
    }
    /**
     * Adds the topological relationship for a sub-device.
     */
    private void gatewayAddSubDevice() {
        BaseInfo baseInfo1 = new BaseInfo();
        baseInfo1.productKey = "a1j7Sy*************";
        baseInfo1.deviceName = "safasd********";
        String deviceSecret = "7lzCJIWHmGF**************";
        LinkKit.getInstance().getGateway().gatewayAddSubDevice(baseInfo1, new ISubDeviceConnectListener() {
            @Override
            public String getSignMethod() {
                // The signing method to use.
                return "hmacsha1";
            }
            @Override
            public String getSignValue() {
                // Get the signature. The user uses the DeviceSecret to generate the signature.
                Map<String, String> signMap = new HashMap<>();
                signMap.put("productKey", baseInfo1.productKey);
                signMap.put("deviceName", baseInfo1.deviceName);
//                signMap.put("timestamp", String.valueOf(System.currentTimeMillis()));
                signMap.put("clientId", getClientId());
                return SignUtils.hmacSign(signMap, deviceSecret);
            }
            @Override
            public String getClientId() {
                // The clientId can be any string.
                return "id";
            }
            @Override
            public Map<String, Object> getSignExtraData() {
                return null;
            }
            @Override
            public void onConnectResult(boolean isSuccess, ISubDeviceChannel iSubDeviceChannel, AError aError) {
                // Result of the add operation.
                if (isSuccess) {
                    // The sub-device is added. You can now proceed to log in the sub-device.
                    ALog.i(TAG, "Successfully added the topological relationship: " + JSONObject.toJSONString(iSubDeviceChannel));
                    //Log in the sub-device.
                    gatewaySubDeviceLogin();
                } else {
                    ALog.i(TAG, "Failed to add the topological relationship: " + JSONObject.toJSONString(aError));
                }
            }
            @Override
            public void onDataPush(String s, AMessage aMessage) {
            }
        });
    }
    public void  gatewayDeleteSubDevice(){
        BaseInfo baseInfo1 = new BaseInfo();
        baseInfo1.productKey = "a1j7S**************";
        baseInfo1.deviceName = "saf*********";
        LinkKit.getInstance().getGateway().gatewayDeleteSubDevice(baseInfo1, new ISubDeviceRemoveListener() {
            @Override
            public void onSuccess() {
                // The listener is called when the sub-device is successfully deleted. You can take the sub-device offline before deleting it.
            }
            @Override
            public void onFailed(AError aError) {
                // Failed to delete the sub-device.
            }
        });
    }
    /**
     * Before you call the API to log in the sub-device, make sure the topological relationship is established. After the gateway discovers a connected sub-device, it must notify IoT Platform that the sub-device is online.
     * After the sub-device is online, you can perform operations such as subscribing to topics and publishing messages.
     */
    public void gatewaySubDeviceLogin(){
        BaseInfo baseInfo1 = new BaseInfo();
        baseInfo1.productKey = "a1j7SyR***********";
        baseInfo1.deviceName = "safa*********";
        LinkKit.getInstance().getGateway().gatewaySubDeviceLogin(baseInfo1, new ISubDeviceActionListener() {
            @Override
            public void onSuccess() {
                // The sub-device is logged in by proxy.
                // After the sub-device is online, you can subscribe to topics, publish messages, and delete or disable the sub-device.
                // subDevDisable(null);
                // subDevDelete(null);
            }
            @Override
            public void onFailed(AError aError) {
                ALog.d(TAG, "onFailed() called with: aError = [" + aError + "]");
            }
        });
    }
}