Commit 120029bb1793737d6e0c8d429d7c2d43eb925fe6

Authored by YunaiV
1 parent f58cf282

reactor:【IoT 物联网】实现 alink 的 IotAlinkDeviceMessageCodec,并尝试接入 http 协议

Showing 14 changed files with 388 additions and 133 deletions
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums/IotDeviceMessageMethodEnum.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.core.enums;
  2 +
  3 +import lombok.AllArgsConstructor;
  4 +import lombok.Getter;
  5 +
  6 +/**
  7 + * IoT 设备消息的方法枚举
  8 + *
  9 + * @author haohao
  10 + */
  11 +@Getter
  12 +@AllArgsConstructor
  13 +public enum IotDeviceMessageMethodEnum {
  14 +
  15 + // ========== 设备状态 ==========
  16 +
  17 + STATE_ONLINE("thing.state.online"),
  18 + STATE_OFFLINE("thing.state.offline"),
  19 +
  20 + ;
  21 +
  22 + private final String method;
  23 +
  24 +
  25 +}
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/message/IotDeviceMessage.java
1 1 package cn.iocoder.yudao.module.iot.core.mq.message;
2 2  
3   -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageIdentifierEnum;
4   -import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageTypeEnum;
  3 +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
5 4 import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
6 5 import lombok.AllArgsConstructor;
7 6 import lombok.Builder;
... ... @@ -9,7 +8,6 @@ import lombok.Data;
9 8 import lombok.NoArgsConstructor;
10 9  
11 10 import java.time.LocalDateTime;
12   -import java.util.Map;
13 11  
14 12 /**
15 13 * IoT 设备消息
... ... @@ -32,109 +30,126 @@ public class IotDeviceMessage {
32 30 */
33 31 public static final String MESSAGE_BUS_GATEWAY_DEVICE_MESSAGE_TOPIC = MESSAGE_BUS_DEVICE_MESSAGE_TOPIC + "_%s";
34 32  
35   - // TODO @芋艿:thingsboard 对应 id,全部由后端生成,由于追溯;是不是调整下?
36 33 /**
37 34 * 消息编号
  35 + *
  36 + * 由后端生成,通过 {@link IotDeviceMessageUtils#generateMessageId()}
38 37 */
39   - private String messageId;
40   -
41   - // TODO @芋艿:thingsboard 是使用 deviceId
42   - /**
43   - * 设备信息
44   - */
45   - private String productKey;
  38 + private String id;
46 39 /**
47   - * 设备名称
  40 + * 上报时间
  41 + *
  42 + * 由后端生成,当前时间
48 43 */
49   - private String deviceName;
  44 + private LocalDateTime reportTime;
  45 +
  46 + // ========== codec(编解码)字段 ==========
50 47  
51   - // TODO @芋艿:thingsboard 只定义了 type;相当于 type + identifier 结合!TbMsgType
52 48 /**
53   - * 消息类型
  49 + * 请求编号
54 50 *
55   - * 枚举 {@link IotDeviceMessageTypeEnum}
  51 + * 由设备生成,对应阿里云 IoT 的 Alink 协议中的 id、华为云 IoTDA 协议的 request_id
56 52 */
57   - private String type;
  53 + private String requestId;
58 54 /**
59   - * 标识符
  55 + * 请求方法
60 56 *
61   - * 枚举 {@link IotDeviceMessageIdentifierEnum}
  57 + * 枚举 {@link IotDeviceMessageMethodEnum}
  58 + * 例如说:thing.property.report 属性上报
62 59 */
63   - private String identifier;
64   -
65   - // TODO @芋艿:thingsboard 只有 data 字段,没有 code 字段;
66   - // TODO @芋艿:要不提前序列化成字符串???类似 thingsboard 的 data 字段
  60 + private String method;
67 61 /**
68 62 * 请求参数
69 63 *
70 64 * 例如说:属性上报的 properties、事件上报的 params
71 65 */
  66 + private Object params;
  67 + /**
  68 + * 响应结果
  69 + */
72 70 private Object data;
73   - // TODO @芋艿:可能会去掉
74 71 /**
75   - * 响应码
76   - *
77   - * 目前只有 server 下行消息给 device 设备时,才会有响应码
  72 + * 响应错误码
78 73 */
79 74 private Integer code;
80 75  
  76 + // ========== 后端字段 ==========
  77 +
81 78 /**
82   - * 上报时间
  79 + * 设备编号
83 80 */
84   - private LocalDateTime reportTime;
  81 + private Long deviceId;
  82 + /**
  83 + * 租户编号
  84 + */
  85 + private Long tenantId;
85 86  
86 87 /**
87 88 * 服务编号,该消息由哪个 server 服务进行消费
88 89 */
89 90 private String serverId;
90 91  
91   - public IotDeviceMessage ofPropertyReport(Map<String, Object> properties) {
92   - this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
93   - this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier());
94   - this.setData(properties);
95   - return this;
96   - }
97   -
98   - public IotDeviceMessage ofPropertySet(Map<String, Object> properties) {
99   - this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
100   - this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
101   - this.setData(properties);
102   - return this;
103   - }
104   -
105   - public IotDeviceMessage ofStateOnline() {
106   - this.setType(IotDeviceMessageTypeEnum.STATE.getType());
107   - this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier());
108   - return this;
109   - }
110   -
111   - public IotDeviceMessage ofStateOffline() {
112   - this.setType(IotDeviceMessageTypeEnum.STATE.getType());
113   - this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier());
114   - return this;
115   - }
116   -
117   - public static IotDeviceMessage of(String productKey, String deviceName) {
118   - return of(productKey, deviceName,
119   - null, null);
120   - }
121   -
122   - public static IotDeviceMessage of(String productKey, String deviceName,
123   - String serverId) {
124   - return of(productKey, deviceName,
125   - null, serverId);
  92 +// public IotDeviceMessage ofPropertyReport(Map<String, Object> properties) {
  93 +// this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
  94 +// this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_REPORT.getIdentifier());
  95 +// this.setData(properties);
  96 +// return this;
  97 +// }
  98 +//
  99 +// public IotDeviceMessage ofPropertySet(Map<String, Object> properties) {
  100 +// this.setType(IotDeviceMessageTypeEnum.PROPERTY.getType());
  101 +// this.setIdentifier(IotDeviceMessageIdentifierEnum.PROPERTY_SET.getIdentifier());
  102 +// this.setData(properties);
  103 +// return this;
  104 +// }
  105 +//
  106 +// public IotDeviceMessage ofStateOnline() {
  107 +// this.setType(IotDeviceMessageTypeEnum.STATE.getType());
  108 +// this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_ONLINE.getIdentifier());
  109 +// return this;
  110 +// }
  111 +//
  112 +// public IotDeviceMessage ofStateOffline() {
  113 +// this.setType(IotDeviceMessageTypeEnum.STATE.getType());
  114 +// this.setIdentifier(IotDeviceMessageIdentifierEnum.STATE_OFFLINE.getIdentifier());
  115 +// return this;
  116 +// }
  117 +//
  118 +// public static IotDeviceMessage of(String productKey, String deviceName) {
  119 +// return of(productKey, deviceName,
  120 +// null, null);
  121 +// }
  122 +//
  123 +// public static IotDeviceMessage of(String productKey, String deviceName,
  124 +// String serverId) {
  125 +// return of(productKey, deviceName,
  126 +// null, serverId);
  127 +// }
  128 +//
  129 +// public static IotDeviceMessage of(String productKey, String deviceName,
  130 +// LocalDateTime reportTime, String serverId) {
  131 +// if (reportTime == null) {
  132 +// reportTime = LocalDateTime.now();
  133 +// }
  134 +// String messageId = IotDeviceMessageUtils.generateMessageId();
  135 +// return IotDeviceMessage.builder()
  136 +// .messageId(messageId).reportTime(reportTime)
  137 +// .productKey(productKey).deviceName(deviceName)
  138 +// .serverId(serverId).build();
  139 +// }
  140 +
  141 + public static IotDeviceMessage of(String requestId, String method, Object params) {
  142 + return of(requestId, method, params, null, null);
126 143 }
127 144  
128   - public static IotDeviceMessage of(String productKey, String deviceName,
129   - LocalDateTime reportTime, String serverId) {
130   - if (reportTime == null) {
131   - reportTime = LocalDateTime.now();
132   - }
133   - String messageId = IotDeviceMessageUtils.generateMessageId();
134   - return IotDeviceMessage.builder()
135   - .messageId(messageId).reportTime(reportTime)
136   - .productKey(productKey).deviceName(deviceName)
137   - .serverId(serverId).build();
  145 + public static IotDeviceMessage of(String requestId, String method,
  146 + Object params, Object data, Integer code) {
  147 + // 通用参数
  148 + IotDeviceMessage message = new IotDeviceMessage()
  149 + .setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now());
  150 + // 当前参数
  151 + message.setRequestId(requestId).setMethod(method).setParams(params).setData(data).setCode(code);
  152 + return message;
138 153 }
139 154  
140 155 }
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/mq/producer/IotDeviceMessageProducer.java
... ... @@ -30,7 +30,7 @@ public class IotDeviceMessageProducer {
30 30 * @param serverId 网关的 serverId 标识
31 31 * @param message 设备消息
32 32 */
33   - public void sendGatewayDeviceMessage(String serverId, Object message) {
  33 + public void sendDeviceMessageToGateway(String serverId, IotDeviceMessage message) {
34 34 messageBus.post(IotDeviceMessageUtils.buildMessageBusGatewayDeviceMessageTopic(serverId), message);
35 35 }
36 36  
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotDeviceMessageUtils.java
... ... @@ -18,6 +18,7 @@ public class IotDeviceMessageUtils {
18 18 return IdUtil.fastSimpleUUID();
19 19 }
20 20  
  21 + // TODO @芋艿:需要优化下;
21 22 /**
22 23 * 是否是上行消息:由设备发送
23 24 *
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/IotDeviceMessageCodec.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.codec;
  2 +
  3 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  4 +
  5 +/**
  6 + * {@link cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage} 的编解码器
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public interface IotDeviceMessageCodec {
  11 +
  12 + /**
  13 + * 编码消息
  14 + *
  15 + * @param message 消息
  16 + * @return 编码后的消息内容
  17 + */
  18 + byte[] encode(IotDeviceMessage message);
  19 +
  20 + /**
  21 + * 解码消息
  22 + *
  23 + * @param bytes 消息内容
  24 + * @return 解码后的消息内容
  25 + */
  26 + IotDeviceMessage decode(byte[] bytes);
  27 +
  28 + /**
  29 + * @return 类型
  30 + */
  31 + String type();
  32 +
  33 +}
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/alink/IotAlinkDeviceMessageCodec.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.codec.alink;
  2 +
  3 +import cn.hutool.core.lang.Assert;
  4 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  5 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  6 +import cn.iocoder.yudao.module.iot.gateway.codec.IotDeviceMessageCodec;
  7 +import lombok.AllArgsConstructor;
  8 +import lombok.Data;
  9 +import lombok.NoArgsConstructor;
  10 +import org.springframework.stereotype.Component;
  11 +
  12 +/**
  13 + * 阿里云 Alink {@link IotDeviceMessage} 的编解码器
  14 + *
  15 + * @author 芋道源码
  16 + */
  17 +@Component
  18 +public class IotAlinkDeviceMessageCodec implements IotDeviceMessageCodec {
  19 +
  20 + @Data
  21 + @NoArgsConstructor
  22 + @AllArgsConstructor
  23 + private static class AlinkMessage {
  24 +
  25 + public static final String VERSION_1 = "1.0";
  26 +
  27 + /**
  28 + * 消息 ID,且每个消息 ID 在当前设备具有唯一性
  29 + */
  30 + private String id;
  31 +
  32 + /**
  33 + * 版本号
  34 + */
  35 + private String version;
  36 +
  37 + /**
  38 + * 请求方法
  39 + */
  40 + private String method;
  41 +
  42 + /**
  43 + * 请求参数
  44 + */
  45 + private Object params;
  46 +
  47 + /**
  48 + * 响应结果
  49 + */
  50 + private Object data;
  51 +
  52 + /**
  53 + * 响应错误码
  54 + */
  55 + private Integer code;
  56 +
  57 + }
  58 +
  59 + @Override
  60 + public byte[] encode(IotDeviceMessage message) {
  61 + AlinkMessage alinkMessage = new AlinkMessage(message.getRequestId(), AlinkMessage.VERSION_1,
  62 + message.getMethod(), message.getParams(), message.getData(), message.getCode());
  63 + return JsonUtils.toJsonByte(alinkMessage);
  64 + }
  65 +
  66 + @Override
  67 + @SuppressWarnings("DataFlowIssue")
  68 + public IotDeviceMessage decode(byte[] bytes) {
  69 + AlinkMessage alinkMessage = JsonUtils.parseObject(bytes, AlinkMessage.class);
  70 + Assert.notNull(alinkMessage, "消息不能为空");
  71 + Assert.equals(alinkMessage.getVersion(), AlinkMessage.VERSION_1, "消息版本号必须是 1.0");
  72 + return IotDeviceMessage.of(alinkMessage.getId(),
  73 + alinkMessage.getMethod(), alinkMessage.getParams(), alinkMessage.getData(), alinkMessage.getCode());
  74 + }
  75 +
  76 + @Override
  77 + public String type() {
  78 + return "alink";
  79 + }
  80 +
  81 +}
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/alink/package-info.java deleted
1   -package cn.iocoder.yudao.module.iot.gateway.codec.alink;
2 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAbstractHandler.java
... ... @@ -33,7 +33,7 @@ public abstract class IotHttpAbstractHandler implements Handler&lt;RoutingContext&gt;
33 33 private final IotDeviceTokenService deviceTokenService = SpringUtil.getBean(IotDeviceTokenService.class);
34 34  
35 35 @Override
36   - public void handle(RoutingContext context) {
  36 + public final void handle(RoutingContext context) {
37 37 try {
38 38 // 1. 前置处理
39 39 CommonResult<Object> result = beforeHandle(context);
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpAuthHandler.java
... ... @@ -13,6 +13,7 @@ import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
13 13 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
14 14 import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
15 15 import cn.iocoder.yudao.module.iot.gateway.service.auth.IotDeviceTokenService;
  16 +import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService;
16 17 import io.vertx.core.json.JsonObject;
17 18 import io.vertx.ext.web.RoutingContext;
18 19  
... ... @@ -40,11 +41,14 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
40 41  
41 42 private final IotDeviceCommonApi deviceClientService;
42 43  
  44 + private final IotDeviceMessageService deviceMessageService;
  45 +
43 46 public IotHttpAuthHandler(IotHttpUpstreamProtocol protocol) {
44 47 this.protocol = protocol;
45 48 this.deviceMessageProducer = SpringUtil.getBean(IotDeviceMessageProducer.class);
46 49 this.deviceTokenService = SpringUtil.getBean(IotDeviceTokenService.class);
47 50 this.deviceClientService = SpringUtil.getBean(IotDeviceCommonApi.class);
  51 + this.deviceMessageService = SpringUtil.getBean(IotDeviceMessageService.class);
48 52 }
49 53  
50 54 @Override
... ... @@ -78,9 +82,9 @@ public class IotHttpAuthHandler extends IotHttpAbstractHandler {
78 82 Assert.notBlank(token, "生成 token 不能为空位");
79 83  
80 84 // 3. 执行上线
81   - deviceMessageProducer.sendDeviceMessage(IotDeviceMessage.of(deviceInfo.getProductKey(), deviceInfo.getDeviceName(),
82   - protocol.getServerId())
83   - .ofStateOnline());
  85 + IotDeviceMessage message = deviceMessageService.buildDeviceMessageOfStateOnline(
  86 + deviceInfo.getProductKey(), deviceInfo.getDeviceName(), protocol.getServerId());
  87 + deviceMessageProducer.sendDeviceMessage(message);
84 88  
85 89 // 构建响应数据
86 90 return success(MapUtil.of("token", token));
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java
1 1 package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.lang.Assert;
4 5 import cn.hutool.core.map.MapUtil;
  6 +import cn.hutool.core.text.StrPool;
5 7 import cn.hutool.core.util.StrUtil;
6 8 import cn.hutool.extra.spring.SpringUtil;
  9 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
7 10 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
8 11 import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
9 12 import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum;
10 13 import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
11   -import io.vertx.core.Handler;
  14 +import cn.iocoder.yudao.module.iot.gateway.service.message.IotDeviceMessageService;
12 15 import io.vertx.core.json.JsonObject;
13 16 import io.vertx.ext.web.RoutingContext;
14 17 import lombok.RequiredArgsConstructor;
... ... @@ -23,49 +26,39 @@ import java.util.Map;
23 26 */
24 27 @RequiredArgsConstructor
25 28 @Slf4j
26   -public class IotHttpUpstreamHandler implements Handler<RoutingContext> {
  29 +public class IotHttpUpstreamHandler extends IotHttpAbstractHandler {
27 30  
28   - // TODO @haohao:你说,咱要不要把 "/sys/:productKey/:deviceName"
29   - // + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic(),也抽到 IotDeviceTopicEnum 的 build 这种?尽量都收敛掉?
30   - /**
31   - * 属性上报路径
32   - */
33   - public static final String PROPERTY_PATH = "/sys/:productKey/:deviceName"
34   - + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic();
35   -
36   - /**
37   - * 事件上报路径
38   - */
39   - public static final String EVENT_PATH = "/sys/:productKey/:deviceName"
40   - + IotDeviceTopicEnum.EVENT_POST_TOPIC_PREFIX.getTopic() + ":identifier"
41   - + IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic();
  31 + public static final String PATH = "/topic/sys/:productKey/:deviceName/*";
42 32  
43 33 private final IotHttpUpstreamProtocol protocol;
44 34  
45 35 private final IotDeviceMessageProducer deviceMessageProducer;
46 36  
  37 + private final IotDeviceMessageService deviceMessageService;
  38 +
47 39 public IotHttpUpstreamHandler(IotHttpUpstreamProtocol protocol) {
48 40 this.protocol = protocol;
49 41 this.deviceMessageProducer = SpringUtil.getBean(IotDeviceMessageProducer.class);
  42 + this.deviceMessageService = SpringUtil.getBean(IotDeviceMessageService.class);
50 43 }
51 44  
52 45 @Override
53   - public void handle(RoutingContext context) {
54   - String path = context.request().path();
  46 + protected CommonResult<Object> handle0(RoutingContext context) {
55 47 // 1. 解析通用参数
56 48 String productKey = context.pathParam("productKey");
57 49 String deviceName = context.pathParam("deviceName");
58   - JsonObject body = context.body().asJsonObject();
59   -
60   - // 2. 根据路径模式处理不同类型的请求
61   - if (isPropertyPostPath(path)) {
62   - // 处理属性上报
63   - handlePropertyPost(context, productKey, deviceName, body);
64   - } else if (isEventPostPath(path)) {
65   - // 处理事件上报
66   - String identifier = context.pathParam("identifier");
67   - handleEventPost(context, productKey, deviceName, identifier, body);
68   - }
  50 + String method = context.pathParam("*").replaceAll(StrPool.SLASH, StrPool.DOT);
  51 +
  52 + // 2.1 解析消息
  53 + byte[] bytes = context.body().buffer().getBytes();
  54 + IotDeviceMessage message = deviceMessageService.decodeDeviceMessage(bytes,
  55 + productKey, deviceName, protocol.getServerId());
  56 + Assert.equals(method, message.getMethod(), "method 不匹配");
  57 + // 2.2 发送消息
  58 + deviceMessageProducer.sendDeviceMessage(message);
  59 +
  60 + // 3. 返回结果
  61 + return CommonResult.success(MapUtil.of("messageId", message.getId()));
69 62 }
70 63  
71 64 /**
... ... @@ -101,7 +94,8 @@ public class IotHttpUpstreamHandler implements Handler&lt;RoutingContext&gt; {
101 94 JsonObject body) {
102 95 // 1.1 构建设备消息
103 96 IotDeviceMessage message = IotDeviceMessage.of(productKey, deviceName, protocol.getServerId())
104   - .ofPropertyReport(parsePropertiesFromBody(body));
  97 +// .ofPropertyReport(parsePropertiesFromBody(body))
  98 + ;
105 99 // 1.2 发送消息
106 100 deviceMessageProducer.sendDeviceMessage(message);
107 101  
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/mqtt/router/package-info.java deleted
1   -/**
2   - * MQTT 协议路由器包
3   - * <p>
4   - * 包含 MQTT 协议的所有路由处理器和抽象基类:
5   - * <ul>
6   - * <li>{@link cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttAbstractHandler}
7   - * - 抽象路由处理器基类</li>
8   - * <li>{@link cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttUpstreamRouter}
9   - * - 上行消息路由器</li>
10   - * <li>{@link cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttAuthRouter}
11   - * - 认证路由器</li>
12   - * <li>{@link cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttPropertyHandler}
13   - * - 属性处理器</li>
14   - * <li>{@link cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttEventHandler}
15   - * - 事件处理器</li>
16   - * <li>{@link cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router.IotMqttServiceHandler}
17   - * - 服务处理器</li>
18   - * </ul>
19   - *
20   - * @author 芋道源码
21   - */
22   -package cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.router;
23 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/auth/IotDeviceTokenService.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.gateway.service.auth;
3 3 import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
4 4  
5 5 /**
6   - * IoT 设备 Token 服务 Service 接口
  6 + * IoT 设备 Token Service 接口
7 7 *
8 8 * @author 芋道源码
9 9 */
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/message/IotDeviceMessageService.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.service.message;
  2 +
  3 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  4 +
  5 +/**
  6 + * IoT 设备消息 Service 接口
  7 + *
  8 + * @author 芋道源码
  9 + */
  10 +public interface IotDeviceMessageService {
  11 +
  12 + /**
  13 + * 编码消息
  14 + *
  15 + * @param message 消息
  16 + * @param productKey 产品 Key
  17 + * @param deviceName 设备名称
  18 + * @return 编码后的消息内容
  19 + */
  20 + byte[] encodeDeviceMessage(IotDeviceMessage message,
  21 + String productKey, String deviceName);
  22 +
  23 + /**
  24 + * 解码消息
  25 + *
  26 + * @param bytes 消息内容
  27 + * @param productKey 产品 Key
  28 + * @param deviceName 设备名称
  29 + * @param serverId 设备连接的 serverId
  30 + * @return 解码后的消息内容
  31 + */
  32 + IotDeviceMessage decodeDeviceMessage(byte[] bytes,
  33 + String productKey, String deviceName, String serverId);
  34 +
  35 + /**
  36 + * 构建【设备上线】消息
  37 + *
  38 + * @return 消息
  39 + */
  40 + IotDeviceMessage buildDeviceMessageOfStateOnline(String productKey, String deviceName, String serverId);
  41 +
  42 +}
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/service/message/IotDeviceMessageServiceImpl.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.service.message;
  2 +
  3 +import cn.hutool.core.util.StrUtil;
  4 +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
  5 +import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
  6 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  7 +import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
  8 +import cn.iocoder.yudao.module.iot.gateway.codec.alink.IotAlinkDeviceMessageCodec;
  9 +import org.springframework.stereotype.Service;
  10 +
  11 +import java.time.LocalDateTime;
  12 +import java.util.List;
  13 +import java.util.Map;
  14 +
  15 +/**
  16 + * IoT 设备消息 Service 实现类
  17 + *
  18 + * @author 芋道源码
  19 + */
  20 +@Service
  21 +public class IotDeviceMessageServiceImpl implements IotDeviceMessageService {
  22 +
  23 + /**
  24 + * 编解码器
  25 + */
  26 + private final Map<String, IotAlinkDeviceMessageCodec> codes;
  27 +
  28 + public IotDeviceMessageServiceImpl(List<IotAlinkDeviceMessageCodec> codes) {
  29 + this.codes = CollectionUtils.convertMap(codes, IotAlinkDeviceMessageCodec::type);
  30 + }
  31 +
  32 + @Override
  33 + public byte[] encodeDeviceMessage(IotDeviceMessage message,
  34 + String productKey, String deviceName) {
  35 + // TODO @芋艿:获取设备信息
  36 + String codecType = "alink";
  37 + return codes.get(codecType).encode(message);
  38 + }
  39 +
  40 + @Override
  41 + public IotDeviceMessage decodeDeviceMessage(byte[] bytes,
  42 + String productKey, String deviceName, String serverId) {
  43 + // TODO @芋艿:获取设备信息
  44 + String codecType = "alink";
  45 + IotDeviceMessage message = codes.get(codecType).decode(bytes);
  46 + // 补充后端字段
  47 + Long deviceId = 25L;
  48 + Long tenantId = 1L;
  49 + appendDeviceMessage(message, deviceId, tenantId, serverId);
  50 + return message;
  51 + }
  52 +
  53 + @Override
  54 + public IotDeviceMessage buildDeviceMessageOfStateOnline(String productKey, String deviceName, String serverId) {
  55 + IotDeviceMessage message = IotDeviceMessage.of(null,
  56 + IotDeviceMessageMethodEnum.STATE_ONLINE.getMethod(), null);
  57 + // 补充后端字段
  58 + Long deviceId = 25L;
  59 + Long tenantId = 1L;
  60 + return appendDeviceMessage(message, deviceId, tenantId, serverId);
  61 + }
  62 +
  63 + /**
  64 + * 补充消息的后端字段
  65 + *
  66 + * @param message 消息
  67 + * @param deviceId 设备编号
  68 + * @param tenantId 租户编号
  69 + * @param serverId 设备连接的 serverId
  70 + * @return 消息
  71 + */
  72 + private IotDeviceMessage appendDeviceMessage(IotDeviceMessage message,
  73 + Long deviceId, Long tenantId, String serverId) {
  74 + message.setId(IotDeviceMessageUtils.generateMessageId()).setReportTime(LocalDateTime.now())
  75 + .setDeviceId(deviceId).setTenantId(tenantId).setServerId(serverId);
  76 + // 特殊:如果设备没有指定 requestId,则使用 messageId
  77 + if (StrUtil.isEmpty(message.getRequestId())) {
  78 + message.setRequestId(message.getId());
  79 + }
  80 + return message;
  81 + }
  82 +
  83 +}
... ...