华为云设备接入

server/2025/2/27 9:22:25/

原生接入方式

支持设备通过MQTT、HTTP、LWM2M、CoAP、WebSocket、QUIC等通用通信协议对接物联网平台。


MQTT(S)协议接入

概述

MQTT消息由固定报头(Fixed header)、可变报头(Variable header)和有效载荷(Payload)三部分组成。

其中固定报头(Fixed header)和可变报头(Variable header)格式的填写请参考MQTT标准规范,有效载荷(Payload)的格式(须使用UTF-8编码格式)由应用定义,即由设备和物联网平台之间定义

常见MQTT消息类型主要有CONNECT、SUBSCRIBE、PUBLISH。

  • CONNECT:指客户端发起与服务端的连接请求。有效载荷(Payload)的主要参数,参考设备连接鉴权填写。
  • SUBSCRIBE:指客户端发起订阅的请求。有效载荷(Payload)中的主要参数“Topic name”,参考Topic定义中订阅者为设备的Topic。
  • PUBLISH:平台发布消息。
    • 可变报头(Variable header)中的主要参数“Topic name”,指当设备上报到物联网平台,发布者为设备时所对应的Topic。详细请参考Topic定义。
    • 有效载荷(Payload)中的主要参数为完整的数据上报和命令下发的消息内容,目前是一个JSON对象。
业务流程
img
  1. 设备接入前,需创建产品(可通过控制台创建或者使用应用侧API创建产品)。
  2. 产品创建完毕后,需注册设备(可通过控制台注册单个设备或者使用应用侧API注册设备创建)。
  3. 设备注册完毕后,可以按照图中流程实现消息/属性上报、接收命令/属性/消息、OTA升级、自定义Topic等功能。关于平台预置Topic可参考Topic定义
具体接入步骤

您可以通过mqtt.fx进行原生协议接入调测,可以参考快速体验mqtt接入。

上述内容只列出相关重要内容,详细内容查看:

MQTT/MQTTS协议接入:https://support.huaweicloud.com/usermanual-iothub/iot_01_0128.html


HTTPS协议接入

概述

HTTPS是基于HTTP协议,通过SSL加密的一种安全通信协议。物联网平台支持HTTPS协议通信。

业务流程
  1. 设备接入前,需创建产品(可通过控制台创建或者使用应用侧API创建产品)。

  2. 产品创建完毕后,需注册设备(可通过控制台注册单个设备或者使用应用侧API注册设备创建)。

  3. 设备注册完毕后,通过设备鉴权接口获取设备的access_token。
    点击放大

  4. 获取到access_token之后,可以使用消息/属性上报等功能。其中access_token放于消息头中,下面示例为上报属性:

    点击放大
    点击放大

具体接入步骤

HTTPS协议接入:

https://support.huaweicloud.com/usermanual-iothub/iot_01_00129.html


LwM2M/CoAP协议接入

概述

LwM2M(Lightweight M2M,轻量级M2M),由开发移动联盟(OMA)提出,是一种轻量级的、标准通用的物联网设备管理协议,可用于快速部署客户端/服务器模式的物联网业务。LwM2M为物联网设备的管理和应用建立了一套标准,它提供了轻便小巧的安全通信接口及高效的数据模型,以实现M2M设备管理和服务支持。物联网平台支持加密与非加密两种接入设备接入方式,其中加密业务数据交互端口为5684端口,采用DTLS+CoAP协议通道接入,非加密端口为5683,接入协议为CoAP。物联网平台从安全角度考虑,强烈建议采用安全接入方式。

具体步骤

流程与步骤和上述两种基本相同。

物联网平台的Endpoint请参见:地区和终端节点。

使用“设备接入-> CoAP (5683)| CoAPS (5684)”对应的Endpoint,端口为5683(非加密接入方式)或者5684(加密接入方式)。

上述内容只列出相关重要内容,详细内容查看:

LwM2M协议接入:https://support.huaweicloud.com/usermanual-iothub/iot_01_0138.html


泛协议接入

概述

目前平台支持基于MQTT/HTTP/LwM2M等标准协议接入,为解决用户自定义协议设备快速接入IoT平台的诉求。华为云IoT提供泛协议适配机制,您可使用泛协议对接SDK,快速构建协议插件,进行设备或平台与IoT的双向数据通信。泛协议插件开发指导可参见泛协议插件开发。

使用场景

  • 设备只支持某种类型协议,而平台目前不支持该协议。

  • 设备与其接入服务器之间已有通信网络,您希望在不修改设备和协议的情况下,将设备接入IoT平台。

  • 由于设备硬件资源或者网络限制,设备无法直接接入IoT平台。

架构框图

img

协议转换网关是一个网关,可以部署在云上或者本地。第三方协议设备作为协议转换网关的子设备接入平台。

协议转换网关一般由三部分组成:

  1. **第三方协议接入。**完成第三方协议的解析,鉴权。
  2. **协议转换。**负责完成第三方协议数据和平台格式数据的互相转换。
    • 上行:把第三方协议数据转成平台格式数据,并调用设备SDK接口进行上报。
    • 下行:收到平台下行数据时,转换为第三方协议数据转发给第三方协议设备。
  3. **设备SDK。**即平台提供的设备接入SDK,提供了网关的通用功能实现,用户可以在此基础上实现自己的网关。

业务流程

  1. 实现泛协议设备接入一般流程

    img
  2. 基于华为云SDK实现泛协议具体流程

img
  1. 在物联网平台上注册网关,详细方法请参考设备注册。
  2. 网关上电,连接到平台,连接所需的鉴权参数在注册网关时获取。
  3. 用户在平台上注册子设备时,平台下发添加子设备事件到网关。网关收到后,保存子设备信息到本地并持久化(SDK提供了默认的持久化实现,用户可以自定义扩展)。
  4. 第三方协议设备连接到网关。网关根据子设备信息对设备进行鉴权。
  5. 设备上报数据到网关。网关转换为平台格式数据后,调用SDK的上报子设备属性/消息 的接口上报给平台。
  6. 平台向设备下发命令。网关收到后,转换为第三方协议,转发给子设备。设备收到后对命令进行处理。

具体接入步骤

以下代码以java举例,具体的内容/代码 可根据文末网址到GitHub sdk相关页面查看

1. 搭建网桥,用于udp设备接入网桥、与云平台进行交互

使用协议网桥来实现UDP协议设备接入。网桥需要为每个UDP设备创建一个客户端(IotClient),使用设备的身份和平台进行通讯。网桥功能包括:

  • 初始化网桥SDK

        public void init() {// 网桥启动初始化BridgeBootstrap bridgeBootstrap = new BridgeBootstrap();// 从环境变量获取配置进行初始化bridgeBootstrap.initBridge();bridgeClient = bridgeBootstrap.getBridgeDevice().getClient();// 设置平台下行数据监听器DownLinkHandler downLinkHandler = new DownLinkHandler();bridgeClient.setBridgeCommandListener(downLinkHandler)   // 设置平台命令下发监听器.setBridgeDeviceMessageListener(downLinkHandler)    // 设置平台消息下发监听器.setBridgeDeviceDisConnListener(downLinkHandler);   // 设置平台通知网桥主动断开设备连接的监听器}
    
  • 设备登录上线

    private void login(Channel channel, BaseMessage message) {if (!(message instanceof DeviceLoginMessage)) {return;}String deviceId = message.getMsgHeader().getDeviceId();String secret = ((DeviceLoginMessage) message).getSecret();DeviceSession deviceSession = new DeviceSession();int resultCode = BridgeService.getBridgeClient().loginSync(deviceId, secret, 5000);// 登录成功保存会话信息if (resultCode == 0) {deviceSession.setDeviceId(deviceId);deviceSession.setChannel(channel);DeviceSessionManger.getInstance().createSession(deviceId, deviceSession);NettyUtils.setDeviceId(channel, deviceId);}// 构造登录响应的消息头MsgHeader msgHeader = new MsgHeader();msgHeader.setDeviceId(deviceId);msgHeader.setFlowNo(message.getMsgHeader().getFlowNo());msgHeader.setDirect(Constants.DIRECT_CLOUD_RSP);msgHeader.setMsgType(Constants.MSG_TYPE_DEVICE_LOGIN);// 调用网桥login接口,向平台发起登录请求DefaultActionListenerImpl defaultLoginActionListener = new DefaultActionListenerImpl("login");BridgeService.getBridgeClient().loginAsync(deviceId, secret, message.getMsgHeader().getFlowNo(),defaultLoginActionListener);
    }
    
  • 设备数据上传

    private void reportProperties(Channel channel, BaseMessage message) {String deviceId = message.getMsgHeader().getDeviceId();DeviceSession deviceSession = DeviceSessionManger.getInstance().getSession(deviceId);if (deviceSession == null) {log.warn("device={} is not login", deviceId);sendResponse(channel, message, 1);return;}ServiceProperty serviceProperty = new ServiceProperty();serviceProperty.setServiceId("Location");serviceProperty.setProperties(JsonUtil.convertJsonStringToObject(JsonUtil.convertObject2String(message), Map.class));// 调用网桥reportProperties接口,上报设备属性数据BridgeService.getBridgeClient().reportProperties(deviceId, Collections.singletonList(serviceProperty), new ActionListener() {@Overridepublic void onSuccess(Object context) {sendResponse(channel, message, 0);}@Overridepublic void onFailure(Object context, Throwable var2) {log.warn("device={} reportProperties failed: {}", deviceId, ExceptionUtil.getBriefStackTrace(var2));sendResponse(channel, message, 1);}});
    }
    
  • 平台指令下发

        @Overridepublic void onCommand(String deviceId, String requestId, BridgeCommand bridgeCommand) {log.info("onCommand deviceId={}, requestId={}, bridgeCommand={}", deviceId, requestId, bridgeCommand);DeviceSession session = DeviceSessionManger.getInstance().getSession(deviceId);if (session == null) {log.warn("device={} session is null", deviceId);return;}// 设置位置上报的周期if (Constants.MSG_TYPE_FREQUENCY_LOCATION_SET.equals(bridgeCommand.getCommand().getCommandName())) {processLocationSetCommand(session, requestId, bridgeCommand);}}
    
  • 设备离线

        @Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception {String deviceId = NettyUtils.getDeviceId(ctx.channel());if (deviceId == null) {return;}DeviceSession deviceSession = DeviceSessionManger.getInstance().getSession(deviceId);if (deviceSession == null) {return;}// 调用网桥的logout接口,通知平台设备离线DefaultActionListenerImpl defaultLogoutActionListener = new DefaultActionListenerImpl("logout");BridgeService.getBridgeClient().logoutAsync(deviceId, UUID.randomUUID().toString(), defaultLogoutActionListener);DeviceSessionManger.getInstance().deleteSession(deviceId);ctx.close();}
    
2. 设备发送udp消息给泛协议插件

要求首条消息是鉴权消息,携带设备标识nodeId

3. 定义解码类

上行数据的消息解码,将原始码流转换为具体对象

/*** 上行数据的UDP消息解码器,将原始码流转换为具体对象*/
public class UdpMessageDecoder extends SimpleChannelInboundHandler<String> {private static final Logger log = LogManager.getLogger(UdpMessageDecoder.class);/*** 处理UDP消息,解码并将结果传递给下一个处理器** @param ctx 上下文对象,用于获取通道信息和传递消息* @param msg 接收到的原始UDP消息字符串*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, String msg) {log.info("UdpMessageDecoder msg={}", msg);BaseMessage message = decodeMessage(msg);if (message == null) {log.warn("decode message failed");return;}ctx.fireChannelRead(message); // 将解码后的消息传递给下一个处理器}/*** 解码UDP消息** @param message 接收到的原始UDP消息字符串* @return 解码后的消息对象,如果解码失败则返回null*/private BaseMessage decodeMessage(String message) {MsgHeader header = decodeHeader(message); // 解码消息头部if (header == null) {return null;}BaseMessage baseMessage = decodeBody(header, message.substring(message.lastIndexOf(",") + 1)); // 解码消息体if (baseMessage == null) {return null;}baseMessage.setMsgHeader(header); // 将头部信息设置到消息对象中return baseMessage;}/*** 解码消息头部** @param message 接收到的原始UDP消息字符串* @return 解码后的消息头部对象,如果解码失败则返回null*/private MsgHeader decodeHeader(String message) {String[] splits = message.split(Constants.HEADER_PARS_DELIMITER); // 按分隔符拆分头部信息if (splits.length <= 4) { // 判断头部信息是否完整return null;}MsgHeader msgHeader = new MsgHeader();msgHeader.setDeviceId(splits[0]); // 设置设备IDmsgHeader.setFlowNo(splits[1]); // 设置流水号msgHeader.setMsgType(splits[2]); // 设置消息类型msgHeader.setDirect(Integer.parseInt(splits[3])); // 设置方向(整数值)return msgHeader;}/*** 根据消息头部解码消息体** @param header  解码后的消息头部对象* @param body    原始消息体字符串* @return 解码后的具体消息对象,如果解码失败则返回null*/private BaseMessage decodeBody(MsgHeader header, String body) {switch (header.getMsgType()) { // 根据消息类型选择解码方式case Constants.MSG_TYPE_DEVICE_LOGIN:return decodeLoginMessage(body); // 解码设备登录消息case Constants.MSG_TYPE_REPORT_LOCATION_INFO:return decodeLocationMessage(body); // 解码位置上报消息case Constants.MSG_TYPE_FREQUENCY_LOCATION_SET:return decodeLocationSetMessage(body); // 解码设置定位频率消息default:log.warn("invalid msgType"); // 非法消息类型return null;}}/*** 解码设备登录消息** @param body 原始消息体字符串* @return 解码后的设备登录消息对象*/private BaseMessage decodeLoginMessage(String body) {DeviceLoginMessage loginMessage = new DeviceLoginMessage();loginMessage.setSecret(body); // 设置登录密钥return loginMessage;}/*** 解码位置上报消息** @param body 原始消息体字符串* @return 解码后的位置上报消息对象*/private BaseMessage decodeLocationMessage(String body) {String[] splits = body.split(Constants.BODY_PARS_DELIMITER); // 按分隔符拆分消息体DeviceLocationMessage deviceLocationMessage = new DeviceLocationMessage();deviceLocationMessage.setLongitude(splits[0]); // 设置经度deviceLocationMessage.setLatitude(splits[1]); // 设置纬度return deviceLocationMessage;}/*** 解码设置定位频率消息** @param body 原始消息体字符串* @return 解码后的设置定位频率响应消息对象*/private BaseMessage decodeLocationSetMessage(String body) {CommonResponse commonResponse = new CommonResponse();commonResponse.setResultCode(Integer.parseInt(body)); // 设置结果码return commonResponse;}
}
4.监听udp端口并对上行数据解码,通过搭建的网桥转发消息给平台
/*** 一个传输字符串数据的UDP server,接收客户端发送的UDP数据包,首条消息是鉴权消息,携带设备标识nodeId。* server将收到的消息通过bridge转发给平台。*/
public class UdpServer {private static final Logger log = LogManager.getLogger(UdpServer.class);private final int port;UdpServer(int port) {this.port = port;}void run() throws Exception {EventLoopGroup group = new NioEventLoopGroup();try {Bootstrap b = new Bootstrap();b.group(group).channel(NioDatagramChannel.class) // 使用NioDatagramChannel处理UDP.option(ChannelOption.SO_BROADCAST, true).handler(new ChannelInitializerImpl());log.info("UDP server start......");Channel channel = b.bind(port).sync().channel();channel.closeFuture().await();} finally {group.shutdownGracefully();log.info("UDP server close");}}private static class ChannelInitializerImpl extends io.netty.channel.ChannelInitializer<NioDatagramChannel> {@Overrideprotected void initChannel(NioDatagramChannel ch) throws Exception {ch.pipeline().addLast("decoder", new StringDecoder(CharsetUtil.UTF_8));ch.pipeline().addLast("encoder", new StringEncoder(CharsetUtil.UTF_8));ch.pipeline().addLast("handler", new UdpHandler());log.info("initChannel: {}", ch.localAddress());}}public static class UdpHandler extends SimpleChannelInboundHandler<DatagramPacket> {@Overrideprotected void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet) throws Exception {String msg = packet.content().toString(CharsetUtil.UTF_8);InetSocketAddress sender = packet.sender();log.info("channelRead0: {}, msg: {}", sender, msg);// 如果是首条消息,创建sessionSession session = Bridge.getInstance().getSessionByChannel(sender.toString());if (session == null) {Bridge.getInstance().createSession(msg, ctx.channel());} else {session.getDeviceClient().reportDeviceMessage(new DeviceMessage(msg), null);}}@Overridepublic void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {log.error("caught exception: {}", cause.getMessage());ctx.close();Bridge.getInstance().removeSession(ctx.channel().id().asLongText());}}public static void main(String[] args) throws Exception {int port = 8888; // 监听的UDP端口new UdpServer(port).run();}
}

附录网址

华为云设备接入:https://support.huaweicloud.com/usermanual-iothub/iot_01_0128.html

  • 原生接入方式

    • MQTT/MQTTS协议接入:https://support.huaweicloud.com/usermanual-iothub/iot_01_0128.html
    • HTTPS协议接入:https://support.huaweicloud.com/usermanual-iothub/iot_01_00129.html
    • LwM2M协议接入:https://support.huaweicloud.com/usermanual-iothub/iot_01_0138.html
  • 泛协议接入方式

    • 通过协议转换网关实现泛协议设备接入:https://support.huaweicloud.com/bestpractice-iothub/iot_bp_0009.html
      • sdk-java:https://github.com/huaweicloud/huaweicloud-iot-device-sdk-java?tab=readme-ov-file#3.14
      • sdk-c:https://github.com/huaweicloud/huaweicloud-iot-device-sdk-c/blob/master/README_CN.md

http://www.ppmy.cn/server/170998.html

相关文章

DeepSeek-R1-671B大模型满血版私有化部署高可用教程-SparkAi系统集成图文教程

DeepSeek官网服务器繁忙的主要原因是由于用户数量激增导致的服务器资源紧张。‌为了解决这一问题&#xff0c;DeepSeek团队已经暂停了API服务充值&#xff0c;以避免对用户造成业务影响。目前&#xff0c;存量充值金额仍可继续调用&#xff0c;但充值功能暂时不可用‌。 DeepSe…

如何实现将http请求转化为rpc请求

以下是10个可以实现HTTP请求转发到内部RPC服务的GitHub项目推荐&#xff0c;这些项目涵盖了多种语言和框架&#xff0c;适用于不同的技术栈和需求&#xff1a; 1. **grpc-gateway** grpc-gateway 是一个流行的开源项目&#xff0c;用于将HTTP请求转发到gRPC服务。它支持通…

如何用HBase轻松管理海量数据?

如何用HBase轻松管理海量数据&#xff1f;小白也能学会的入门指南 数据太多&#xff0c;头都大了&#xff1f; 你有没有过这样的经历&#xff1a;面对堆积如山的数据文件&#xff0c;感觉像是被淹没在信息的海洋里&#xff1f;别担心&#xff0c;今天我们要聊的HBase&#xf…

HBase常用的Filter过滤器操作

HBase常用的Filter过滤器操作_hbase filter-CSDN博客 HBase过滤器种类很多&#xff0c;我们选择8种常用的过滤器进行介绍。为了获得更好的示例效果&#xff0c;先利用HBase Shell新建students表格&#xff0c;并往表格中进行写入多行数据。 一、数据准备工作 &#xff08;1&am…

树和二叉树

文章目录 树和二叉树1.树的概念1.1特点1.2基本概念 2.二叉树2.1二叉树的定义2.2特殊的树2.3 二叉树的性质2.4二叉树的存储 二叉树的遍历 树和二叉树 1.树的概念 树是一种非线性的数据结构&#xff0c;它是由n个有限结点组成一个有具体层次关系的集合 1.1特点 没有前驱结点的…

MySQL企业开发中高频使用语句

以下是企业级MySQL开发中高频使用的语句分类及示例&#xff0c;结合典型业务场景说明&#xff1a; 一、数据定义&#xff08;DDL&#xff09; 表结构管理 -- 创建用户表&#xff08;含索引优化&#xff09; CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR…

【算法】哈希表详解

【算法】哈希表详解 1. 哈希表的基本概念2. 哈希表的优缺点3. 哈希表的实现方法4. 哈希表的应用场景5. 哈希表的性能优化6. 哈希表 vs 其他数据结构7. 总结 哈希表&#xff08;Hash Table&#xff09; 是一种高效的数据结构&#xff0c;用于存储键值对&#xff08;Key-Value Pa…

go-zero中定时任务的用法

文章目录 使用扩展定义调度器测试方法 使用扩展 在go-zero框架中使用定时任务调度的写法示例&#xff0c;首先需要用到的扩展&#xff1a;go get -u github.com/robfig/cron/v3 扩展网址&#xff1a;robfig/cron: a cron library for go (github.com) 定义调度器 在 gozero/i…