Un sous-appareil ne se connecte pas directement à IoT Platform, mais via une passerelle. Une fois connecté à la passerelle, celle-ci interroge la relation topologique, signale les informations du sous-appareil à IoT Platform, puis relaie sa connexion à la plateforme.
Prérequis
Assurez-vous d'avoir effectué les opérations suivantes :
Contexte
-
Développement d'un sous-appareil
Comme un sous-appareil ne se connecte pas directement à IoT Platform, il n'est pas nécessaire d'y installer le SDK d'appareil IoT Platform. Le fabricant du sous-appareil développe son propre logiciel côté appareil.
-
Cette démonstration
Le fichier DeviceTopoManager situé dans le répertoire java/src/main/java/com/aliyun/iot/api/common/deviceApi contient le code permettant de gérer les relations topologiques, de récupérer les certificats des sous-appareils et de connecter un sous-appareil.
Étape 1 : Gérer la relation topologique
Une fois la passerelle connectée à IoT Platform, elle doit synchroniser la relation topologique avec la plateforme. Cela lui permet de relayer la communication entre le sous-appareil et IoT Platform. Vous pouvez consulter et ajouter la relation topologique via la console ou à l'aide de l'exemple de code.
-
Dans la console IoT Platform, sous l'
instance
correspondante, consultez et ajoutez la relation topologique entre la passerelle et le sous-appareil.
Dans le volet de navigation de gauche, choisissez , puis repérez l'appareil passerelle dans la liste.
Cliquez sur Sub-device dans la ligne correspondant à la passerelle pour accéder à la page de gestion des sous-appareils. Consultez les informations relatives aux sous-appareils de la passerelle.
Cliquez sur Add Sub-device pour ajouter le sous-appareil créé lors de l'étape Créer une passerelle et un sous-appareil.
-
Utilisez l'exemple de code suivant pour interroger et ajouter la relation topologique.
-
Interroger la relation topologique :
/** * 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)); } }); } -
Ajouter une relation topologique :
RemarqueL'étape suivante explique comment obtenir le certificat d'appareil pour un sous-appareil.
Une fois qu'IoT Platform a confirmé la relation topologique entre le sous-appareil et la passerelle, le sous-appareil peut se mettre en ligne et réutiliser le canal physique de la passerelle pour communiquer avec 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) { } }); }
-
Étape 2 : Obtenir le certificat du sous-appareil
Une fois un sous-appareil créé, IoT Platform émet un certificat d'appareil pour celui-ci. La passerelle peut obtenir ce certificat par l'une des méthodes suivantes.
-
Utiliser l'authentification par certificat unique par appareil.
Après la création du sous-appareil, récupérez sa ProductKey, DeviceName et DeviceSecret depuis la page des détails de l'appareil dans la console.
Définissez un protocole entre la passerelle et le sous-appareil permettant à la passerelle de découvrir le sous-appareil et d'obtenir son certificat d'appareil. Ce protocole est défini par les fabricants de la passerelle et du sous-appareil.
Alternativement, le fabricant de la passerelle peut fournir une méthode pour préconfigurer les informations de certificat du sous-appareil sur la passerelle.
-
Utiliser l'enregistrement dynamique pour le sous-appareil.
La passerelle enregistre le sous-appareil en signalant sa ProductKey et sa DeviceName à IoT Platform. Après validation de la ProductKey et de la DeviceName par IoT Platform, un DeviceSecret est émis dynamiquement pour le sous-appareil.
-
Lors de la création d'un sous-appareil, utilisez son numéro de série (SN) ou son adresse MAC comme DeviceName. Une fois le sous-appareil créé, activez l'enregistrement dynamique pour le produit.
Dans la console IoT Platform, accédez à la page des détails du produit correspondant et activez l'option Dynamic Registration.
Lors du développement de la passerelle, implémentez un protocole permettant à la passerelle de découvrir les sous-appareils et de récupérer leur modèle ainsi que leur identifiant unique (SN ou adresse MAC). Vous devez également mapper le modèle du sous-appareil à une ProductKey dans Alibaba Cloud IoT Platform.
Utilisez la fonctionnalité d'enregistrement dynamique d'IoT Platform pour obtenir le DeviceSecret du sous-appareil.
Exemple de 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)); } }); }Pour plus d'informations sur l'enregistrement dynamique des appareils, consultez la rubrique Enregistrement dynamique des sous-appareils.
-
Étape 3 : Connecter un sous-appareil
/**
* 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 + "]");
}
});
}
}
Annexe : Démonstration de code
Le code suivant illustre comment une passerelle découvre et signale les informations des sous-appareils, établit un canal logique entre le sous-appareil et IoT Platform, et permet au sous-appareil de réutiliser le canal physique de la passerelle pour se connecter à 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 + "]");
}
});
}
}