华为云IotDA支持基于MQTT/HTTP/CoAP等标准协议接入,为解决用户自定义处理设备数据以及自定义协议设备快速接入IOT平台的诉求。华为云IoTDA提供泛协议适配机制,您可使用泛协议对接SDK,快速构建桥接服务,搭建设备或平台与IoT的双向数据通道。
- 使用场景设备只支持某种类型协议,而平台目前不支持该协议。
- 设备与其接入服务器之间已有通信网络,您希望在不修改设备和协议的情况下,将设备接入IOT平台。
- 由于设备硬件资源或者网络限制,设备无法直接接入IOT平台。
各种不同协议类型的设备,通过泛协议插件,最终以MQTT协议和华为云物联网平台进行链接。泛协议插件是各种不同协议类型设备和华为云物联网平台之间的中间层,用以屏蔽各种不同协议之间的差异。泛协议插件由三部分组成:
- “泛协议设备接入层”:用于以特定网络协议与泛协议设备建链。
- “协议桥接适配层”:负责完成第三方协议数据和平台格式数据的互相转换。 上行:把第三方协议数据转成平台格式数据,并调用泛协议SDK接口进行上报。 下行:收到平台下行数据时,转换为第三方协议数据转发给第三方协议设备。
- “泛协议SDK”:即平台提供的泛协议接入接入SDK,提供了网桥的通用功能实现。
依赖的版本:
- JDK :1.8 +
创建BridgeBootstrap对象实例,调用initBridge方法,在该方法中会读取环境变量的配置信息,并同IoT平台建立网桥连接。 初始化成功后,需要设置平台下行数据的监听器,监听平台的下行数据。 代码样例:
public void init() {
//网桥启动初始化
BridgeBootstrap bridgeBootstrap = new BridgeBootstrap();
// 从环境变量获取配置进行初始化
bridgeBootstrap.initBridge();
bridgeClient = bridgeBootstrap.getBridgeDevice().getClient();
DownLinkHandler downLinkHandler = new DownLinkHandler();
// 设置平台下发设备登录响应监听器
bridgeClient.setLoginListener(downLinkHandler);
// 设置平台命令下发监听器
bridgeClient.setBridgeCommandListener(downLinkHandler);
// 设置平台消息下发监听器
bridgeClient.setBridgeDeviceMessageListener(downLinkHandler);
// 设置平台通知网桥主动断开设备的连接监听器
bridgeClient.setBridgeDeviceDisConnListener(downLinkHandler);
}
设备登录上线的实现样例如下:
private void login(Channel channel, DeviceLoginMessage message) {
// 调用网桥login接口,向平台发起登录请求
DefaultActionListenerImpl defaultLoginActionListener = new DefaultActionListenerImpl("login");
BridgeService.getBridgeClient()
.login(deviceId, secret, 1, message.getMsgHeader().getFlowNo(),
defaultLoginActionListener);
}
设备上线时,需要从原始设备消息中解析出鉴权信息(设备ID和秘钥),再调用SDK提供的login接口向平台发起登录请求,平台收到设备的login请求后,会对设备的鉴权信息进行认证,认证通过后会通过LoginListener告知网桥SDK设备的登录结果。您需要实现该接口,并根据登录结果对设备进行记录会话信息,给设备返回响应等处理。 代码样例参考:
public void onLogin(String requestId, String deviceId, Map<String, Object> map) {
// 获取Session
DeviceSession session = DeviceSessionManger.getInstance().getSession(deviceId);
if (session == null) {
log.warn("device={} session is null", deviceId);
return;
}
int result = (int) map.get(BridgeSDKConstants.RESULET_CODE);
// 返回0表示登录成功
if (result == 0) {
session.setLoginSuccess(true);
}
.........................
// 给设备返回登陆的响应消息
session.getChannel().writeAndFlush(commonResponse);
}
设备登录成功后,收到设备的上行数据时,可调用SDK的reportProperties将解码后的数据上报到IoT平台。代码样例参考:
private void reportProperties(Channel channel, BaseMessage message) {
String deviceId = message.getMsgHeader().getDeviceId();
DeviceSession deviceSession = DeviceSessionManger.getInstance().getSession(deviceId);
if (deviceSession == null || !deviceSession.isLoginSuccess()) {
log.warn("device={} is not login", deviceId);
sendResponse(channel, message, 1);
return;
}
// 调用网桥reportProperties接口,上报设备属性数据
BridgeService.getBridgeClient()
.reportProperties(deviceId, Collections.singletonList(serviceProperty), new ActionListener() {
@Override
public void onSuccess(Object context) {
sendResponse(channel, message, 0);
}
@Override
public void onFailure(Object context, Throwable var2) {
log.warn("device={} reportProperties failed: {}", deviceId, var2.getMessage());
sendResponse(channel, message, 1);
}
});}
网桥在初始化时向SDK注册了BridgeCommandListener的监听。当有下行指令时,网桥SDK就会回调BridgeCommandListener的onCommand方法。您可在onCommand中对平台的下行指令进行处理。 代码样例参考:
public 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);
}
}
网桥检查到设备到服务端的长连接断开时,需要调用SDK的logout接口通知平台设备离线。代码样例参考:
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
String deviceId = NettyUtils.getDeviceId(ctx.channel());
DeviceSessionManger.getInstance().getSession(deviceId);
if (deviceId == null) {
return;
}
// 调用网桥的logout接口,通知平台设备离线
DefaultActionListenerImpl defaultLogoutActionListener = new DefaultActionListenerImpl("logout");
BridgeService.getBridgeClient().logout(deviceId, UUID.randomUUID().toString(), defaultLogoutActionListener);
DeviceSessionManger.getInstance().deleteSession(deviceId);
ctx.close();
}