首页 > 编程语言 >Java开发如何通过IoT边缘ModuleSDK进行协议转换?

Java开发如何通过IoT边缘ModuleSDK进行协议转换?

时间:2022-12-13 15:33:37浏览次数:76  
标签:Java IoT ModuleSDK 4022 c5133122054a bf40f0c4 id 41c6 设备

摘要:使用ModuleSDK开发插件应用,接入其他协议设备(如HTTP请求数据),将其他协议的数据转化为MQTT协议JSON数据上报到IoTDA。

本文分享自华为云社区《【华为云IoTEdge开发实战】Java开发如何通过IoT边缘ModuleSDK进行协议转换》,作者: 华为IoT云服务 。

操作场景

使用ModuleSDK开发插件应用,接入其他协议设备(如HTTP请求数据),将其他协议的数据转化为MQTT协议JSON数据上报到IoTDA。

代码解析

项目结构如下

ModbusDriver代码解析

片段一

通过DriverClient.createFromEnv初始化客户端,调用driverClient来完成数据的发送。

public ModbusDriver() throws GeneraException {
  driverClient = DriverClient.createFromEnv();
  }
  public void start() throws Exception {
  //设置回调,打开客户端
  driverClient.setGatewayCallback(this);
  driverClient.open();
  loadConfig();
  startCollection();
  }

片段二

此为模拟http请求的代码,随机数模拟设备数采。

private void startCollection() {
  scheduler.scheduleAtFixedRate(() -> {
  String s = null;
  //todo 采集点位数据,保存到points
  try {
  //1、主动发HTTP请求采集子设备数据
//                s = HttpUtils.doGet("http://127.0.0.1:8080/module/sdk", null);
//                System.out.println(s);
//                Module module = JSON.parseObject(s, Module.class);
  //2、模拟设备数采数据
  //构造上报参数 设备id.服务id.属性
  Module module = new Module();
  module.setStatus(String.valueOf(Math.random()));
  module.setTemp(String.valueOf(Math.random()));
  points.put("bf40f0c4-4022-41c6-a201-c5133122054a.BasicData.status", module.getStatus());
  points.put("bf40f0c4-4022-41c6-a201-c5133122054a.BasicData.temp", module.getTemp());
  } catch (Exception exception) {
  System.out.println("http请求异常");
  }
  //上报数据
  List<DeviceService> devices = new LinkedList<>();
  for (Device device : modbusCfg.getDevices()) {
  List<ServiceData> services = new LinkedList<>();
  for (Service service : device.getServices()) {
  Map<String, Object> properties = new HashMap<>();
  for (Property property : service.getProperties()) {
  String key = device.getId() + "." + service.getServiceId() + "." + property.getPropertyName();
  properties.put(property.getPropertyName(), points.get(key));
  }
  services.add(new ServiceData(service.getServiceId(), properties, ZonedDateTime.now()));
  }
  String deviceId = deviceIds.get(device.getId());
  if (deviceId != null) {
  devices.add(new DeviceService(deviceId, services));
  }
  }
  try {
 driverClient.reportSubDevicesProperties(new SubDevicesPropsReport(devices));
  } catch (Exception e) {
  System.out.println("上报数据异常" + e.getMessage());
  }
  }, 0, modbusCfg.getPeriod(), TimeUnit.SECONDS);
  }

片段三

查看“modbus.json”文件,点位上报数据关系对应:设备id.模型id.服务id.属性名;设备id需要与添加边缘设备时设置的“设备标识码”一致。

{
  "period": 10,
  "server": "10.69.33.154:502",
  "devices": [{
 "id": "bf40f0c4-4022-41c6-a201-c5133122054a",
  "product_id": "6247f7e36fe7862a3aa0d803",
  "name": "TEST1",
  "slave_id": 1,
  "services": [{
  "service_id": "BasicData",
  "properties": [{
  "property_name": "status",
  "register_address": 0,
  "data_type": "string"
  },{
  "property_name": "temp",
  "register_address": 1,
  "data_type": "string"
  }]
  }]
  }]
}

片段四

查看“device_ids.json”文件,设备id需要与添加边缘设备时设置的“设备标识码”一致。

{
  "bf40f0c4-4022-41c6-a201-c5133122054a": "bf40f0c4-4022-41c6-a201-c5133122054a"
}

片段五

平台对部署此应用模块下的设备下发命令后,回调此函数。

  @Override
  public CommandRsp onDeviceCommandCalled(String requestId, Command command) {
  // command json体
  //{
  //    "object_device_id": "bf40f0c4-4022-41c6-a201-c5133122054a", 设备id
  //    "service_id": "BasicData", 模型service_id
  //    "command_name": "Control",  命令下发名称
  //    "paras": {                   命令下发参数
  //    "State": "1"
  //}
  //}
  // 响应示例
  return new CommandRsp(200, "supported ok", null);
  }

片段六

平台对部署此应用模块下的设备的影子属性配置后,回调此函数。

 @Override
  public IotResult onDevicePropertiesSet(String requestId, PropsSet propsSet) {
  //propsSet的json结构体
  //    {
  //        "object_device_id": "bf40f0c4-4022-41c6-a201-c5133122054a", 设备id
  //        "services": [
  //        {
  //            "service_id": "$config",  模型service_id
  //            "properties": {
  //            "password": ""            模型属性
  //        }
  //        },
  //        {
  //            "service_id": "BasicData",   模型service_id
  //            "properties": {              模型属性
  //            "status": "123",
  //             "temp": "123"
  //        }
  //        }
  //]
  //    }
  // 响应
  return new IotResult(200, "supported");
  }

片段七

子设备收到属性获取的请求后,调用此函数。

设备接入后,可通过IOTDA提供的接口触发此函数,请参考IOTDA接口指引

 @Override
  public PropsGetRsp onDevicePropertiesGet(String requestId, PropsGet propsGet) {
  //propsGet的json结构体
  //{
  //    "objectDeviceId": "bf40f0c4-4022-41c6-a201-c5133122054a",
  //    "serviceId": "BasicData"
  //}
  return new PropsGetRsp();
  }

片段八

边缘设备的影子属性配置后,回调此函数。

  @Override
  public void onDeviceShadowReceived(String requestId, ShadowGetRsp shadowGetRsp) {
  //    {
  //        "objectDeviceId": "bf40f0c4-4022-41c6-a201-c5133122054a", 设备id
  //        "shadow": [
  //        {
  //            "desired": {
  //            "eventTime": "2022-05-07T07:44:53Z[UTC]",
  //                "properties": {
  //                "status": "22222222222",             设备影子期望属性
  //                    "temp": "11111111111111"         设备影子期望属性
  //            }
  //        },
  //            "reported": {
  //            "eventTime": "2022-05-07T07:34:15Z[UTC]",
  //                "properties": {
  //                "status": "1595803812",          设备上报属性
  //                    "temp": "-947623559"         设备上报属性
  //            }
  //        },
  //            "serviceId": "BasicData",            模型服务id
  //            "version": 19
  //        }
  //]
 //    }
  }

片段九

平台对部署此应用模块下的节点的添加边缘设备后,回调此函数。

注意:部署边缘设备的模块id是集成了ModuleSDK应用的模块ID。

 @Override
  public void onSubDevicesAdded(String eventId, AddSubDevicesEvent addSubDevicesEvent) {
  //  addSubDevicesEvent的json结构体
  //    {
 //        "devices": [
  //        {
  //            "description": "",              描述
  //            "deviceId": "bf40f0c4-4022-41c6-a201-c5133122054a",     设备id
  //            "extensionInfo": {
  //            "module_id": "user_ot_test"       模块id
  //        },
  //            "fwVersion": "",
  //            "name": "TEST1",
  //            "nodeId": "bf40f0c4-4022-41c6-a201-c5133122054a",        设备id
  //            "parentDeviceId": "720259701929160704",  父设备id
  //            "productId": "6247f7e36fe7862a3aa0d803",  模型id
  //            "status": "INACTIVE",              状态
  //            "swVersion": ""
  //        }
  //],
  //        "version": 13
  //    }
  //保存本地设备Id与云端设备Id映射关系
  }

片段十

平台对部署此应用模块下的节点的删除边缘设备后,回调此函数。

注意:部署边缘设备的模块id是集成了ModuleSDK应用的模块ID。

  @Override
  public void onSubDevicesDeleted(String eventId, DeleteSubDevicesEvent deleteSubDevicesEvent) {
  // deleteSubDevicesEvent的json结构体
  //    {
  //        "devices": [
  //        {
  //            "description": "",
  //            "deviceId": "bf40f0c4-4022-41c6-a201-c5133122054a",
  //            "fwVersion": "",
 //            "name": "",
  //            "nodeId": "bf40f0c4-4022-41c6-a201-c5133122054a",
  //            "parentDeviceId": "720259701929160704",
  //            "productId": "",
  //            "status": "",
  //            "swVersion": ""
  //        }
  //],
  //        "version": 14
  //    }
  }

片段十一

收到获取模型的请求,调用此函数。

  @Override
  public void onGetProductsResponse(String eventId, GetProductsRspEvent response) {
  //使用 driverClient.getProducts()可获得模型数据
  //try {
  //    GetProductsEvent event = new GetProductsEvent();   
  //event.setProductIds(Collections.singletonList("6247f7e36fe7862a3aa0d803"));
  //   driverClient.getProducts("12345", event);
  //} catch (JsonException e) {
  //    log.error("getProducts exception:" + e);
  //}
  // response的json结构体
  //    {
  //        "products": [
  //        {
  //            "dataFormat": "json",
  //            "description": "",
  //            "deviceType": "moduleSDK测试",            模型名字
  //            "industry": "",
  //            "name": "moduleSDK测试",
  //            "productId": "6247f7e36fe7862a3aa0d803",      模型id
  //            "protocolType": "MQTT",
  //            "serviceCapabilities": [
  //            {
  //                "commands": [
  //                {
  //                    "commandName": "Control",    命令名称
  //                    "paras": [                   命令配置
  //                    {
  //                        "dataType": "string",
  //                        "max": "2147483647",
  //                        "maxLength": 200,
  //                        "min": "1",
  //                        "paraName": "State",
  //                        "required": true,
  //                        "step": 0.0,
  //                        "unit": ""
  //                    }
  //                        ]
  //                }
  //                ],
  //                "description": "",
  //                "option": "Optional",
  //                "properties": [                 属性配置
 //                {
  //                    "dataType": "string",
  //                    "maxLength": 50,
  //                    "method": "R",
  //                    "propertyName": "temp",
  //                    "required": false,
  //                    "step": 0.0
  //                },
  //                {
  //                    "dataType": "string",
  //                    "maxLength": 50,
  //                    "method": "RW",
  //                    "propertyName": "status",
  //                    "required": false,
  //                    "step": 0.0
  //                }
  //                ],
  //                "serviceId": "BasicData",
  //                "serviceType": "BasicData"
  //            },
  //            {
  //                "description": "mqtt_config",
  //                "option": "Optional",
  //                "properties": [
 //                {
  //                    "dataType": "string",
  //                    "description": "mqtt设备接入平台密码",
  //                    "max": "32",
  //                    "maxLength": 10240,
  //                    "method": "RW",
  //                    "min": "8",
  //                    "propertyName": "password",
  //                    "required": false,
  //                    "step": 0.0
  //                }
  //                ],
  //                "serviceId": "$config",
  //                "serviceType": "$config"
  //            }
  //        ]
  //        }
  //]
  //    }
  }

注册节点

注册节点,请参照注册边缘节点

设备建模

1.访问IoT边缘,单击“立即使用”进入IoT边缘控制台。

2.在左侧导航中选择“设备建模”,单击页面右上角“创建产品”。

3.填写参数信息,如图所示,单击“立即创建”。

4.进入产品详情页,单击“自定义模型”,添加“BasicData”服务ID,并“确认”。

5.展开服务列表,依次添加“temp”、“status”两个属性。

6.单击添加命令,添加Control命令名称。

7.单击新增下发参数,填写对应参数。

说明:产品ID、服务ID、属性名称需要与代码中示例保持一致。

项目打包

打包参考项目打包

将modbusdriver进行打包得到modbusdriver.jar。

制作镜像包

将jar文件打包成镜像文件上,请参照制作镜像包或插件包

dockerfile内容参照如下(具体可参考编写高效的Dockerfile )。

FROM registry-cbu.huawei.com/csopenjdk/openjdk
RUN mkdir -p /opt/iot/edge/monitor / && chmod -R 777 /opt/ 
COPY monitor /opt/iot/edge/monitor   
USER root     
EXPOSE 8080
CMD ["java", "-jar", "/opt/iot/edge/monitor/monitor-app.jar", "run"] 
#构造镜像
#docker build -t edge_monitor:1.0.0 /home --no-cache  
#打标签
#docker tag edge_monitor:1.0.0 swr.cn-north-4.myhuaweicloud.com/iot_edge_test/ot_test:v1 
#推送
#docker push swr.cn-north-4.myhuaweicloud.com/iot_edge_test/ot_test:v1
#打成镜像包
#docker save swr.cn-north-4.myhuaweicloud.com/iot_edge_test/ot_test:v1 > ot_test.tar

添加应用

以容器镜像方式为例,镜像包上传到容器镜像服务SWR后,创建应用。

1.在IoT边缘单击创建应用,进入软件部署配置、运行配置,并确认发布。

2.在左侧导航栏,单击“应用管理”,选择“应用名称”进入页面,查看应用为“已发布”状态。

部署应用

部署应用,具体请参考部署应用,进入我们的节点详情页安装应用。

添加边缘设备

1.进入边缘节点概览页,在左侧导航中选择“边缘设备”,单击“添加边缘设备”。

    • 所属产品:选择设备建模中创建的产品
    • 设备标识码:与代码示例保持一致
    • 设备名称:与代码示例保持一致
    • 模块ID: 与部署应用的模块id保持一致

2.单击“确认”,添加设备完成。

启动HTTP服务端,进入设备详情页可看到上报的数据。设备状态显示未激活。如需更改可参照集成ModuleSDK后,上报数据成功后,设备状态显示为未激活,如何上报子设备状态?

 

点击关注,第一时间了解华为云新鲜技术~

标签:Java,IoT,ModuleSDK,4022,c5133122054a,bf40f0c4,id,41c6,设备
From: https://www.cnblogs.com/huaweiyun/p/16978962.html

相关文章

  • Java中double保留2位小数(精度丢失)的两种方式
    Java中double保留2位小数(精度丢失)的两种方式在我们日常开发中,使用double数据类型进行计算,偶尔会出现精度丢失的情况,例如实际结果是0.75,就可能出现0.7500000000000001或0......
  • HTML转图片-JAVA
    依赖组件<dependency> <groupId>gui.ava</groupId> <artifactId>html2image</artifactId> <version>0.9</version></dependency>示例HtmlImageGeneratorgenerator......
  • Effective Java-2. 当构造方法参数过多时使用builder模式
    背景静态工厂和构造方法不能很好的拓展到很多可选参数的场景,因为参数过多的时候,调用其构造方法不太能知道每个位置参数的含义,容易出bug那么为这个类编写什么样下的构造方......
  • Effective Java-1.考虑使用静态工厂方法代替构造方法
    静态工厂方法的优点不像构造方法,静态工厂是有名字的精心构造的名称使得静态工厂方法更容易使用和理解,即知道创建的是什么对象与构造方法不同,不用每次都创建一个新的......
  • javascript中setInterval越来越快的问题解决方法
    vartimerfunctionrun(){ //clearInterval要放在方法开始,不然的话,下面的代码还没运行到clearInterval,又开始了循环了。if(timer){clearInter......
  • Java NIO、NIO.2学习笔记
    相关学习资料http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html 目录1.NIO、NIO.2简介2.NIO中的关键技术 1.NIO、NIO.2简介Java中的输入流、输出......
  • java 将小数拆分为两部分+浮点型精度丢失问题
    问题:将一个String类型的小数拆分为整数部分和小数部分,如9.9拆分为9和0.91.将小数的整数和小数部分拆分开publicfloatnumberSub(StringtotalMoney){floatmoneyFl......
  • Java方法
    方法方法的定义方法就是一段可重复调用的代码段,例如:有某段长度约100行的代码,要在多个地方使用此段代码,如果在各个地方都重复编写此部分代码的话,则肯定会比较麻烦,而且此部......
  • pom之 数据源信息 spring-boot-starter-jdbc ,mysql-connector-java
    <!--    数据源信息--><!--    <dependency>--><!--      <groupId>org.springframework.boot</groupId>--><!--      <arti......
  • [Java EE] java.net.SocketException: Connection reset【解决中】
    1错误描述6:44:33.112][DEBUG][http-nio-9527-exec-3][HttpClientUtil]httpposturl:http://bdp-gateway-service-parent-backend-service.bigdata/bdp/public/api/......