Commit c3485a3f3daa2dbcdb03c6c0484afefb8ae655ee

Authored by YunaiV
1 parent 81cbc61f

reactor:【IoT 物联网】将 http component 合并到 gateway 里

Showing 46 changed files with 524 additions and 922 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/device/IotDeviceDO.java
... ... @@ -33,6 +33,7 @@ public class IotDeviceDO extends TenantBaseDO {
33 33 */
34 34 @TableId
35 35 private Long id;
  36 + // TODO @芋艿:看看怎么弱化 deviceKey
36 37 /**
37 38 * 设备唯一标识符,全局唯一,用于识别设备
38 39 *
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/redis/RedisKeyConstants.java
... ... @@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDevicePropertyDO;
9 9 */
10 10 public interface RedisKeyConstants {
11 11  
  12 + // TODO @芋艿:弱化 deviceKey;使用 product_key + device_name 替代
12 13 /**
13 14 * 设备属性的数据缓存,采用 HASH 结构
14 15 * <p>
... ... @@ -18,6 +19,7 @@ public interface RedisKeyConstants {
18 19 */
19 20 String DEVICE_PROPERTY = "iot:device_property:%s";
20 21  
  22 + // TODO @芋艿:弱化 deviceKey;使用 product_key + device_name 替代
21 23 /**
22 24 * 设备的最后上报时间,采用 ZSET 结构
23 25 *
... ... @@ -29,7 +31,7 @@ public interface RedisKeyConstants {
29 31 /**
30 32 * 设备信息的数据缓存,使用 Spring Cache 操作(忽略租户)
31 33 *
32   - * KEY 格式:device_${productKey}_${deviceKey}
  34 + * KEY 格式:device_${productKey}_${deviceName}
33 35 * VALUE 数据类型:String(JSON)
34 36 */
35 37 String DEVICE = "iot:device";
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageBusSubscriber.java renamed to yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mq/consumer/device/IotDeviceLogMessageSubscriber.java
1 1 package cn.iocoder.yudao.module.iot.mq.consumer.device;
2 2  
3 3 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
4   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber;
  4 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
5 5 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
6 6 import cn.iocoder.yudao.module.iot.service.device.data.IotDeviceLogService;
7 7 import jakarta.annotation.PostConstruct;
... ... @@ -16,7 +16,7 @@ import org.springframework.stereotype.Component;
16 16 */
17 17 @Component
18 18 @Slf4j
19   -public class IotDeviceLogMessageBusSubscriber implements IotMessageBusSubscriber<IotDeviceMessage> {
  19 +public class IotDeviceLogMessageSubscriber implements IotMessageSubscriber<IotDeviceMessage> {
20 20  
21 21 @Resource
22 22 private IotMessageBus messageBus;
... ...
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/control/IotDeviceDownstreamServiceImpl.java
... ... @@ -20,7 +20,6 @@ import jakarta.annotation.Resource;
20 20 import lombok.extern.slf4j.Slf4j;
21 21 import org.springframework.stereotype.Service;
22 22 import org.springframework.validation.annotation.Validated;
23   -import org.springframework.web.client.RestTemplate;
24 23  
25 24 import java.time.LocalDateTime;
26 25 import java.util.List;
... ... @@ -45,9 +44,6 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
45 44 private IotDeviceService deviceService;
46 45  
47 46 @Resource
48   - private RestTemplate restTemplate;
49   -
50   - @Resource
51 47 private IotDeviceProducer deviceProducer;
52 48 @Resource
53 49 private IotDeviceMessageProducer deviceMessageProducer;
... ... @@ -156,7 +152,7 @@ public class IotDeviceDownstreamServiceImpl implements IotDeviceDownstreamServic
156 152 cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage message = cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage
157 153 .of(getProductKey(device, parentDevice), getDeviceName(device, parentDevice), deviceName,
158 154 null, tenantId);
159   - String serverId = "yy";
  155 + String serverId = "192_168_64_1_8092";
160 156 deviceMessageProducer.sendGatewayDeviceMessage(serverId, message);
161 157 // TODO @芋艿:后续可以清理掉
162 158 return null;
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBus.java
... ... @@ -22,6 +22,6 @@ public interface IotMessageBus {
22 22 *
23 23 * @param subscriber 订阅者
24 24 */
25   - void register(IotMessageBusSubscriber<?> subscriber);
  25 + void register(IotMessageSubscriber<?> subscriber);
26 26  
27 27 }
28 28 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageBusSubscriber.java renamed to yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/IotMessageSubscriber.java
... ... @@ -7,7 +7,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core;
7 7 *
8 8 * @author 芋道源码
9 9 */
10   -public interface IotMessageBusSubscriber<T> {
  10 +public interface IotMessageSubscriber<T> {
11 11  
12 12 /**
13 13 * @return 主题
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBus.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.local;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
5   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber;
  5 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
6 6 import lombok.RequiredArgsConstructor;
7 7 import lombok.extern.slf4j.Slf4j;
8 8 import org.springframework.context.ApplicationContext;
... ... @@ -30,7 +30,7 @@ public class LocalIotMessageBus implements IotMessageBus {
30 30 * 订阅者映射表
31 31 * Key: topic
32 32 */
33   - private final Map<String, List<IotMessageBusSubscriber<?>>> subscribers = new HashMap<>();
  33 + private final Map<String, List<IotMessageSubscriber<?>>> subscribers = new HashMap<>();
34 34  
35 35 @Override
36 36 public void post(String topic, Object message) {
... ... @@ -38,9 +38,9 @@ public class LocalIotMessageBus implements IotMessageBus {
38 38 }
39 39  
40 40 @Override
41   - public void register(IotMessageBusSubscriber<?> subscriber) {
  41 + public void register(IotMessageSubscriber<?> subscriber) {
42 42 String topic = subscriber.getTopic();
43   - List<IotMessageBusSubscriber<?>> topicSubscribers = subscribers.computeIfAbsent(topic, k -> new ArrayList<>());
  43 + List<IotMessageSubscriber<?>> topicSubscribers = subscribers.computeIfAbsent(topic, k -> new ArrayList<>());
44 44 topicSubscribers.add(subscriber);
45 45 log.info("[register][topic({}/{}) 注册消费者({})成功]",
46 46 topic, subscriber.getGroup(), subscriber.getClass().getName());
... ... @@ -50,11 +50,11 @@ public class LocalIotMessageBus implements IotMessageBus {
50 50 @SuppressWarnings({"unchecked", "rawtypes"})
51 51 public void onMessage(LocalIotMessage message) {
52 52 String topic = message.getTopic();
53   - List<IotMessageBusSubscriber<?>> topicSubscribers = subscribers.get(topic);
  53 + List<IotMessageSubscriber<?>> topicSubscribers = subscribers.get(topic);
54 54 if (CollUtil.isEmpty(topicSubscribers)) {
55 55 return;
56 56 }
57   - for (IotMessageBusSubscriber subscriber : topicSubscribers) {
  57 + for (IotMessageSubscriber subscriber : topicSubscribers) {
58 58 try {
59 59 subscriber.onMessage(message.getMessage());
60 60 } catch (Exception ex) {
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBus.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq;
3 3 import cn.hutool.core.util.TypeUtil;
4 4 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
5 5 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
6   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber;
  6 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
7 7 import lombok.RequiredArgsConstructor;
8 8 import lombok.SneakyThrows;
9 9 import lombok.extern.slf4j.Slf4j;
... ... @@ -47,7 +47,7 @@ public class RocketMQIotMessageBus implements IotMessageBus {
47 47  
48 48 @Override
49 49 @SneakyThrows
50   - public void register(IotMessageBusSubscriber<?> subscriber) {
  50 + public void register(IotMessageSubscriber<?> subscriber) {
51 51 Type type = TypeUtil.getTypeArgument(subscriber.getClass(), 0);
52 52 if (type == null) {
53 53 throw new IllegalStateException(String.format("类型(%s) 需要设置消息类型", getClass().getName()));
... ...
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.hutool.core.util.IdUtil;
4 3 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageIdentifierEnum;
5 4 import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageTypeEnum;
  5 +import cn.iocoder.yudao.module.iot.core.util.IotCoreUtils;
6 6 import lombok.AllArgsConstructor;
7 7 import lombok.Builder;
8 8 import lombok.Data;
... ... @@ -119,7 +119,7 @@ public class IotDeviceMessage {
119 119 String requestId, LocalDateTime reportTime,
120 120 String serverId, Long tenantId) {
121 121 if (requestId == null) {
122   - requestId = IdUtil.fastSimpleUUID();
  122 + requestId = IotCoreUtils.generateRequestId();
123 123 }
124 124 if (reportTime == null) {
125 125 reportTime = LocalDateTime.now();
... ...
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/util/IotCoreUtils.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.core.util;
  2 +
  3 +import cn.hutool.core.util.IdUtil;
  4 +import cn.hutool.system.SystemUtil;
  5 +
  6 +/**
  7 + * IoT 核心模块的工具类
  8 + *
  9 + * @author 芋道源码
  10 + */
  11 +public class IotCoreUtils {
  12 +
  13 + /**
  14 + * 生成服务器编号
  15 + *
  16 + * @param serverPort 服务器端口
  17 + * @return 服务器编号
  18 + */
  19 + public static String generateServerId(Integer serverPort) {
  20 + String serverId = String.format("%s.%d", SystemUtil.getHostInfo().getAddress(), serverPort);
  21 + // 避免一些场景无法使用 . 符号,例如说 RocketMQ Topic
  22 + return serverId.replaceAll("\\.", "_");
  23 + }
  24 +
  25 + public static String generateRequestId() {
  26 + return IdUtil.fastSimpleUUID();
  27 + }
  28 +
  29 +}
0 30 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/local/LocalIotMessageBusIntegrationTest.java
... ... @@ -2,7 +2,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.local;
2 2  
3 3 import cn.iocoder.yudao.module.iot.core.messagebus.config.IotMessageBusAutoConfiguration;
4 4 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
5   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber;
  5 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
6 6 import jakarta.annotation.Resource;
7 7 import lombok.extern.slf4j.Slf4j;
8 8 import org.junit.jupiter.api.Test;
... ... @@ -47,7 +47,7 @@ public class LocalIotMessageBusIntegrationTest {
47 47 AtomicInteger subscriber2Count = new AtomicInteger(0);
48 48  
49 49 // 创建第一个订阅者
50   - IotMessageBusSubscriber<String> subscriber1 = new IotMessageBusSubscriber<>() {
  50 + IotMessageSubscriber<String> subscriber1 = new IotMessageSubscriber<>() {
51 51  
52 52 @Override
53 53 public String getTopic() {
... ... @@ -69,7 +69,7 @@ public class LocalIotMessageBusIntegrationTest {
69 69  
70 70 };
71 71 // 创建第二个订阅者
72   - IotMessageBusSubscriber<String> subscriber2 = new IotMessageBusSubscriber<>() {
  72 + IotMessageSubscriber<String> subscriber2 = new IotMessageSubscriber<>() {
73 73  
74 74 @Override
75 75 public String getTopic() {
... ... @@ -120,7 +120,7 @@ public class LocalIotMessageBusIntegrationTest {
120 120 CountDownLatch latch = new CountDownLatch(2);
121 121  
122 122 // 创建订阅者 1 - 只订阅设备状态
123   - IotMessageBusSubscriber<String> statusSubscriber = new IotMessageBusSubscriber<>() {
  123 + IotMessageSubscriber<String> statusSubscriber = new IotMessageSubscriber<>() {
124 124  
125 125 @Override
126 126 public String getTopic() {
... ... @@ -141,7 +141,7 @@ public class LocalIotMessageBusIntegrationTest {
141 141  
142 142 };
143 143 // 创建订阅者 2 - 只订阅设备数据
144   - IotMessageBusSubscriber<String> dataSubscriber = new IotMessageBusSubscriber<>() {
  144 + IotMessageSubscriber<String> dataSubscriber = new IotMessageSubscriber<>() {
145 145  
146 146 @Override
147 147 public String getTopic() {
... ...
yudao-module-iot/yudao-module-iot-core/src/test/java/cn/iocoder/yudao/module/iot/core/messagebus/core/rocketmq/RocketMQIotMessageBusTest.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.iot.core.messagebus.core.rocketmq;
3 3 import cn.hutool.core.util.IdUtil;
4 4 import cn.iocoder.yudao.module.iot.core.messagebus.config.IotMessageBusAutoConfiguration;
5 5 import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
6   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber;
  6 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
7 7 import cn.iocoder.yudao.module.iot.core.messagebus.core.TestMessage;
8 8 import jakarta.annotation.Resource;
9 9 import lombok.extern.slf4j.Slf4j;
... ... @@ -59,7 +59,7 @@ public class RocketMQIotMessageBusTest {
59 59 messageBus.post(topic, testMessage);
60 60  
61 61 // 创建订阅者
62   - IotMessageBusSubscriber<String> subscriber1 = new IotMessageBusSubscriber<>() {
  62 + IotMessageSubscriber<String> subscriber1 = new IotMessageSubscriber<>() {
63 63  
64 64 @Override
65 65 public String getTopic() {
... ... @@ -117,7 +117,7 @@ public class RocketMQIotMessageBusTest {
117 117 messageBus.post(topic, testMessage);
118 118  
119 119 // 创建第一个订阅者
120   - IotMessageBusSubscriber<TestMessage> subscriber1 = new IotMessageBusSubscriber<>() {
  120 + IotMessageSubscriber<TestMessage> subscriber1 = new IotMessageSubscriber<>() {
121 121  
122 122 @Override
123 123 public String getTopic() {
... ... @@ -141,7 +141,7 @@ public class RocketMQIotMessageBusTest {
141 141  
142 142 };
143 143 // 创建第二个订阅者
144   - IotMessageBusSubscriber<TestMessage> subscriber2 = new IotMessageBusSubscriber<>() {
  144 + IotMessageSubscriber<TestMessage> subscriber2 = new IotMessageSubscriber<>() {
145 145  
146 146 @Override
147 147 public String getTopic() {
... ... @@ -204,7 +204,7 @@ public class RocketMQIotMessageBusTest {
204 204 messageBus.post(topic2, message2);
205 205  
206 206 // 创建订阅者 1 - 只订阅设备状态
207   - IotMessageBusSubscriber<String> statusSubscriber = new IotMessageBusSubscriber<>() {
  207 + IotMessageSubscriber<String> statusSubscriber = new IotMessageSubscriber<>() {
208 208  
209 209 @Override
210 210 public String getTopic() {
... ... @@ -227,7 +227,7 @@ public class RocketMQIotMessageBusTest {
227 227  
228 228 };
229 229 // 创建订阅者 2 - 只订阅设备数据
230   - IotMessageBusSubscriber<String> dataSubscriber = new IotMessageBusSubscriber<>() {
  230 + IotMessageSubscriber<String> dataSubscriber = new IotMessageSubscriber<>() {
231 231  
232 232 @Override
233 233 public String getTopic() {
... ...
yudao-module-iot/yudao-module-iot-gateway/pom.xml
... ... @@ -16,4 +16,46 @@
16 16 ② 功能二:接收来自消息网关的消息(由 iot-biz 发送),并进行编码(encode)后,发送给设备
17 17 </description>
18 18  
  19 + <dependencies>
  20 + <dependency>
  21 + <groupId>cn.iocoder.boot</groupId>
  22 + <artifactId>yudao-module-iot-core</artifactId>
  23 + <version>${revision}</version>
  24 + </dependency>
  25 +
  26 + <!-- 消息队列相关 -->
  27 + <dependency>
  28 + <groupId>org.apache.rocketmq</groupId>
  29 + <artifactId>rocketmq-spring-boot-starter</artifactId>
  30 + <!-- TODO @芋艿:消息队列,后续可能去掉,默认不使用 rocketmq -->
  31 +<!-- <optional>true</optional> -->
  32 + </dependency>
  33 +
  34 + <!-- 工具类相关 -->
  35 + <dependency>
  36 + <groupId>io.vertx</groupId>
  37 + <artifactId>vertx-web</artifactId>
  38 + </dependency>
  39 + </dependencies>
  40 +
  41 + <build>
  42 + <!-- 设置构建的 jar 包名 -->
  43 + <finalName>${project.artifactId}</finalName>
  44 + <plugins>
  45 + <!-- 打包 -->
  46 + <plugin>
  47 + <groupId>org.springframework.boot</groupId>
  48 + <artifactId>spring-boot-maven-plugin</artifactId>
  49 + <version>${spring.boot.version}</version>
  50 + <executions>
  51 + <execution>
  52 + <goals>
  53 + <goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
  54 + </goals>
  55 + </execution>
  56 + </executions>
  57 + </plugin>
  58 + </plugins>
  59 + </build>
  60 +
19 61 </project>
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/IotGatewayServerApplication.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway;
  2 +
  3 +import org.springframework.boot.SpringApplication;
  4 +import org.springframework.boot.autoconfigure.SpringBootApplication;
  5 +
  6 +@SpringBootApplication
  7 +public class IotGatewayServerApplication {
  8 +
  9 + public static void main(String[] args) {
  10 + SpringApplication.run(IotGatewayServerApplication.class, args);
  11 + }
  12 +
  13 +}
0 14 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/codec/package-info.java
  1 +/**
  2 + * 提供设备接入的各种数据(请求、响应)的编解码
  3 + */
1 4 package cn.iocoder.yudao.module.iot.gateway.codec;
2 5 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.config;
  2 +
  3 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
  4 +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
  5 +import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpDownstreamSubscriber;
  6 +import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
  7 +import lombok.extern.slf4j.Slf4j;
  8 +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  9 +import org.springframework.boot.context.properties.EnableConfigurationProperties;
  10 +import org.springframework.context.annotation.Bean;
  11 +import org.springframework.context.annotation.Configuration;
  12 +
  13 +@Configuration
  14 +@EnableConfigurationProperties(IotGatewayProperties.class)
  15 +@Slf4j
  16 +public class IotGatewayConfiguration {
  17 +
  18 + /**
  19 + * IoT 网关 HTTP 协议配置类
  20 + */
  21 + @Configuration
  22 + @ConditionalOnProperty(prefix = "yudao.iot.gateway.protocol.http", name = "enabled", havingValue = "true")
  23 + @Slf4j
  24 + public static class HttpProtocolConfiguration {
  25 +
  26 + @Bean
  27 + public IotHttpUpstreamProtocol iotHttpUpstreamProtocol(IotGatewayProperties gatewayProperties,
  28 + IotDeviceMessageProducer deviceMessageProducer) {
  29 + return new IotHttpUpstreamProtocol(gatewayProperties.getProtocol().getHttp(), deviceMessageProducer);
  30 + }
  31 +
  32 + @Bean
  33 + public IotHttpDownstreamSubscriber iotHttpDownstreamSubscriber(IotHttpUpstreamProtocol httpUpstreamProtocol,
  34 + IotMessageBus messageBus) {
  35 + return new IotHttpDownstreamSubscriber(httpUpstreamProtocol,messageBus);
  36 + }
  37 + }
  38 +
  39 +}
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayProperties.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.config;
  2 +
  3 +import lombok.Data;
  4 +import org.springframework.boot.context.properties.ConfigurationProperties;
  5 +import org.springframework.validation.annotation.Validated;
  6 +
  7 +import java.util.List;
  8 +
  9 +@ConfigurationProperties(prefix = "yudao.iot.gateway")
  10 +@Validated
  11 +@Data
  12 +public class IotGatewayProperties {
  13 +
  14 + /**
  15 + * 设备 RPC 服务配置
  16 + */
  17 + private RpcProperties rpc;
  18 +
  19 + /**
  20 + * 协议配置
  21 + */
  22 + private ProtocolProperties protocol;
  23 +
  24 + @Data
  25 + public static class RpcProperties {
  26 +
  27 + /**
  28 + * 主程序 API 地址
  29 + */
  30 + private String url;
  31 + /**
  32 + * 连接超时时间
  33 + */
  34 + private String connectTimeout;
  35 + /**
  36 + * 读取超时时间
  37 + */
  38 + private String readTimeout;
  39 +
  40 + }
  41 +
  42 + @Data
  43 + public static class ProtocolProperties {
  44 +
  45 + /**
  46 + * HTTP 组件配置
  47 + */
  48 + private HttpProperties http;
  49 +
  50 + /**
  51 + * EMQX 组件配置
  52 + */
  53 + private EmqxProperties emqx;
  54 +
  55 + }
  56 +
  57 + @Data
  58 + public static class HttpProperties {
  59 +
  60 + /**
  61 + * 是否开启
  62 + */
  63 + private Boolean enabled;
  64 + /**
  65 + * 服务端口
  66 + */
  67 + private Integer serverPort;
  68 +
  69 + }
  70 +
  71 + @Data
  72 + public static class EmqxProperties {
  73 +
  74 + /**
  75 + * 是否开启
  76 + */
  77 + private Boolean enabled;
  78 + /**
  79 + * MQTT 服务器地址
  80 + */
  81 + private String mqttHost;
  82 + /**
  83 + * MQTT 服务器端口
  84 + */
  85 + private Integer mqttPort;
  86 + /**
  87 + * MQTT 用户名
  88 + */
  89 + private String mqttUsername;
  90 + /**
  91 + * MQTT 密码
  92 + */
  93 + private String mqttPassword;
  94 + /**
  95 + * MQTT 是否开启 SSL
  96 + */
  97 + private Boolean mqttSsl;
  98 + /**
  99 + * MQTT 主题
  100 + */
  101 + private List<String> mqttTopics;
  102 + /**
  103 + * 认证端口
  104 + */
  105 + private Integer authPort;
  106 +
  107 + }
  108 +
  109 +}
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/constants/IotDeviceTopicEnum.java renamed to yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/enums/IotDeviceTopicEnum.java
1   -package cn.iocoder.yudao.module.iot.net.component.core.constants;
  1 +package cn.iocoder.yudao.module.iot.gateway.enums;
2 2  
3 3 import lombok.Getter;
  4 +import lombok.RequiredArgsConstructor;
4 5  
5   -// TODO @haohao:要不放到 enums 包下;
6 6 /**
7 7 * IoT 设备主题枚举
8 8 * <p>
... ... @@ -10,6 +10,7 @@ import lombok.Getter;
10 10 *
11 11 * @author haohao
12 12 */
  13 +@RequiredArgsConstructor
13 14 @Getter
14 15 public enum IotDeviceTopicEnum {
15 16  
... ... @@ -27,36 +28,36 @@ public enum IotDeviceTopicEnum {
27 28 // TODO @haohao:注释时,中英文之间,有个空格;
28 29 /**
29 30 * 设备属性设置主题
30   - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/set
31   - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply
  31 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/property/set
  32 + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/property/set_reply
32 33 */
33 34 PROPERTY_SET_TOPIC("/thing/service/property/set", "设备属性设置主题"),
34 35  
35 36 /**
36 37 * 设备属性获取主题
37   - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/property/get
38   - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/property/get_reply
  38 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/property/get
  39 + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/property/get_reply
39 40 */
40 41 PROPERTY_GET_TOPIC("/thing/service/property/get", "设备属性获取主题"),
41 42  
42 43 /**
43 44 * 设备配置设置主题
44   - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/config/set
45   - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/config/set_reply
  45 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/config/set
  46 + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/config/set_reply
46 47 */
47 48 CONFIG_SET_TOPIC("/thing/service/config/set", "设备配置设置主题"),
48 49  
49 50 /**
50 51 * 设备OTA升级主题
51   - * 请求Topic:/sys/${productKey}/${deviceName}/thing/service/ota/upgrade
52   - * 响应Topic:/sys/${productKey}/${deviceName}/thing/service/ota/upgrade_reply
  52 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/service/ota/upgrade
  53 + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/service/ota/upgrade_reply
53 54 */
54 55 OTA_UPGRADE_TOPIC("/thing/service/ota/upgrade", "设备OTA升级主题"),
55 56  
56 57 /**
57 58 * 设备属性上报主题
58   - * 请求Topic:/sys/${productKey}/${deviceName}/thing/event/property/post
59   - * 响应Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply
  59 + * 请求 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post
  60 + * 响应 Topic:/sys/${productKey}/${deviceName}/thing/event/property/post_reply
60 61 */
61 62 PROPERTY_POST_TOPIC("/thing/event/property/post", "设备属性上报主题"),
62 63  
... ... @@ -78,12 +79,6 @@ public enum IotDeviceTopicEnum {
78 79 private final String topic;
79 80 private final String description;
80 81  
81   - // TODO @haohao:使用 lombok 去除
82   - IotDeviceTopicEnum(String topic, String description) {
83   - this.topic = topic;
84   - this.description = description;
85   - }
86   -
87 82 /**
88 83 * 构建设备服务调用主题
89 84 *
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/package-info.java deleted
1   -package cn.iocoder.yudao.module.iot.gateway;
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/IotHttpDownstreamSubscriber.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.protocol.http;
  2 +
  3 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
  4 +import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageSubscriber;
  5 +import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
  6 +import jakarta.annotation.PostConstruct;
  7 +import lombok.RequiredArgsConstructor;
  8 +import lombok.extern.slf4j.Slf4j;
  9 +
  10 +/**
  11 + * IoT 网关 HTTP 订阅者:接收下行给设备的消息
  12 + *
  13 + * @author 芋道源码
  14 + */
  15 +@RequiredArgsConstructor
  16 +@Slf4j
  17 +public class IotHttpDownstreamSubscriber implements IotMessageSubscriber<IotDeviceMessage> {
  18 +
  19 + private final IotHttpUpstreamProtocol protocol;
  20 +
  21 + private final IotMessageBus messageBus;
  22 +
  23 + @PostConstruct
  24 + public void init() {
  25 + messageBus.register(this);
  26 + }
  27 +
  28 + @Override
  29 + public String getTopic() {
  30 + return IotDeviceMessage.buildMessageBusGatewayDeviceMessageTopic(protocol.getServerId());
  31 + }
  32 +
  33 + @Override
  34 + public String getGroup() {
  35 + // 保证点对点消费,需要保证独立的 Group,所以使用 Topic 作为 Group
  36 + return getTopic();
  37 + }
  38 +
  39 + @Override
  40 + public void onMessage(IotDeviceMessage message) {
  41 + log.error("[onMessage][IoT 网关 HTTP 协议不支持下行消息,忽略消息:{}]", message);
  42 + }
  43 +
  44 +}
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/IotHttpUpstreamProtocol.java 0 → 100644
  1 +package cn.iocoder.yudao.module.iot.gateway.protocol.http;
  2 +
  3 +import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
  4 +import cn.iocoder.yudao.module.iot.core.util.IotCoreUtils;
  5 +import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
  6 +import cn.iocoder.yudao.module.iot.gateway.protocol.http.router.IotHttpUpstreamHandler;
  7 +import io.vertx.core.AbstractVerticle;
  8 +import io.vertx.core.Vertx;
  9 +import io.vertx.core.http.HttpServer;
  10 +import io.vertx.ext.web.Router;
  11 +import io.vertx.ext.web.handler.BodyHandler;
  12 +import jakarta.annotation.PostConstruct;
  13 +import jakarta.annotation.PreDestroy;
  14 +import lombok.RequiredArgsConstructor;
  15 +import lombok.extern.slf4j.Slf4j;
  16 +
  17 +/**
  18 + * IoT 网关 HTTP 协议:接收设备上行消息
  19 + *
  20 + * @author 芋道源码
  21 + */
  22 +@RequiredArgsConstructor
  23 +@Slf4j
  24 +public class IotHttpUpstreamProtocol extends AbstractVerticle {
  25 +
  26 + private final IotGatewayProperties.HttpProperties httpProperties;
  27 +
  28 + private final IotDeviceMessageProducer deviceMessageProducer;
  29 +
  30 + private HttpServer httpServer;
  31 +
  32 + @Override
  33 + @PostConstruct
  34 + public void start() {
  35 + // 创建路由
  36 + Vertx vertx = Vertx.vertx();
  37 + Router router = Router.router(vertx);
  38 + router.route().handler(BodyHandler.create());
  39 +
  40 + // 创建处理器,添加路由处理器
  41 + IotHttpUpstreamHandler upstreamHandler = new IotHttpUpstreamHandler(
  42 + this, deviceMessageProducer);
  43 + router.post(IotHttpUpstreamHandler.PROPERTY_PATH).handler(upstreamHandler);
  44 + router.post(IotHttpUpstreamHandler.EVENT_PATH).handler(upstreamHandler);
  45 +
  46 + // 启动 HTTP 服务器
  47 + try {
  48 + httpServer = vertx.createHttpServer()
  49 + .requestHandler(router)
  50 + .listen(httpProperties.getServerPort())
  51 + .result();
  52 + log.info("[start][IoT 网关 HTTP 协议启动成功,端口:{}]", httpProperties.getServerPort());
  53 + } catch (Exception e) {
  54 + log.error("[start][IoT 网关 HTTP 协议启动失败]", e);
  55 + throw e;
  56 + }
  57 + }
  58 +
  59 + @Override
  60 + @PreDestroy
  61 + public void stop() {
  62 + if (httpServer != null) {
  63 + try {
  64 + httpServer.close().result();
  65 + log.info("[stop][IoT 网关 HTTP 协议已停止]");
  66 + } catch (Exception e) {
  67 + log.error("[stop][IoT 网关 HTTP 协议停止失败]", e);
  68 + }
  69 + }
  70 + }
  71 +
  72 + public String getServerId() {
  73 + return IotCoreUtils.generateServerId(httpProperties.getServerPort());
  74 + }
  75 +
  76 +}
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/package-info.java deleted
1   -package cn.iocoder.yudao.module.iot.gateway.protocol.http;
2 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/router/IotDeviceUpstreamVertxHandler.java renamed to yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/http/router/IotHttpUpstreamHandler.java
1   -package cn.iocoder.yudao.module.iot.net.component.http.upstream.router;
  1 +package cn.iocoder.yudao.module.iot.gateway.protocol.http.router;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.map.MapUtil;
... ... @@ -6,13 +6,10 @@ import cn.hutool.core.util.IdUtil;
6 6 import cn.hutool.core.util.ObjUtil;
7 7 import cn.hutool.core.util.StrUtil;
8 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
9   -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
10   -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.IotDeviceEventReportReqDTO;
11 9 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
12 10 import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
13   -import cn.iocoder.yudao.module.iot.net.component.core.constants.IotDeviceTopicEnum;
14   -import cn.iocoder.yudao.module.iot.net.component.core.pojo.IotStandardResponse;
15   -import cn.iocoder.yudao.module.iot.net.component.core.util.IotNetComponentCommonUtils;
  11 +import cn.iocoder.yudao.module.iot.gateway.enums.IotDeviceTopicEnum;
  12 +import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpUpstreamProtocol;
16 13 import io.vertx.core.Handler;
17 14 import io.vertx.core.json.JsonObject;
18 15 import io.vertx.ext.web.RoutingContext;
... ... @@ -26,15 +23,13 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
26 23 import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
27 24  
28 25 /**
29   - * IoT 设备上行统一处理的 Vert.x Handler
30   - * <p>
31   - * 统一处理设备属性上报和事件上报的请求。
  26 + * IoT 网关 HTTP 协议的处理器
32 27 *
33 28 * @author 芋道源码
34 29 */
35 30 @RequiredArgsConstructor
36 31 @Slf4j
37   -public class IotDeviceUpstreamVertxHandler implements Handler<RoutingContext> {
  32 +public class IotHttpUpstreamHandler implements Handler<RoutingContext> {
38 33  
39 34 // TODO @haohao:你说,咱要不要把 "/sys/:productKey/:deviceName"
40 35 // + IotDeviceTopicEnum.PROPERTY_POST_TOPIC.getTopic(),也抽到 IotDeviceTopicEnum 的 build 这种?尽量都收敛掉?
... ... @@ -52,11 +47,6 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
52 47 + IotDeviceTopicEnum.EVENT_POST_TOPIC_SUFFIX.getTopic();
53 48  
54 49 /**
55   - * 属性上报方法标识
56   - */
57   - private static final String PROPERTY_METHOD = "thing.event.property.post";
58   -
59   - /**
60 50 * 事件上报方法前缀
61 51 */
62 52 private static final String EVENT_METHOD_PREFIX = "thing.event.";
... ... @@ -66,10 +56,11 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
66 56 */
67 57 private static final String EVENT_METHOD_SUFFIX = ".post";
68 58  
69   - /**
70   - * 设备上行 API
71   - */
72   - private final IotDeviceUpstreamApi deviceUpstreamApi;
  59 + private final IotHttpUpstreamProtocol protocol;
  60 +// /**
  61 +// * 设备上行 API
  62 +// */
  63 +// private final IotDeviceUpstreamApi deviceUpstreamApi;
73 64 /**
74 65 * 设备消息生产者
75 66 */
... ... @@ -167,13 +158,14 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
167 158 String deviceKey = "xxx"; // TODO @芋艿:待支持
168 159 Long tenantId = 1L; // TODO @芋艿:待支持
169 160 IotDeviceMessage message = IotDeviceMessage.of(productKey, deviceName, deviceKey,
170   - requestId, LocalDateTime.now(), IotNetComponentCommonUtils.getProcessId(), tenantId)
  161 + requestId, LocalDateTime.now(),
  162 + protocol.getServerId(), tenantId)
171 163 .ofPropertyReport(parsePropertiesFromBody(body));
172 164 // 1.2 发送消息
173 165 deviceMessageProducer.sendDeviceMessage(message);
174 166  
175 167 // 2. 返回响应
176   - sendResponse(routingContext, requestId, PROPERTY_METHOD, null);
  168 + sendResponse(routingContext, requestId, null, null);
177 169 }
178 170  
179 171 /**
... ... @@ -188,16 +180,16 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
188 180 */
189 181 private void handleEventPost(RoutingContext routingContext, String productKey, String deviceName,
190 182 String identifier, String requestId, JsonObject body) {
191   - // 处理事件上报
192   - IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier,
193   - requestId, body);
194   -
195   - // 事件上报
196   - CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO);
197   - String method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX;
198   -
199   - // 返回响应
200   - sendResponse(routingContext, requestId, method, result);
  183 +// // 处理事件上报
  184 +// IotDeviceEventReportReqDTO reportReqDTO = parseEventReportRequest(productKey, deviceName, identifier,
  185 +// requestId, body);
  186 +//
  187 +// // 事件上报
  188 +// CommonResult<Boolean> result = deviceUpstreamApi.reportDeviceEvent(reportReqDTO);
  189 +// String method = EVENT_METHOD_PREFIX + identifier + EVENT_METHOD_SUFFIX;
  190 +//
  191 +// // 返回响应
  192 +// sendResponse(routingContext, requestId, method, result);
201 193 }
202 194  
203 195 /**
... ... @@ -210,16 +202,16 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
210 202 */
211 203 private void sendResponse(RoutingContext routingContext, String requestId, String method,
212 204 CommonResult<Boolean> result) {
213   - // TODO @芋艿:后续再优化
214   - IotStandardResponse response;
215   - if (result == null ) {
216   - response = IotStandardResponse.success(requestId, method, null);
217   - } else if (result.isSuccess()) {
218   - response = IotStandardResponse.success(requestId, method, result.getData());
219   - } else {
220   - response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg());
221   - }
222   - IotNetComponentCommonUtils.writeJsonResponse(routingContext, response);
  205 +// // TODO @芋艿:后续再优化
  206 +// IotStandardResponse response;
  207 +// if (result == null ) {
  208 +// response = IotStandardResponse.success(requestId, method, null);
  209 +// } else if (result.isSuccess()) {
  210 +// response = IotStandardResponse.success(requestId, method, result.getData());
  211 +// } else {
  212 +// response = IotStandardResponse.error(requestId, method, result.getCode(), result.getMsg());
  213 +// }
  214 +// IotNetComponentCommonUtils.writeJsonResponse(routingContext, response);
223 215 }
224 216  
225 217 /**
... ... @@ -233,8 +225,8 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
233 225 */
234 226 private void sendErrorResponse(RoutingContext routingContext, String requestId, String method, Integer code,
235 227 String message) {
236   - IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message);
237   - IotNetComponentCommonUtils.writeJsonResponse(routingContext, errorResponse);
  228 +// IotStandardResponse errorResponse = IotStandardResponse.error(requestId, method, code, message);
  229 +// IotNetComponentCommonUtils.writeJsonResponse(routingContext, errorResponse);
238 230 }
239 231  
240 232 /**
... ... @@ -246,7 +238,7 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
246 238 */
247 239 private String determineMethodFromPath(String path, RoutingContext routingContext) {
248 240 if (StrUtil.contains(path, "/property/")) {
249   - return PROPERTY_METHOD;
  241 + return null;
250 242 }
251 243  
252 244 return EVENT_METHOD_PREFIX
... ... @@ -285,29 +277,29 @@ public class IotDeviceUpstreamVertxHandler implements Handler&lt;RoutingContext&gt; {
285 277 return properties;
286 278 }
287 279  
288   - /**
289   - * 解析事件上报请求
290   - *
291   - * @param productKey 产品 Key
292   - * @param deviceName 设备名称
293   - * @param identifier 事件标识符
294   - * @param requestId 请求 ID
295   - * @param body 请求体
296   - * @return 事件上报请求 DTO
297   - */
298   - private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier,
299   - String requestId, JsonObject body) {
300   - // 解析参数
301   - Map<String, Object> params = parseParamsFromBody(body);
302   -
303   - // 构建事件上报请求 DTO
304   - return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO()
305   - .setRequestId(requestId)
306   - .setProcessId(IotNetComponentCommonUtils.getProcessId())
307   - .setReportTime(LocalDateTime.now())
308   - .setProductKey(productKey)
309   - .setDeviceName(deviceName)).setIdentifier(identifier).setParams(params);
310   - }
  280 +// /**
  281 +// * 解析事件上报请求
  282 +// *
  283 +// * @param productKey 产品 Key
  284 +// * @param deviceName 设备名称
  285 +// * @param identifier 事件标识符
  286 +// * @param requestId 请求 ID
  287 +// * @param body 请求体
  288 +// * @return 事件上报请求 DTO
  289 +// */
  290 +// private IotDeviceEventReportReqDTO parseEventReportRequest(String productKey, String deviceName, String identifier,
  291 +// String requestId, JsonObject body) {
  292 +// // 解析参数
  293 +// Map<String, Object> params = parseParamsFromBody(body);
  294 +//
  295 +// // 构建事件上报请求 DTO
  296 +// return ((IotDeviceEventReportReqDTO) new IotDeviceEventReportReqDTO()
  297 +// .setRequestId(requestId)
  298 +// .setProcessId(IotNetComponentCommonUtils.getProcessId())
  299 +// .setReportTime(LocalDateTime.now())
  300 +// .setProductKey(productKey)
  301 +// .setDeviceName(deviceName)).setIdentifier(identifier).setParams(params);
  302 +// }
311 303  
312 304 /**
313 305 * 从请求体解析参数
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/package-info.java
1 1 /**
2   - * TODO 占位
  2 + * 提供设备接入的各种协议的实现
3 3 */
4 4 package cn.iocoder.yudao.module.iot.gateway.protocol;
5 5 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-gateway/src/main/resources/application.yaml 0 → 100644
  1 +spring:
  2 + application:
  3 + name: iot-gateway-server
  4 +
  5 +--- #################### 消息队列相关 ####################
  6 +
  7 +# rocketmq 配置项,对应 RocketMQProperties 配置类
  8 +rocketmq:
  9 + name-server: 127.0.0.1:9876 # RocketMQ Namesrv
  10 + # Producer 配置项
  11 + producer:
  12 + group: ${spring.application.name}_PRODUCER # 生产者分组
  13 +
  14 +--- #################### 芋道相关配置 ####################
  15 +
  16 +yudao:
  17 + iot:
  18 + # 网关配置
  19 + gateway:
  20 + # 设备 RPC 配置
  21 + rpc:
  22 + url: http://127.0.0.1:48080 # 主程序 API 地址
  23 + connect-timeout: 30s
  24 + read-timeout: 30s
  25 +
  26 + # 协议配置
  27 + protocol:
  28 + # ====================================
  29 + # 针对引入的 HTTP 组件的配置
  30 + # ====================================
  31 + http:
  32 + enabled: true
  33 + server-port: 8092
  34 + # ====================================
  35 + # 针对引入的 EMQX 组件的配置
  36 + # ====================================
  37 + emqx:
  38 + enabled: true
  39 + mqtt-host: 127.0.0.1
  40 + mqtt-port: 1883
  41 + mqtt-username: admin
  42 + mqtt-password: admin123
  43 + mqtt-ssl: false
  44 + mqtt-topics:
  45 + - "/sys/#"
  46 + auth-port: 8101
  47 +
  48 + # 消息总线配置
  49 + message-bus:
  50 + type: rocketmq # 消息总线的类型
  51 +
  52 +# 日志配置
  53 +# TODO 芋艿:是不是可以删除
  54 +logging:
  55 + level:
  56 + cn.iocoder.yudao: INFO
  57 + root: INFO
... ...
yudao-module-iot/yudao-module-iot-net-components/README.md deleted
1   -# IOT 组件使用说明
2   -
3   -## 组件介绍
4   -
5   -该模块包含多个 IoT 设备连接组件,提供不同的通信协议支持:
6   -
7   -- `yudao-module-iot-net-component-core`: 核心接口和通用类
8   -- `yudao-module-iot-net-component-http`: 基于 HTTP 协议的设备通信组件
9   -- `yudao-module-iot-net-component-emqx`: 基于 MQTT/EMQX 的设备通信组件
10   -
11   -## 组件架构
12   -
13   -### 架构设计
14   -
15   -各组件采用统一的架构设计和命名规范:
16   -
17   -- 配置类: `IotComponentXxxAutoConfiguration` - 提供Bean定义和组件初始化逻辑
18   -- 属性类: `IotComponentXxxProperties` - 定义组件的配置属性
19   -- 下行接口: `*DownstreamHandler` - 处理从平台到设备的下行通信
20   -- 上行接口: `*UpstreamServer` - 处理从设备到平台的上行通信
21   -
22   -### Bean 命名规范
23   -
24   -为避免 Bean 冲突,各个组件中的 Bean 已添加特定前缀:
25   -
26   -- HTTP 组件: `httpDeviceUpstreamServer`, `httpDeviceDownstreamHandler`
27   -- EMQX 组件: `emqxDeviceUpstreamServer`, `emqxDeviceDownstreamHandler`
28   -
29   -### 组件启用规则
30   -
31   -现在系统支持同时使用多个组件,但有以下规则:
32   -
33   -1. 当`yudao.iot.component.emqx.enabled=true`时,核心模块将优先使用EMQX组件
34   -2. 如果同时启用了多个组件,需要在业务代码中使用`@Qualifier`指定要使用的具体实现
35   -
36   -> **重要提示:**
37   -> 1. 组件库内部的默认配置文件**不会**被自动加载。必须将上述配置添加到主应用的配置文件中。
38   -> 2. 所有配置项现在都已增加空值处理,配置缺失时将使用合理的默认值
39   -> 3. `mqtt-host` 是唯一必须配置的参数,其他参数均有默认值
40   -> 4. `mqtt-ssl` 和 `auth-port` 缺失时的默认值分别为 `false` 和 `8080`
41   -> 5. `mqtt-topics` 缺失时将使用默认主题 `/device/#`
42   -
43   -### 如何引用特定的 Bean
44   -
45   -在其他组件中引用这些 Bean 时,需要使用 `@Qualifier` 注解指定 Bean 名称:
46   -
47   -```java
48   -import org.springframework.beans.factory.annotation.Autowired;
49   -import org.springframework.beans.factory.annotation.Qualifier;
50   -import cn.iocoder.yudao.module.iot.component.core.downstream.IotDeviceDownstreamHandler;
51   -
52   -@Service
53   -public class YourServiceClass {
54   -
55   - // 注入 HTTP 组件的下行处理器
56   - @Autowired
57   - @Qualifier("httpDeviceDownstreamHandler")
58   - private IotDeviceDownstreamHandler httpDeviceDownstreamHandler;
59   -
60   - // 注入 EMQX 组件的下行处理器
61   - @Autowired
62   - @Qualifier("emqxDeviceDownstreamHandler")
63   - private IotDeviceDownstreamHandler emqxDeviceDownstreamHandler;
64   -
65   - // 使用示例
66   - public void example() {
67   - // 使用 HTTP 组件
68   - httpDeviceDownstreamHandler.invokeDeviceService(...);
69   -
70   - // 使用 EMQX 组件
71   - emqxDeviceDownstreamHandler.invokeDeviceService(...);
72   - }
73   -}
74   -```
75   -
76   -### 组件选择指南
77   -
78   -- **HTTP 组件**:适用于简单场景,设备通过 HTTP 接口与平台通信
79   -- **EMQX 组件**:适用于实时性要求高的场景,基于 MQTT 协议,支持发布/订阅模式
80   -
81   -## 常见问题
82   -
83   -### 1. 配置未加载问题
84   -
85   -如果遇到以下日志:
86   -
87   -```
88   -MQTT配置: host=null, port=null, username=null, ssl=null
89   -[connectMqtt][MQTT Host为null,无法连接]
90   -```
91   -
92   -这表明配置没有被正确加载。请确保:
93   -
94   -1. 在主应用的配置文件中(如 `application.yml` 或 `application-dev.yml`)添加了必要的 EMQX 配置
95   -2. 配置前缀正确:`yudao.iot.component.emqx`
96   -3. 配置了必要的 `mqtt-host` 属性
97   -
98   -### 2. mqttSsl 空指针异常
99   -
100   -如果遇到以下错误:
101   -
102   -```
103   -Cannot invoke "java.lang.Boolean.booleanValue()" because the return value of "cn.iocoder.yudao.module.iot.component.emqx.config.IotEmqxComponentProperties.getMqttSsl()" is null
104   -```
105   -
106   -此问题已通过代码修复,现在会自动使用默认值 `false`。同样适用于其他配置项的空值问题。
107   -
108   -### 3. authPort 空指针异常
109   -
110   -如果遇到以下错误:
111   -
112   -```
113   -Cannot invoke "java.lang.Integer.intValue()" because the return value of "cn.iocoder.yudao.module.iot.component.emqx.config.IotEmqxComponentProperties.getAuthPort()" is null
114   -```
115   -
116   -此问题已通过代码修复,现在会自动使用默认值 `8080`。
117   -
118   -### 4. Bean注入问题
119   -
120   -如果遇到以下错误:
121   -
122   -```
123   -Parameter 1 of method deviceDownstreamServer in IotPluginCommonAutoConfiguration required a single bean, but 2 were found
124   -```
125   -
126   -此问题已通过修改核心配置类来解决。现在系统会根据组件的启用状态自动选择合适的实现:
127   -
128   -1. 优先使用EMQX组件(当`yudao.iot.component.emqx.enabled=true`时)
129   -2. 如果EMQX未启用,则使用HTTP组件(当`yudao.iot.component.http.enabled=true`时)
130   -
131   -如果需要同时使用两个组件,业务代码中必须使用`@Qualifier`明确指定要使用的Bean。
132   -
133   -### 5. 使用默认配置
134   -
135   -组件现已加入完善的默认配置和空值处理机制,使配置更加灵活。但需要注意的是,这些默认配置值必须通过在主应用配置文件中设置相应的属性才能生效。
136   -
137   -// TODO 芋艿:后续继续完善 README.md
138 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/pom.xml
... ... @@ -18,9 +18,8 @@
18 18  
19 19 <modules>
20 20 <module>yudao-module-iot-net-component-core</module>
21   - <module>yudao-module-iot-net-component-http</module>
22 21 <module>yudao-module-iot-net-component-emqx</module>
23 22 <module>yudao-module-iot-net-component-server</module>
24 23 </modules>
25 24  
26   -</project>
27 25 \ No newline at end of file
  26 +</project>
28 27 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonAutoConfiguration.java
... ... @@ -11,9 +11,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
11 11 *
12 12 * @author haohao
13 13 */
14   -@AutoConfiguration
15 14 @EnableConfigurationProperties(IotNetComponentCommonProperties.class)
16   -@EnableScheduling // 开启定时任务,因为 IotNetComponentInstanceHeartbeatJob 是一个定时任务
17 15 public class IotNetComponentCommonAutoConfiguration {
18 16  
19 17 /**
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/config/IotNetComponentCommonProperties.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.core.config;
2   -
3   -import lombok.Data;
4   -import org.springframework.boot.context.properties.ConfigurationProperties;
5   -import org.springframework.validation.annotation.Validated;
6   -
7   -/**
8   - * IoT 网络组件通用配置属性
9   - *
10   - * @author haohao
11   - */
12   -@ConfigurationProperties(prefix = "yudao.iot.component")
13   -@Validated
14   -@Data
15   -public class IotNetComponentCommonProperties {
16   -
17   - /**
18   - * 组件的唯一标识
19   - * <p>
20   - * 注意:该值将在运行时由各组件设置,不再从配置读取
21   - */
22   - private String pluginKey;
23   -
24   -}
25 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/pojo/IotStandardResponse.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.net.component.core.pojo;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
4 4 import lombok.Data;
5   -import lombok.experimental.Accessors;
6 5  
7 6 /**
8 7 * IoT 标准协议响应实体类
... ... @@ -12,7 +11,6 @@ import lombok.experimental.Accessors;
12 11 * @author haohao
13 12 */
14 13 @Data
15   -@Accessors(chain = true) // TODO @haohao:貌似不用写 @Accessors(chain = true),我全局加啦,可见 lombok.config
16 14 public class IotStandardResponse {
17 15  
18 16 /**
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-core/src/main/java/cn/iocoder/yudao/module/iot/net/component/core/util/IotNetComponentCommonUtils.java
1 1 package cn.iocoder.yudao.module.iot.net.component.core.util;
2 2  
3   -import cn.hutool.core.util.IdUtil;
4   -import cn.hutool.core.util.StrUtil;
5   -import cn.hutool.system.SystemUtil;
6 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
7 4 import cn.iocoder.yudao.module.iot.net.component.core.pojo.IotStandardResponse;
8 5 import io.vertx.core.http.HttpHeaders;
... ... @@ -17,40 +14,6 @@ import org.springframework.http.MediaType;
17 14 public class IotNetComponentCommonUtils {
18 15  
19 16 /**
20   - * 流程实例的进程编号
21   - */
22   - private static String processId;
23   -
24   - /**
25   - * 获取进程ID
26   - *
27   - * @return 进程ID
28   - */
29   - public static String getProcessId() {
30   - if (StrUtil.isEmpty(processId)) {
31   - initProcessId();
32   - }
33   - return processId;
34   - }
35   -
36   - /**
37   - * 初始化进程ID
38   - */
39   - private synchronized static void initProcessId() {
40   - processId = String.format("%s@%d@%s", // IP@PID@${uuid}
41   - SystemUtil.getHostInfo().getAddress(), SystemUtil.getCurrentPID(), IdUtil.fastSimpleUUID());
42   - }
43   -
44   - /**
45   - * 生成请求ID
46   - *
47   - * @return 生成的唯一请求ID
48   - */
49   - public static String generateRequestId() {
50   - return IdUtil.fastSimpleUUID();
51   - }
52   -
53   - /**
54 17 * 将对象转换为JSON字符串后写入HTTP响应
55 18 *
56 19 * @param routingContext 路由上下文
... ... @@ -89,4 +52,5 @@ public class IotNetComponentCommonUtils {
89 52 .putHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_UTF8_VALUE)
90 53 .end(JsonUtils.toJsonString(response));
91 54 }
  55 +
92 56 }
93 57 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/pom.xml deleted
1   -<?xml version="1.0" encoding="UTF-8"?>
2   -<project xmlns="http://maven.apache.org/POM/4.0.0"
3   - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4   - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5   - <parent>
6   - <artifactId>yudao-module-iot-net-components</artifactId>
7   - <groupId>cn.iocoder.boot</groupId>
8   - <version>${revision}</version>
9   - </parent>
10   - <modelVersion>4.0.0</modelVersion>
11   - <artifactId>yudao-module-iot-net-component-http</artifactId>
12   - <packaging>jar</packaging>
13   -
14   - <name>${project.artifactId}</name>
15   - <description>
16   - 物联网网络组件 HTTP 模块
17   - </description>
18   -
19   - <dependencies>
20   - <dependency>
21   - <groupId>cn.iocoder.boot</groupId>
22   - <artifactId>yudao-module-iot-net-component-core</artifactId>
23   - <version>${revision}</version>
24   - </dependency>
25   -
26   - <!-- 脚本解析相关 -->
27   - <!-- <dependency>-->
28   - <!-- <groupId>cn.iocoder.boot</groupId>-->
29   - <!-- <artifactId>yudao-module-iot-plugin-script</artifactId>-->
30   - <!-- <version>${revision}</version>-->
31   - <!-- </dependency>-->
32   -
33   - <!-- 工具类相关 -->
34   - <dependency>
35   - <groupId>io.vertx</groupId>
36   - <artifactId>vertx-web</artifactId>
37   - </dependency>
38   -
39   - <!-- 参数校验 -->
40   - <dependency>
41   - <groupId>org.springframework.boot</groupId>
42   - <artifactId>spring-boot-starter-validation</artifactId>
43   - <optional>true</optional>
44   - </dependency>
45   - </dependencies>
46   -
47   -</project>
48 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpAutoConfiguration.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.http.config;
2   -
3   -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
4   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
5   -import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBusSubscriber;
6   -import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
7   -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
8   -import cn.iocoder.yudao.module.iot.net.component.http.upstream.IotDeviceUpstreamServer;
9   -import io.vertx.core.Vertx;
10   -import lombok.extern.slf4j.Slf4j;
11   -import org.springframework.beans.factory.annotation.Qualifier;
12   -import org.springframework.boot.autoconfigure.AutoConfiguration;
13   -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
14   -import org.springframework.boot.context.event.ApplicationStartedEvent;
15   -import org.springframework.boot.context.properties.EnableConfigurationProperties;
16   -import org.springframework.context.annotation.Bean;
17   -import org.springframework.context.annotation.ComponentScan;
18   -import org.springframework.context.annotation.Lazy;
19   -import org.springframework.context.event.EventListener;
20   -
21   -/**
22   - * IoT 网络组件 HTTP 的自动配置类
23   - *
24   - * @author haohao
25   - */
26   -@Slf4j
27   -@AutoConfiguration
28   -@EnableConfigurationProperties(IotNetComponentHttpProperties.class)
29   -@ConditionalOnProperty(prefix = "yudao.iot.component.http", name = "enabled", havingValue = "true", matchIfMissing = false)
30   -@ComponentScan(basePackages = {
31   - "cn.iocoder.yudao.module.iot.net.component.http" // 只扫描 HTTP 组件包
32   -})
33   -public class IotNetComponentHttpAutoConfiguration {
34   -
35   - /**
36   - * 初始化 HTTP 组件
37   - *
38   - * @param event 应用启动事件
39   - */
40   - @EventListener(ApplicationStartedEvent.class)
41   - public void initialize(ApplicationStartedEvent event) {
42   - log.info("[IotNetComponentHttpAutoConfiguration][开始初始化]");
43   -
44   - // TODO @芋艿:临时处理
45   - IotMessageBus messageBus = event.getApplicationContext()
46   - .getBean(IotMessageBus.class);
47   - messageBus.register(new IotMessageBusSubscriber<IotDeviceMessage>() {
48   -
49   - @Override
50   - public String getTopic() {
51   - return IotDeviceMessage.buildMessageBusGatewayDeviceMessageTopic("yy");
52   - }
53   -
54   - @Override
55   - public String getGroup() {
56   - return "test";
57   - }
58   -
59   - @Override
60   - public void onMessage(IotDeviceMessage message) {
61   - System.out.println(message);
62   - }
63   -
64   - });
65   - }
66   -
67   - // TODO @芋艿:貌似这里不用注册 bean?
68   - /**
69   - * 创建 Vert.x 实例
70   - *
71   - * @return Vert.x 实例
72   - */
73   - @Bean(name = "httpVertx")
74   - public Vertx vertx() {
75   - return Vertx.vertx();
76   - }
77   -
78   - /**
79   - * 创建设备上行服务器
80   - */
81   - @Bean(name = "httpDeviceUpstreamServer", initMethod = "start", destroyMethod = "stop")
82   - public IotDeviceUpstreamServer deviceUpstreamServer(
83   - @Lazy @Qualifier("httpVertx") Vertx vertx,
84   - IotDeviceUpstreamApi deviceUpstreamApi,
85   - IotNetComponentHttpProperties properties,
86   - IotDeviceMessageProducer deviceMessageProducer) {
87   - return new IotDeviceUpstreamServer(vertx, properties, deviceUpstreamApi, deviceMessageProducer);
88   - }
89   -
90   -}
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/config/IotNetComponentHttpProperties.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.http.config;
2   -
3   -import lombok.Data;
4   -import org.springframework.boot.context.properties.ConfigurationProperties;
5   -import org.springframework.validation.annotation.Validated;
6   -
7   -/**
8   - * IoT HTTP 网络组件配置属性
9   - *
10   - * @author haohao
11   - */
12   -@ConfigurationProperties(prefix = "yudao.iot.component.http")
13   -@Validated
14   -@Data
15   -public class IotNetComponentHttpProperties {
16   -
17   - /**
18   - * 是否启用 HTTP 组件
19   - */
20   - private Boolean enabled;
21   -
22   - /**
23   - * HTTP 服务端口
24   - */
25   - private Integer serverPort;
26   -
27   - /**
28   - * 连接超时时间(毫秒)
29   - * <p>
30   - * 默认值:10000 毫秒
31   - */
32   - private Integer connectionTimeoutMs = 10000;
33   -}
34 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/downstream/IotDeviceDownstreamHandlerImpl.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.http.downstream;
2   -
3   -// TODO @芋艿:实现下;
4   -///**
5   -// * HTTP 网络组件的 {@link IotDeviceDownstreamHandler} 实现类
6   -// * <p>
7   -// * 但是:由于设备通过 HTTP 短链接接入,导致其实无法下行指导给 device 设备,所以基本都是直接返回失败!!!
8   -// * 类似 MQTT、WebSocket、TCP 网络组件,是可以实现下行指令的。
9   -// *
10   -// * @author 芋道源码
11   -// */
12   -//@Slf4j
13   -//public class IotDeviceDownstreamHandlerImpl implements IotDeviceDownstreamHandler {
14   -//
15   -// /**
16   -// * 不支持的错误消息
17   -// */
18   -// private static final String NOT_SUPPORTED_MSG = "HTTP 不支持设备下行通信";
19   -//
20   -// @Override
21   -// public CommonResult<Boolean> invokeDeviceService(IotDeviceServiceInvokeReqDTO invokeReqDTO) {
22   -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG);
23   -// }
24   -//
25   -// @Override
26   -// public CommonResult<Boolean> getDeviceProperty(IotDevicePropertyGetReqDTO getReqDTO) {
27   -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG);
28   -// }
29   -//
30   -// @Override
31   -// public CommonResult<Boolean> setDeviceProperty(IotDevicePropertySetReqDTO setReqDTO) {
32   -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG);
33   -// }
34   -//
35   -// @Override
36   -// public CommonResult<Boolean> setDeviceConfig(IotDeviceConfigSetReqDTO setReqDTO) {
37   -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG);
38   -// }
39   -//
40   -// @Override
41   -// public CommonResult<Boolean> upgradeDeviceOta(IotDeviceOtaUpgradeReqDTO upgradeReqDTO) {
42   -// return CommonResult.error(NOT_IMPLEMENTED.getCode(), NOT_SUPPORTED_MSG);
43   -// }
44   -//}
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/IotDeviceUpstreamServer.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.http.upstream;
2   -
3   -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
4   -import cn.iocoder.yudao.module.iot.core.mq.producer.IotDeviceMessageProducer;
5   -import cn.iocoder.yudao.module.iot.net.component.http.config.IotNetComponentHttpProperties;
6   -import cn.iocoder.yudao.module.iot.net.component.http.upstream.router.IotDeviceUpstreamVertxHandler;
7   -import io.vertx.core.AbstractVerticle;
8   -import io.vertx.core.Promise;
9   -import io.vertx.core.Vertx;
10   -import io.vertx.ext.web.Router;
11   -import io.vertx.ext.web.handler.BodyHandler;
12   -import lombok.RequiredArgsConstructor;
13   -import lombok.extern.slf4j.Slf4j;
14   -
15   -/**
16   - * IoT 设备上行服务器
17   - * <p>
18   - * 处理设备通过 HTTP 方式接入的上行消息
19   - *
20   - * @author 芋道源码
21   - */
22   -@RequiredArgsConstructor
23   -@Slf4j
24   -public class IotDeviceUpstreamServer extends AbstractVerticle {
25   -
26   - private final Vertx vertx;
27   -
28   - private final IotNetComponentHttpProperties httpProperties;
29   -
30   - private final IotDeviceUpstreamApi deviceUpstreamApi;
31   -
32   - private final IotDeviceMessageProducer deviceMessageProducer;
33   -
34   - @Override
35   - public void start() {
36   - start(Promise.promise());
37   - }
38   -
39   - // TODO @haohao:这样貌似初始化不到;我临时拷贝上去了
40   - @Override
41   - public void start(Promise<Void> startPromise) {
42   - // 创建路由
43   - Router router = Router.router(vertx);
44   - router.route().handler(BodyHandler.create());
45   -
46   - // 创建处理器
47   - IotDeviceUpstreamVertxHandler upstreamHandler = new IotDeviceUpstreamVertxHandler(
48   - deviceUpstreamApi, deviceMessageProducer);
49   -
50   - // 添加路由处理器
51   - router.post(IotDeviceUpstreamVertxHandler.PROPERTY_PATH).handler(upstreamHandler::handle);
52   - router.post(IotDeviceUpstreamVertxHandler.EVENT_PATH).handler(upstreamHandler::handle);
53   -
54   - // 启动 HTTP 服务器
55   - vertx.createHttpServer()
56   - .requestHandler(router)
57   - .listen(httpProperties.getServerPort(), result -> {
58   - if (result.succeeded()) {
59   - log.info("[start][IoT 设备上行服务器启动成功,端口:{}]", httpProperties.getServerPort());
60   - startPromise.complete();
61   - } else {
62   - log.error("[start][IoT 设备上行服务器启动失败]", result.cause());
63   - startPromise.fail(result.cause());
64   - }
65   - });
66   - }
67   -
68   - @Override
69   - public void stop(Promise<Void> stopPromise) {
70   - log.info("[stop][IoT 设备上行服务器已停止]");
71   - stopPromise.complete();
72   - }
73   -}
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/java/cn/iocoder/yudao/module/iot/net/component/http/upstream/auth/IotDeviceAuthProvider.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.http.upstream.auth;
2   -
3   -import io.vertx.core.Future;
4   -import io.vertx.ext.web.RoutingContext;
5   -import lombok.extern.slf4j.Slf4j;
6   -import org.springframework.context.ApplicationContext;
7   -
8   -// TODO @haohao:待实现,或者不需要?
9   -/**
10   - * IoT 设备认证提供者
11   - * <p>
12   - * 用于 HTTP 设备接入时的身份认证
13   - *
14   - * @author haohao
15   - */
16   -@Slf4j
17   -public class IotDeviceAuthProvider {
18   -
19   - private final ApplicationContext applicationContext;
20   -
21   - /**
22   - * 构造函数
23   - *
24   - * @param applicationContext Spring 应用上下文
25   - */
26   - public IotDeviceAuthProvider(ApplicationContext applicationContext) {
27   - this.applicationContext = applicationContext;
28   - }
29   -
30   - /**
31   - * 认证设备
32   - *
33   - * @param context 路由上下文
34   - * @param clientId 设备唯一标识
35   - * @return 认证结果 Future 对象
36   - */
37   - public Future<Void> authenticate(RoutingContext context, String clientId) {
38   - if (clientId == null || clientId.isEmpty()) {
39   - return Future.failedFuture("clientId 不能为空");
40   - }
41   -
42   - try {
43   - log.info("[authenticate][设备认证成功,clientId={}]", clientId);
44   - return Future.succeededFuture();
45   - } catch (Exception e) {
46   - log.error("[authenticate][设备认证异常,clientId={}]", clientId, e);
47   - return Future.failedFuture(e);
48   - }
49   - }
50   -}
51 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports deleted
1   -cn.iocoder.yudao.module.iot.net.component.http.config.IotNetComponentHttpAutoConfiguration
2 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-http/src/main/resources/application.yml deleted
1   -# HTTP组件默认配置
2   -yudao:
3   - iot:
4   - component:
5   - core:
6   - plugin-key: http # 插件的唯一标识
7   -# http:
8   -# enabled: true # 是否启用HTTP组件,默认启用
9   -# server-port: 8092
10   -
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/pom.xml
... ... @@ -17,32 +17,12 @@
17 17 </description>
18 18  
19 19 <dependencies>
20   - <!-- Spring Boot 核心 -->
21   - <dependency>
22   - <groupId>org.springframework.boot</groupId>
23   - <artifactId>spring-boot-starter</artifactId>
24   - </dependency>
25   -
26 20 <!-- Web 相关 -->
27 21 <dependency>
28 22 <groupId>org.springframework.boot</groupId>
29 23 <artifactId>spring-boot-starter-web</artifactId>
30 24 </dependency>
31 25  
32   - <!-- Net Component 核心 -->
33   - <dependency>
34   - <groupId>cn.iocoder.boot</groupId>
35   - <artifactId>yudao-module-iot-net-component-core</artifactId>
36   - <version>${revision}</version>
37   - </dependency>
38   -
39   - <!-- Net Component HTTP -->
40   - <dependency>
41   - <groupId>cn.iocoder.boot</groupId>
42   - <artifactId>yudao-module-iot-net-component-http</artifactId>
43   - <version>${revision}</version>
44   - </dependency>
45   -
46 26 <!-- Net Component EMQX -->
47 27 <dependency>
48 28 <groupId>cn.iocoder.boot</groupId>
... ... @@ -50,32 +30,8 @@
50 30 <version>${revision}</version>
51 31 </dependency>
52 32  
53   - <!-- TODO @芋艿:消息队列,后续可能去掉,默认不使用 rocketmq -->
54   - <dependency>
55   - <groupId>org.apache.rocketmq</groupId>
56   - <artifactId>rocketmq-spring-boot-starter</artifactId>
57   - </dependency>
58 33  
59   - </dependencies>
60 34  
61   - <build>
62   - <!-- 设置构建的 jar 包名 -->
63   - <finalName>${project.artifactId}</finalName>
64   - <plugins>
65   - <!-- 打包 -->
66   - <plugin>
67   - <groupId>org.springframework.boot</groupId>
68   - <artifactId>spring-boot-maven-plugin</artifactId>
69   - <version>${spring.boot.version}</version> <!-- 需要确认父 POM 中有定义 -->
70   - <executions>
71   - <execution>
72   - <goals>
73   - <goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
74   - </goals>
75   - </execution>
76   - </executions>
77   - </plugin>
78   - </plugins>
79   - </build>
  35 + </dependencies>
80 36  
81 37 </project>
82 38 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/NetComponentServerApplication.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.server;
2   -
3   -import org.springframework.boot.SpringApplication;
4   -import org.springframework.boot.autoconfigure.SpringBootApplication;
5   -
6   -/**
7   - * IoT 网络组件聚合启动服务
8   - *
9   - * @author haohao
10   - */
11   -@SpringBootApplication(scanBasePackages = {"${yudao.info.base-package}.module.iot.net.component"})
12   -public class NetComponentServerApplication {
13   -
14   - public static void main(String[] args) {
15   - SpringApplication.run(NetComponentServerApplication.class, args);
16   - }
17   -
18   -}
19 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerConfiguration.java
... ... @@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.iot.net.component.server.config;
2 2  
3 3 import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
4 4 import cn.iocoder.yudao.module.iot.net.component.server.upstream.IotComponentUpstreamClient;
5   -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
6 5 import org.springframework.boot.context.properties.EnableConfigurationProperties;
7 6 import org.springframework.boot.web.client.RestTemplateBuilder;
8 7 import org.springframework.context.annotation.Bean;
... ... @@ -50,28 +49,4 @@ public class IotNetComponentServerConfiguration {
50 49 return new IotComponentUpstreamClient(properties, restTemplate);
51 50 }
52 51  
53   - /**
54   - * 配置默认的设备上行客户端,避免在独立运行模式下的循环依赖问题
55   - *
56   - * @return 设备上行客户端
57   - */
58   - @Bean
59   - @ConditionalOnMissingBean(name = "serverDeviceUpstreamClient")
60   - public Object serverDeviceUpstreamClient() {
61   - // 返回一个空对象,避免找不到类的问题
62   - return new Object();
63   - }
64   -
65   - // TODO @haohao:这个是不是木有用呀?
66   - /**
67   - * 配置默认的组件实例注册客户端
68   - *
69   - * @return 插件实例注册客户端
70   - */
71   - @Bean
72   - @ConditionalOnMissingBean(name = "serverPluginInstanceRegistryClient")
73   - public Object serverPluginInstanceRegistryClient() {
74   - // 返回一个空对象,避免找不到类的问题
75   - return new Object();
76   - }
77 52 }
78 53 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/config/IotNetComponentServerProperties.java
... ... @@ -18,8 +18,6 @@ public class IotNetComponentServerProperties {
18 18  
19 19 /**
20 20 * 上行 URL,用于向主应用程序上报数据
21   - * <p>
22   - * 默认:http://127.0.0.1:48080
23 21 */
24 22 private String upstreamUrl = "http://127.0.0.1:48080";
25 23  
... ... @@ -33,18 +31,4 @@ public class IotNetComponentServerProperties {
33 31 */
34 32 private Duration upstreamReadTimeout = Duration.ofSeconds(30);
35 33  
36   - /**
37   - * 下行服务端口,用于接收主应用程序的请求
38   - * <p>
39   - * 默认:18888
40   - */
41   - private Integer downstreamPort = 18888;
42   -
43   - /**
44   - * 组件服务器唯一标识
45   - * <p>
46   - * 默认:yudao-module-iot-net-component-server
47   - */
48   - private String serverKey = "yudao-module-iot-net-component-server";
49   -
50 34 }
51 35 \ No newline at end of file
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/controller/HealthController.java deleted
1   -package cn.iocoder.yudao.module.iot.net.component.server.controller;
2   -
3   -import org.springframework.web.bind.annotation.GetMapping;
4   -import org.springframework.web.bind.annotation.RequestMapping;
5   -import org.springframework.web.bind.annotation.RestController;
6   -
7   -import java.util.HashMap;
8   -import java.util.Map;
9   -
10   -// TODO @haohao:这个是必须的哇?可以考虑基于 spring boot actuator;
11   -/**
12   - * 健康检查接口
13   - *
14   - * @author haohao
15   - */
16   -@RestController
17   -@RequestMapping("/health")
18   -public class HealthController {
19   -
20   - /**
21   - * 健康检查接口
22   - *
23   - * @return 返回服务状态信息
24   - */
25   - @GetMapping("/status")
26   - public Map<String, Object> status() {
27   - Map<String, Object> result = new HashMap<>();
28   - result.put("status", "UP");
29   - result.put("message", "IoT 网络组件服务运行正常");
30   - result.put("timestamp", System.currentTimeMillis());
31   - return result;
32   - }
33   -}
34 0 \ No newline at end of file
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/java/cn/iocoder/yudao/module/iot/net/component/server/upstream/IotComponentUpstreamClient.java
1 1 package cn.iocoder.yudao.module.iot.net.component.server.upstream;
2 2  
3 3 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4   -import cn.iocoder.yudao.module.iot.api.device.IotDeviceUpstreamApi;
5   -import cn.iocoder.yudao.module.iot.api.device.dto.control.upstream.*;
6 4 import cn.iocoder.yudao.module.iot.net.component.server.config.IotNetComponentServerProperties;
7 5 import lombok.RequiredArgsConstructor;
8 6 import lombok.extern.slf4j.Slf4j;
... ... @@ -19,7 +17,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
19 17 */
20 18 @RequiredArgsConstructor
21 19 @Slf4j
22   -public class IotComponentUpstreamClient implements IotDeviceUpstreamApi {
  20 +public class IotComponentUpstreamClient {
23 21  
24 22 public static final String URL_PREFIX = "/rpc-api/iot/device/upstream";
25 23  
... ... @@ -27,47 +25,11 @@ public class IotComponentUpstreamClient implements IotDeviceUpstreamApi {
27 25  
28 26 private final RestTemplate restTemplate;
29 27  
30   - @Override
31   - public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
32   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/update-state";
33   - return doPost(url, updateReqDTO);
34   - }
35   -
36   - @Override
37   - public CommonResult<Boolean> reportDeviceEvent(IotDeviceEventReportReqDTO reportReqDTO) {
38   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-event";
39   - return doPost(url, reportReqDTO);
40   - }
41   -
42   - @Override
43   - public CommonResult<Boolean> registerDevice(IotDeviceRegisterReqDTO registerReqDTO) {
44   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/register-device";
45   - return doPost(url, registerReqDTO);
46   - }
47   -
48   - @Override
49   - public CommonResult<Boolean> registerSubDevice(IotDeviceRegisterSubReqDTO registerReqDTO) {
50   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/register-sub-device";
51   - return doPost(url, registerReqDTO);
52   - }
53   -
54   - @Override
55   - public CommonResult<Boolean> addDeviceTopology(IotDeviceTopologyAddReqDTO addReqDTO) {
56   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/add-device-topology";
57   - return doPost(url, addReqDTO);
58   - }
59   -
60   - @Override
61   - public CommonResult<Boolean> authenticateEmqxConnection(IotDeviceEmqxAuthReqDTO authReqDTO) {
62   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/authenticate-emqx-connection";
63   - return doPost(url, authReqDTO);
64   - }
65   -
66   - @Override
67   - public CommonResult<Boolean> reportDeviceProperty(IotDevicePropertyReportReqDTO reportReqDTO) {
68   - String url = properties.getUpstreamUrl() + URL_PREFIX + "/report-property";
69   - return doPost(url, reportReqDTO);
70   - }
  28 +// @Override
  29 +// public CommonResult<Boolean> updateDeviceState(IotDeviceStateUpdateReqDTO updateReqDTO) {
  30 +// String url = properties.getUpstreamUrl() + URL_PREFIX + "/update-state";
  31 +// return doPost(url, updateReqDTO);
  32 +// }
71 33  
72 34 @SuppressWarnings("unchecked")
73 35 private <T> CommonResult<Boolean> doPost(String url, T requestBody) {
... ...
yudao-module-iot/yudao-module-iot-net-components/yudao-module-iot-net-component-server/src/main/resources/application.yml deleted
1   -# 服务器配置
2   -server:
3   - port: 18080 # 修改端口,避免与主应用的8080端口冲突
4   -
5   -# Spring 配置
6   -spring:
7   - application:
8   - name: iot-component-server
9   - # 允许循环引用
10   - main:
11   - allow-circular-references: true
12   - allow-bean-definition-overriding: true
13   -
14   -# Yudao 配置
15   -yudao:
16   - info:
17   - base-package: cn.iocoder.yudao # 主项目包路径,确保正确
18   - iot:
19   - component:
20   -
21   - # 网络组件服务器专用配置
22   - server:
23   - # 上行通信配置,用于向主程序上报数据
24   - upstream-url: http://127.0.0.1:48080 # 主程序 API 地址
25   - upstream-connect-timeout: 30s # 连接超时
26   - upstream-read-timeout: 30s # 读取超时
27   -
28   - # 下行通信配置,用于接收主程序的控制指令
29   - downstream-port: 18888 # 下行服务器端口
30   -
31   - # 组件服务唯一标识
32   - server-key: yudao-module-iot-net-component-server
33   -
34   - # ====================================
35   - # 针对引入的 HTTP 组件的配置
36   - # ====================================
37   - http:
38   - enabled: true # 启用HTTP组件
39   - server-port: 8092 # HTTP组件服务端口
40   -
41   - # ====================================
42   - # 针对引入的 EMQX 组件的配置
43   - # ====================================
44   - emqx:
45   - enabled: true # 启用EMQX组件
46   - mqtt-host: 127.0.0.1 # MQTT服务器主机地址
47   - mqtt-port: 1883 # MQTT服务器端口
48   - mqtt-username: admin # MQTT服务器用户名
49   - mqtt-password: admin123 # MQTT服务器密码
50   - mqtt-ssl: false # 是否启用SSL
51   - mqtt-topics: # 订阅的主题列表
52   - - "/sys/#"
53   - auth-port: 8101 # 认证端口
54   - message-bus:
55   - type: rocketmq # 消息总线的类型
56   -
57   -# 日志配置
58   -logging:
59   - level:
60   - cn.iocoder.yudao: INFO
61   - root: INFO
62   -
63   ---- #################### 消息队列相关 ####################
64   -
65   -# rocketmq 配置项,对应 RocketMQProperties 配置类
66   -rocketmq:
67   - name-server: 127.0.0.1:9876 # RocketMQ Namesrv
68   - # Producer 配置项
69   - producer:
70   - group: ${spring.application.name}_PRODUCER # 生产者分组