【华为云IoTEdge开发实战】Java开发如何通过IoT边缘ModuleSDK进行协议转换

举报
华为IoT云服务 发表于 2022/12/12 11:09:13 2022/12/12
【摘要】 Java开发如何通过IoT边缘ModuleSDK进行协议转换实操步骤

 

  • 操作场景

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

  • 代码解析

项目结构如下

image001.png

 

表1 类相关说明

类名称

描述

Device

设备类,包含设备的id,产品id,slaveId及能力定义。

HttpUtils

HTTP请求工具类,采集子设备数据。

Main

主启动类。

ModbusCfg

modbus配置。

ModbusDriver

业务主体类,该类含边侧设备添加,设备同步,数据收集及上报等演示。

Module

子设备数据封装类。

Property

设备属性。

Service

设备能力。

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) {

        //propsSetjson结构体

        //    {

        //        "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) {

        //propsGetjson结构体

        //{

        //    "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) {

        //  addSubDevicesEventjson结构体

        //    {

        //        "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) {

        // deleteSubDevicesEventjson结构体

        //    {

        //        "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);

        //}

 

        // responsejson结构体

        //    {

        //        "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.在左侧导航中选择设备建模,单击页面右上角创建产品

image003.png

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

image005.png

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

image005.png

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

image007.png

image009.png

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

image011.png

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

image013.png

说明:

产品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边缘单击创建应用,进入软件部署配置、运行配置,并确认发布。

image017.png

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

image019.png

  • 部署应用

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

image021.png

  • 添加边缘设备

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

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

image023.png

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

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

image025.png

image027.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。