/huaweicloud-iot-device-sdk-java

Primary LanguageJavaBSD 3-Clause "New" or "Revised" LicenseBSD-3-Clause

huaweicloud-iot-device-sdk-java

huaweicloud-iot-device-sdk-java提供设备接入华为云IoT物联网平台的Java版本的SDK,提供设备和平台之间通讯能力,以及设备服务、网关服务、OTA等高级服务,并且针对各种场景提供了丰富的demo代码。IoT设备开发者使用SDK可以大大简化开发复杂度,快速的接入平台。

支持特性

  • 支持设备消息、属性上报、属性读写、命令下发
  • 支持网关服务、子设备管理、子设备消息转发
  • 支持设备OTA服务
  • 支持面向物模型编程
  • 提供设备代码生成器根据产品模型自动生成设备代码
  • 支持密码认证和证书认证两种设备认证方式
  • 支持自定义topic

如何使用

依赖的版本:

  • JDK :1.8 +

设备初始化

创建设备并初始化

        IoTDevice device = new IoTDevice("ssl://iot-mqtts.cn-north-4.myhuaweicloud.com:8883",
                "5e06bfee334dd4f33759f5b3_demo", "mysecret", file);
        if (device.init() != 0) {
            return;
        }

上报消息

上报设备消息:

       device.getClient().reportDeviceMessage(new DeviceMessage("hello"), new ActionListener() {
        @Override
        public void onSuccess(Object context) {
            log.info("reportDeviceMessage success: ");
        }

        @Override
        public void onFailure(Object context, Throwable var2) {
            log.error("reportDeviceMessage fail: "+var2);
        }
    });

上报自定义topic消息(注意需要先在平台配置自定义topic):

		String topic = "$oc/devices/"+  device.getDeviceId() + "/user/wpy";
		device.getClient().publishRawMessage(new RawMessage(topic, "hello raw message "),
				new ActionListener() {
					@Override
					public void onSuccess(Object context) {
						log.info("publishRawMessage ok: ");
					}

					@Override
					public void onFailure(Object context, Throwable var2) {
						log.error("publishRawMessage fail: " + var2);
					}
				});

完整代码参见MessageSample.java

上报设备属性

     Map<String ,Object> json = new HashMap<>();
     Random rand = new Random();

     //按照物模型设置属性
     json.put("alarm", alarm);
     json.put("temperature", rand.nextFloat()*100.0f);
     json.put("humidity", rand.nextFloat()*100.0f);
     json.put("smokeConcentration", rand.nextFloat() * 100.0f);

     ServiceProperty serviceProperty = new ServiceProperty();
     serviceProperty.setProperties(json);
     serviceProperty.setServiceId("smokeDetector");//serviceId要和物模型一致

     device.getClient().reportProperties(Arrays.asList(serviceProperty), new ActionListener() {
         @Override
         public void onSuccess(Object context) {
             log.info("reportProperties success" );
         }

         @Override
         public void onFailure(Object context, Throwable var2) {
             log.error("reportProperties failed" + var2.toString());
         }   });

完整代码参见PropertySample.java

上报子设备属性

     Map<String ,Object> json = new HashMap<>();
     Random rand = new Random();
     String subdeviceId = "xxxxx";

     //按照物模型设置属性
     json.put("alarm", alarm);
     json.put("temperature", rand.nextFloat()*100.0f);
     json.put("humidity", rand.nextFloat()*100.0f);
     json.put("smokeConcentration", rand.nextFloat() * 100.0f);

     ServiceProperty serviceProperty = new ServiceProperty();
     serviceProperty.setProperties(json);
     serviceProperty.setServiceId("smokeDetector");//serviceId要和物模型一致

     device.getClient().reportProperties(subdeviceId, Arrays.asList(serviceProperty), new ActionListener() {
         @Override
         public void onSuccess(Object context) {
             log.info("reportProperties success" );
         }

         @Override
         public void onFailure(Object context, Throwable var2) {
             log.error("reportProperties failed" + var2.toString());
         }   });

处理平台下发的属性读写

    device.getClient().setPropertyListener(new PropertyListener() {

    //处理写属性
    @Override
    public void onPropertiesSet(String requestId, List<ServiceProperty> services) {

        //遍历service
        for (ServiceProperty serviceProperty: services){

            log.info("OnPropertiesSet, serviceId =  " + serviceProperty.getServiceId());

            //遍历属性
            for (String name :serviceProperty.getProperties().keySet()){
                log.info("property name = "+ name);
                log.info("set property value = "+ serviceProperty.getProperties().get(name));
                if (name.equals("alarm")){
                    //修改本地值
                    alarm = (Integer) serviceProperty.getProperties().get(name);
                }
            }

        }
        //修改本地的属性值
        device.getClient().respondPropsSet(requestId, IotResult.SUCCESS);
    }

    //处理读属性
    @Override
    public void onPropertiesGet(String requestId, String serviceId) {

        log.info("OnPropertiesGet " + serviceId);
        Map<String ,Object> json = new HashMap<>();
        Random rand = new Random();
        json.put("alarm", alarm);
        json.put("temperature", rand.nextFloat()*100.0f);
        json.put("humidity", rand.nextFloat()*100.0f);
        json.put("smokeConcentration", rand.nextFloat() * 100.0f);

        ServiceProperty serviceProperty = new ServiceProperty();
        serviceProperty.setProperties(json);
        serviceProperty.setServiceId("smokeDetector");

        device.getClient().respondPropsGet(requestId, Arrays.asList(serviceProperty));
    }
});

完整代码参见PropertySample.java

处理平台下发的命令

    client.setCommandListener(new CommandListener() {
    @Override
    public void onCommand(String requestId, String serviceId, String commandName, Map<String, Object> paras) {
        log.info("onCommand, serviceId = " +serviceId);
        log.info("onCommand , name = " + commandName);
        log.info("onCommand, paras =  " + paras.toString());

        //处理命令

        //发送命令响应
        device.getClient().respondCommand(requestId, new CommandRsp(0));
    }   });

完整代码参见CommandSample.java

面向物模型编程

面向物模型编程指的是,基于SDK提供的物模型抽象能力,设备代码只需要按照物模型定义设备服务,SDK就能自动的和平台通讯,完成属性的同步和命令的调用。 相比直接调用客户端接口和平台进行通讯,面向物模型编程简化了设备侧代码的复杂度,让设备代码只需要关注业务,而不用关注和平台的通讯过程。

首先定义一个烟感服务类,继承自AbstractService

    public static class SmokeDetectorService extends AbstractService {
	}

定义服务属性,属性和产品模型保持一致。writeable用来标识属性是否可写

    @Property(name = "alarm", writeable = true)
    int smokeAlarm = 0;

    @Property(name = "smokeConcentration", writeable = false)
    float concentration = 0.0f;

    @Property(writeable = false)
    int humidity;

    @Property(writeable = false)
    float temperature;

定义属性的读写接口: getter接口为读接口,在属性上报和平台主动查属性时被sdk调用 setter接口为写接口,在平台修改属性时被sdk调用,如果属性是只读的,则setter接口保留空实现。

        public int getHumidity() {

            //模拟从传感器读取数据
            humidity = new Random().nextInt(100);
            return humidity;
        }

        public void setHumidity(int humidity) {
            //humidity是只读的,不需要实现
        }

        public float getTemperature() {

            //模拟从传感器读取数据
            temperature = new Random().nextInt(100);
            return temperature;
        }

        public void setTemperature(float temperature) {
            //只读字段不需要实现set接口
        }

        public float getConcentration() {

            //模拟从传感器读取数据
            concentration = new Random().nextFloat()*100.0f;
            return concentration;
        }

        public void setConcentration(float concentration) {
            //只读字段不需要实现set接口
        }

        public int getSmokeAlarm() {
            return smokeAlarm;
        }

        public void setSmokeAlarm(int smokeAlarm) {

            this.smokeAlarm = smokeAlarm;
            if (smokeAlarm == 0){
                log.info("alarm is cleared by app");
            }
        }

定义服务的命令: 命令的入参和返回值类型固定不能修改。

    @DeviceCommand(name = "ringAlarm")
    public CommandRsp alarm(Map<String, Object> paras) {
        int duration = (int) paras.get("duration");
        log.info("ringAlarm  duration = " + duration);
        return new CommandRsp(0);
    }

上面完成了服务的定义 接下来创建设备,注册烟感服务,然后初始化设备:

    //创建设备
   IoTDevice device = new IoTDevice("ssl://iot-mqtts.cn-north-4.myhuaweicloud.com:8883",
           "5e06bfee334dd4f33759f5b3_demo", "mysecret", file);

   //创建设备服务
   SmokeDetectorService smokeDetectorService = new SmokeDetectorService();
   device.addService("smokeDetector", smokeDetectorService);

   if (device.init() != 0) {
       return;
   }

启动服务属性自动周期上报

    smokeDetectorService.enableAutoReport(10000);

使用设备代码生成器

上面基于物模型编程中,要求服务的定义必须和产品模型保持一致,基于这一点,我们提供了代码生成器,能根据产品模型自动生成设备代码。 代码生成器的源码在iot-device-code-generator目录 具体参见

使用网关和子设备

使用iot-gateway-demo模块,先启动StringTcpServer服务端,然后再启动TcpDevice客户端,并且TcpDevice启动后,在控制台输入的第一条消息是node_id,然后再发送业务数据。

不同IoTDA接入说明

除了换服务端的域名以外,需要在各demo的resource下替换对应服务端的ca证书,具体请参考(https://support.huaweicloud.com/devg-iothub/iot_02_1004.html#section3)。

使用证书认证

完整代码参见X509CertificateDeviceSample.java

首选读取证书,如果是pem格式的证书:

    KeyStore keyStore = DemoUtil.getKeyStore("D:\\SDK\\cert\\deviceCert.pem", "D:\\SDK\\cert\\deviceCert.key", "keypassword");
   

如果是keystore格式证书:

    KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
    keyStore.load(new FileInputStream("D:\\SDK\\cert\\my.keystore"), "keystorepassword".toCharArray());

然后使用证书创建设备

    IoTDevice iotDevice = new IoTDevice("ssl://iot-mqtts.cn-north-4.myhuaweicloud.com:8883",
                "5e06bfee334dd4f33759f5b3_demo3", keyStore, "keypassword", file);

License

SDK的开源License类型为 BSD 3-Clause License。详情参见LICENSE.txt

如何贡献代码

1、创建github账号 2、fork huaweicloud-iot-device-sdk-java源代码 3、同步huaweicloud-iot-device-sdk-java主仓库代码到fork的仓库 4、在本地修改代码并push到fork的仓库 5、在fork的仓库提交pull request到主仓库

版本更新说明

1、增加压缩接口

2、隐式订阅

3、可靠性预埋、退避重连

4、用户名、密码错误不重连

5、时间同步功能

6、代码重构

7、设备日志上报

8、网关主动管理子设备(子设备的添加/删除)

9、支持iotda发放设备流程

10、sdk日志组件更改

11、增加消息发放功能

12、修改发放功能问题

13、兼容多region不同证书场景

14、解决异常连接场景错误码为0的问题

15、解决消息中文乱码问题

2022/11/30

release版本,请下载:https://github.com/huaweicloud/huaweicloud-iot-device-sdk-java/releases