mirror of
https://gitee.com/zhijiantianya/ruoyi-vue-pro.git
synced 2026-03-22 05:07:17 +08:00
feat(iot):Modbus 支持 Master/Slave 双模式,配置表单和详情按协议类型区分展示
This commit is contained in:
@@ -29,12 +29,6 @@ public class IotDeviceModbusPointDO extends TenantBaseDO {
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
/**
|
||||
* 产品编号
|
||||
*
|
||||
* 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
|
||||
*/
|
||||
private Long productId;
|
||||
/**
|
||||
* 设备编号
|
||||
*
|
||||
|
||||
@@ -75,14 +75,14 @@ public class IotDeviceModbusConfigServiceImpl implements IotDeviceModbusConfigSe
|
||||
if (protocolTypeEnum == null) {
|
||||
return;
|
||||
}
|
||||
if (protocolTypeEnum == IotProtocolTypeEnum.MODBUS_TCP_MASTER) {
|
||||
Assert.isTrue(StrUtil.isNotEmpty(saveReqVO.getIp()), "Master 模式下,IP 地址不能为空");
|
||||
Assert.notNull(saveReqVO.getPort(), "Master 模式下,端口不能为空");
|
||||
Assert.notNull(saveReqVO.getTimeout(), "Master 模式下,连接超时时间不能为空");
|
||||
Assert.notNull(saveReqVO.getRetryInterval(), "Master 模式下,重试间隔不能为空");
|
||||
} else if (protocolTypeEnum == IotProtocolTypeEnum.MODBUS_TCP_SLAVE) {
|
||||
Assert.notNull(saveReqVO.getMode(), "Slave 模式下,工作模式不能为空");
|
||||
Assert.notNull(saveReqVO.getFrameFormat(), "Slave 模式下,数据帧格式不能为空");
|
||||
if (protocolTypeEnum == IotProtocolTypeEnum.MODBUS_TCP_CLIENT) {
|
||||
Assert.isTrue(StrUtil.isNotEmpty(saveReqVO.getIp()), "Client 模式下,IP 地址不能为空");
|
||||
Assert.notNull(saveReqVO.getPort(), "Client 模式下,端口不能为空");
|
||||
Assert.notNull(saveReqVO.getTimeout(), "Client 模式下,连接超时时间不能为空");
|
||||
Assert.notNull(saveReqVO.getRetryInterval(), "Client 模式下,重试间隔不能为空");
|
||||
} else if (protocolTypeEnum == IotProtocolTypeEnum.MODBUS_TCP_SERVER) {
|
||||
Assert.notNull(saveReqVO.getMode(), "Server 模式下,工作模式不能为空");
|
||||
Assert.notNull(saveReqVO.getFrameFormat(), "Server 模式下,数据帧格式不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,8 @@ public enum IotProtocolTypeEnum implements ArrayValuable<String> {
|
||||
MQTT("mqtt"),
|
||||
EMQX("emqx"),
|
||||
COAP("coap"),
|
||||
MODBUS_TCP_MASTER("modbus_tcp_master"),
|
||||
MODBUS_TCP_SLAVE("modbus_tcp_slave");
|
||||
MODBUS_TCP_CLIENT("modbus_tcp_client"),
|
||||
MODBUS_TCP_SERVER("modbus_tcp_server");
|
||||
|
||||
public static final String[] ARRAYS = Arrays.stream(values()).map(IotProtocolTypeEnum::getType).toArray(String[]::new);
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import cn.iocoder.yudao.module.iot.core.enums.IotProtocolTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.coap.IotCoapConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.IotModbusTcpMasterConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.IotModbusTcpSlaveConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.IotModbusTcpClientConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.IotModbusTcpServerConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpConfig;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.udp.IotUdpConfig;
|
||||
@@ -169,16 +169,16 @@ public class IotGatewayProperties {
|
||||
private IotEmqxConfig emqx;
|
||||
|
||||
/**
|
||||
* Modbus TCP Master 协议配置
|
||||
* Modbus TCP Client 协议配置
|
||||
*/
|
||||
@Valid
|
||||
private IotModbusTcpMasterConfig modbusTcpMaster;
|
||||
private IotModbusTcpClientConfig modbusTcpClient;
|
||||
|
||||
/**
|
||||
* Modbus TCP Slave 协议配置
|
||||
* Modbus TCP Server 协议配置
|
||||
*/
|
||||
@Valid
|
||||
private IotModbusTcpSlaveConfig modbusTcpSlave;
|
||||
private IotModbusTcpServerConfig modbusTcpServer;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.coap.IotCoapProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.emqx.IotEmqxProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.http.IotHttpProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.IotModbusTcpMasterProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.IotModbusTcpSlaveProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.IotModbusTcpClientProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.IotModbusTcpServerProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.mqtt.IotMqttProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.IotTcpProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.udp.IotUdpProtocol;
|
||||
@@ -114,10 +114,10 @@ public class IotProtocolManager implements SmartLifecycle {
|
||||
return createMqttProtocol(config);
|
||||
case EMQX:
|
||||
return createEmqxProtocol(config);
|
||||
case MODBUS_TCP_MASTER:
|
||||
return createModbusTcpMasterProtocol(config);
|
||||
case MODBUS_TCP_SLAVE:
|
||||
return createModbusTcpSlaveProtocol(config);
|
||||
case MODBUS_TCP_CLIENT:
|
||||
return createModbusTcpClientProtocol(config);
|
||||
case MODBUS_TCP_SERVER:
|
||||
return createModbusTcpServerProtocol(config);
|
||||
default:
|
||||
throw new IllegalArgumentException(String.format(
|
||||
"[createProtocol][协议实例 %s 的协议类型 %s 暂不支持]", config.getId(), protocolType));
|
||||
@@ -195,23 +195,23 @@ public class IotProtocolManager implements SmartLifecycle {
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Modbus TCP Master 协议实例
|
||||
* 创建 Modbus TCP Client 协议实例
|
||||
*
|
||||
* @param config 协议实例配置
|
||||
* @return Modbus TCP Master 协议实例
|
||||
* @return Modbus TCP Client 协议实例
|
||||
*/
|
||||
private IotModbusTcpMasterProtocol createModbusTcpMasterProtocol(IotGatewayProperties.ProtocolProperties config) {
|
||||
return new IotModbusTcpMasterProtocol(config);
|
||||
private IotModbusTcpClientProtocol createModbusTcpClientProtocol(IotGatewayProperties.ProtocolProperties config) {
|
||||
return new IotModbusTcpClientProtocol(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 Modbus TCP Slave 协议实例
|
||||
* 创建 Modbus TCP Server 协议实例
|
||||
*
|
||||
* @param config 协议实例配置
|
||||
* @return Modbus TCP Slave 协议实例
|
||||
* @return Modbus TCP Server 协议实例
|
||||
*/
|
||||
private IotModbusTcpSlaveProtocol createModbusTcpSlaveProtocol(IotGatewayProperties.ProtocolProperties config) {
|
||||
return new IotModbusTcpSlaveProtocol(config);
|
||||
private IotModbusTcpServerProtocol createModbusTcpServerProtocol(IotGatewayProperties.ProtocolProperties config) {
|
||||
return new IotModbusTcpServerProtocol(config);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusByteOrderEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusRawDataTypeEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrame;
|
||||
import lombok.experimental.UtilityClass;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager.IotModbusTcpMasterConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientConnectionManager;
|
||||
import com.ghgande.j2mod.modbus.io.ModbusTCPTransaction;
|
||||
import com.ghgande.j2mod.modbus.msg.*;
|
||||
import com.ghgande.j2mod.modbus.procimg.InputRegister;
|
||||
@@ -19,14 +19,14 @@ import static cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.I
|
||||
* <p>
|
||||
* 封装基于 j2mod 的 Modbus TCP 读写操作:
|
||||
* 1. 根据功能码创建对应的 Modbus 读/写请求
|
||||
* 2. 通过 {@link IotModbusTcpMasterConnectionManager.ModbusConnection} 执行事务
|
||||
* 2. 通过 {@link IotModbusTcpClientConnectionManager.ModbusConnection} 执行事务
|
||||
* 3. 从响应中提取原始值
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@UtilityClass
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterUtils {
|
||||
public class IotModbusTcpClientUtils {
|
||||
|
||||
/**
|
||||
* 读取 Modbus 数据
|
||||
@@ -36,7 +36,7 @@ public class IotModbusTcpMasterUtils {
|
||||
* @param point 点位配置
|
||||
* @return 原始值(int 数组)
|
||||
*/
|
||||
public static Future<int[]> read(IotModbusTcpMasterConnectionManager.ModbusConnection connection,
|
||||
public static Future<int[]> read(IotModbusTcpClientConnectionManager.ModbusConnection connection,
|
||||
Integer slaveId,
|
||||
IotModbusPointRespDTO point) {
|
||||
return connection.executeBlocking(tcpConnection -> {
|
||||
@@ -70,7 +70,7 @@ public class IotModbusTcpMasterUtils {
|
||||
* @param values 要写入的值
|
||||
* @return 是否成功
|
||||
*/
|
||||
public static Future<Boolean> write(IotModbusTcpMasterConnectionManager.ModbusConnection connection,
|
||||
public static Future<Boolean> write(IotModbusTcpClientConnectionManager.ModbusConnection connection,
|
||||
Integer slaveId,
|
||||
IotModbusPointRespDTO point,
|
||||
int[] values) {
|
||||
@@ -1,16 +1,16 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient;
|
||||
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Master 协议配置
|
||||
* IoT Modbus TCP Client 协议配置
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotModbusTcpMasterConfig {
|
||||
public class IotModbusTcpClientConfig {
|
||||
|
||||
/**
|
||||
* 配置刷新间隔(秒)
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
@@ -9,12 +9,12 @@ import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
|
||||
import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties.ProtocolProperties;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.downstream.IotModbusTcpMasterDownstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.downstream.IotModbusTcpMasterDownstreamSubscriber;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.upstream.IotModbusTcpMasterUpstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager.IotModbusTcpMasterConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager.IotModbusTcpMasterConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager.IotModbusTcpMasterPollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.downstream.IotModbusTcpClientDownstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.downstream.IotModbusTcpClientDownstreamSubscriber;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.upstream.IotModbusTcpClientUpstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientPollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
|
||||
import io.vertx.core.Vertx;
|
||||
import lombok.Getter;
|
||||
@@ -26,12 +26,12 @@ import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* IoT 网关 Modbus TCP Master 协议:主动轮询 Modbus 从站设备数据
|
||||
* IoT 网关 Modbus TCP Client 协议:主动轮询 Modbus 从站设备数据
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
public class IotModbusTcpClientProtocol implements IotProtocol {
|
||||
|
||||
/**
|
||||
* 协议配置
|
||||
@@ -61,18 +61,18 @@ public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
/**
|
||||
* 连接管理器
|
||||
*/
|
||||
private final IotModbusTcpMasterConnectionManager connectionManager;
|
||||
private final IotModbusTcpClientConnectionManager connectionManager;
|
||||
/**
|
||||
* 下行消息订阅者
|
||||
*/
|
||||
private IotModbusTcpMasterDownstreamSubscriber downstreamSubscriber;
|
||||
private IotModbusTcpClientDownstreamSubscriber downstreamSubscriber;
|
||||
|
||||
private final IotModbusTcpMasterConfigCacheService configCacheService;
|
||||
private final IotModbusTcpMasterPollScheduler pollScheduler;
|
||||
private final IotModbusTcpClientConfigCacheService configCacheService;
|
||||
private final IotModbusTcpClientPollScheduler pollScheduler;
|
||||
|
||||
public IotModbusTcpMasterProtocol(ProtocolProperties properties) {
|
||||
IotModbusTcpMasterConfig modbusTcpMasterConfig = properties.getModbusTcpMaster();
|
||||
Assert.notNull(modbusTcpMasterConfig, "Modbus TCP Master 协议配置(modbusTcpMaster)不能为空");
|
||||
public IotModbusTcpClientProtocol(ProtocolProperties properties) {
|
||||
IotModbusTcpClientConfig modbusTcpClientConfig = properties.getModbusTcpClient();
|
||||
Assert.notNull(modbusTcpClientConfig, "Modbus TCP Client 协议配置(modbusTcpClient)不能为空");
|
||||
this.properties = properties;
|
||||
this.serverId = IotDeviceMessageUtils.generateServerId(properties.getPort());
|
||||
|
||||
@@ -83,15 +83,15 @@ public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
RedissonClient redissonClient = SpringUtil.getBean(RedissonClient.class);
|
||||
IotDeviceCommonApi deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class);
|
||||
IotDeviceMessageService messageService = SpringUtil.getBean(IotDeviceMessageService.class);
|
||||
this.configCacheService = new IotModbusTcpMasterConfigCacheService(deviceApi);
|
||||
this.connectionManager = new IotModbusTcpMasterConnectionManager(redissonClient, vertx,
|
||||
this.configCacheService = new IotModbusTcpClientConfigCacheService(deviceApi);
|
||||
this.connectionManager = new IotModbusTcpClientConnectionManager(redissonClient, vertx,
|
||||
messageService, configCacheService, serverId);
|
||||
|
||||
// 初始化 Handler
|
||||
IotModbusTcpMasterUpstreamHandler upstreamHandler = new IotModbusTcpMasterUpstreamHandler(messageService, serverId);
|
||||
IotModbusTcpClientUpstreamHandler upstreamHandler = new IotModbusTcpClientUpstreamHandler(messageService, serverId);
|
||||
|
||||
// 初始化轮询调度器
|
||||
this.pollScheduler = new IotModbusTcpMasterPollScheduler(vertx, connectionManager, upstreamHandler, configCacheService);
|
||||
this.pollScheduler = new IotModbusTcpClientPollScheduler(vertx, connectionManager, upstreamHandler, configCacheService);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -101,13 +101,13 @@ public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
|
||||
@Override
|
||||
public IotProtocolTypeEnum getType() {
|
||||
return IotProtocolTypeEnum.MODBUS_TCP_MASTER;
|
||||
return IotProtocolTypeEnum.MODBUS_TCP_CLIENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (running) {
|
||||
log.warn("[start][IoT Modbus TCP Master 协议 {} 已经在运行中]", getId());
|
||||
log.warn("[start][IoT Modbus TCP Client 协议 {} 已经在运行中]", getId());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -115,22 +115,22 @@ public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
// 1.1 首次加载配置
|
||||
refreshConfig();
|
||||
// 1.2 启动配置刷新定时器
|
||||
int refreshInterval = properties.getModbusTcpMaster().getConfigRefreshInterval();
|
||||
int refreshInterval = properties.getModbusTcpClient().getConfigRefreshInterval();
|
||||
configRefreshTimerId = vertx.setPeriodic(
|
||||
TimeUnit.SECONDS.toMillis(refreshInterval),
|
||||
id -> refreshConfig()
|
||||
);
|
||||
running = true;
|
||||
log.info("[start][IoT Modbus TCP Master 协议 {} 启动成功,serverId={}]", getId(), serverId);
|
||||
log.info("[start][IoT Modbus TCP Client 协议 {} 启动成功,serverId={}]", getId(), serverId);
|
||||
|
||||
// 2. 启动下行消息订阅者
|
||||
IotMessageBus messageBus = SpringUtil.getBean(IotMessageBus.class);
|
||||
IotModbusTcpMasterDownstreamHandler downstreamHandler = new IotModbusTcpMasterDownstreamHandler(connectionManager,
|
||||
IotModbusTcpClientDownstreamHandler downstreamHandler = new IotModbusTcpClientDownstreamHandler(connectionManager,
|
||||
configCacheService);
|
||||
this.downstreamSubscriber = new IotModbusTcpMasterDownstreamSubscriber(this, downstreamHandler, messageBus);
|
||||
this.downstreamSubscriber = new IotModbusTcpClientDownstreamSubscriber(this, downstreamHandler, messageBus);
|
||||
this.downstreamSubscriber.start();
|
||||
} catch (Exception e) {
|
||||
log.error("[start][IoT Modbus TCP Master 协议 {} 启动失败]", getId(), e);
|
||||
log.error("[start][IoT Modbus TCP Client 协议 {} 启动失败]", getId(), e);
|
||||
stop0();
|
||||
throw e;
|
||||
}
|
||||
@@ -149,9 +149,9 @@ public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
if (downstreamSubscriber != null) {
|
||||
try {
|
||||
downstreamSubscriber.stop();
|
||||
log.info("[stop][IoT Modbus TCP Master 协议 {} 下行消息订阅者已停止]", getId());
|
||||
log.info("[stop][IoT Modbus TCP Client 协议 {} 下行消息订阅者已停止]", getId());
|
||||
} catch (Exception e) {
|
||||
log.error("[stop][IoT Modbus TCP Master 协议 {} 下行消息订阅者停止失败]", getId(), e);
|
||||
log.error("[stop][IoT Modbus TCP Client 协议 {} 下行消息订阅者停止失败]", getId(), e);
|
||||
}
|
||||
downstreamSubscriber = null;
|
||||
}
|
||||
@@ -170,13 +170,13 @@ public class IotModbusTcpMasterProtocol implements IotProtocol {
|
||||
if (vertx != null) {
|
||||
try {
|
||||
vertx.close().result();
|
||||
log.info("[stop][IoT Modbus TCP Master 协议 {} Vertx 已关闭]", getId());
|
||||
log.info("[stop][IoT Modbus TCP Client 协议 {} Vertx 已关闭]", getId());
|
||||
} catch (Exception e) {
|
||||
log.error("[stop][IoT Modbus TCP Master 协议 {} Vertx 关闭失败]", getId(), e);
|
||||
log.error("[stop][IoT Modbus TCP Client 协议 {} Vertx 关闭失败]", getId(), e);
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
log.info("[stop][IoT Modbus TCP Master 协议 {} 已停止]", getId());
|
||||
log.info("[stop][IoT Modbus TCP Client 协议 {} 已停止]", getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.downstream;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.downstream;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
|
||||
@@ -6,16 +6,16 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusTcpMasterUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager.IotModbusTcpMasterConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager.IotModbusTcpMasterConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusTcpClientUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager.IotModbusTcpClientConnectionManager;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Master 下行消息处理器
|
||||
* IoT Modbus TCP Client 下行消息处理器
|
||||
* <p>
|
||||
* 负责:
|
||||
* 1. 处理下行消息(如属性设置 thing.service.property.set)
|
||||
@@ -25,10 +25,10 @@ import java.util.Map;
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterDownstreamHandler {
|
||||
public class IotModbusTcpClientDownstreamHandler {
|
||||
|
||||
private final IotModbusTcpMasterConnectionManager connectionManager;
|
||||
private final IotModbusTcpMasterConfigCacheService configCacheService;
|
||||
private final IotModbusTcpClientConnectionManager connectionManager;
|
||||
private final IotModbusTcpClientConfigCacheService configCacheService;
|
||||
|
||||
/**
|
||||
* 处理下行消息
|
||||
@@ -36,8 +36,11 @@ public class IotModbusTcpMasterDownstreamHandler {
|
||||
@SuppressWarnings({"unchecked", "DuplicatedCode"})
|
||||
public void handle(IotDeviceMessage message) {
|
||||
// 1.1 检查是否是属性设置消息
|
||||
if (ObjUtil.equals(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(), message.getMethod())) {
|
||||
return;
|
||||
}
|
||||
if (ObjUtil.notEqual(IotDeviceMessageMethodEnum.PROPERTY_SET.getMethod(), message.getMethod())) {
|
||||
log.debug("[handle][忽略非属性设置消息: {}]", message.getMethod());
|
||||
log.warn("[handle][忽略非属性设置消息: {}]", message.getMethod());
|
||||
return;
|
||||
}
|
||||
// 1.2 获取设备配置
|
||||
@@ -79,7 +82,7 @@ public class IotModbusTcpMasterDownstreamHandler {
|
||||
*/
|
||||
private void writeProperty(IotModbusDeviceConfigRespDTO config, IotModbusPointRespDTO point, Object value) {
|
||||
// 1.1 获取连接
|
||||
IotModbusTcpMasterConnectionManager.ModbusConnection connection = connectionManager.getConnection(config.getDeviceId());
|
||||
IotModbusTcpClientConnectionManager.ModbusConnection connection = connectionManager.getConnection(config.getDeviceId());
|
||||
if (connection == null) {
|
||||
log.warn("[writeProperty][设备 {} 没有连接]", config.getDeviceId());
|
||||
return;
|
||||
@@ -94,7 +97,7 @@ public class IotModbusTcpMasterDownstreamHandler {
|
||||
// 2.1 转换属性值为原始值
|
||||
int[] rawValues = IotModbusCommonUtils.convertToRawValues(value, point);
|
||||
// 2.2 执行 Modbus 写入
|
||||
IotModbusTcpMasterUtils.write(connection, slaveId, point, rawValues)
|
||||
IotModbusTcpClientUtils.write(connection, slaveId, point, rawValues)
|
||||
.onSuccess(success -> log.info("[writeProperty][写入成功, deviceId={}, identifier={}, value={}]",
|
||||
config.getDeviceId(), point.getIdentifier(), value))
|
||||
.onFailure(e -> log.error("[writeProperty][写入失败, deviceId={}, identifier={}]",
|
||||
@@ -1,9 +1,9 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.downstream;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.downstream;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.AbstractIotProtocolDownstreamSubscriber;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.IotModbusTcpMasterProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.IotModbusTcpClientProtocol;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
@@ -12,12 +12,12 @@ import lombok.extern.slf4j.Slf4j;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterDownstreamSubscriber extends AbstractIotProtocolDownstreamSubscriber {
|
||||
public class IotModbusTcpClientDownstreamSubscriber extends AbstractIotProtocolDownstreamSubscriber {
|
||||
|
||||
private final IotModbusTcpMasterDownstreamHandler downstreamHandler;
|
||||
private final IotModbusTcpClientDownstreamHandler downstreamHandler;
|
||||
|
||||
public IotModbusTcpMasterDownstreamSubscriber(IotModbusTcpMasterProtocol protocol,
|
||||
IotModbusTcpMasterDownstreamHandler downstreamHandler,
|
||||
public IotModbusTcpClientDownstreamSubscriber(IotModbusTcpClientProtocol protocol,
|
||||
IotModbusTcpClientDownstreamHandler downstreamHandler,
|
||||
IotMessageBus messageBus) {
|
||||
super(protocol, messageBus);
|
||||
this.downstreamHandler = downstreamHandler;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.upstream;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.upstream;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
|
||||
@@ -17,13 +17,13 @@ import java.util.Map;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterUpstreamHandler {
|
||||
public class IotModbusTcpClientUpstreamHandler {
|
||||
|
||||
private final IotDeviceMessageService messageService;
|
||||
|
||||
private final String serverId;
|
||||
|
||||
public IotModbusTcpMasterUpstreamHandler(IotDeviceMessageService messageService,
|
||||
public IotModbusTcpClientUpstreamHandler(IotDeviceMessageService messageService,
|
||||
String serverId) {
|
||||
this.messageService = messageService;
|
||||
this.serverId = serverId;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||
@@ -19,13 +19,13 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Master 配置缓存服务
|
||||
* IoT Modbus TCP Client 配置缓存服务
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterConfigCacheService {
|
||||
public class IotModbusTcpClientConfigCacheService {
|
||||
|
||||
private final IotDeviceCommonApi deviceApi;
|
||||
|
||||
@@ -51,7 +51,7 @@ public class IotModbusTcpMasterConfigCacheService {
|
||||
// 1. 从远程获取配置
|
||||
CommonResult<List<IotModbusDeviceConfigRespDTO>> result = deviceApi.getModbusDeviceConfigList(
|
||||
new IotModbusDeviceConfigListReqDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())
|
||||
.setMode(IotModbusModeEnum.POLLING.getMode()).setProtocolType(IotProtocolTypeEnum.MODBUS_TCP_MASTER.getType()));
|
||||
.setMode(IotModbusModeEnum.POLLING.getMode()).setProtocolType(IotProtocolTypeEnum.MODBUS_TCP_CLIENT.getType()));
|
||||
result.checkError();
|
||||
List<IotModbusDeviceConfigRespDTO> configs = result.getData();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
|
||||
@@ -30,14 +30,14 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterConnectionManager {
|
||||
public class IotModbusTcpClientConnectionManager {
|
||||
|
||||
private static final String LOCK_KEY_PREFIX = "iot:modbus-tcp:connection:";
|
||||
|
||||
private final RedissonClient redissonClient;
|
||||
private final Vertx vertx;
|
||||
private final IotDeviceMessageService messageService;
|
||||
private final IotModbusTcpMasterConfigCacheService configCacheService;
|
||||
private final IotModbusTcpClientConfigCacheService configCacheService;
|
||||
private final String serverId;
|
||||
|
||||
/**
|
||||
@@ -50,9 +50,9 @@ public class IotModbusTcpMasterConnectionManager {
|
||||
*/
|
||||
private final Map<Long, String> deviceConnectionMap = new ConcurrentHashMap<>();
|
||||
|
||||
public IotModbusTcpMasterConnectionManager(RedissonClient redissonClient, Vertx vertx,
|
||||
public IotModbusTcpClientConnectionManager(RedissonClient redissonClient, Vertx vertx,
|
||||
IotDeviceMessageService messageService,
|
||||
IotModbusTcpMasterConfigCacheService configCacheService,
|
||||
IotModbusTcpClientConfigCacheService configCacheService,
|
||||
String serverId) {
|
||||
this.redissonClient = redissonClient;
|
||||
this.vertx = vertx;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.manager;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
@@ -6,27 +6,27 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.manager.AbstractIotModbusPollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusTcpMasterUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster.handler.upstream.IotModbusTcpMasterUpstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusTcpClientUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient.handler.upstream.IotModbusTcpClientUpstreamHandler;
|
||||
import io.vertx.core.Vertx;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Master 轮询调度器:管理点位的轮询定时器,调度读取任务并上报结果
|
||||
* IoT Modbus TCP Client 轮询调度器:管理点位的轮询定时器,调度读取任务并上报结果
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpMasterPollScheduler extends AbstractIotModbusPollScheduler {
|
||||
public class IotModbusTcpClientPollScheduler extends AbstractIotModbusPollScheduler {
|
||||
|
||||
private final IotModbusTcpMasterConnectionManager connectionManager;
|
||||
private final IotModbusTcpMasterUpstreamHandler upstreamHandler;
|
||||
private final IotModbusTcpMasterConfigCacheService configCacheService;
|
||||
private final IotModbusTcpClientConnectionManager connectionManager;
|
||||
private final IotModbusTcpClientUpstreamHandler upstreamHandler;
|
||||
private final IotModbusTcpClientConfigCacheService configCacheService;
|
||||
|
||||
public IotModbusTcpMasterPollScheduler(Vertx vertx,
|
||||
IotModbusTcpMasterConnectionManager connectionManager,
|
||||
IotModbusTcpMasterUpstreamHandler upstreamHandler,
|
||||
IotModbusTcpMasterConfigCacheService configCacheService) {
|
||||
public IotModbusTcpClientPollScheduler(Vertx vertx,
|
||||
IotModbusTcpClientConnectionManager connectionManager,
|
||||
IotModbusTcpClientUpstreamHandler upstreamHandler,
|
||||
IotModbusTcpClientConfigCacheService configCacheService) {
|
||||
super(vertx);
|
||||
this.connectionManager = connectionManager;
|
||||
this.upstreamHandler = upstreamHandler;
|
||||
@@ -54,7 +54,7 @@ public class IotModbusTcpMasterPollScheduler extends AbstractIotModbusPollSchedu
|
||||
}
|
||||
|
||||
// 2.1 获取连接
|
||||
IotModbusTcpMasterConnectionManager.ModbusConnection connection = connectionManager.getConnection(deviceId);
|
||||
IotModbusTcpClientConnectionManager.ModbusConnection connection = connectionManager.getConnection(deviceId);
|
||||
if (connection == null) {
|
||||
log.warn("[pollPoint][设备 {} 没有连接]", deviceId);
|
||||
return;
|
||||
@@ -64,7 +64,7 @@ public class IotModbusTcpMasterPollScheduler extends AbstractIotModbusPollSchedu
|
||||
Assert.notNull(slaveId, "设备 {} 没有配置 slaveId", deviceId);
|
||||
|
||||
// 3. 执行 Modbus 读取
|
||||
IotModbusTcpMasterUtils.read(connection, slaveId, point)
|
||||
IotModbusTcpClientUtils.read(connection, slaveId, point)
|
||||
.onSuccess(rawValue -> upstreamHandler.handleReadResult(config, point, rawValue))
|
||||
.onFailure(e -> log.error("[pollPoint][读取点位失败, deviceId={}, identifier={}]",
|
||||
deviceId, point.getIdentifier(), e));
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Modbus TCP Master(主站)协议:网关主动连接并轮询 Modbus 从站设备
|
||||
* Modbus TCP Client(主站)协议:网关主动连接并轮询 Modbus 从站设备
|
||||
* <p>
|
||||
* 基于 j2mod 实现,支持 FC01-04 读、FC05/06/15/16 写,定时轮询 + 下发属性设置
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver;
|
||||
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
@@ -6,12 +6,12 @@ import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 协议配置
|
||||
* IoT Modbus TCP Server 协议配置
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Data
|
||||
public class IotModbusTcpSlaveConfig {
|
||||
public class IotModbusTcpServerConfig {
|
||||
|
||||
/**
|
||||
* 配置刷新间隔(秒)
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
@@ -11,16 +11,16 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.core.util.IotDeviceMessageUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.config.IotGatewayProperties.ProtocolProperties;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.IotProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameDecoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.handler.downstream.IotModbusTcpSlaveDownstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.handler.downstream.IotModbusTcpSlaveDownstreamSubscriber;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.handler.upstream.IotModbusTcpSlaveUpstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlavePendingRequestManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlavePollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameDecoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.handler.downstream.IotModbusTcpServerDownstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.handler.downstream.IotModbusTcpServerDownstreamSubscriber;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.handler.upstream.IotModbusTcpServerUpstreamHandler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerPendingRequestManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerPollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
|
||||
import io.vertx.core.Vertx;
|
||||
@@ -37,7 +37,7 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* IoT 网关 Modbus TCP Slave 协议
|
||||
* IoT 网关 Modbus TCP Server 协议
|
||||
* <p>
|
||||
* 作为 TCP Server 接收设备主动连接:
|
||||
* 1. 设备通过自定义功能码(FC 65)发送认证请求
|
||||
@@ -46,7 +46,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
public class IotModbusTcpServerProtocol implements IotProtocol {
|
||||
|
||||
/**
|
||||
* 协议配置
|
||||
@@ -84,25 +84,25 @@ public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
/**
|
||||
* 连接管理器
|
||||
*/
|
||||
private final IotModbusTcpSlaveConnectionManager connectionManager;
|
||||
private final IotModbusTcpServerConnectionManager connectionManager;
|
||||
/**
|
||||
* 下行消息订阅者
|
||||
*/
|
||||
private IotModbusTcpSlaveDownstreamSubscriber downstreamSubscriber;
|
||||
private IotModbusTcpServerDownstreamSubscriber downstreamSubscriber;
|
||||
|
||||
private final IotModbusFrameDecoder frameDecoder;
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private final IotModbusFrameEncoder frameEncoder;
|
||||
|
||||
private final IotModbusTcpSlaveConfigCacheService configCacheService;
|
||||
private final IotModbusTcpSlavePendingRequestManager pendingRequestManager;
|
||||
private final IotModbusTcpSlaveUpstreamHandler upstreamHandler;
|
||||
private final IotModbusTcpSlavePollScheduler pollScheduler;
|
||||
private final IotModbusTcpServerConfigCacheService configCacheService;
|
||||
private final IotModbusTcpServerPendingRequestManager pendingRequestManager;
|
||||
private final IotModbusTcpServerUpstreamHandler upstreamHandler;
|
||||
private final IotModbusTcpServerPollScheduler pollScheduler;
|
||||
private final IotDeviceMessageService messageService;
|
||||
|
||||
public IotModbusTcpSlaveProtocol(ProtocolProperties properties) {
|
||||
IotModbusTcpSlaveConfig slaveConfig = properties.getModbusTcpSlave();
|
||||
Assert.notNull(slaveConfig, "Modbus TCP Slave 协议配置(modbusTcpSlave)不能为空");
|
||||
public IotModbusTcpServerProtocol(ProtocolProperties properties) {
|
||||
IotModbusTcpServerConfig slaveConfig = properties.getModbusTcpServer();
|
||||
Assert.notNull(slaveConfig, "Modbus TCP Server 协议配置(modbusTcpServer)不能为空");
|
||||
this.properties = properties;
|
||||
this.serverId = IotDeviceMessageUtils.generateServerId(properties.getPort());
|
||||
|
||||
@@ -111,9 +111,9 @@ public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
|
||||
// 初始化 Manager
|
||||
IotDeviceCommonApi deviceApi = SpringUtil.getBean(IotDeviceCommonApi.class);
|
||||
this.connectionManager = new IotModbusTcpSlaveConnectionManager();
|
||||
this.configCacheService = new IotModbusTcpSlaveConfigCacheService(deviceApi);
|
||||
this.pendingRequestManager = new IotModbusTcpSlavePendingRequestManager();
|
||||
this.connectionManager = new IotModbusTcpServerConnectionManager();
|
||||
this.configCacheService = new IotModbusTcpServerConfigCacheService(deviceApi);
|
||||
this.pendingRequestManager = new IotModbusTcpServerPendingRequestManager();
|
||||
|
||||
// 初始化帧编解码器
|
||||
this.frameDecoder = new IotModbusFrameDecoder(slaveConfig.getCustomFunctionCode());
|
||||
@@ -122,14 +122,14 @@ public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
// 初始化共享事务 ID 自增器(PollScheduler 和 DownstreamHandler 共用,避免 transactionId 冲突)
|
||||
AtomicInteger transactionIdCounter = new AtomicInteger(0);
|
||||
// 初始化轮询调度器
|
||||
this.pollScheduler = new IotModbusTcpSlavePollScheduler(
|
||||
this.pollScheduler = new IotModbusTcpServerPollScheduler(
|
||||
vertx, connectionManager, frameEncoder, pendingRequestManager,
|
||||
slaveConfig.getRequestTimeout(), transactionIdCounter, configCacheService);
|
||||
|
||||
// 初始化 Handler
|
||||
this.messageService = SpringUtil.getBean(IotDeviceMessageService.class);
|
||||
IotDeviceService deviceService = SpringUtil.getBean(IotDeviceService.class);
|
||||
this.upstreamHandler = new IotModbusTcpSlaveUpstreamHandler(
|
||||
this.upstreamHandler = new IotModbusTcpServerUpstreamHandler(
|
||||
deviceApi, this.messageService, frameEncoder,
|
||||
connectionManager, configCacheService, pendingRequestManager,
|
||||
pollScheduler, deviceService, serverId);
|
||||
@@ -142,19 +142,19 @@ public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
|
||||
@Override
|
||||
public IotProtocolTypeEnum getType() {
|
||||
return IotProtocolTypeEnum.MODBUS_TCP_SLAVE;
|
||||
return IotProtocolTypeEnum.MODBUS_TCP_SERVER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (running) {
|
||||
log.warn("[start][IoT Modbus TCP Slave 协议 {} 已经在运行中]", getId());
|
||||
log.warn("[start][IoT Modbus TCP Server 协议 {} 已经在运行中]", getId());
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 1. 启动配置刷新定时器
|
||||
IotModbusTcpSlaveConfig slaveConfig = properties.getModbusTcpSlave();
|
||||
IotModbusTcpServerConfig slaveConfig = properties.getModbusTcpServer();
|
||||
configRefreshTimerId = vertx.setPeriodic(
|
||||
TimeUnit.SECONDS.toMillis(slaveConfig.getConfigRefreshInterval()),
|
||||
id -> refreshConfig());
|
||||
@@ -167,18 +167,18 @@ public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
slaveConfig.getRequestCleanupInterval(),
|
||||
id -> pendingRequestManager.cleanupExpired());
|
||||
running = true;
|
||||
log.info("[start][IoT Modbus TCP Slave 协议 {} 启动成功, serverId={}, port={}]",
|
||||
log.info("[start][IoT Modbus TCP Server 协议 {} 启动成功, serverId={}, port={}]",
|
||||
getId(), serverId, properties.getPort());
|
||||
|
||||
// 3. 启动下行消息订阅
|
||||
IotMessageBus messageBus = SpringUtil.getBean(IotMessageBus.class);
|
||||
IotModbusTcpSlaveDownstreamHandler downstreamHandler = new IotModbusTcpSlaveDownstreamHandler(
|
||||
IotModbusTcpServerDownstreamHandler downstreamHandler = new IotModbusTcpServerDownstreamHandler(
|
||||
connectionManager, configCacheService, frameEncoder, this.pollScheduler.getTransactionIdCounter());
|
||||
this.downstreamSubscriber = new IotModbusTcpSlaveDownstreamSubscriber(
|
||||
this.downstreamSubscriber = new IotModbusTcpServerDownstreamSubscriber(
|
||||
this, downstreamHandler, messageBus);
|
||||
downstreamSubscriber.start();
|
||||
} catch (Exception e) {
|
||||
log.error("[start][IoT Modbus TCP Slave 协议 {} 启动失败]", getId(), e);
|
||||
log.error("[start][IoT Modbus TCP Server 协议 {} 启动失败]", getId(), e);
|
||||
stop0();
|
||||
throw e;
|
||||
}
|
||||
@@ -238,7 +238,7 @@ public class IotModbusTcpSlaveProtocol implements IotProtocol {
|
||||
}
|
||||
}
|
||||
running = false;
|
||||
log.info("[stop][IoT Modbus TCP Slave 协议 {} 已停止]", getId());
|
||||
log.info("[stop][IoT Modbus TCP Server 协议 {} 已停止]", getId());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.handler.downstream;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.handler.downstream;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
@@ -8,17 +8,17 @@ import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager.ConnectionInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 下行消息处理器
|
||||
* IoT Modbus TCP Server 下行消息处理器
|
||||
* <p>
|
||||
* 负责:
|
||||
* 1. 处理下行消息(如属性设置 thing.service.property.set)
|
||||
@@ -27,10 +27,10 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlaveDownstreamHandler {
|
||||
public class IotModbusTcpServerDownstreamHandler {
|
||||
|
||||
private final IotModbusTcpSlaveConnectionManager connectionManager;
|
||||
private final IotModbusTcpSlaveConfigCacheService configCacheService;
|
||||
private final IotModbusTcpServerConnectionManager connectionManager;
|
||||
private final IotModbusTcpServerConfigCacheService configCacheService;
|
||||
private final IotModbusFrameEncoder frameEncoder;
|
||||
|
||||
/**
|
||||
@@ -38,8 +38,8 @@ public class IotModbusTcpSlaveDownstreamHandler {
|
||||
*/
|
||||
private final AtomicInteger transactionIdCounter;
|
||||
|
||||
public IotModbusTcpSlaveDownstreamHandler(IotModbusTcpSlaveConnectionManager connectionManager,
|
||||
IotModbusTcpSlaveConfigCacheService configCacheService,
|
||||
public IotModbusTcpServerDownstreamHandler(IotModbusTcpServerConnectionManager connectionManager,
|
||||
IotModbusTcpServerConfigCacheService configCacheService,
|
||||
IotModbusFrameEncoder frameEncoder,
|
||||
AtomicInteger transactionIdCounter) {
|
||||
this.connectionManager = connectionManager;
|
||||
@@ -54,6 +54,9 @@ public class IotModbusTcpSlaveDownstreamHandler {
|
||||
@SuppressWarnings({"unchecked", "DuplicatedCode"})
|
||||
public void handle(IotDeviceMessage message) {
|
||||
// 1.1 检查是否是属性设置消息
|
||||
if (ObjUtil.equals(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(), message.getMethod())) {
|
||||
return;
|
||||
}
|
||||
if (ObjUtil.notEqual(IotDeviceMessageMethodEnum.PROPERTY_SET.getMethod(), message.getMethod())) {
|
||||
log.debug("[handle][忽略非属性设置消息: {}]", message.getMethod());
|
||||
return;
|
||||
@@ -1,23 +1,23 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.handler.downstream;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.handler.downstream;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.messagebus.core.IotMessageBus;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.AbstractIotProtocolDownstreamSubscriber;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.IotModbusTcpSlaveProtocol;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.IotModbusTcpServerProtocol;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 下行消息订阅器:订阅消息总线的下行消息并转发给处理器
|
||||
* IoT Modbus TCP Server 下行消息订阅器:订阅消息总线的下行消息并转发给处理器
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlaveDownstreamSubscriber extends AbstractIotProtocolDownstreamSubscriber {
|
||||
public class IotModbusTcpServerDownstreamSubscriber extends AbstractIotProtocolDownstreamSubscriber {
|
||||
|
||||
private final IotModbusTcpSlaveDownstreamHandler downstreamHandler;
|
||||
private final IotModbusTcpServerDownstreamHandler downstreamHandler;
|
||||
|
||||
public IotModbusTcpSlaveDownstreamSubscriber(IotModbusTcpSlaveProtocol protocol,
|
||||
IotModbusTcpSlaveDownstreamHandler downstreamHandler,
|
||||
public IotModbusTcpServerDownstreamSubscriber(IotModbusTcpServerProtocol protocol,
|
||||
IotModbusTcpServerDownstreamHandler downstreamHandler,
|
||||
IotMessageBus messageBus) {
|
||||
super(protocol, messageBus);
|
||||
this.downstreamHandler = downstreamHandler;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.handler.upstream;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.handler.upstream;
|
||||
|
||||
import cn.hutool.core.lang.Assert;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
@@ -20,14 +20,14 @@ import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.core.topic.IotDeviceIdentity;
|
||||
import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlavePendingRequestManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlavePendingRequestManager.PendingRequest;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlavePollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConfigCacheService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerPendingRequestManager;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerPendingRequestManager.PendingRequest;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerPollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
|
||||
import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
|
||||
import io.vertx.core.net.NetSocket;
|
||||
@@ -40,7 +40,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.invalidParamException;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 上行数据处理器
|
||||
* IoT Modbus TCP Server 上行数据处理器
|
||||
* <p>
|
||||
* 处理:
|
||||
* 1. 自定义 FC 认证
|
||||
@@ -49,28 +49,28 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlaveUpstreamHandler {
|
||||
public class IotModbusTcpServerUpstreamHandler {
|
||||
|
||||
private static final String METHOD_AUTH = "auth";
|
||||
|
||||
private final IotDeviceCommonApi deviceApi;
|
||||
private final IotDeviceMessageService messageService;
|
||||
private final IotModbusFrameEncoder frameEncoder;
|
||||
private final IotModbusTcpSlaveConnectionManager connectionManager;
|
||||
private final IotModbusTcpSlaveConfigCacheService configCacheService;
|
||||
private final IotModbusTcpSlavePendingRequestManager pendingRequestManager;
|
||||
private final IotModbusTcpSlavePollScheduler pollScheduler;
|
||||
private final IotModbusTcpServerConnectionManager connectionManager;
|
||||
private final IotModbusTcpServerConfigCacheService configCacheService;
|
||||
private final IotModbusTcpServerPendingRequestManager pendingRequestManager;
|
||||
private final IotModbusTcpServerPollScheduler pollScheduler;
|
||||
private final IotDeviceService deviceService;
|
||||
|
||||
private final String serverId;
|
||||
|
||||
public IotModbusTcpSlaveUpstreamHandler(IotDeviceCommonApi deviceApi,
|
||||
public IotModbusTcpServerUpstreamHandler(IotDeviceCommonApi deviceApi,
|
||||
IotDeviceMessageService messageService,
|
||||
IotModbusFrameEncoder frameEncoder,
|
||||
IotModbusTcpSlaveConnectionManager connectionManager,
|
||||
IotModbusTcpSlaveConfigCacheService configCacheService,
|
||||
IotModbusTcpSlavePendingRequestManager pendingRequestManager,
|
||||
IotModbusTcpSlavePollScheduler pollScheduler,
|
||||
IotModbusTcpServerConnectionManager connectionManager,
|
||||
IotModbusTcpServerConfigCacheService configCacheService,
|
||||
IotModbusTcpServerPendingRequestManager pendingRequestManager,
|
||||
IotModbusTcpServerPollScheduler pollScheduler,
|
||||
IotDeviceService deviceService,
|
||||
String serverId) {
|
||||
this.deviceApi = deviceApi;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
|
||||
@@ -18,13 +18,13 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 配置缓存:认证时按需加载,断连时清理,定时刷新已连接设备
|
||||
* IoT Modbus TCP Server 配置缓存:认证时按需加载,断连时清理,定时刷新已连接设备
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlaveConfigCacheService {
|
||||
public class IotModbusTcpServerConfigCacheService {
|
||||
|
||||
private final IotDeviceCommonApi deviceApi;
|
||||
|
||||
@@ -45,7 +45,7 @@ public class IotModbusTcpSlaveConfigCacheService {
|
||||
IotModbusDeviceConfigListReqDTO reqDTO = new IotModbusDeviceConfigListReqDTO()
|
||||
.setStatus(CommonStatusEnum.ENABLE.getStatus())
|
||||
.setMode(IotModbusModeEnum.POLLING.getMode())
|
||||
.setProtocolType(IotProtocolTypeEnum.MODBUS_TCP_SLAVE.getType())
|
||||
.setProtocolType(IotProtocolTypeEnum.MODBUS_TCP_SERVER.getType())
|
||||
.setDeviceIds(Collections.singleton(deviceId));
|
||||
CommonResult<List<IotModbusDeviceConfigRespDTO>> result = deviceApi.getModbusDeviceConfigList(reqDTO);
|
||||
result.checkError();
|
||||
@@ -81,7 +81,7 @@ public class IotModbusTcpSlaveConfigCacheService {
|
||||
CommonResult<List<IotModbusDeviceConfigRespDTO>> result = deviceApi.getModbusDeviceConfigList(
|
||||
new IotModbusDeviceConfigListReqDTO().setStatus(CommonStatusEnum.ENABLE.getStatus())
|
||||
.setMode(IotModbusModeEnum.POLLING.getMode())
|
||||
.setProtocolType(IotProtocolTypeEnum.MODBUS_TCP_SLAVE.getType())
|
||||
.setProtocolType(IotProtocolTypeEnum.MODBUS_TCP_SERVER.getType())
|
||||
.setDeviceIds(connectedDeviceIds));
|
||||
List<IotModbusDeviceConfigRespDTO> modbusConfigs = result.getCheckedData();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager;
|
||||
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import io.vertx.core.Future;
|
||||
@@ -15,14 +15,14 @@ import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 连接管理器
|
||||
* IoT Modbus TCP Server 连接管理器
|
||||
* <p>
|
||||
* 管理设备 TCP 连接:socket ↔ 设备双向映射
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlaveConnectionManager {
|
||||
public class IotModbusTcpServerConnectionManager {
|
||||
|
||||
/**
|
||||
* socket → 连接信息
|
||||
@@ -1,9 +1,9 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrame;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -15,7 +15,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 待响应请求管理器
|
||||
* IoT Modbus TCP Server 待响应请求管理器
|
||||
* <p>
|
||||
* 管理轮询下发的请求,用于匹配设备响应:
|
||||
* - TCP 模式:按 transactionId 精确匹配
|
||||
@@ -24,7 +24,7 @@ import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlavePendingRequestManager {
|
||||
public class IotModbusTcpServerPendingRequestManager {
|
||||
|
||||
/**
|
||||
* deviceId → 有序队列
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Assert;
|
||||
@@ -7,9 +7,9 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.manager.AbstractIotModbusPollScheduler;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlaveConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.manager.IotModbusTcpSlavePendingRequestManager.PendingRequest;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerConnectionManager.ConnectionInfo;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.manager.IotModbusTcpServerPendingRequestManager.PendingRequest;
|
||||
import io.vertx.core.Vertx;
|
||||
import lombok.Getter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -17,17 +17,17 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 轮询调度器:编码读请求帧,通过 TCP 连接发送到设备,注册 PendingRequest 等待响应
|
||||
* IoT Modbus TCP Server 轮询调度器:编码读请求帧,通过 TCP 连接发送到设备,注册 PendingRequest 等待响应
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Slf4j
|
||||
public class IotModbusTcpSlavePollScheduler extends AbstractIotModbusPollScheduler {
|
||||
public class IotModbusTcpServerPollScheduler extends AbstractIotModbusPollScheduler {
|
||||
|
||||
private final IotModbusTcpSlaveConnectionManager connectionManager;
|
||||
private final IotModbusTcpServerConnectionManager connectionManager;
|
||||
private final IotModbusFrameEncoder frameEncoder;
|
||||
private final IotModbusTcpSlavePendingRequestManager pendingRequestManager;
|
||||
private final IotModbusTcpSlaveConfigCacheService configCacheService;
|
||||
private final IotModbusTcpServerPendingRequestManager pendingRequestManager;
|
||||
private final IotModbusTcpServerConfigCacheService configCacheService;
|
||||
private final int requestTimeout;
|
||||
/**
|
||||
* TCP 事务 ID 自增器(与 DownstreamHandler 共享)
|
||||
@@ -35,13 +35,13 @@ public class IotModbusTcpSlavePollScheduler extends AbstractIotModbusPollSchedul
|
||||
@Getter
|
||||
private final AtomicInteger transactionIdCounter;
|
||||
|
||||
public IotModbusTcpSlavePollScheduler(Vertx vertx,
|
||||
IotModbusTcpSlaveConnectionManager connectionManager,
|
||||
public IotModbusTcpServerPollScheduler(Vertx vertx,
|
||||
IotModbusTcpServerConnectionManager connectionManager,
|
||||
IotModbusFrameEncoder frameEncoder,
|
||||
IotModbusTcpSlavePendingRequestManager pendingRequestManager,
|
||||
IotModbusTcpServerPendingRequestManager pendingRequestManager,
|
||||
int requestTimeout,
|
||||
AtomicInteger transactionIdCounter,
|
||||
IotModbusTcpSlaveConfigCacheService configCacheService) {
|
||||
IotModbusTcpServerConfigCacheService configCacheService) {
|
||||
super(vertx);
|
||||
this.connectionManager = connectionManager;
|
||||
this.frameEncoder = frameEncoder;
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Modbus TCP Slave(从站)协议:设备主动连接网关,自定义 FC65 认证后由网关云端轮询
|
||||
* Modbus TCP Server(从站)协议:设备主动连接网关,自定义 FC65 认证后由网关云端轮询
|
||||
* <p>
|
||||
* TCP Server 模式,支持 MODBUS_TCP / MODBUS_RTU 帧格式自动检测
|
||||
*/
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver;
|
||||
@@ -1,5 +1,7 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.tcp.handler.downstream;
|
||||
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.IotDeviceMessageMethodEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.codec.IotTcpFrameCodec;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.tcp.manager.IotTcpConnectionManager;
|
||||
@@ -33,9 +35,17 @@ public class IotTcpDownstreamHandler {
|
||||
*/
|
||||
public void handle(IotDeviceMessage message) {
|
||||
try {
|
||||
// 1.1 检查是否是属性设置消息
|
||||
if (ObjUtil.equals(IotDeviceMessageMethodEnum.PROPERTY_POST.getMethod(), message.getMethod())) {
|
||||
return;
|
||||
}
|
||||
if (ObjUtil.notEqual(IotDeviceMessageMethodEnum.PROPERTY_SET.getMethod(), message.getMethod())) {
|
||||
log.warn("[handle][忽略非属性设置消息: {}]", message.getMethod());
|
||||
return;
|
||||
}
|
||||
log.info("[handle][处理下行消息,设备 ID: {},方法: {},消息 ID: {}]",
|
||||
message.getDeviceId(), message.getMethod(), message.getId());
|
||||
// 1. 检查设备连接
|
||||
// 1.2 检查设备连接
|
||||
IotTcpConnectionManager.ConnectionInfo connectionInfo = connectionManager.getConnectionInfoByDeviceId(
|
||||
message.getDeviceId());
|
||||
if (connectionInfo == null) {
|
||||
|
||||
@@ -164,22 +164,22 @@ yudao:
|
||||
trust-store-path: "classpath:certs/trust.jks" # 信任的 CA 证书库路径
|
||||
trust-store-password: "your-truststore-password" # 信任的 CA 证书库密码
|
||||
# ====================================
|
||||
# 针对引入的 Modbus TCP Master 组件的配置
|
||||
# 针对引入的 Modbus TCP Client 组件的配置
|
||||
# ====================================
|
||||
- id: modbus-tcp-master-1
|
||||
- id: modbus-tcp-client-1
|
||||
enabled: false
|
||||
protocol: modbus_tcp_master
|
||||
protocol: modbus_tcp_client
|
||||
port: 502
|
||||
modbus-tcp-master:
|
||||
modbus-tcp-client:
|
||||
config-refresh-interval: 30 # 配置刷新间隔(秒)
|
||||
# ====================================
|
||||
# 针对引入的 Modbus TCP Slave 组件的配置
|
||||
# 针对引入的 Modbus TCP Server 组件的配置
|
||||
# ====================================
|
||||
- id: modbus-tcp-slave-1
|
||||
- id: modbus-tcp-server-1
|
||||
enabled: false
|
||||
protocol: modbus_tcp_slave
|
||||
protocol: modbus_tcp_server
|
||||
port: 503
|
||||
modbus-tcp-slave:
|
||||
modbus-tcp-server:
|
||||
config-refresh-interval: 30 # 配置刷新间隔(秒)
|
||||
custom-function-code: 65 # 自定义功能码(用于认证等扩展交互)
|
||||
request-timeout: 5000 # Pending Request 超时时间(毫秒)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpmaster;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpclient;
|
||||
|
||||
import com.ghgande.j2mod.modbus.procimg.*;
|
||||
import com.ghgande.j2mod.modbus.slave.ModbusSlave;
|
||||
@@ -10,13 +10,13 @@ import org.junit.jupiter.api.Test;
|
||||
/**
|
||||
* Modbus TCP 从站模拟器(手动测试)
|
||||
*
|
||||
* <p>测试场景:模拟一个标准 Modbus TCP 从站设备,供 Modbus TCP Master 网关连接和读写数据
|
||||
* <p>测试场景:模拟一个标准 Modbus TCP 从站设备,供 Modbus TCP Client 网关连接和读写数据
|
||||
*
|
||||
* <p>使用步骤:
|
||||
* <ol>
|
||||
* <li>运行 {@link #testStartSlaveSimulator()} 启动模拟从站(默认端口 5020,从站地址 1)</li>
|
||||
* <li>启动 yudao-module-iot-gateway 服务(需开启 modbus-tcp-master 协议)</li>
|
||||
* <li>确保数据库有对应的 Modbus Master 设备配置(ip=127.0.0.1, port=5020, slaveId=1)</li>
|
||||
* <li>启动 yudao-module-iot-gateway 服务(需开启 modbus-tcp-client 协议)</li>
|
||||
* <li>确保数据库有对应的 Modbus Client 设备配置(ip=127.0.0.1, port=5020, slaveId=1)</li>
|
||||
* <li>网关会自动连接模拟从站并开始轮询读取寄存器数据</li>
|
||||
* <li>模拟器每 5 秒自动更新输入寄存器和保持寄存器的值,模拟传感器数据变化</li>
|
||||
* </ol>
|
||||
@@ -33,7 +33,7 @@ import org.junit.jupiter.api.Test;
|
||||
*/
|
||||
@Slf4j
|
||||
@Disabled
|
||||
public class IoTModbusTcpMasterIntegrationTest {
|
||||
public class IoTModbusTcpClientIntegrationTest {
|
||||
|
||||
private static final int PORT = 5020;
|
||||
private static final int SLAVE_ID = 1;
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver;
|
||||
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
@@ -7,9 +7,9 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.common.utils.IotModbusCommonUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameDecoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameDecoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameEncoder;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.net.NetClient;
|
||||
@@ -28,13 +28,13 @@ import java.util.concurrent.TimeUnit;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 协议集成测试 — MODBUS_RTU 帧格式(手动测试)
|
||||
* IoT Modbus TCP Server 协议集成测试 — MODBUS_RTU 帧格式(手动测试)
|
||||
*
|
||||
* <p>测试场景:设备(TCP Client)连接到网关(TCP Server),使用 MODBUS_RTU(CRC16)帧格式通信
|
||||
*
|
||||
* <p>使用步骤:
|
||||
* <ol>
|
||||
* <li>启动 yudao-module-iot-gateway 服务(需开启 modbus-tcp-slave 协议,默认端口 503)</li>
|
||||
* <li>启动 yudao-module-iot-gateway 服务(需开启 modbus-tcp-server 协议,默认端口 503)</li>
|
||||
* <li>确保数据库有对应的 Modbus 设备配置(mode=1, frameFormat=modbus_rtu)</li>
|
||||
* <li>运行以下测试方法:
|
||||
* <ul>
|
||||
@@ -49,7 +49,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
*/
|
||||
@Slf4j
|
||||
@Disabled
|
||||
public class IotModbusTcpSlaveRtuIntegrationTest {
|
||||
public class IotModbusTcpServerRtuIntegrationTest {
|
||||
|
||||
private static final String SERVER_HOST = "127.0.0.1";
|
||||
private static final int SERVER_PORT = 503;
|
||||
@@ -68,8 +68,8 @@ public class IotModbusTcpSlaveRtuIntegrationTest {
|
||||
|
||||
// ===================== 设备信息(根据实际情况修改,从 iot_device 表查询) =====================
|
||||
|
||||
private static final String PRODUCT_KEY = "modbus_tcp_slave_product_demo";
|
||||
private static final String DEVICE_NAME = "modbus_tcp_slave_device_demo_rtu";
|
||||
private static final String PRODUCT_KEY = "modbus_tcp_server_product_demo";
|
||||
private static final String DEVICE_NAME = "modbus_tcp_server_device_demo_rtu";
|
||||
private static final String DEVICE_SECRET = "af01c55eb8e3424bb23fc6c783936b2e";
|
||||
|
||||
@BeforeAll
|
||||
@@ -1,4 +1,4 @@
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave;
|
||||
package cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver;
|
||||
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
@@ -6,9 +6,9 @@ import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.yudao.module.iot.core.biz.dto.IotDeviceAuthReqDTO;
|
||||
import cn.iocoder.yudao.module.iot.core.enums.modbus.IotModbusFrameFormatEnum;
|
||||
import cn.iocoder.yudao.module.iot.core.util.IotDeviceAuthUtils;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameDecoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpslave.codec.IotModbusFrameEncoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrame;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameDecoder;
|
||||
import cn.iocoder.yudao.module.iot.gateway.protocol.modbus.tcpserver.codec.IotModbusFrameEncoder;
|
||||
import io.vertx.core.Vertx;
|
||||
import io.vertx.core.buffer.Buffer;
|
||||
import io.vertx.core.net.NetClient;
|
||||
@@ -29,13 +29,13 @@ import java.util.concurrent.TimeUnit;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
/**
|
||||
* IoT Modbus TCP Slave 协议集成测试 — MODBUS_TCP 帧格式(手动测试)
|
||||
* IoT Modbus TCP Server 协议集成测试 — MODBUS_TCP 帧格式(手动测试)
|
||||
*
|
||||
* <p>测试场景:设备(TCP Client)连接到网关(TCP Server),使用 MODBUS_TCP(MBAP 头)帧格式通信
|
||||
*
|
||||
* <p>使用步骤:
|
||||
* <ol>
|
||||
* <li>启动 yudao-module-iot-gateway 服务(需开启 modbus-tcp-slave 协议,默认端口 503)</li>
|
||||
* <li>启动 yudao-module-iot-gateway 服务(需开启 modbus-tcp-server 协议,默认端口 503)</li>
|
||||
* <li>确保数据库有对应的 Modbus 设备配置(mode=1, frameFormat=modbus_tcp)</li>
|
||||
* <li>运行以下测试方法:
|
||||
* <ul>
|
||||
@@ -50,7 +50,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
*/
|
||||
@Slf4j
|
||||
@Disabled
|
||||
public class IotModbusTcpSlaveTcpIntegrationTest {
|
||||
public class IotModbusTcpServerTcpIntegrationTest {
|
||||
|
||||
private static final String SERVER_HOST = "127.0.0.1";
|
||||
private static final int SERVER_PORT = 503;
|
||||
@@ -69,8 +69,8 @@ public class IotModbusTcpSlaveTcpIntegrationTest {
|
||||
|
||||
// ===================== 设备信息(根据实际情况修改,从 iot_device 表查询) =====================
|
||||
|
||||
private static final String PRODUCT_KEY = "modbus_tcp_slave_product_demo";
|
||||
private static final String DEVICE_NAME = "modbus_tcp_slave_device_demo_tcp";
|
||||
private static final String PRODUCT_KEY = "modbus_tcp_server_product_demo";
|
||||
private static final String DEVICE_NAME = "modbus_tcp_server_device_demo_tcp";
|
||||
private static final String DEVICE_SECRET = "8e4adeb3d25342ab88643421d3fba3f6";
|
||||
|
||||
@BeforeAll
|
||||
Reference in New Issue
Block a user