Your device can connect to and communicate with Alibaba Cloud IoT Platform by using the bridge feature that is provided by the generic-protocol SDK. This article describes how to configure the generic-protocol SDK to implement basic features. These including device connection and disconnection, and upstream and downstream message transmission.

For more information about the generic-protocol SDK demo, visit Generic-protocol SDK demo in GitHub.

Implementation

The following figure shows the overall process to use the generic-protocol SDK to connect a device to IoT Platform.

Bridge

Deploy the development environment

Deploy the development environment to use the SDK for Java and add the following dependency to your Maven project to import the generic-protocol SDK.

<dependency>
  <groupId>com.aliyun.openservices</groupId>
  <artifactId>iot-as-bridge-sdk-core</artifactId>
  <version>2.1.3</version>
</dependency>

Initialize SDK and specify bridge information

  • Initialize the SDK.

    Create a BridgeBootstrap object and call the bootstrap() method. After the generic-protocol SDK is initialized, the SDK reads the bridge information and sends a request for the bridge to connect to IoT Platform.

    When you call the bootstrap() method, you can register the DownlinkChannelHandler callback with the generic-protocol SDK to receive downstream messages from IoT Platform.

    Sample code:

    BridgeBootstrap bridgeBootstrap = new BridgeBootstrap();
    bridgeBootstrap.bootstrap(new DownlinkChannelHandler() {
        @Override
        public boolean pushToDevice(Session session, String topic, byte[] payload) {
            //get message from cloud
            String content = new String(bytes);
            log.info("Get DownLink message, session:{}, {}, {}", session, topic, content);
            return true;
        }
    
        @Override
        public boolean broadcast(String topic, byte[] payload) {
            return false;
        }
    });
  • Specify bridge information.

    By default, a bridge is configured in a configuration file. The configuration file is the application.conf file under the default resource directory of the Java project (file path src/main/resources/). The file is in the HOCON (a JSON superset) format. The generic-protocol SDK uses typesafe.config to parse the configuration file.

    You can configure a bridge either by specifying a device or dynamically registering a device. This topic describes how to specify a device as a bridge. For more information about how to dynamically register a bridge device, see Dynamically register a bridge device.

    The following table describes the bridge parameters.

    Parameter Required Description
    productKey Yes The key of the product to which the bridge device belongs.
    deviceName No The name of the bridge device.
    • You must specify this parameter if you have registered the device and want to specify the device as the bridge device. In this case, the certificate information of the device is required.
    • You do not need to specify this parameter if you want to dynamically register a device, but have not registered the bridge device. In this case, you can use the MAC address of the bridge server as the device name.
    deviceSecret No The device secret of the bridge device.
    • You must specify this parameter if you specify a device that has been registered as the bridge. In this case, the certificate information of the device is required.
    • You do not need to specify this parameter if you dynamically register the bridge device.
    http2Endpoint Yes The endpoint of the HTTP/2 gateway. The bridge and IoT Platform establish a persistent connection over the HTTP/2 protocol.
    • For the public instance, the endpoint of the HTTP/2 gateway is in the format of https://${productKey}.iot-as-http2.${RegionId}.aliyuncs.com:443.

      Replace ${productKey} with the ProductKey of the product to which your bridge device belongs.

      Replace ${RegionId} with the ID of the region where you purchased the IoT Platform service. For more information, see Regions and zones.

      For example, if the product key of a bridge device is alabcab**** and the IoT Platform service is purchased in the China (Shanghai) region, the endpoint of the HTTP/2 gateway is https://alabcab****.iot-as-http2.cn-shanghai.aliyuncs.com:443.

    • For a purchased instance, the endpoint of the HTTP/2 gateway is in the format of https://${IotInstanceId}.http2.iothub.aliyuncs.com:443.

      Replace ${IotInstanceId} with the ID of the purchased instance.

      For example, if the instance ID is iot-cn-g06kwb****, the endpoint of the HTTP/2 gateway is https://iot-cn-g06kwb****.http2.iothub.aliyuncs.com:443.

    authEndpoint Yes The endpoint of the device authentication server.
    • For the public instance, the endpoint of the device authentication server is in the format of https://iot-auth.${RegionId}.aliyuncs.com/auth/bridge.

      Replace ${RegionId} with the ID of the region where you purchased the IoT Platform service. For more information, see Regions and zones.

      For example, if the IoT Platform service is purchased in the China (Shanghai) region, the endpoint of the device authentication server is https://iot-auth.cn-shanghai.aliyuncs.com/auth/bridge.

    • For a purchased instance, the endpoint of the device authentication server is in the format of https://${IotInstanceId}.auth.iothub.aliyuncs.com/auth/bridge.

      Replace ${IotInstanceId} with the ID of the purchased instance.

      For example, if the instance ID is iot-cn-g06kwb****, the endpoint of the device authentication server is https://iot-cn-g06kwb****.auth.iothub.aliyuncs.com/auth/bridge.

    popClientProfile No You must specify this parameter if you want to use the MAC address of the bridge server to dynamically register the bridge device.

    For more information about how to set the parameter, see Dynamically register a bridge device.

    The following example shows how to configure the certificate information of a bridge device when you are using the public instance.

    # Server endpoint
    http2Endpoint = "https://a1tN7OBmTcd.iot-as-http2.cn-shanghai.aliyuncs.com:443"
    authEndpoint = "https://iot-auth.cn-shanghai.aliyuncs.com/auth/bridge"
    
    # Gateway device info, productKey & deviceName & deviceSecret
    productKey = ${bridge-ProductKey-in-Iot-Plaform}
    deviceName = ${bridge-DeviceName-in-Iot-Plaform}
    deviceSecret = ${bridge-DeviceSecret-in-Iot-Plaform}

Authenticate a device and connect the device to IoT Platform

  • Configure device connection.

    The method that is used for device connection in the generic-protocol SDK is as follows:

    /**
     * Device authentication
     * @param newSession: the device session information that is returned in a downstream callback.
     * @param originalIdentity: the original identifier of the device.
     * @return
     */
    public boolean doOnline(Session newSession, String originalIdentity);

    When the device is connected to the bridge, it must pass the Session parameter. The Session parameter is returned to the bridge by using a callback function of a downstream message. The Session parameter contains a field that indicates the original identifier of the device. The field ensures that the bridge can identify the device that sends the messages.

    In addition, the Session parameter also contains an optional channel field. The field can cotain the information of the device connection. For example, your bridge server is built based on Netty. You can use this field to carry the channel object that corresponds to the persistent connection of the device. When a message is received from IoT Platform, the bridge can directly obtain the channel object from the Session parameter for subsequent use. The data type of the channel field is object. The generic-protocol SDK does not process the data of the channel field. You can also use the channel field to carry the device-related information.

    Sample code:

    UplinkChannelHandler uplinkHandler = new UplinkChannelHandler();
    //Create a session.
    Object channel = new Object();
    Session session = Session.newInstance(originalIdentity, channel);
    //Connect a device to the bridge.
    boolean success = uplinkHandler.doOnline(session, originalIdentity);
    if (success) {
        //If the device is connected, the bridge accepts subsequent communication requests from the device.
    } else {
        //If the device connection fails, the bridge rejects subsequent communication requests, such as disconnection requests.
    }
  • Map an original device identifier to a device certificate.

    You must configure the mapping between device certificates and original device identifiers. By default, the mapping is configured in a configuration file. The configuration file is the devices.conf file under the default resource directory of the Java project (src/main/resources/ in most cases). The file is in the HOCON (JSON superset) format. The generic protocol SDK uses the typesafe.config file to parse the configuration file.

    Configure the device certificate information in the following format:

    ${device-originalIdentity} {
      productKey : ${device-ProductKey-in-Iot-Plaform}
      deviceName : ${device-DeviceName-in-Iot-Platform}
      deviceSecret : ${device-DeviceSceret-in-Iot-Platform}
    }
    Parameter Required Description
    productKey Yes The key of the product to which the device belongs.
    deviceName Yes The name of the device.
    deviceSecret Yes The secret of the device.

Send data from a device to IoT Platform

The method that is used to send data from a device to IoT Platform in the generic-protocol SDK is as follows:

/**
 * Send messages from the device by synchronously calling the method.
 * @param originalIdentity: the original identifier of the device.
 * @param protocolMsg: the message to be sent, including the topic, payload, and Quality of Service (QoS) information.
 * @param timeout: the timeout period, in seconds
 * @return: indicates whether the message is sent within the timeout period.
 */
boolean doPublish(String originalIdentity, ProtocolMessage protocolMsg, int timeout);
/**
 * Send messages from the device by asynchronously calling the method.
 * @param originalIdentity: the original identifier of the device.
 * @param protocolMsg: the message to be sent, including the topic, payload, and QoS information.
 * @return: After this method is called, CompletableFuture is immediately returned. The caller can further process this CompletableFuture.
 */
CompletableFuture<ProtocolMessage> doPublishAsync(String originalIdentity, 
                                                  ProtocolMessage protocolMsg);

Sample code:

DeviceIdentity deviceIdentity = 
    ConfigFactory.getDeviceConfigManager().getDeviceIdentity(originalIdentity);
ProtocolMessage protocolMessage = new ProtocolMessage();
protocolMessage.setPayload("Hello world".getBytes());
protocolMessage.setQos(0);
protocolMessage.setTopic(String.format("/%s/%s/update", 
        deviceIdentity.getProductKey(), deviceIdentity.getDeviceName()));
//Synchronous sending.
int timeoutSeconds = 3;
boolean success = upLinkHandler.doPublish(originalIdentity, protocolMessage, timeoutSeconds);
//Asynchronous sending.
upLinkHandler.doPublishAsync(originalIdentity, protocolMessage);

Push data from the bridge to devices

When the bridge calls the bootstrap() method, it registers DownlinkChannelHandler with the generic-protocol SDK. When the generic-protocol SDK receives a downstream message, it calls the pushToDevice() method in DownlinkChannelHandler() method. You can modify the pushToDevice() method to enable the bridge to process downstream messages.

Note Do not implement a time-consuming logic in the pushToDevice method. Otherwise, the thread that receives downstream messages will be blocked. If a time-consuming logic or I/O logic is required (for example, a logic to use a persistent connection to forward downstream messages to a device), implement it asynchronously.

Sample code:

private static ExecutorService executorService  = new ThreadPoolExecutor(
    Runtime.getRuntime().availableProcessors(),
    Runtime.getRuntime().availableProcessors() * 2,
    60, TimeUnit.SECONDS,
    new LinkedBlockingQueue<>(1000),
    new ThreadFactoryBuilder().setDaemon(true).setNameFormat("bridge-downlink-handle-%d").build(),
    new ThreadPoolExecutor.AbortPolicy());
public static void main(String args[]) {
    //Use application.conf & devices.conf by default
    bridgeBootstrap = new BridgeBootstrap();
    bridgeBootstrap.bootstrap(new DownlinkChannelHandler() {
        @Override
        public boolean pushToDevice(Session session, String topic, byte[] payload) {
            //get message from cloud
            //get downlink message from cloud
            executorService.submit(() -> handleDownLinkMessage(session, topic, payload));
            return true;
        }
        @Override
        public boolean broadcast(String s, byte[] bytes) {
            return false;
        }
    });
}
private static void handleDownLinkMessage(Session session, String topic, byte[] payload) {
    String content = new String(payload);
    log.info("Get DownLink message, session:{}, topic:{}, content:{}", session, topic, content);
    Object channel = session.getChannel();
    String originalIdentity = session.getOriginalIdentity();
    //for example, you can send the message to device via channel, it depends on you specific server implementation
}
Parameter Description
Session A session that is received from a device when the device is connecting to the bridge. A session is used to identify the device to which the downstream message is sent.
topic The topic of the downstream message.
payload

The payload of the downstream message in the binary format.

Disconnect device

A device is disconnected in the following scenarios:

  • When the bridge is disconnected from IoT Platform, all devices that are connected to the bridge are automatically disconnected from IoT Platform.
  • The bridge sends IoT Platform a request to disconnect a device from IoT Platform.

    The method that is used to send a disconnection request is as follows:

    /**
     * Send IoT Platform a request to disconnect a device from IoT Platform.
     * @param originalIdentity: the original identifier of the device
     * @return: indicates whether the disconnection request is sent
     */
    boolean doOffline(String originalIdentity);

    Sample code:

    upLinkHandler.doOffline(originalIdentity);