更新时间:2024-12-25 GMT+08:00

Java Demo使用说明

概述

本文以Java语言为例,介绍通过MQTTS/MQTT协议接入平台,基于平台接口实现“属性上报”“订阅接收命令”等功能。

本文中使用的代码为样例代码,仅用于体验平台通信功能,如需进行商用,可以参考资源获取获取对应语言的IoT Device SDK进行集成。

前提条件

准备工作

安装IntelliJ IDEA

  1. 访问IntelliJ IDEA官网,选择合适系统的版本下载。(本文以windows 64-bit系统IntelliJ IDEA 2019.2.3 Ultimate为例)。

  2. 下载完成后,运行安装文件,根据界面提示安装。

导入代码样例

  1. 下载JAVA样例
  2. 打开IDEA开发者工具,单击“ Import Project”

  3. 选择步骤1中下载的样例,然后根据界面提示,单击“next”

  4. 完成代码导入。

建立连接

设备或网关在接入物联网平台时首先需要和平台建立连接,从而将设备或网关与平台进行关联。开发者通过传入设备信息,将设备或网关连接到物联网平台。

  1. 在建立连接之前,先修改以下参数:
    1
    2
    3
    4
    5
    //IoT平台mqtt对接地址(要替换为设备所在的平台域名地址)
    static String serverIp = "xxx.myhuaweicloud.com";
    //注册设备时获得的deviceId,密钥(要替换为自己注册的设备ID与密钥)
    static String deviceId = "722cb****************";
    static String secret = "******";
    
    • serverIp为物联网平台的设备对接地址,可参考平台对接信息获取(获取的是域名信息,可通过在cmd命令框中执行“ping 域名”,获取IP地址)。
    • deviceId和secret为设备ID和密钥,在成功注册设备后获取。
  2. 修改完1中的参数后就可使用MqttClient建立连接了。mqtt连接心跳时间的建议值是120秒,有使用限制
    1
    2
    3
    4
    5
    6
    7
    8
    9
    MqttConnectOptions options = new MqttConnectOptions();
    options.setCleanSession(false);
    options.setKeepAliveInterval(120);  //心跳时间限定为30至1200秒
    options.setConnectionTimeout(5000);
    options.setAutomaticReconnect(true);
    options.setUserName(deviceId);
    options.setPassword(getPassword().toCharArray());
    client = new MqttAsyncClient(url, getClientId(), new MemoryPersistence());
    client.setCallback(callback);
    

    1883是mqtt非安全加密接入端口,8883是mqtts安全加密接入端口(使用SSL加载证书)。

    1
    2
    3
    4
    5
    if (isSSL) {
        url = "ssl://" + serverIp + ":" + 8883; //mqtts连接
    } else {
        url = "tcp://" + serverIp + ":" + 1883; //mqtt连接
    }
    
    如果建立MQTTS连接,需要加载服务器端SSL证书,需要添加SocketFactory参数。DigiCertGlobalRootCA.jks在demo的resources目录下,是设备校验平台身份的证书,用于设备侧接入物联网平台登录鉴权使用,可以在资源获取中下载证书文件
    1
    options.setSocketFactory(getOptionSocketFactory(MqttDemo.class.getClassLoader().getResource("DigiCertGlobalRootCA.jks").getPath()));
    
  3. 调用client.connect(options, null, new IMqttActionListener())发起连接。连接时,需要向函数传入MqttConnectOptions连接参数。
    1
    client.connect(options, null, new IMqttActionListener()
    
  4. 在创建MqttConnectOptions连接参数时,调用options.setPassword()传入的密码会做一个加密。getPassword()为获取加密后的密钥。
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    public static String getPassword() {
        return sha256_mac(secret, getTimeStamp());
    }
    /* 调用sha256算法进行哈希 */
    public static String sha256_mac(String message, String tStamp) {    
        String passWord = null;
        try {        
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");        
            SecretKeySpec secret_key = new SecretKeySpec(tStamp.getBytes(), "HmacSHA256");        
            sha256_HMAC.init(secret_key);byte[] bytes = sha256_HMAC.doFinal(message.getBytes());        
            passWord = byteArrayToHexString(bytes);    
        } catch (Exception e) {
            e.printStackTrace();    
        }
        return passWord;
    
  5. 连接成功后,设备显示在线。
    图1 设备列表-设备在线

    注:如果连接失败,在onFailure函数中已实现退避重连,代码样例如下:

    @Override
    public void onFailure(IMqttToken iMqttToken, Throwable throwable) {
        System.out.println("Mqtt connect fail.");
    
        //退避重连
        int lowBound = (int) (defaultBackoff * 0.8);
        int highBound = (int) (defaultBackoff * 1.2);
        long randomBackOff = random.nextInt(highBound - lowBound);
        long backOffWithJitter = (int) (Math.pow(2.0, (double) retryTimes)) * (randomBackOff + lowBound);
        long waitTImeUntilNextRetry = (int) (minBackoff + backOffWithJitter) > maxBackoff ? maxBackoff : (minBackoff + backOffWithJitter);
        System.out.println("----  " + waitTImeUntilNextRetry);
        try {
            Thread.sleep(waitTImeUntilNextRetry);
            } catch (InterruptedException e) {
                System.out.println("sleep failed, the reason is" + e.getMessage().toString());
            }
            retryTimes++;
            MqttDemo.this.connect(true);
    }

订阅接收命令

订阅某Topic的设备才能接收broker发布的关于该Topic的消息,关于平台预置Topic可参考Topic定义。详细接口信息请参考命令下发

1
2
//订阅接收命令
client.subscribe(getCmdRequestTopic(), qosLevel, null, new IMqttActionListener();
getCmdRequestTopic()获取接收命令的Topic,向平台订阅该Topic的命令。
1
2
3
public static String getCmdRequestTopic() {
    return "$oc/devices/" + deviceId + "/sys/commands/#";
}

属性上报

属性上报是指设备主动向平台上报自己的属性,更多信息请参考设备属性上报

1
2
3
4
//上报json数据,注意serviceId要与产品模型中的定义对应
String jsonMsg = "{\"services\": [{\"service_id\": \"Temperature\",\"properties\": {\"value\": 57}},{\"service_id\": \"Battery\",\"properties\": {\"level\": 80}}]}";
MqttMessage message = new MqttMessage(jsonMsg.getBytes());
client.publish(getRreportTopic(), message, qosLevel, new IMqttActionListener();

消息体jsonMsg组装格式为JSON,其中service_id要与产品模型中的定义对应,properties是设备的属性,57为对应的属性值。event_time为可选项,为设备采集数据UTC时间,不填写默认使用系统时间。

设备或网关成功连接到物联网平台后,即可调用MqttClient.publish(String topic,MqttMessage message)向平台上报设备属性值。

getRreportTopic()即为获取上报数据的Topic。
1
2
3
public static String getRreportTopic() {
    return "$oc/devices/" + deviceId + "/sys/properties/report";
}

查看上报数据

运行main方法成功启动后,即可在设备设备详情页面查看上报的设备属性数据。详细接口信息请参考设备属性上报

图2 查看上报数据-level
图3 查看上报数据-temperature_value

如果在“设备详情”页面没有最新上报数据,请确认设备上报的服务/属性和产品模型中的服务/属性一致。

相关资源

您可以参考MQTT接口文档,把具备MQTT通信能力的设备接入物联网平台。您也可以在线开发MQTT协议的智慧路灯,快速验证是否可以与物联网平台服务交互发布或订阅消息。

由于是同步命令需要端侧回复响应可参考接口