当前位置: 首页 > news >正文

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

操作场景

使用 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后,上报数据成功后,设备状态显示为未激活,如何上报子设备状态?

相关文章:

  • 1.专题 存储结构和逻辑结构
  • 47 岁从华为退休,操作系统老兵转战 OpenHarmony 生态 | 近匠
  • 拷贝构造,赋值运算符重载(六千字长文详解!)
  • 设计模式概述之工厂方法模式(二)
  • 【SSM框架】为集合类型属性赋值
  • 不想写日报、周报,这个报表自动化软件太牛了,仅需三分钟
  • 14:30面试,14:38就出来了 ,问的实在是太...
  • electron-vue项目从搭建、运行到打包(以及electron-vue的bug修改)
  • 使用小爱同学语音控制电脑关机 - Winform C#
  • [附源码]Python计算机毕业设计仿咸鱼二手物品交易系统Django(程序+LW)
  • 31.前端笔记-CSS-CSS3盒子模型和其他特性
  • C语言split分割字符串
  • Python篇之编译py文件为pyc文件的方法总结
  • Windows学习总结(25)—— Windows 11 cmd 命令大全
  • 识破贷后资金归集——关联网络
  • 《深入 React 技术栈》
  • CSS相对定位
  • Effective Java 笔记(一)
  • Python利用正则抓取网页内容保存到本地
  • Vue 动态创建 component
  • 测试如何在敏捷团队中工作?
  • 再谈express与koa的对比
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • ​Spring Boot 分片上传文件
  • ​VRRP 虚拟路由冗余协议(华为)
  • # 达梦数据库知识点
  • $GOPATH/go.mod exists but should not goland
  • (BFS)hdoj2377-Bus Pass
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (二)springcloud实战之config配置中心
  • (已解决)什么是vue导航守卫
  • (转)重识new
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • .NET / MSBuild 扩展编译时什么时候用 BeforeTargets / AfterTargets 什么时候用 DependsOnTargets?
  • .NET Framework杂记
  • .NetCore项目nginx发布
  • .NET开发不可不知、不可不用的辅助类(一)
  • .net连接oracle数据库
  • @column注解_MyBatis注解开发 -MyBatis(15)
  • @hook扩展分析
  • @Transactional 竟也能解决分布式事务?
  • [ CTF ] WriteUp-2022年春秋杯网络安全联赛-冬季赛
  • [ SNOI 2013 ] Quare
  • [ 蓝桥杯Web真题 ]-布局切换
  • []指针
  • [2013][note]通过石墨烯调谐用于开关、传感的动态可重构Fano超——
  • [Assignment] C++1
  • [bzoj4010][HNOI2015]菜肴制作_贪心_拓扑排序
  • [C]整形提升(转载)
  • [COGS 622] [NOIP2011] 玛雅游戏 模拟
  • [Delphi]一个功能完备的国密SM4类(TSM4)[20230329更新]
  • [Docker]十一.Docker Swarm集群raft算法,Docker Swarm Web管理工具
  • [Flutter]打包IPA
  • [JavaEE系列] wait(等待) 和 notify(唤醒)
  • [java进阶]——方法引用改写Lambda表达式