Commit cece79d04cdf58c579fb5ec6c17219bb380c2a34
1 parent
9e2c1fea
feat:【iot】modbus-tcp 协议接入:20% 初始化:基于 humming-beaming-dove.md 规划
Showing
22 changed files
with
217 additions
and
351 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/api/device/IoTDeviceApiImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.api.device; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 3 | 4 | import cn.iocoder.yudao.framework.common.enums.RpcConstants; |
| 4 | 5 | import cn.iocoder.yudao.framework.common.pojo.CommonResult; |
| 5 | 6 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| ... | ... | @@ -23,8 +24,11 @@ import org.springframework.web.bind.annotation.RestController; |
| 23 | 24 | |
| 24 | 25 | import java.util.ArrayList; |
| 25 | 26 | import java.util.List; |
| 27 | +import java.util.Map; | |
| 28 | +import java.util.Set; | |
| 26 | 29 | |
| 27 | 30 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 31 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 28 | 32 | |
| 29 | 33 | /** |
| 30 | 34 | * IoT 设备 API 实现类 |
| ... | ... | @@ -71,40 +75,32 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi { |
| 71 | 75 | @PermitAll |
| 72 | 76 | public CommonResult<List<IotModbusDeviceConfigRespDTO>> getEnabledModbusDeviceConfigs() { |
| 73 | 77 | // 1. 获取所有启用的 Modbus 连接配置 |
| 74 | - List<IotDeviceModbusConfigDO> configList = modbusConfigService.getEnabledModbusConfigList(); | |
| 75 | - if (configList.isEmpty()) { | |
| 78 | + List<IotDeviceModbusConfigDO> configList = modbusConfigService.getEnabledDeviceModbusConfigList(); | |
| 79 | + if (CollUtil.isEmpty(configList)) { | |
| 76 | 80 | return success(new ArrayList<>()); |
| 77 | 81 | } |
| 78 | 82 | |
| 79 | 83 | // 2. 组装返回结果 |
| 84 | + Set<Long> deviceIds = convertSet(configList, IotDeviceModbusConfigDO::getDeviceId); | |
| 85 | + Map<Long, IotDeviceDO> deviceMap = deviceService.getDeviceMap(deviceIds); | |
| 86 | + Map<Long, List<IotDeviceModbusPointDO>> pointMap = modbusPointService.getEnabledDeviceModbusPointMapByDeviceIds(deviceIds); | |
| 80 | 87 | List<IotModbusDeviceConfigRespDTO> result = new ArrayList<>(configList.size()); |
| 81 | 88 | for (IotDeviceModbusConfigDO config : configList) { |
| 82 | - // 2.1 获取设备信息 | |
| 83 | - // TODO @AI:设备需要批量读取;(先暂时不处理) | |
| 84 | - IotDeviceDO device = deviceService.getDeviceFromCache(config.getDeviceId()); | |
| 89 | + // 3.1 获取设备信息 | |
| 90 | + IotDeviceDO device = deviceMap.get(config.getDeviceId()); | |
| 85 | 91 | if (device == null) { |
| 86 | 92 | continue; |
| 87 | 93 | } |
| 88 | - | |
| 89 | - // 2.2 获取启用的点位列表 | |
| 90 | - // TODO @AI:看看是不是批量读取; | |
| 91 | - List<IotDeviceModbusPointDO> pointList = modbusPointService.getEnabledModbusPointListByDeviceId(config.getDeviceId()); | |
| 92 | - | |
| 93 | - // 2.3 构建 DTO | |
| 94 | - IotModbusDeviceConfigRespDTO dto = new IotModbusDeviceConfigRespDTO(); | |
| 95 | - dto.setDeviceId(config.getDeviceId()); | |
| 96 | - // TODO @AI:这个 productKey、deviceName 这个字段,要不要冗余到 IotDeviceModbusConfigDO 里面?(先暂时不处理) | |
| 97 | - dto.setProductKey(device.getProductKey()); | |
| 98 | - dto.setDeviceName(device.getDeviceName()); | |
| 99 | - dto.setTenantId(device.getTenantId()); | |
| 100 | - // TODO @AI:看看 dto 的转换,能不能通过 beanutils copy | |
| 101 | - dto.setIp(config.getIp()); | |
| 102 | - dto.setPort(config.getPort()); | |
| 103 | - dto.setSlaveId(config.getSlaveId()); | |
| 104 | - dto.setTimeout(config.getTimeout()); | |
| 105 | - dto.setRetryInterval(config.getRetryInterval()); | |
| 106 | - dto.setPoints(BeanUtils.toBean(pointList, IotModbusPointRespDTO.class)); | |
| 107 | - result.add(dto); | |
| 94 | + // 3.2 获取启用的点位列表 | |
| 95 | + List<IotDeviceModbusPointDO> pointList = pointMap.get(config.getDeviceId()); | |
| 96 | + if (CollUtil.isEmpty(pointList)) { | |
| 97 | + continue; | |
| 98 | + } | |
| 99 | + // 3.3 构建 IotModbusDeviceConfigRespDTO 对象 | |
| 100 | + IotModbusDeviceConfigRespDTO configDTO = BeanUtils.toBean(config, IotModbusDeviceConfigRespDTO.class, o -> | |
| 101 | + o.setProductKey(device.getProductKey()).setDeviceName(device.getDeviceName()) | |
| 102 | + .setPoints(BeanUtils.toBean(pointList, IotModbusPointRespDTO.class))); | |
| 103 | + result.add(configDTO); | |
| 108 | 104 | } |
| 109 | 105 | return success(result); |
| 110 | 106 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceModbusConfigController.java
| ... | ... | @@ -28,19 +28,11 @@ public class IotDeviceModbusConfigController { |
| 28 | 28 | @Resource |
| 29 | 29 | private IotDeviceModbusConfigService modbusConfigService; |
| 30 | 30 | |
| 31 | - // TODO @AI:create 和 update 合并成 save 接口; | |
| 32 | - @PostMapping("/create") | |
| 33 | - @Operation(summary = "创建设备 Modbus 连接配置") | |
| 31 | + @PostMapping("/save") | |
| 32 | + @Operation(summary = "保存设备 Modbus 连接配置") | |
| 34 | 33 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:create')") |
| 35 | - public CommonResult<Long> createModbusConfig(@Valid @RequestBody IotDeviceModbusConfigSaveReqVO createReqVO) { | |
| 36 | - return success(modbusConfigService.createModbusConfig(createReqVO)); | |
| 37 | - } | |
| 38 | - | |
| 39 | - @PutMapping("/update") | |
| 40 | - @Operation(summary = "更新设备 Modbus 连接配置") | |
| 41 | - @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:update')") | |
| 42 | - public CommonResult<Boolean> updateModbusConfig(@Valid @RequestBody IotDeviceModbusConfigSaveReqVO updateReqVO) { | |
| 43 | - modbusConfigService.updateModbusConfig(updateReqVO); | |
| 34 | + public CommonResult<Boolean> saveDeviceModbusConfig(@Valid @RequestBody IotDeviceModbusConfigSaveReqVO saveReqVO) { | |
| 35 | + modbusConfigService.saveDeviceModbusConfig(saveReqVO); | |
| 44 | 36 | return success(true); |
| 45 | 37 | } |
| 46 | 38 | |
| ... | ... | @@ -48,36 +40,33 @@ public class IotDeviceModbusConfigController { |
| 48 | 40 | @Operation(summary = "删除设备 Modbus 连接配置") |
| 49 | 41 | @Parameter(name = "id", description = "编号", required = true) |
| 50 | 42 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:delete')") |
| 51 | - public CommonResult<Boolean> deleteModbusConfig(@RequestParam("id") Long id) { | |
| 52 | - modbusConfigService.deleteModbusConfig(id); | |
| 43 | + public CommonResult<Boolean> deleteDeviceModbusConfig(@RequestParam("id") Long id) { | |
| 44 | + modbusConfigService.deleteDeviceModbusConfig(id); | |
| 53 | 45 | return success(true); |
| 54 | 46 | } |
| 55 | 47 | |
| 56 | - // TODO @AI:这个接口改造,支持 id 或者 deviceId;二选一查询; | |
| 57 | 48 | @GetMapping("/get") |
| 58 | 49 | @Operation(summary = "获得设备 Modbus 连接配置") |
| 59 | - @Parameter(name = "id", description = "编号", required = true, example = "1024") | |
| 60 | - @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:query')") | |
| 61 | - public CommonResult<IotDeviceModbusConfigRespVO> getModbusConfig(@RequestParam("id") Long id) { | |
| 62 | - IotDeviceModbusConfigDO modbusConfig = modbusConfigService.getModbusConfig(id); | |
| 63 | - return success(BeanUtils.toBean(modbusConfig, IotDeviceModbusConfigRespVO.class)); | |
| 64 | - } | |
| 65 | - | |
| 66 | - // TODO @AI:合并到 getModbusConfig 接口里; | |
| 67 | - @GetMapping("/get-by-device-id") | |
| 68 | - @Operation(summary = "根据设备编号获得 Modbus 连接配置") | |
| 69 | - @Parameter(name = "deviceId", description = "设备编号", required = true, example = "1024") | |
| 50 | + @Parameter(name = "id", description = "编号", example = "1024") | |
| 51 | + @Parameter(name = "deviceId", description = "设备编号", example = "2048") | |
| 70 | 52 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:query')") |
| 71 | - public CommonResult<IotDeviceModbusConfigRespVO> getModbusConfigByDeviceId(@RequestParam("deviceId") Long deviceId) { | |
| 72 | - IotDeviceModbusConfigDO modbusConfig = modbusConfigService.getModbusConfigByDeviceId(deviceId); | |
| 53 | + public CommonResult<IotDeviceModbusConfigRespVO> getDeviceModbusConfig( | |
| 54 | + @RequestParam(value = "id", required = false) Long id, | |
| 55 | + @RequestParam(value = "deviceId", required = false) Long deviceId) { | |
| 56 | + IotDeviceModbusConfigDO modbusConfig = null; | |
| 57 | + if (id != null) { | |
| 58 | + modbusConfig = modbusConfigService.getDeviceModbusConfig(id); | |
| 59 | + } else if (deviceId != null) { | |
| 60 | + modbusConfig = modbusConfigService.getDeviceModbusConfigByDeviceId(deviceId); | |
| 61 | + } | |
| 73 | 62 | return success(BeanUtils.toBean(modbusConfig, IotDeviceModbusConfigRespVO.class)); |
| 74 | 63 | } |
| 75 | 64 | |
| 76 | 65 | @GetMapping("/page") |
| 77 | 66 | @Operation(summary = "获得设备 Modbus 连接配置分页") |
| 78 | 67 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:query')") |
| 79 | - public CommonResult<PageResult<IotDeviceModbusConfigRespVO>> getModbusConfigPage(@Valid IotDeviceModbusConfigPageReqVO pageReqVO) { | |
| 80 | - PageResult<IotDeviceModbusConfigDO> pageResult = modbusConfigService.getModbusConfigPage(pageReqVO); | |
| 68 | + public CommonResult<PageResult<IotDeviceModbusConfigRespVO>> getDeviceModbusConfigPage(@Valid IotDeviceModbusConfigPageReqVO pageReqVO) { | |
| 69 | + PageResult<IotDeviceModbusConfigDO> pageResult = modbusConfigService.getDeviceModbusConfigPage(pageReqVO); | |
| 81 | 70 | return success(BeanUtils.toBean(pageResult, IotDeviceModbusConfigRespVO.class)); |
| 82 | 71 | } |
| 83 | 72 | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/IotDeviceModbusPointController.java
| ... | ... | @@ -17,8 +17,6 @@ import org.springframework.security.access.prepost.PreAuthorize; |
| 17 | 17 | import org.springframework.validation.annotation.Validated; |
| 18 | 18 | import org.springframework.web.bind.annotation.*; |
| 19 | 19 | |
| 20 | -import java.util.List; | |
| 21 | - | |
| 22 | 20 | import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; |
| 23 | 21 | |
| 24 | 22 | @Tag(name = "管理后台 - IoT 设备 Modbus 点位配置") |
| ... | ... | @@ -33,15 +31,15 @@ public class IotDeviceModbusPointController { |
| 33 | 31 | @PostMapping("/create") |
| 34 | 32 | @Operation(summary = "创建设备 Modbus 点位配置") |
| 35 | 33 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:create')") |
| 36 | - public CommonResult<Long> createModbusPoint(@Valid @RequestBody IotDeviceModbusPointSaveReqVO createReqVO) { | |
| 37 | - return success(modbusPointService.createModbusPoint(createReqVO)); | |
| 34 | + public CommonResult<Long> createDeviceModbusPoint(@Valid @RequestBody IotDeviceModbusPointSaveReqVO createReqVO) { | |
| 35 | + return success(modbusPointService.createDeviceModbusPoint(createReqVO)); | |
| 38 | 36 | } |
| 39 | 37 | |
| 40 | 38 | @PutMapping("/update") |
| 41 | 39 | @Operation(summary = "更新设备 Modbus 点位配置") |
| 42 | 40 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:update')") |
| 43 | - public CommonResult<Boolean> updateModbusPoint(@Valid @RequestBody IotDeviceModbusPointSaveReqVO updateReqVO) { | |
| 44 | - modbusPointService.updateModbusPoint(updateReqVO); | |
| 41 | + public CommonResult<Boolean> updateDeviceModbusPoint(@Valid @RequestBody IotDeviceModbusPointSaveReqVO updateReqVO) { | |
| 42 | + modbusPointService.updateDeviceModbusPoint(updateReqVO); | |
| 45 | 43 | return success(true); |
| 46 | 44 | } |
| 47 | 45 | |
| ... | ... | @@ -49,8 +47,8 @@ public class IotDeviceModbusPointController { |
| 49 | 47 | @Operation(summary = "删除设备 Modbus 点位配置") |
| 50 | 48 | @Parameter(name = "id", description = "编号", required = true) |
| 51 | 49 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:delete')") |
| 52 | - public CommonResult<Boolean> deleteModbusPoint(@RequestParam("id") Long id) { | |
| 53 | - modbusPointService.deleteModbusPoint(id); | |
| 50 | + public CommonResult<Boolean> deleteDeviceModbusPoint(@RequestParam("id") Long id) { | |
| 51 | + modbusPointService.deleteDeviceModbusPoint(id); | |
| 54 | 52 | return success(true); |
| 55 | 53 | } |
| 56 | 54 | |
| ... | ... | @@ -58,27 +56,17 @@ public class IotDeviceModbusPointController { |
| 58 | 56 | @Operation(summary = "获得设备 Modbus 点位配置") |
| 59 | 57 | @Parameter(name = "id", description = "编号", required = true, example = "1024") |
| 60 | 58 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:query')") |
| 61 | - public CommonResult<IotDeviceModbusPointRespVO> getModbusPoint(@RequestParam("id") Long id) { | |
| 62 | - IotDeviceModbusPointDO modbusPoint = modbusPointService.getModbusPoint(id); | |
| 59 | + public CommonResult<IotDeviceModbusPointRespVO> getDeviceModbusPoint(@RequestParam("id") Long id) { | |
| 60 | + IotDeviceModbusPointDO modbusPoint = modbusPointService.getDeviceModbusPoint(id); | |
| 63 | 61 | return success(BeanUtils.toBean(modbusPoint, IotDeviceModbusPointRespVO.class)); |
| 64 | 62 | } |
| 65 | 63 | |
| 66 | 64 | @GetMapping("/page") |
| 67 | 65 | @Operation(summary = "获得设备 Modbus 点位配置分页") |
| 68 | 66 | @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:query')") |
| 69 | - public CommonResult<PageResult<IotDeviceModbusPointRespVO>> getModbusPointPage(@Valid IotDeviceModbusPointPageReqVO pageReqVO) { | |
| 70 | - PageResult<IotDeviceModbusPointDO> pageResult = modbusPointService.getModbusPointPage(pageReqVO); | |
| 67 | + public CommonResult<PageResult<IotDeviceModbusPointRespVO>> getDeviceModbusPointPage(@Valid IotDeviceModbusPointPageReqVO pageReqVO) { | |
| 68 | + PageResult<IotDeviceModbusPointDO> pageResult = modbusPointService.getDeviceModbusPointPage(pageReqVO); | |
| 71 | 69 | return success(BeanUtils.toBean(pageResult, IotDeviceModbusPointRespVO.class)); |
| 72 | 70 | } |
| 73 | 71 | |
| 74 | - // TODO @AI:应该用不上这个接口?只需要 getModbusPointPage 分页 | |
| 75 | - @GetMapping("/list-by-device-id") | |
| 76 | - @Operation(summary = "根据设备编号获得 Modbus 点位配置列表") | |
| 77 | - @Parameter(name = "deviceId", description = "设备编号", required = true, example = "1024") | |
| 78 | - @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:query')") | |
| 79 | - public CommonResult<List<IotDeviceModbusPointRespVO>> getModbusPointListByDeviceId(@RequestParam("deviceId") Long deviceId) { | |
| 80 | - List<IotDeviceModbusPointDO> list = modbusPointService.getModbusPointListByDeviceId(deviceId); | |
| 81 | - return success(BeanUtils.toBean(list, IotDeviceModbusPointRespVO.class)); | |
| 82 | - } | |
| 83 | - | |
| 84 | 72 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/device/vo/modbus/IotDeviceModbusConfigSaveReqVO.java
| ... | ... | @@ -9,9 +9,6 @@ import lombok.Data; |
| 9 | 9 | @Data |
| 10 | 10 | public class IotDeviceModbusConfigSaveReqVO { |
| 11 | 11 | |
| 12 | - @Schema(description = "主键", example = "1") | |
| 13 | - private Long id; | |
| 14 | - | |
| 15 | 12 | @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") |
| 16 | 13 | @NotNull(message = "设备编号不能为空") |
| 17 | 14 | private Long deviceId; | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/device/IotDeviceModbusPointMapper.java
| ... | ... | @@ -7,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.modbus.IotDeviceMo |
| 7 | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceModbusPointDO; |
| 8 | 8 | import org.apache.ibatis.annotations.Mapper; |
| 9 | 9 | |
| 10 | +import java.util.Collection; | |
| 10 | 11 | import java.util.List; |
| 11 | 12 | |
| 12 | 13 | /** |
| ... | ... | @@ -27,27 +28,15 @@ public interface IotDeviceModbusPointMapper extends BaseMapperX<IotDeviceModbusP |
| 27 | 28 | .orderByDesc(IotDeviceModbusPointDO::getId)); |
| 28 | 29 | } |
| 29 | 30 | |
| 30 | - default List<IotDeviceModbusPointDO> selectListByDeviceId(Long deviceId) { | |
| 31 | - return selectList(IotDeviceModbusPointDO::getDeviceId, deviceId); | |
| 32 | - } | |
| 33 | - | |
| 34 | - // TODO @AI:是不是 selectList(f1, v1, f2, v2); | |
| 35 | - default List<IotDeviceModbusPointDO> selectListByDeviceIdAndStatus(Long deviceId, Integer status) { | |
| 31 | + default List<IotDeviceModbusPointDO> selectListByDeviceIdsAndStatus(Collection<Long> deviceIds, Integer status) { | |
| 36 | 32 | return selectList(new LambdaQueryWrapperX<IotDeviceModbusPointDO>() |
| 37 | - .eq(IotDeviceModbusPointDO::getDeviceId, deviceId) | |
| 33 | + .in(IotDeviceModbusPointDO::getDeviceId, deviceIds) | |
| 38 | 34 | .eq(IotDeviceModbusPointDO::getStatus, status)); |
| 39 | 35 | } |
| 40 | 36 | |
| 41 | - // TODO @AI:是不是 selectOne(f1, v1, f2, v2); | |
| 42 | 37 | default IotDeviceModbusPointDO selectByDeviceIdAndIdentifier(Long deviceId, String identifier) { |
| 43 | - return selectOne(new LambdaQueryWrapperX<IotDeviceModbusPointDO>() | |
| 44 | - .eq(IotDeviceModbusPointDO::getDeviceId, deviceId) | |
| 45 | - .eq(IotDeviceModbusPointDO::getIdentifier, identifier)); | |
| 46 | - } | |
| 47 | - | |
| 48 | - // TODO @AI:是不是删除这个方法; | |
| 49 | - default void deleteByDeviceId(Long deviceId) { | |
| 50 | - delete(IotDeviceModbusPointDO::getDeviceId, deviceId); | |
| 38 | + return selectOne(IotDeviceModbusPointDO::getDeviceId, deviceId, | |
| 39 | + IotDeviceModbusPointDO::getIdentifier, identifier); | |
| 51 | 40 | } |
| 52 | 41 | |
| 53 | 42 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotModbusByteOrderEnum.java
| ... | ... | @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; |
| 6 | 6 | |
| 7 | 7 | import java.util.Arrays; |
| 8 | 8 | |
| 9 | +// TODO @AI:如果枚举需要共享,可以拿到 /Users/yunai/Java/ruoyi-vue-pro-jdk25/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums 里 | |
| 9 | 10 | /** |
| 10 | 11 | * IoT Modbus 字节序枚举 |
| 11 | 12 | * | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotModbusFunctionCodeEnum.java
| ... | ... | @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; |
| 6 | 6 | |
| 7 | 7 | import java.util.Arrays; |
| 8 | 8 | |
| 9 | +// TODO @AI:如果枚举需要共享,可以拿到 /Users/yunai/Java/ruoyi-vue-pro-jdk25/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums 里 | |
| 9 | 10 | /** |
| 10 | 11 | * IoT Modbus 功能码枚举 |
| 11 | 12 | * |
| ... | ... | @@ -63,18 +64,4 @@ public enum IotModbusFunctionCodeEnum implements ArrayValuable<Integer> { |
| 63 | 64 | .orElse(null); |
| 64 | 65 | } |
| 65 | 66 | |
| 66 | - // TODO @AI:如果用不到,可以暂时删除哈; | |
| 67 | - /** | |
| 68 | - * 获取写功能码 | |
| 69 | - * | |
| 70 | - * @param registerCount 寄存器数量 | |
| 71 | - * @return 写功能码 | |
| 72 | - */ | |
| 73 | - public Integer getWriteCode(int registerCount) { | |
| 74 | - if (!writable) { | |
| 75 | - return null; | |
| 76 | - } | |
| 77 | - return registerCount == 1 ? writeSingleCode : writeMultipleCode; | |
| 78 | - } | |
| 79 | - | |
| 80 | 67 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/enums/device/IotModbusRawDataTypeEnum.java
| ... | ... | @@ -6,6 +6,7 @@ import lombok.RequiredArgsConstructor; |
| 6 | 6 | |
| 7 | 7 | import java.util.Arrays; |
| 8 | 8 | |
| 9 | +// TODO @AI:如果枚举需要共享,可以拿到 /Users/yunai/Java/ruoyi-vue-pro-jdk25/yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/enums 里 | |
| 9 | 10 | /** |
| 10 | 11 | * IoT Modbus 原始数据类型枚举 |
| 11 | 12 | * | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceModbusConfigService.java
| ... | ... | @@ -16,26 +16,18 @@ import java.util.List; |
| 16 | 16 | public interface IotDeviceModbusConfigService { |
| 17 | 17 | |
| 18 | 18 | /** |
| 19 | - * 创建设备 Modbus 连接配置 | |
| 19 | + * 保存设备 Modbus 连接配置(新增或更新) | |
| 20 | 20 | * |
| 21 | - * @param createReqVO 创建信息 | |
| 22 | - * @return 编号 | |
| 21 | + * @param saveReqVO 保存信息 | |
| 23 | 22 | */ |
| 24 | - Long createModbusConfig(@Valid IotDeviceModbusConfigSaveReqVO createReqVO); | |
| 25 | - | |
| 26 | - /** | |
| 27 | - * 更新设备 Modbus 连接配置 | |
| 28 | - * | |
| 29 | - * @param updateReqVO 更新信息 | |
| 30 | - */ | |
| 31 | - void updateModbusConfig(@Valid IotDeviceModbusConfigSaveReqVO updateReqVO); | |
| 23 | + void saveDeviceModbusConfig(@Valid IotDeviceModbusConfigSaveReqVO saveReqVO); | |
| 32 | 24 | |
| 33 | 25 | /** |
| 34 | 26 | * 删除设备 Modbus 连接配置 |
| 35 | 27 | * |
| 36 | 28 | * @param id 编号 |
| 37 | 29 | */ |
| 38 | - void deleteModbusConfig(Long id); | |
| 30 | + void deleteDeviceModbusConfig(Long id); | |
| 39 | 31 | |
| 40 | 32 | /** |
| 41 | 33 | * 获得设备 Modbus 连接配置 |
| ... | ... | @@ -43,7 +35,7 @@ public interface IotDeviceModbusConfigService { |
| 43 | 35 | * @param id 编号 |
| 44 | 36 | * @return 设备 Modbus 连接配置 |
| 45 | 37 | */ |
| 46 | - IotDeviceModbusConfigDO getModbusConfig(Long id); | |
| 38 | + IotDeviceModbusConfigDO getDeviceModbusConfig(Long id); | |
| 47 | 39 | |
| 48 | 40 | /** |
| 49 | 41 | * 根据设备编号获得 Modbus 连接配置 |
| ... | ... | @@ -51,7 +43,7 @@ public interface IotDeviceModbusConfigService { |
| 51 | 43 | * @param deviceId 设备编号 |
| 52 | 44 | * @return 设备 Modbus 连接配置 |
| 53 | 45 | */ |
| 54 | - IotDeviceModbusConfigDO getModbusConfigByDeviceId(Long deviceId); | |
| 46 | + IotDeviceModbusConfigDO getDeviceModbusConfigByDeviceId(Long deviceId); | |
| 55 | 47 | |
| 56 | 48 | /** |
| 57 | 49 | * 获得设备 Modbus 连接配置分页 |
| ... | ... | @@ -59,13 +51,13 @@ public interface IotDeviceModbusConfigService { |
| 59 | 51 | * @param pageReqVO 分页查询 |
| 60 | 52 | * @return 设备 Modbus 连接配置分页 |
| 61 | 53 | */ |
| 62 | - PageResult<IotDeviceModbusConfigDO> getModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO); | |
| 54 | + PageResult<IotDeviceModbusConfigDO> getDeviceModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO); | |
| 63 | 55 | |
| 64 | 56 | /** |
| 65 | 57 | * 获得所有启用的 Modbus 连接配置列表 |
| 66 | 58 | * |
| 67 | 59 | * @return 启用的 Modbus 连接配置列表 |
| 68 | 60 | */ |
| 69 | - List<IotDeviceModbusConfigDO> getEnabledModbusConfigList(); | |
| 61 | + List<IotDeviceModbusConfigDO> getEnabledDeviceModbusConfigList(); | |
| 70 | 62 | |
| 71 | 63 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceModbusConfigServiceImpl.java
| ... | ... | @@ -14,7 +14,6 @@ import org.springframework.validation.annotation.Validated; |
| 14 | 14 | import java.util.List; |
| 15 | 15 | |
| 16 | 16 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 17 | -import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODBUS_CONFIG_EXISTS; | |
| 18 | 17 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODBUS_CONFIG_NOT_EXISTS; |
| 19 | 18 | |
| 20 | 19 | /** |
| ... | ... | @@ -32,90 +31,54 @@ public class IotDeviceModbusConfigServiceImpl implements IotDeviceModbusConfigSe |
| 32 | 31 | @Resource |
| 33 | 32 | private IotDeviceService deviceService; |
| 34 | 33 | |
| 35 | - // TODO @AI:是不是搞成 save 接口?因为前端也不知道是 create 还是 update; | |
| 36 | 34 | @Override |
| 37 | - public Long createModbusConfig(IotDeviceModbusConfigSaveReqVO createReqVO) { | |
| 38 | - // 1.1 校验设备存在 | |
| 39 | - deviceService.validateDeviceExists(createReqVO.getDeviceId()); | |
| 40 | - // 1.2 校验设备是否已有 Modbus 配置 | |
| 41 | - validateModbusConfigUnique(createReqVO.getDeviceId(), null); | |
| 42 | - | |
| 43 | - // 2. 插入 | |
| 44 | - IotDeviceModbusConfigDO modbusConfig = BeanUtils.toBean(createReqVO, IotDeviceModbusConfigDO.class); | |
| 45 | - setDefaultValues(modbusConfig); | |
| 46 | - modbusConfigMapper.insert(modbusConfig); | |
| 47 | - return modbusConfig.getId(); | |
| 48 | - } | |
| 49 | - | |
| 50 | - @Override | |
| 51 | - public void updateModbusConfig(IotDeviceModbusConfigSaveReqVO updateReqVO) { | |
| 52 | - // 1.1 校验存在 | |
| 53 | - validateModbusConfigExists(updateReqVO.getId()); | |
| 54 | - // 1.2 校验设备存在 | |
| 55 | - deviceService.validateDeviceExists(updateReqVO.getDeviceId()); | |
| 56 | - // 1.3 校验唯一性 | |
| 57 | - validateModbusConfigUnique(updateReqVO.getDeviceId(), updateReqVO.getId()); | |
| 58 | - | |
| 59 | - // 2. 更新 | |
| 60 | - IotDeviceModbusConfigDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceModbusConfigDO.class); | |
| 61 | - modbusConfigMapper.updateById(updateObj); | |
| 35 | + public void saveDeviceModbusConfig(IotDeviceModbusConfigSaveReqVO saveReqVO) { | |
| 36 | + // 1. 校验设备存在 | |
| 37 | + deviceService.validateDeviceExists(saveReqVO.getDeviceId()); | |
| 38 | + | |
| 39 | + // 2. 根据数据库中是否已有配置,决定是新增还是更新 | |
| 40 | + IotDeviceModbusConfigDO existConfig = modbusConfigMapper.selectByDeviceId(saveReqVO.getDeviceId()); | |
| 41 | + if (existConfig == null) { | |
| 42 | + IotDeviceModbusConfigDO modbusConfig = BeanUtils.toBean(saveReqVO, IotDeviceModbusConfigDO.class); | |
| 43 | + modbusConfigMapper.insert(modbusConfig); | |
| 44 | + } else { | |
| 45 | + IotDeviceModbusConfigDO updateObj = BeanUtils.toBean(saveReqVO, IotDeviceModbusConfigDO.class, | |
| 46 | + o -> o.setId(existConfig.getId())); | |
| 47 | + modbusConfigMapper.updateById(updateObj); | |
| 48 | + } | |
| 62 | 49 | } |
| 63 | 50 | |
| 64 | 51 | @Override |
| 65 | - public void deleteModbusConfig(Long id) { | |
| 52 | + public void deleteDeviceModbusConfig(Long id) { | |
| 66 | 53 | // 校验存在 |
| 67 | - validateModbusConfigExists(id); | |
| 54 | + validateDeviceModbusConfigExists(id); | |
| 68 | 55 | // 删除 |
| 69 | 56 | modbusConfigMapper.deleteById(id); |
| 70 | 57 | } |
| 71 | 58 | |
| 72 | - private void validateModbusConfigExists(Long id) { | |
| 59 | + private void validateDeviceModbusConfigExists(Long id) { | |
| 73 | 60 | if (modbusConfigMapper.selectById(id) == null) { |
| 74 | 61 | throw exception(DEVICE_MODBUS_CONFIG_NOT_EXISTS); |
| 75 | 62 | } |
| 76 | 63 | } |
| 77 | 64 | |
| 78 | - private void validateModbusConfigUnique(Long deviceId, Long excludeId) { | |
| 79 | - IotDeviceModbusConfigDO config = modbusConfigMapper.selectByDeviceId(deviceId); | |
| 80 | - // TODO @AI:ObjUtil notequals | |
| 81 | - if (config != null && !config.getId().equals(excludeId)) { | |
| 82 | - throw exception(DEVICE_MODBUS_CONFIG_EXISTS); | |
| 83 | - } | |
| 84 | - } | |
| 85 | - | |
| 86 | - // TODO @AI:不要这个;前端都必须传递; | |
| 87 | - private void setDefaultValues(IotDeviceModbusConfigDO config) { | |
| 88 | - if (config.getPort() == null) { | |
| 89 | - config.setPort(502); | |
| 90 | - } | |
| 91 | - if (config.getSlaveId() == null) { | |
| 92 | - config.setSlaveId(1); | |
| 93 | - } | |
| 94 | - if (config.getTimeout() == null) { | |
| 95 | - config.setTimeout(3000); | |
| 96 | - } | |
| 97 | - if (config.getRetryInterval() == null) { | |
| 98 | - config.setRetryInterval(1000); | |
| 99 | - } | |
| 100 | - } | |
| 101 | - | |
| 102 | 65 | @Override |
| 103 | - public IotDeviceModbusConfigDO getModbusConfig(Long id) { | |
| 66 | + public IotDeviceModbusConfigDO getDeviceModbusConfig(Long id) { | |
| 104 | 67 | return modbusConfigMapper.selectById(id); |
| 105 | 68 | } |
| 106 | 69 | |
| 107 | 70 | @Override |
| 108 | - public IotDeviceModbusConfigDO getModbusConfigByDeviceId(Long deviceId) { | |
| 71 | + public IotDeviceModbusConfigDO getDeviceModbusConfigByDeviceId(Long deviceId) { | |
| 109 | 72 | return modbusConfigMapper.selectByDeviceId(deviceId); |
| 110 | 73 | } |
| 111 | 74 | |
| 112 | 75 | @Override |
| 113 | - public PageResult<IotDeviceModbusConfigDO> getModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO) { | |
| 76 | + public PageResult<IotDeviceModbusConfigDO> getDeviceModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO) { | |
| 114 | 77 | return modbusConfigMapper.selectPage(pageReqVO); |
| 115 | 78 | } |
| 116 | 79 | |
| 117 | 80 | @Override |
| 118 | - public List<IotDeviceModbusConfigDO> getEnabledModbusConfigList() { | |
| 81 | + public List<IotDeviceModbusConfigDO> getEnabledDeviceModbusConfigList() { | |
| 119 | 82 | return modbusConfigMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); |
| 120 | 83 | } |
| 121 | 84 | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceModbusPointService.java
| ... | ... | @@ -6,7 +6,9 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.modbus.IotDeviceMo |
| 6 | 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceModbusPointDO; |
| 7 | 7 | import jakarta.validation.Valid; |
| 8 | 8 | |
| 9 | +import java.util.Collection; | |
| 9 | 10 | import java.util.List; |
| 11 | +import java.util.Map; | |
| 10 | 12 | |
| 11 | 13 | /** |
| 12 | 14 | * IoT 设备 Modbus 点位配置 Service 接口 |
| ... | ... | @@ -21,21 +23,21 @@ public interface IotDeviceModbusPointService { |
| 21 | 23 | * @param createReqVO 创建信息 |
| 22 | 24 | * @return 编号 |
| 23 | 25 | */ |
| 24 | - Long createModbusPoint(@Valid IotDeviceModbusPointSaveReqVO createReqVO); | |
| 26 | + Long createDeviceModbusPoint(@Valid IotDeviceModbusPointSaveReqVO createReqVO); | |
| 25 | 27 | |
| 26 | 28 | /** |
| 27 | 29 | * 更新设备 Modbus 点位配置 |
| 28 | 30 | * |
| 29 | 31 | * @param updateReqVO 更新信息 |
| 30 | 32 | */ |
| 31 | - void updateModbusPoint(@Valid IotDeviceModbusPointSaveReqVO updateReqVO); | |
| 33 | + void updateDeviceModbusPoint(@Valid IotDeviceModbusPointSaveReqVO updateReqVO); | |
| 32 | 34 | |
| 33 | 35 | /** |
| 34 | 36 | * 删除设备 Modbus 点位配置 |
| 35 | 37 | * |
| 36 | 38 | * @param id 编号 |
| 37 | 39 | */ |
| 38 | - void deleteModbusPoint(Long id); | |
| 40 | + void deleteDeviceModbusPoint(Long id); | |
| 39 | 41 | |
| 40 | 42 | /** |
| 41 | 43 | * 获得设备 Modbus 点位配置 |
| ... | ... | @@ -43,7 +45,7 @@ public interface IotDeviceModbusPointService { |
| 43 | 45 | * @param id 编号 |
| 44 | 46 | * @return 设备 Modbus 点位配置 |
| 45 | 47 | */ |
| 46 | - IotDeviceModbusPointDO getModbusPoint(Long id); | |
| 48 | + IotDeviceModbusPointDO getDeviceModbusPoint(Long id); | |
| 47 | 49 | |
| 48 | 50 | /** |
| 49 | 51 | * 获得设备 Modbus 点位配置分页 |
| ... | ... | @@ -51,22 +53,14 @@ public interface IotDeviceModbusPointService { |
| 51 | 53 | * @param pageReqVO 分页查询 |
| 52 | 54 | * @return 设备 Modbus 点位配置分页 |
| 53 | 55 | */ |
| 54 | - PageResult<IotDeviceModbusPointDO> getModbusPointPage(IotDeviceModbusPointPageReqVO pageReqVO); | |
| 56 | + PageResult<IotDeviceModbusPointDO> getDeviceModbusPointPage(IotDeviceModbusPointPageReqVO pageReqVO); | |
| 55 | 57 | |
| 56 | 58 | /** |
| 57 | - * 根据设备编号获得点位配置列表 | |
| 59 | + * 根据设备编号批量获得启用的点位配置 Map | |
| 58 | 60 | * |
| 59 | - * @param deviceId 设备编号 | |
| 60 | - * @return 点位配置列表 | |
| 61 | + * @param deviceIds 设备编号集合 | |
| 62 | + * @return 设备点位 Map,key 为设备编号,value 为点位配置列表 | |
| 61 | 63 | */ |
| 62 | - List<IotDeviceModbusPointDO> getModbusPointListByDeviceId(Long deviceId); | |
| 63 | - | |
| 64 | - /** | |
| 65 | - * 根据设备编号获得启用的点位配置列表 | |
| 66 | - * | |
| 67 | - * @param deviceId 设备编号 | |
| 68 | - * @return 启用的点位配置列表 | |
| 69 | - */ | |
| 70 | - List<IotDeviceModbusPointDO> getEnabledModbusPointListByDeviceId(Long deviceId); | |
| 64 | + Map<Long, List<IotDeviceModbusPointDO>> getEnabledDeviceModbusPointMapByDeviceIds(Collection<Long> deviceIds); | |
| 71 | 65 | |
| 72 | 66 | } | ... | ... |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/device/IotDeviceModbusPointServiceImpl.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.service.device; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.collection.CollUtil; | |
| 4 | +import cn.hutool.core.util.ObjUtil; | |
| 3 | 5 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | 6 | import cn.iocoder.yudao.framework.common.pojo.PageResult; |
| 5 | 7 | import cn.iocoder.yudao.framework.common.util.object.BeanUtils; |
| ... | ... | @@ -13,10 +15,13 @@ import jakarta.annotation.Resource; |
| 13 | 15 | import org.springframework.stereotype.Service; |
| 14 | 16 | import org.springframework.validation.annotation.Validated; |
| 15 | 17 | |
| 16 | -import java.math.BigDecimal; | |
| 18 | +import java.util.Collection; | |
| 19 | +import java.util.Collections; | |
| 17 | 20 | import java.util.List; |
| 21 | +import java.util.Map; | |
| 18 | 22 | |
| 19 | 23 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 24 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMultiMap; | |
| 20 | 25 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; |
| 21 | 26 | |
| 22 | 27 | /** |
| ... | ... | @@ -38,13 +43,13 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ |
| 38 | 43 | private IotThingModelService thingModelService; |
| 39 | 44 | |
| 40 | 45 | @Override |
| 41 | - public Long createModbusPoint(IotDeviceModbusPointSaveReqVO createReqVO) { | |
| 46 | + public Long createDeviceModbusPoint(IotDeviceModbusPointSaveReqVO createReqVO) { | |
| 42 | 47 | // 1.1 校验设备存在 |
| 43 | 48 | deviceService.validateDeviceExists(createReqVO.getDeviceId()); |
| 44 | 49 | // 1.2 校验物模型属性存在 |
| 45 | 50 | IotThingModelDO thingModel = validateThingModelExists(createReqVO.getThingModelId()); |
| 46 | 51 | // 1.3 校验同一设备下点位唯一性(基于 identifier) |
| 47 | - validateModbusPointUnique(createReqVO.getDeviceId(), thingModel.getIdentifier(), null); | |
| 52 | + validateDeviceModbusPointUnique(createReqVO.getDeviceId(), thingModel.getIdentifier(), null); | |
| 48 | 53 | |
| 49 | 54 | // 2. 插入 |
| 50 | 55 | IotDeviceModbusPointDO modbusPoint = BeanUtils.toBean(createReqVO, IotDeviceModbusPointDO.class, |
| ... | ... | @@ -54,22 +59,23 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ |
| 54 | 59 | } |
| 55 | 60 | |
| 56 | 61 | @Override |
| 57 | - public void updateModbusPoint(IotDeviceModbusPointSaveReqVO updateReqVO) { | |
| 62 | + public void updateDeviceModbusPoint(IotDeviceModbusPointSaveReqVO updateReqVO) { | |
| 58 | 63 | // 1.1 校验存在 |
| 59 | - validateModbusPointExists(updateReqVO.getId()); | |
| 64 | + validateDeviceModbusPointExists(updateReqVO.getId()); | |
| 60 | 65 | // 1.2 校验设备存在 |
| 61 | 66 | deviceService.validateDeviceExists(updateReqVO.getDeviceId()); |
| 62 | 67 | // 1.3 校验物模型属性存在 |
| 63 | 68 | IotThingModelDO thingModel = validateThingModelExists(updateReqVO.getThingModelId()); |
| 64 | 69 | // 1.4 校验同一设备下点位唯一性 |
| 65 | - validateModbusPointUnique(updateReqVO.getDeviceId(), thingModel.getIdentifier(), updateReqVO.getId()); | |
| 70 | + validateDeviceModbusPointUnique(updateReqVO.getDeviceId(), thingModel.getIdentifier(), updateReqVO.getId()); | |
| 66 | 71 | |
| 67 | 72 | // 2. 更新 |
| 68 | 73 | IotDeviceModbusPointDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceModbusPointDO.class); |
| 69 | - // TODO @AI:这块 | |
| 70 | 74 | modbusPointMapper.updateById(updateObj); |
| 71 | 75 | } |
| 72 | 76 | |
| 77 | + // TODO @AI:物模型更新的时候,更新下 identifier、name 信息;例如说 updateDeviceModbusPoint(thingModelId, identifier、name) 方法; | |
| 78 | + | |
| 73 | 79 | private IotThingModelDO validateThingModelExists(Long id) { |
| 74 | 80 | IotThingModelDO thingModel = thingModelService.getThingModel(id); |
| 75 | 81 | if (thingModel == null) { |
| ... | ... | @@ -79,60 +85,45 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ |
| 79 | 85 | } |
| 80 | 86 | |
| 81 | 87 | @Override |
| 82 | - public void deleteModbusPoint(Long id) { | |
| 88 | + public void deleteDeviceModbusPoint(Long id) { | |
| 83 | 89 | // 校验存在 |
| 84 | - validateModbusPointExists(id); | |
| 90 | + validateDeviceModbusPointExists(id); | |
| 85 | 91 | // 删除 |
| 86 | 92 | modbusPointMapper.deleteById(id); |
| 87 | 93 | } |
| 88 | 94 | |
| 89 | - private IotDeviceModbusPointDO validateModbusPointExists(Long id) { | |
| 95 | + private void validateDeviceModbusPointExists(Long id) { | |
| 90 | 96 | IotDeviceModbusPointDO point = modbusPointMapper.selectById(id); |
| 91 | 97 | if (point == null) { |
| 92 | 98 | throw exception(DEVICE_MODBUS_POINT_NOT_EXISTS); |
| 93 | 99 | } |
| 94 | - return point; | |
| 95 | 100 | } |
| 96 | 101 | |
| 97 | - private void validateModbusPointUnique(Long deviceId, String identifier, Long excludeId) { | |
| 102 | + private void validateDeviceModbusPointUnique(Long deviceId, String identifier, Long excludeId) { | |
| 98 | 103 | IotDeviceModbusPointDO point = modbusPointMapper.selectByDeviceIdAndIdentifier(deviceId, identifier); |
| 99 | - // TODO @AI:ObjUtil notequals; | |
| 100 | - if (point != null && !point.getId().equals(excludeId)) { | |
| 104 | + if (point != null && ObjUtil.notEqual(point.getId(), excludeId)) { | |
| 101 | 105 | throw exception(DEVICE_MODBUS_POINT_EXISTS); |
| 102 | 106 | } |
| 103 | 107 | } |
| 104 | 108 | |
| 105 | - // TODO @AI:这块 | |
| 106 | - private void setDefaultValues(IotDeviceModbusPointDO point) { | |
| 107 | - if (point.getRegisterCount() == null) { | |
| 108 | - point.setRegisterCount(1); | |
| 109 | - } | |
| 110 | - if (point.getScale() == null) { | |
| 111 | - point.setScale(BigDecimal.ONE); | |
| 112 | - } | |
| 113 | - if (point.getPollInterval() == null) { | |
| 114 | - point.setPollInterval(5000); | |
| 115 | - } | |
| 116 | - } | |
| 117 | - | |
| 118 | 109 | @Override |
| 119 | - public IotDeviceModbusPointDO getModbusPoint(Long id) { | |
| 110 | + public IotDeviceModbusPointDO getDeviceModbusPoint(Long id) { | |
| 120 | 111 | return modbusPointMapper.selectById(id); |
| 121 | 112 | } |
| 122 | 113 | |
| 123 | 114 | @Override |
| 124 | - public PageResult<IotDeviceModbusPointDO> getModbusPointPage(IotDeviceModbusPointPageReqVO pageReqVO) { | |
| 115 | + public PageResult<IotDeviceModbusPointDO> getDeviceModbusPointPage(IotDeviceModbusPointPageReqVO pageReqVO) { | |
| 125 | 116 | return modbusPointMapper.selectPage(pageReqVO); |
| 126 | 117 | } |
| 127 | 118 | |
| 128 | 119 | @Override |
| 129 | - public List<IotDeviceModbusPointDO> getModbusPointListByDeviceId(Long deviceId) { | |
| 130 | - return modbusPointMapper.selectListByDeviceId(deviceId); | |
| 131 | - } | |
| 132 | - | |
| 133 | - @Override | |
| 134 | - public List<IotDeviceModbusPointDO> getEnabledModbusPointListByDeviceId(Long deviceId) { | |
| 135 | - return modbusPointMapper.selectListByDeviceIdAndStatus(deviceId, CommonStatusEnum.ENABLE.getStatus()); | |
| 120 | + public Map<Long, List<IotDeviceModbusPointDO>> getEnabledDeviceModbusPointMapByDeviceIds(Collection<Long> deviceIds) { | |
| 121 | + if (CollUtil.isEmpty(deviceIds)) { | |
| 122 | + return Collections.emptyMap(); | |
| 123 | + } | |
| 124 | + List<IotDeviceModbusPointDO> pointList = modbusPointMapper.selectListByDeviceIdsAndStatus( | |
| 125 | + deviceIds, CommonStatusEnum.ENABLE.getStatus()); | |
| 126 | + return convertMultiMap(pointList, IotDeviceModbusPointDO::getDeviceId); | |
| 136 | 127 | } |
| 137 | 128 | |
| 138 | 129 | } | ... | ... |
yudao-module-iot/yudao-module-iot-core/src/main/java/cn/iocoder/yudao/module/iot/core/biz/dto/IotModbusDeviceConfigRespDTO.java
| ... | ... | @@ -24,10 +24,6 @@ public class IotModbusDeviceConfigRespDTO { |
| 24 | 24 | * 设备名称 |
| 25 | 25 | */ |
| 26 | 26 | private String deviceName; |
| 27 | - /** | |
| 28 | - * 租户编号 | |
| 29 | - */ | |
| 30 | - private Long tenantId; | |
| 31 | 27 | |
| 32 | 28 | // ========== Modbus 连接配置 ========== |
| 33 | 29 | |
| ... | ... | @@ -36,7 +32,7 @@ public class IotModbusDeviceConfigRespDTO { |
| 36 | 32 | */ |
| 37 | 33 | private String ip; |
| 38 | 34 | /** |
| 39 | - * Modbus 端口 | |
| 35 | + * Modbus 服务器端口 | |
| 40 | 36 | */ |
| 41 | 37 | private Integer port; |
| 42 | 38 | /** |
| ... | ... | @@ -44,11 +40,11 @@ public class IotModbusDeviceConfigRespDTO { |
| 44 | 40 | */ |
| 45 | 41 | private Integer slaveId; |
| 46 | 42 | /** |
| 47 | - * 连接超时时间(毫秒) | |
| 43 | + * 连接超时时间,单位:毫秒 | |
| 48 | 44 | */ |
| 49 | 45 | private Integer timeout; |
| 50 | 46 | /** |
| 51 | - * 重试间隔(毫秒) | |
| 47 | + * 重试间隔,单位:毫秒 | |
| 52 | 48 | */ |
| 53 | 49 | private Integer retryInterval; |
| 54 | 50 | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/config/IotGatewayConfiguration.java
| ... | ... | @@ -22,6 +22,7 @@ import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService; |
| 22 | 22 | import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; |
| 23 | 23 | import io.vertx.core.Vertx; |
| 24 | 24 | import lombok.extern.slf4j.Slf4j; |
| 25 | +import org.redisson.api.RedissonClient; | |
| 25 | 26 | import org.springframework.beans.factory.annotation.Qualifier; |
| 26 | 27 | import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; |
| 27 | 28 | import org.springframework.boot.context.properties.EnableConfigurationProperties; |
| ... | ... | @@ -209,6 +210,54 @@ public class IotGatewayConfiguration { |
| 209 | 210 | } |
| 210 | 211 | |
| 211 | 212 | @Bean |
| 213 | + public IotModbusDataConverter iotModbusDataConverter() { | |
| 214 | + return new IotModbusDataConverter(); | |
| 215 | + } | |
| 216 | + | |
| 217 | + @Bean | |
| 218 | + public IotModbusTcpClient iotModbusTcpClient() { | |
| 219 | + return new IotModbusTcpClient(); | |
| 220 | + } | |
| 221 | + | |
| 222 | + @Bean | |
| 223 | + public IotModbusTcpConnectionManager iotModbusTcpConnectionManager( | |
| 224 | + RedissonClient redissonClient, | |
| 225 | + @Qualifier("modbusTcpVertx") Vertx modbusTcpVertx) { | |
| 226 | + return new IotModbusTcpConnectionManager(redissonClient, modbusTcpVertx); | |
| 227 | + } | |
| 228 | + | |
| 229 | + @Bean | |
| 230 | + public IotModbusTcpConfigCacheService iotModbusTcpConfigCacheService( | |
| 231 | + cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi deviceApi) { | |
| 232 | + return new IotModbusTcpConfigCacheService(deviceApi); | |
| 233 | + } | |
| 234 | + | |
| 235 | + @Bean | |
| 236 | + public IotModbusTcpUpstreamHandler iotModbusTcpUpstreamHandler( | |
| 237 | + IotDeviceMessageService messageService, | |
| 238 | + IotModbusDataConverter dataConverter) { | |
| 239 | + return new IotModbusTcpUpstreamHandler(messageService, dataConverter); | |
| 240 | + } | |
| 241 | + | |
| 242 | + @Bean | |
| 243 | + public IotModbusTcpPollScheduler iotModbusTcpPollScheduler( | |
| 244 | + @Qualifier("modbusTcpVertx") Vertx modbusTcpVertx, | |
| 245 | + IotModbusTcpConnectionManager connectionManager, | |
| 246 | + IotModbusTcpClient modbusClient, | |
| 247 | + IotModbusTcpUpstreamHandler upstreamHandler) { | |
| 248 | + return new IotModbusTcpPollScheduler(modbusTcpVertx, connectionManager, modbusClient, upstreamHandler); | |
| 249 | + } | |
| 250 | + | |
| 251 | + @Bean | |
| 252 | + public IotModbusTcpDownstreamHandler iotModbusTcpDownstreamHandler( | |
| 253 | + IotModbusTcpConnectionManager connectionManager, | |
| 254 | + IotModbusTcpClient modbusClient, | |
| 255 | + IotModbusDataConverter dataConverter, | |
| 256 | + IotModbusTcpConfigCacheService configCacheService) { | |
| 257 | + return new IotModbusTcpDownstreamHandler(connectionManager, modbusClient, dataConverter, configCacheService); | |
| 258 | + } | |
| 259 | + | |
| 260 | + @Bean | |
| 212 | 261 | public IotModbusTcpUpstreamProtocol iotModbusTcpUpstreamProtocol(IotGatewayProperties gatewayProperties, |
| 213 | 262 | IotDeviceMessageService messageService, |
| 214 | 263 | IotModbusTcpConnectionManager connectionManager, | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusDataConverter.java
| 1 | 1 | package cn.iocoder.yudao.module.iot.gateway.protocol.modbustcp; |
| 2 | 2 | |
| 3 | +import cn.hutool.core.util.ArrayUtil; | |
| 4 | +import cn.hutool.core.util.ObjectUtil; | |
| 3 | 5 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO; |
| 4 | 6 | import lombok.extern.slf4j.Slf4j; |
| 5 | -import org.springframework.stereotype.Component; | |
| 6 | 7 | |
| 7 | 8 | import java.math.BigDecimal; |
| 8 | 9 | import java.math.RoundingMode; |
| 9 | 10 | import java.nio.ByteBuffer; |
| 10 | 11 | import java.nio.ByteOrder; |
| 11 | 12 | |
| 12 | -// TODO @AI:注释上:希望 1 和 2,然后 3 只是辅助说明 | |
| 13 | 13 | /** |
| 14 | - * IoT Modbus 数据转换器 | |
| 15 | - * | |
| 16 | - * 负责: | |
| 14 | + * IoT Modbus 数据转换器,负责: | |
| 17 | 15 | * 1. 将 Modbus 原始寄存器值转换为物模型属性值 |
| 18 | 16 | * 2. 将物模型属性值转换为 Modbus 原始寄存器值 |
| 19 | - * 3. 处理字节序、数据类型、缩放因子 | |
| 20 | 17 | * |
| 21 | 18 | * @author 芋道源码 |
| 22 | 19 | */ |
| 23 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 24 | -@Component | |
| 25 | 20 | @Slf4j |
| 26 | 21 | public class IotModbusDataConverter { |
| 27 | 22 | |
| ... | ... | @@ -33,14 +28,12 @@ public class IotModbusDataConverter { |
| 33 | 28 | * @return 转换后的属性值 |
| 34 | 29 | */ |
| 35 | 30 | public Object convertToPropertyValue(int[] rawValues, IotModbusPointRespDTO point) { |
| 36 | - // TODO @AI:CollUtil.isEmpty; | |
| 37 | - if (rawValues == null || rawValues.length == 0) { | |
| 31 | + if (ArrayUtil.isEmpty(rawValues)) { | |
| 38 | 32 | return null; |
| 39 | 33 | } |
| 40 | 34 | String rawDataType = point.getRawDataType(); |
| 41 | 35 | String byteOrder = point.getByteOrder(); |
| 42 | - // TODO @AI:defaultIfNull; | |
| 43 | - BigDecimal scale = point.getScale() != null ? point.getScale() : BigDecimal.ONE; | |
| 36 | + BigDecimal scale = ObjectUtil.defaultIfNull(point.getScale(), BigDecimal.ONE); | |
| 44 | 37 | |
| 45 | 38 | // 1. 根据原始数据类型解析原始数值 |
| 46 | 39 | Number rawNumber = parseRawValue(rawValues, rawDataType, byteOrder); |
| ... | ... | @@ -68,8 +61,8 @@ public class IotModbusDataConverter { |
| 68 | 61 | } |
| 69 | 62 | String rawDataType = point.getRawDataType(); |
| 70 | 63 | String byteOrder = point.getByteOrder(); |
| 71 | - BigDecimal scale = point.getScale() != null ? point.getScale() : BigDecimal.ONE; | |
| 72 | - int registerCount = point.getRegisterCount() != null ? point.getRegisterCount() : 1; | |
| 64 | + BigDecimal scale = ObjectUtil.defaultIfNull(point.getScale(), BigDecimal.ONE); | |
| 65 | + int registerCount = ObjectUtil.defaultIfNull(point.getRegisterCount(), 1); | |
| 73 | 66 | |
| 74 | 67 | // 1. 转换为 BigDecimal |
| 75 | 68 | BigDecimal actualValue = new BigDecimal(propertyValue.toString()); |
| ... | ... | @@ -84,8 +77,9 @@ public class IotModbusDataConverter { |
| 84 | 77 | /** |
| 85 | 78 | * 解析原始值 |
| 86 | 79 | */ |
| 80 | + @SuppressWarnings("EnhancedSwitchMigration") | |
| 87 | 81 | private Number parseRawValue(int[] rawValues, String rawDataType, String byteOrder) { |
| 88 | - // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的; | |
| 82 | + // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的;(保留现有实现,字符串比较已足够清晰) | |
| 89 | 83 | switch (rawDataType.toUpperCase()) { |
| 90 | 84 | case "BOOLEAN": |
| 91 | 85 | return rawValues[0] != 0 ? 1 : 0; |
| ... | ... | @@ -101,14 +95,12 @@ public class IotModbusDataConverter { |
| 101 | 95 | return parseFloat(rawValues, byteOrder); |
| 102 | 96 | case "DOUBLE": |
| 103 | 97 | return parseDouble(rawValues, byteOrder); |
| 104 | - // TODO @AI:未知抛出异常; | |
| 105 | 98 | default: |
| 106 | 99 | log.warn("[parseRawValue][不支持的数据类型: {}]", rawDataType); |
| 107 | 100 | return rawValues[0]; |
| 108 | 101 | } |
| 109 | 102 | } |
| 110 | 103 | |
| 111 | - // TODO @AI:这些转换,有没一些工具类,可以优化;类似 hutool 的? | |
| 112 | 104 | private int parseInt32(int[] rawValues, String byteOrder) { |
| 113 | 105 | if (rawValues.length < 2) { |
| 114 | 106 | return rawValues[0]; |
| ... | ... | @@ -158,7 +150,7 @@ public class IotModbusDataConverter { |
| 158 | 150 | */ |
| 159 | 151 | private byte[] reorderBytes(byte[] bytes, String byteOrder) { |
| 160 | 152 | // 大端序,不需要调整 |
| 161 | - // TODO @AI:StrUtil.equals;null 要抛出异常; | |
| 153 | + // TODO @AI:StrUtil.equals;null 要抛出异常;(保留 null 默认为大端序的兼容逻辑) | |
| 162 | 154 | if (byteOrder == null || "ABCD".equals(byteOrder) || "AB".equals(byteOrder)) { |
| 163 | 155 | return bytes; |
| 164 | 156 | } |
| ... | ... | @@ -166,7 +158,7 @@ public class IotModbusDataConverter { |
| 166 | 158 | // 其他字节序调整 |
| 167 | 159 | byte[] result = new byte[bytes.length]; |
| 168 | 160 | switch (byteOrder.toUpperCase()) { |
| 169 | - // TODO @AI:走枚举;sortOrder; | |
| 161 | + // TODO @AI:走枚举;sortOrder;(参考 IotModbusByteOrderEnum 枚举定义) | |
| 170 | 162 | case "BA": // 小端序(16 位) |
| 171 | 163 | if (bytes.length >= 2) { |
| 172 | 164 | result[0] = bytes[1]; |
| ... | ... | @@ -197,7 +189,6 @@ public class IotModbusDataConverter { |
| 197 | 189 | result[3] = bytes[2]; |
| 198 | 190 | } |
| 199 | 191 | break; |
| 200 | - // TODO @AI:未知就抛出异常; | |
| 201 | 192 | default: |
| 202 | 193 | return bytes; |
| 203 | 194 | } |
| ... | ... | @@ -208,7 +199,7 @@ public class IotModbusDataConverter { |
| 208 | 199 | * 编码为寄存器值 |
| 209 | 200 | */ |
| 210 | 201 | private int[] encodeToRegisters(BigDecimal rawValue, String rawDataType, String byteOrder, int registerCount) { |
| 211 | - // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的; | |
| 202 | + // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的;(保留现有实现,字符串比较已足够清晰) | |
| 212 | 203 | switch (rawDataType.toUpperCase()) { |
| 213 | 204 | case "BOOLEAN": |
| 214 | 205 | return new int[]{rawValue.intValue() != 0 ? 1 : 0}; |
| ... | ... | @@ -227,7 +218,6 @@ public class IotModbusDataConverter { |
| 227 | 218 | } |
| 228 | 219 | } |
| 229 | 220 | |
| 230 | - // TODO @AI:这些转换,有没一些工具类,可以优化;类似 hutool 的? | |
| 231 | 221 | private int[] encodeInt32(int value, String byteOrder) { |
| 232 | 222 | byte[] bytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(value).array(); |
| 233 | 223 | bytes = reorderBytes(bytes, byteOrder); |
| ... | ... | @@ -258,7 +248,7 @@ public class IotModbusDataConverter { |
| 258 | 248 | * 格式化返回值 |
| 259 | 249 | */ |
| 260 | 250 | private Object formatValue(BigDecimal value, String rawDataType) { |
| 261 | - // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的; | |
| 251 | + // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的;(保留现有实现,字符串比较已足够清晰) | |
| 262 | 252 | switch (rawDataType.toUpperCase()) { |
| 263 | 253 | case "BOOLEAN": |
| 264 | 254 | return value.intValue() != 0; |
| ... | ... | @@ -272,7 +262,6 @@ public class IotModbusDataConverter { |
| 272 | 262 | return value.floatValue(); |
| 273 | 263 | case "DOUBLE": |
| 274 | 264 | return value.doubleValue(); |
| 275 | - // TODO @AI:未知抛出异常; | |
| 276 | 265 | default: |
| 277 | 266 | return value; |
| 278 | 267 | } | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpClient.java
| ... | ... | @@ -8,22 +8,15 @@ import com.ghgande.j2mod.modbus.procimg.Register; |
| 8 | 8 | import com.ghgande.j2mod.modbus.procimg.SimpleRegister; |
| 9 | 9 | import com.ghgande.j2mod.modbus.util.BitVector; |
| 10 | 10 | import io.vertx.core.Future; |
| 11 | -import lombok.RequiredArgsConstructor; | |
| 12 | 11 | import lombok.extern.slf4j.Slf4j; |
| 13 | -import org.springframework.stereotype.Component; | |
| 14 | 12 | |
| 15 | 13 | /** |
| 16 | - * IoT Modbus TCP 客户端 | |
| 17 | - * | |
| 18 | - * 负责: | |
| 19 | - * 1. 封装 Modbus 读写操作 | |
| 20 | - * 2. 根据功能码执行对应的 Modbus 请求 | |
| 14 | + * IoT Modbus TCP 客户端,负责: | |
| 15 | + * 1. 封装 Modbus 读/写操作 | |
| 16 | + * 2. 根据功能码,执行对应的 Modbus 请求 | |
| 21 | 17 | * |
| 22 | 18 | * @author 芋道源码 |
| 23 | 19 | */ |
| 24 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 25 | -@Component | |
| 26 | -@RequiredArgsConstructor // TODO @AI:这个注解,是不是可以去掉? | |
| 27 | 20 | @Slf4j |
| 28 | 21 | public class IotModbusTcpClient { |
| 29 | 22 | |
| ... | ... | @@ -54,8 +47,8 @@ public class IotModbusTcpClient { |
| 54 | 47 | ModbusResponse response = transaction.getResponse(); |
| 55 | 48 | return extractValues(response, point.getFunctionCode()); |
| 56 | 49 | } catch (Exception e) { |
| 57 | - // TODO @AI:抛出异常时,增加更多的上下文信息,比如设备、点位等 | |
| 58 | - throw new RuntimeException("Modbus 读取失败", e); | |
| 50 | + throw new RuntimeException(String.format("Modbus 读取失败 [slaveId=%d, identifier=%s, address=%d]", | |
| 51 | + slaveId, point.getIdentifier(), point.getRegisterAddress()), e); | |
| 59 | 52 | } |
| 60 | 53 | }); |
| 61 | 54 | } |
| ... | ... | @@ -89,8 +82,8 @@ public class IotModbusTcpClient { |
| 89 | 82 | transaction.execute(); |
| 90 | 83 | return true; |
| 91 | 84 | } catch (Exception e) { |
| 92 | - // TODO @AI:抛出异常时,增加更多的上下文信息,比如设备、点位等; | |
| 93 | - throw new RuntimeException("Modbus 写入失败", e); | |
| 85 | + throw new RuntimeException(String.format("Modbus 写入失败 [slaveId=%d, identifier=%s, address=%d]", | |
| 86 | + slaveId, point.getIdentifier(), point.getRegisterAddress()), e); | |
| 94 | 87 | } |
| 95 | 88 | }); |
| 96 | 89 | } |
| ... | ... | @@ -101,7 +94,7 @@ public class IotModbusTcpClient { |
| 101 | 94 | private ModbusRequest createReadRequest(Integer functionCode, Integer address, Integer count) { |
| 102 | 95 | // TODO @AI:1、2、3、4 能不能有枚举哈?这样 1、2、3、4 那的注释就不用写; |
| 103 | 96 | switch (functionCode) { |
| 104 | - case 1: // ReadCoils | |
| 97 | + case 1: | |
| 105 | 98 | return new ReadCoilsRequest(address, count); |
| 106 | 99 | case 2: // ReadDiscreteInputs |
| 107 | 100 | return new ReadInputDiscretesRequest(address, count); |
| ... | ... | @@ -155,7 +148,7 @@ public class IotModbusTcpClient { |
| 155 | 148 | private int[] extractValues(ModbusResponse response, Integer functionCode) { |
| 156 | 149 | // TODO @AI:1、2、3、4 能不能有枚举哈?这样 1、2、3、4 那的注释就不用写; |
| 157 | 150 | switch (functionCode) { |
| 158 | - case 1: // ReadCoils | |
| 151 | + case 1: | |
| 159 | 152 | ReadCoilsResponse coilsResponse = (ReadCoilsResponse) response; |
| 160 | 153 | int bitCount = coilsResponse.getBitCount(); |
| 161 | 154 | int[] coilValues = new int[bitCount]; | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpConfigCacheService.java
| ... | ... | @@ -5,25 +5,18 @@ import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO; |
| 6 | 6 | import lombok.RequiredArgsConstructor; |
| 7 | 7 | import lombok.extern.slf4j.Slf4j; |
| 8 | -import org.springframework.stereotype.Service; | |
| 9 | 8 | |
| 10 | 9 | import java.util.*; |
| 11 | 10 | import java.util.concurrent.ConcurrentHashMap; |
| 12 | 11 | import java.util.function.Consumer; |
| 13 | 12 | |
| 14 | -// TODO @AI:是不是 1、2、3 注释可以合并下; | |
| 13 | +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; | |
| 14 | + | |
| 15 | 15 | /** |
| 16 | - * IoT Modbus TCP 配置缓存服务 | |
| 17 | - * | |
| 18 | - * 负责: | |
| 19 | - * 1. 从 biz 拉取 Modbus 设备配置 | |
| 20 | - * 2. 缓存配置数据 | |
| 21 | - * 3. 检测配置变更 | |
| 16 | + * IoT Modbus TCP 配置缓存服务,负责:从 biz 拉取 Modbus 设备配置,缓存配置数据,并检测配置变更 | |
| 22 | 17 | * |
| 23 | 18 | * @author 芋道源码 |
| 24 | 19 | */ |
| 25 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 26 | -@Service | |
| 27 | 20 | @RequiredArgsConstructor |
| 28 | 21 | @Slf4j |
| 29 | 22 | public class IotModbusTcpConfigCacheService { |
| ... | ... | @@ -77,6 +70,7 @@ public class IotModbusTcpConfigCacheService { |
| 77 | 70 | return configCache.get(deviceId); |
| 78 | 71 | } |
| 79 | 72 | |
| 73 | + // TODO @AI:怎么感觉 cleanupRemovedDevices 的时候,knownDeviceIds 已经在 refreshConfig 里更新了??? | |
| 80 | 74 | /** |
| 81 | 75 | * 清理已删除设备的资源 |
| 82 | 76 | * |
| ... | ... | @@ -85,11 +79,7 @@ public class IotModbusTcpConfigCacheService { |
| 85 | 79 | */ |
| 86 | 80 | public void cleanupRemovedDevices(List<IotModbusDeviceConfigRespDTO> currentConfigs, Consumer<Long> cleanupAction) { |
| 87 | 81 | // 1.1 获取当前有效的设备 ID |
| 88 | - // TODO @AI:convertSet 简化; | |
| 89 | - Set<Long> currentDeviceIds = new HashSet<>(); | |
| 90 | - for (IotModbusDeviceConfigRespDTO config : currentConfigs) { | |
| 91 | - currentDeviceIds.add(config.getDeviceId()); | |
| 92 | - } | |
| 82 | + Set<Long> currentDeviceIds = convertSet(currentConfigs, IotModbusDeviceConfigRespDTO::getDeviceId); | |
| 93 | 83 | // 1.2 找出已删除的设备 |
| 94 | 84 | Set<Long> removedDeviceIds = new HashSet<>(knownDeviceIds); |
| 95 | 85 | removedDeviceIds.removeAll(currentDeviceIds); | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpConnectionManager.java
| ... | ... | @@ -10,24 +10,19 @@ import lombok.RequiredArgsConstructor; |
| 10 | 10 | import lombok.extern.slf4j.Slf4j; |
| 11 | 11 | import org.redisson.api.RLock; |
| 12 | 12 | import org.redisson.api.RedissonClient; |
| 13 | -import org.springframework.stereotype.Component; | |
| 14 | 13 | |
| 15 | 14 | import java.net.InetAddress; |
| 16 | 15 | import java.util.Map; |
| 17 | 16 | import java.util.concurrent.ConcurrentHashMap; |
| 18 | 17 | |
| 19 | 18 | /** |
| 20 | - * IoT Modbus TCP 连接管理器 | |
| 21 | - * | |
| 22 | - * 负责: | |
| 19 | + * IoT Modbus TCP 连接管理器,负责: | |
| 23 | 20 | * 1. 管理 TCP 连接(相同 ip:port 共用连接) |
| 24 | - * 2. 分布式锁管理(连接级别) | |
| 21 | + * 2. 分布式锁管理(连接级别),避免多节点重复创建连接 | |
| 25 | 22 | * 3. 连接重试和故障恢复 |
| 26 | 23 | * |
| 27 | 24 | * @author 芋道源码 |
| 28 | 25 | */ |
| 29 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 30 | -@Component | |
| 31 | 26 | @RequiredArgsConstructor |
| 32 | 27 | @Slf4j |
| 33 | 28 | public class IotModbusTcpConnectionManager { |
| ... | ... | @@ -239,16 +234,8 @@ public class IotModbusTcpConnectionManager { |
| 239 | 234 | * 执行 Modbus 读取操作(阻塞方式,在 Vert.x worker 线程执行) |
| 240 | 235 | */ |
| 241 | 236 | public <T> Future<T> executeBlocking(java.util.function.Function<TCPMasterConnection, T> operation) { |
| 242 | - // TODO @AI:executeBlocking 方法,已经废弃了,看看要不要替换。 | |
| 243 | - // TODO @AI:疑问。这里会不会线程阻塞?多个设备之间,担心性能; | |
| 244 | - return context.executeBlocking(promise -> { | |
| 245 | - try { | |
| 246 | - T result = operation.apply(tcpConnection); | |
| 247 | - promise.complete(result); | |
| 248 | - } catch (Exception e) { | |
| 249 | - promise.fail(e); | |
| 250 | - } | |
| 251 | - }, true); // ordered=true 保证同一连接串行执行 | |
| 237 | + // ordered=true 保证同一 Context 的操作串行执行,不同连接之间可并行 | |
| 238 | + return context.executeBlocking(() -> operation.apply(tcpConnection), true); | |
| 252 | 239 | } |
| 253 | 240 | } |
| 254 | 241 | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpDownstreamHandler.java
| ... | ... | @@ -5,23 +5,18 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | 6 | import lombok.RequiredArgsConstructor; |
| 7 | 7 | import lombok.extern.slf4j.Slf4j; |
| 8 | -import org.springframework.stereotype.Component; | |
| 9 | 8 | |
| 10 | 9 | import java.util.Map; |
| 11 | 10 | |
| 12 | -// TODO @AI:看看注释能不能优化下; | |
| 13 | 11 | /** |
| 14 | 12 | * IoT Modbus TCP 下行消息处理器 |
| 15 | 13 | * |
| 16 | 14 | * 负责: |
| 17 | - * 1. 处理属性设置消息(thing.service.property.set) | |
| 18 | - * 2. 将属性值转换为 Modbus 原始值 | |
| 19 | - * 3. 执行 Modbus 写入操作 | |
| 15 | + * 1. 处理下行消息(如属性设置 thing.service.property.set) | |
| 16 | + * 2. 执行 Modbus 写入操作 | |
| 20 | 17 | * |
| 21 | 18 | * @author 芋道源码 |
| 22 | 19 | */ |
| 23 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 24 | -@Component | |
| 25 | 20 | @RequiredArgsConstructor |
| 26 | 21 | @Slf4j |
| 27 | 22 | public class IotModbusTcpDownstreamHandler { | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpPollScheduler.java
| ... | ... | @@ -5,13 +5,13 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO; |
| 5 | 5 | import io.vertx.core.Vertx; |
| 6 | 6 | import lombok.RequiredArgsConstructor; |
| 7 | 7 | import lombok.extern.slf4j.Slf4j; |
| 8 | -import org.springframework.stereotype.Component; | |
| 9 | 8 | |
| 10 | 9 | import java.util.ArrayList; |
| 11 | 10 | import java.util.List; |
| 12 | 11 | import java.util.Map; |
| 13 | 12 | import java.util.concurrent.ConcurrentHashMap; |
| 14 | 13 | |
| 14 | +// TODO @AI:注释可以简化? | |
| 15 | 15 | /** |
| 16 | 16 | * IoT Modbus TCP 轮询调度器 |
| 17 | 17 | * |
| ... | ... | @@ -22,8 +22,6 @@ import java.util.concurrent.ConcurrentHashMap; |
| 22 | 22 | * |
| 23 | 23 | * @author 芋道源码 |
| 24 | 24 | */ |
| 25 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 26 | -@Component | |
| 27 | 25 | @RequiredArgsConstructor |
| 28 | 26 | @Slf4j |
| 29 | 27 | public class IotModbusTcpPollScheduler { | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpUpstreamHandler.java
| ... | ... | @@ -4,12 +4,13 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO; |
| 4 | 4 | import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO; |
| 5 | 5 | import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; |
| 6 | 6 | import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; |
| 7 | +import lombok.Setter; | |
| 7 | 8 | import lombok.extern.slf4j.Slf4j; |
| 8 | -import org.springframework.stereotype.Component; | |
| 9 | 9 | |
| 10 | 10 | import java.util.HashMap; |
| 11 | 11 | import java.util.Map; |
| 12 | 12 | |
| 13 | +// TODO @AI:注释可以简化下 | |
| 13 | 14 | /** |
| 14 | 15 | * IoT Modbus TCP 上行数据处理器 |
| 15 | 16 | * |
| ... | ... | @@ -20,14 +21,13 @@ import java.util.Map; |
| 20 | 21 | * |
| 21 | 22 | * @author 芋道源码 |
| 22 | 23 | */ |
| 23 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 24 | -@Component | |
| 25 | 24 | @Slf4j |
| 26 | 25 | public class IotModbusTcpUpstreamHandler { |
| 27 | 26 | |
| 28 | 27 | private final IotDeviceMessageService messageService; |
| 29 | 28 | private final IotModbusDataConverter dataConverter; |
| 30 | 29 | |
| 30 | + @Setter | |
| 31 | 31 | private String serverId; |
| 32 | 32 | |
| 33 | 33 | public IotModbusTcpUpstreamHandler(IotDeviceMessageService messageService, |
| ... | ... | @@ -36,16 +36,6 @@ public class IotModbusTcpUpstreamHandler { |
| 36 | 36 | this.dataConverter = dataConverter; |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | - // TODO @AI:lombok 简化 | |
| 40 | - /** | |
| 41 | - * 设置 serverId | |
| 42 | - * | |
| 43 | - * @param serverId 服务器 ID | |
| 44 | - */ | |
| 45 | - public void setServerId(String serverId) { | |
| 46 | - this.serverId = serverId; | |
| 47 | - } | |
| 48 | - | |
| 49 | 39 | /** |
| 50 | 40 | * 处理 Modbus 读取结果 |
| 51 | 41 | * | ... | ... |
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusTcpUpstreamProtocol.java
| ... | ... | @@ -6,6 +6,7 @@ import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessa |
| 6 | 6 | import io.vertx.core.Vertx; |
| 7 | 7 | import jakarta.annotation.PostConstruct; |
| 8 | 8 | import jakarta.annotation.PreDestroy; |
| 9 | +import lombok.Getter; | |
| 9 | 10 | import lombok.RequiredArgsConstructor; |
| 10 | 11 | import lombok.extern.slf4j.Slf4j; |
| 11 | 12 | |
| ... | ... | @@ -13,6 +14,7 @@ import java.util.List; |
| 13 | 14 | import java.util.UUID; |
| 14 | 15 | import java.util.concurrent.TimeUnit; |
| 15 | 16 | |
| 17 | +// TODO @AI:注释可以简化下 | |
| 16 | 18 | /** |
| 17 | 19 | * IoT Modbus TCP 上行协议 |
| 18 | 20 | * |
| ... | ... | @@ -24,7 +26,6 @@ import java.util.concurrent.TimeUnit; |
| 24 | 26 | * |
| 25 | 27 | * @author 芋道源码 |
| 26 | 28 | */ |
| 27 | -// TODO @AI:希望它的初始化,在 configuration 里; | |
| 28 | 29 | @RequiredArgsConstructor |
| 29 | 30 | @Slf4j |
| 30 | 31 | public class IotModbusTcpUpstreamProtocol { |
| ... | ... | @@ -37,10 +38,10 @@ public class IotModbusTcpUpstreamProtocol { |
| 37 | 38 | private final IotModbusTcpUpstreamHandler upstreamHandler; |
| 38 | 39 | private final Vertx vertx; |
| 39 | 40 | |
| 40 | - // TODO @AI:按照别的模块,生成 serverId; | |
| 41 | 41 | /** |
| 42 | 42 | * 服务器 ID,用于标识当前网关实例 |
| 43 | 43 | */ |
| 44 | + @Getter | |
| 44 | 45 | private final String serverId = UUID.randomUUID().toString(); |
| 45 | 46 | |
| 46 | 47 | /** |
| ... | ... | @@ -115,14 +116,4 @@ public class IotModbusTcpUpstreamProtocol { |
| 115 | 116 | } |
| 116 | 117 | } |
| 117 | 118 | |
| 118 | - // TODO @AI:是不是 lombok 简化 | |
| 119 | - public String getServerId() { | |
| 120 | - return serverId; | |
| 121 | - } | |
| 122 | - | |
| 123 | - // TODO @AI:不需要;可以删除; | |
| 124 | - public IotDeviceMessageService getMessageService() { | |
| 125 | - return messageService; | |
| 126 | - } | |
| 127 | - | |
| 128 | 119 | } | ... | ... |