Sub-devices cannot directly connect to IoT Platform. Instead, they must connect to IoT Platform through a gateway. After a sub-device connects to a gateway, the gateway queries the topological relationship with the sub-device, reports the information about the sub-device to IoT Platform, and then connects the sub-device to IoT Platform.
Prerequisites
Develop a sub-device
A sub-device does not directly connect to IoT Platform, so you do no need to install a device SDK of IoT Platform on the sub-device. The sub-device supplier develops the sub-device.
Gateway obtains the certificate of the sub-device
The gateway reports the certificate of the sub-device including the ProductKey, DeviceName, and DeviceSecret for IoT Platform to authenticate the connection. The gateway supplier implements the method how the gateway obtains the certificate. Alibaba Cloud does not provide corresponding code. The gateway obtains the certificate of the sub-device in three ways:
- The gateway obtains the certificate directly from the sub-device.
The gateway discovers a sub-device and obtains the certificate of the sub-device based on a protocol defined between the gateway and the sub-device. The gateway supplier and the sub-device supplier define this protocol.
- Preset the certificate of the sub-device on the gateway.
The gateway supplier implements the configuration method for presetting the certificate of the sub-device on the gateway. Alibaba Cloud does not provide corresponding code.
- The gateway obtains the certificate of the sub-device during dynamic registration.
- When you create a sub-device in IoT Platform, set the DeviceName parameter to the serial number or MAC address of the sub-device. Afterward, enable dynamic registration for the sub-device.
- Develop a gateway that can discover the sub-device based on a specified protocol and obtain the model and identifier such as the serial number or MAC address of the sub-device. Also, the gateway can map the sub-device model to the ProductKey in IoT Platform.
- Obtain the DeviceSecret of the sub-device from IoT Platform during dynamic registration.
Connect the sub-device to IoT Platform through the gateway
The DeviceTopoManager file in the directory java/src/main/java/com/aliyun/iot/api/common/deviceApi contains the code for the gateway to manage topological relationships and dynamically register sub-devices. In this file, you can configure the gateway and the sub-device to create a topological relationship and dynamically register the sub-device.
Appendix: Sample code
The gateway discovers and reports the sub-device, and establishes a logical channel between the sub-device and IoT Platform. Afterward, the sub-device can use the physical channel of the gateway to connect to IoT Platform. The following example shows the code for these features:
package com.aliyun.iot.api.common.openApi;
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;
import static java.awt.SystemColor.info;
public class DeviceTopoManager {
private static String regionId = "cn-shanghai";
private static final String TAG = "TOPO";
//The gateway.
private static String GWproductKey = "a1BxptK****";
private static String GWdeviceName = "XMtrv3yvftEHAzrTfX1U";
private static String GWdeviceSecret = "19xJNybifnmgcK057vYhazYK4b64****";
public static void main(String[] args) {
/**
* The information about the MQTT connection.
*/
DeviceTopoManager manager = new DeviceTopoManager();
/**
* The Java HTTP client of this device supports TSLv1.2.
*/
System.setProperty("https.protocols", "TLSv2");
manager.init();
}
public void init() {
LinkKitInitParams params = new LinkKitInitParams();
/**
* Specifies the parameters for the MQTT initialization.
*/
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.
* The cleanSession field corresponding to the MQTT connection.
*/
config.receiveOfflineMsg = false;
params.mqttClientConfig = config;
ALog.setLevel(LEVEL_DEBUG);
ALog.i(TAG, "mqtt connetcion info=" + params);
/**
* Specifies the initialization and passes in the certificate information of the specified sub-device.
*/
DeviceInfo deviceInfo = new DeviceInfo();
deviceInfo.productKey = GWproductKey;
deviceInfo.deviceName = GWdeviceName;
deviceInfo.deviceSecret = GWdeviceSecret;
params.deviceInfo = deviceInfo;
/** Establishes 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);
//Queries the topological relationships under the gateway, and checks whether a topological relationship exists between the gateway and the specified sub-device.
//Connects the sub-device to IoT Platform if the topological relationship exists.
getGWDeviceTopo();
//Dynamically registers the sub-device to obtain the deviceSecret of the sub-device, and if the gateway has obtained the certificate, skips this step and adds the topological relationship.
//When you create the sub-device in IoT Platform, set the DeviceName parameter to the serial number or MAC address of the sub-device.
gatewaySubDevicRegister();
//The information about the sub-device in the topological relationship.
gatewayAddSubDevice();
//Connects the sub-device to IoT Platform.
gatewaySubDeviceLogin();
}
});
}
/**
* Queries the topological relationships under the gateway, and checks whether a topological relationship exists between the gateway and the specified sub-device.
*/
private void getGWDeviceTopo() {
LinkKit.getInstance().getGateway().gatewayGetSubDevices(new IConnectSendListener() {
@Override
public void onResponse(ARequest request, AResponse aResponse) {
ALog.i(TAG, "The topological relationship under the gateway is queried: " + JSONObject.toJSONString(aResponse));
// Queries the sub-devices.
try {
ResponseModel<List<DeviceInfo>> response = JSONObject.parseObject(aResponse.data.toString(), new TypeReference<ResponseModel<List<DeviceInfo>>>() {
}.getType());
// Processes the request according to actual application scenarios.
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onFailure(ARequest request, AError error) {
ALog.i(TAG, "Failed to query the topological relationship under the gateway: " + JSONObject.toJSONString(error));
}
});
}
/**
* Dynamically registers the sub-device to obtain the deviceSecret of the sub-device, and if the gateway has obtained the certificate, skips this step.
* When you create the sub-device in IoT Platform, set the DeviceName parameter to the serial number or MAC address of the sub-device.
*/
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, "The sub-device is registered: " + JSONObject.toJSONString(response));
}
@Override
public void onFailure(ARequest request, AError error) {
ALog.i(TAG, "Failed to register the sub-device: " + JSONObject.toJSONString(error));
}
});
}
/**
* The information about the sub-device in the topological relationship.
*/
private void gatewayAddSubDevice() {
BaseInfo baseInfo1 = new BaseInfo();
baseInfo1.productKey = "a1j7SyR****";
baseInfo1.deviceName = "safasdf";
String deviceSecret = "7lzCJIWHmGFpZpDKbJdVucDHUz6C****";
LinkKit.getInstance().getGateway().gatewayAddSubDevice(baseInfo1, new ISubDeviceConnectListener() {
@Override
public String getSignMethod() {
// The method that you use to sign the request.
return "hmacsha1";
}
@Override
public String getSignValue() {
// Generates the signature based on the deviceSecret.
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() {
// Specifies any value as clientId.
return "id";
}
@Override
public Map<String, Object> getSignExtraData() {
return null;
}
@Override
public void onConnectResult(boolean isSuccess, ISubDeviceChannel iSubDeviceChannel, AError aError) {
// The result of the operation for adding the topological relationship between the sub-device and the gateway.
if (isSuccess) {
// Connects the sub-device to IoT Platform through the gateway after the topological relationship between the sub-device and the gateway is added.
ALog.i(TAG, "The topological relationship is added: " + JSONObject.toJSONString(iSubDeviceChannel));
} 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 = "a1j7SyR****";
baseInfo1.deviceName = "safasdf";
LinkKit.getInstance().getGateway().gatewayDeleteSubDevice(baseInfo1, new ISubDeviceRemoveListener() {
@Override
public void onSuceess() {
// The sub-device is deleted. Before you delete the sub-device, you can disconnect the sub-device from IoT Platform.
}
@Override
public void onFailed(AError aError) {
// Failed to delete the sub-device.
}
});
}
/**
* Before the sub-device is connected to IoT Platform through the gateway, make sure that you have established the topological relationship between the sub-device and the gateway. After the gateway discovers the sub-device,
* the gateway reports the sub-device to IoT Platform. After the sub-device is connected to IoT Platform, the gateway can subscribe to topics and publish 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 connected to IoT Platform through the gateway.
// Subscribes to topics, publishes messages, and deletes or disables the online sub-device.
// subDevDisable(null);
// subDevDelete(null);
}
@Override
public void onFailed(AError aError) {
ALog.d(TAG, "onFailed() called with: aError = [" + aError + "]");
}
});
}
}