diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml
index fb3cf8562d..0a9d0bf454 100644
--- a/yudao-dependencies/pom.xml
+++ b/yudao-dependencies/pom.xml
@@ -626,6 +626,12 @@
vertx-web
${vertx.version}
+
+
+ io.vertx
+ vertx-mqtt
+ ${vertx.version}
+
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java
deleted file mode 100644
index c7a0500030..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/config/MqttConfig.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package cn.iocoder.yudao.module.iot.mqttrpc.config;
-
-import lombok.Data;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Configuration;
-
-@Data
-@Configuration
-@ConfigurationProperties(prefix = "mqtt")
-public class MqttConfig {
- /**
- * MQTT 代理地址
- */
- private String broker;
-
- /**
- * MQTT 用户名
- */
- private String username;
-
- /**
- * MQTT 密码
- */
- private String password;
-
- /**
- * MQTT 客户端 ID
- */
- private String clientId;
-
- /**
- * MQTT 请求主题
- */
- private String requestTopic;
-
- /**
- * MQTT 响应主题前缀
- */
- private String responseTopicPrefix;
-}
diff --git a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java b/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java
deleted file mode 100644
index 90ce2a3875..0000000000
--- a/yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/mqttrpc/server/RpcServer.java
+++ /dev/null
@@ -1,100 +0,0 @@
-package cn.iocoder.yudao.module.iot.mqttrpc.server;
-
-import cn.hutool.core.lang.UUID;
-import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcRequest;
-import cn.iocoder.yudao.module.iot.mqttrpc.common.RpcResponse;
-import cn.iocoder.yudao.module.iot.mqttrpc.common.SerializationUtils;
-import cn.iocoder.yudao.module.iot.mqttrpc.config.MqttConfig;
-import lombok.extern.slf4j.Slf4j;
-import org.eclipse.paho.client.mqttv3.*;
-import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
-import java.util.HashMap;
-import java.util.Map;
-
-// TODO @芋艿:server 逻辑,再瞅瞅;
-// TODO @haohao:如果只写在 iot biz 里,那么后续 server => client 貌似不方便?微信再讨论下~;
-@Service
-@Slf4j
-public class RpcServer {
-
- private final MqttConfig mqttConfig;
- private final MqttClient mqttClient;
- private final Map methodRegistry = new HashMap<>();
-
- public RpcServer(MqttConfig mqttConfig) throws MqttException {
- this.mqttConfig = mqttConfig;
- this.mqttClient = new MqttClient(mqttConfig.getBroker(), "rpc-server-" + UUID.randomUUID(), new MemoryPersistence());
- MqttConnectOptions options = new MqttConnectOptions();
- options.setAutomaticReconnect(true);
- options.setCleanSession(true);
- options.setUserName(mqttConfig.getUsername());
- options.setPassword(mqttConfig.getPassword().toCharArray());
- this.mqttClient.connect(options);
- }
-
- @PostConstruct
- public void init() throws MqttException {
- mqttClient.subscribe(mqttConfig.getRequestTopic(), this::handleRequest);
- log.info("RPC Server subscribed to topic: {}", mqttConfig.getRequestTopic());
- }
-
- private void handleRequest(String topic, MqttMessage message) {
- RpcRequest request = SerializationUtils.deserialize(new String(message.getPayload()), RpcRequest.class);
- RpcResponse response = new RpcResponse();
- response.setCorrelationId(request.getCorrelationId());
-
- try {
- MethodInvoker invoker = methodRegistry.get(request.getMethod());
- if (invoker == null) {
- throw new NoSuchMethodException("Unknown method: " + request.getMethod());
- }
- Object result = invoker.invoke(request.getParams());
- response.setResult(result);
- } catch (Exception e) {
- response.setError(e.getMessage());
- log.error("Error processing RPC request: {}", e.getMessage(), e);
- }
-
- String replyPayload = SerializationUtils.serialize(response);
- MqttMessage replyMessage = new MqttMessage(replyPayload.getBytes());
- replyMessage.setQos(1);
- try {
- mqttClient.publish(request.getReplyTo(), replyMessage);
- log.info("Published response to {}", request.getReplyTo());
- } catch (MqttException e) {
- log.error("Failed to publish response: {}", e.getMessage(), e);
- }
- }
-
- /**
- * 注册可调用的方法
- *
- * @param methodName 方法名称
- * @param invoker 方法调用器
- */
- public void registerMethod(String methodName, MethodInvoker invoker) {
- methodRegistry.put(methodName, invoker);
- log.info("Registered method: {}", methodName);
- }
-
- @PreDestroy
- public void cleanup() throws MqttException {
- mqttClient.disconnect();
- log.info("RPC Server disconnected");
- }
-
- /**
- * 方法调用器接口
- */
- @FunctionalInterface
- public interface MethodInvoker {
-
- Object invoke(Object[] params) throws Exception;
-
- }
-
-}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties
new file mode 100644
index 0000000000..a23bafcf79
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/plugin.properties
@@ -0,0 +1,6 @@
+plugin.id=emqx-plugin
+plugin.class=cn.iocoder.yudao.module.iot.plugin.EmqxPlugin
+plugin.version=0.0.1
+plugin.provider=ahh
+plugin.dependencies=
+plugin.description=emqx-plugin-0.0.1
diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml
new file mode 100644
index 0000000000..43d67f5207
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/pom.xml
@@ -0,0 +1,164 @@
+
+
+
+ yudao-module-iot-plugin
+ cn.iocoder.boot
+ ${revision}
+
+ 4.0.0
+ jar
+
+ yudao-module-iot-emqx-plugin
+
+ ${project.artifactId}
+
+ 物联网 插件模块 - emqx 插件
+
+
+
+
+ emqx-plugin
+ cn.iocoder.yudao.module.iot.plugin.EmqxPlugin
+ 0.0.1
+ ahh
+ emqx-plugin-0.0.1
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+ 1.6
+
+
+ unzip jar file
+ package
+
+
+
+
+
+
+ run
+
+
+
+
+
+
+ maven-assembly-plugin
+ 2.3
+
+
+
+ src/main/assembly/assembly.xml
+
+
+ false
+
+
+
+ make-assembly
+ package
+
+ attached
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 2.4
+
+
+
+ ${plugin.id}
+ ${plugin.class}
+ ${plugin.version}
+ ${plugin.provider}
+ ${plugin.description}
+ ${plugin.dependencies}
+
+
+
+
+
+
+ maven-deploy-plugin
+
+ true
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.pf4j
+ pf4j-spring
+ provided
+
+
+
+ cn.iocoder.boot
+ yudao-module-iot-api
+ ${revision}
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+ provided
+
+
+
+ io.vertx
+ vertx-core
+
+
+
+ io.vertx
+ vertx-web
+
+
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+
+
+
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml
new file mode 100644
index 0000000000..daec9e4315
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/assembly/assembly.xml
@@ -0,0 +1,31 @@
+
+ plugin
+
+ zip
+
+ false
+
+
+ false
+ runtime
+ lib
+
+ *:jar:*
+
+
+
+
+
+
+ target/plugin-classes
+ classes
+
+
+
diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java
new file mode 100644
index 0000000000..e64695b06d
--- /dev/null
+++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-emqx-plugin/src/main/java/cn/iocoder/yudao/module/iot/plugin/EmqxPlugin.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.iot.plugin;
+
+import cn.iocoder.yudao.module.iot.api.ServiceRegistry;
+import cn.iocoder.yudao.module.iot.api.device.DeviceDataApi;
+import lombok.extern.slf4j.Slf4j;
+import org.pf4j.Plugin;
+import org.pf4j.PluginWrapper;
+
+import javax.annotation.Resource;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+@Slf4j
+public class EmqxPlugin extends Plugin {
+
+ private ExecutorService executorService;
+ @Resource
+ private DeviceDataApi deviceDataApi;
+
+ public EmqxPlugin(PluginWrapper wrapper) {
+ super(wrapper);
+ this.executorService = Executors.newSingleThreadExecutor();
+ }
+
+ @Override
+ public void start() {
+ log.info("EmqxPlugin.start()");
+
+ if (executorService.isShutdown() || executorService.isTerminated()) {
+ executorService = Executors.newSingleThreadExecutor();
+ }
+
+ deviceDataApi = ServiceRegistry.getService(DeviceDataApi.class);
+ if (deviceDataApi == null) {
+ log.error("未能从 ServiceRegistry 获取 DeviceDataApi 实例,请确保主程序已正确注册!");
+ return;
+ }
+
+ }
+
+ @Override
+ public void stop() {
+ log.info("EmqxPlugin.stop()");
+ }
+}
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml
index 29c0200f1c..22cb439681 100644
--- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml
+++ b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/pom.xml
@@ -147,20 +147,11 @@
${lombok.version}
provided
-
-
- io.vertx
- vertx-core
-
-
+
io.vertx
vertx-web
-
-
-
- org.eclipse.paho
- org.eclipse.paho.client.mqttv3
+ 4.5.11
\ No newline at end of file
diff --git a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java b/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java
deleted file mode 100644
index 4615dcf96f..0000000000
--- a/yudao-module-iot/yudao-module-iot-plugin/yudao-module-iot-http-plugin/src/main/java/cn/iocoder/yudao/module/iot/controller/RpcController.java
+++ /dev/null
@@ -1,38 +0,0 @@
-
-package cn.iocoder.yudao.module.iot.controller;
-
-import cn.iocoder.yudao.module.iot.mqttrpc.client.RpcClient;
-import lombok.RequiredArgsConstructor;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.Resource;
-import java.util.concurrent.CompletableFuture;
-
-// TODO 芋艿:后续 review 下
-/**
- * 插件实例 RPC 接口
- *
- * @author 芋道源码
- */
-@RestController
-@RequestMapping("/rpc")
-@RequiredArgsConstructor
-public class RpcController {
-
- @Resource
- private RpcClient rpcClient;
-
- @PostMapping("/add")
- public CompletableFuture