Commit cece79d04cdf58c579fb5ec6c17219bb380c2a34

Authored by YunaiV
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 package cn.iocoder.yudao.module.iot.api.device; 1 package cn.iocoder.yudao.module.iot.api.device;
2 2
  3 +import cn.hutool.core.collection.CollUtil;
3 import cn.iocoder.yudao.framework.common.enums.RpcConstants; 4 import cn.iocoder.yudao.framework.common.enums.RpcConstants;
4 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -23,8 +24,11 @@ import org.springframework.web.bind.annotation.RestController; @@ -23,8 +24,11 @@ import org.springframework.web.bind.annotation.RestController;
23 24
24 import java.util.ArrayList; 25 import java.util.ArrayList;
25 import java.util.List; 26 import java.util.List;
  27 +import java.util.Map;
  28 +import java.util.Set;
26 29
27 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 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 * IoT 设备 API 实现类 34 * IoT 设备 API 实现类
@@ -71,40 +75,32 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi { @@ -71,40 +75,32 @@ public class IoTDeviceApiImpl implements IotDeviceCommonApi {
71 @PermitAll 75 @PermitAll
72 public CommonResult<List<IotModbusDeviceConfigRespDTO>> getEnabledModbusDeviceConfigs() { 76 public CommonResult<List<IotModbusDeviceConfigRespDTO>> getEnabledModbusDeviceConfigs() {
73 // 1. 获取所有启用的 Modbus 连接配置 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 return success(new ArrayList<>()); 80 return success(new ArrayList<>());
77 } 81 }
78 82
79 // 2. 组装返回结果 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 List<IotModbusDeviceConfigRespDTO> result = new ArrayList<>(configList.size()); 87 List<IotModbusDeviceConfigRespDTO> result = new ArrayList<>(configList.size());
81 for (IotDeviceModbusConfigDO config : configList) { 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 if (device == null) { 91 if (device == null) {
86 continue; 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 return success(result); 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,19 +28,11 @@ public class IotDeviceModbusConfigController {
28 @Resource 28 @Resource
29 private IotDeviceModbusConfigService modbusConfigService; 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 @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:create')") 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 return success(true); 36 return success(true);
45 } 37 }
46 38
@@ -48,36 +40,33 @@ public class IotDeviceModbusConfigController { @@ -48,36 +40,33 @@ public class IotDeviceModbusConfigController {
48 @Operation(summary = "删除设备 Modbus 连接配置") 40 @Operation(summary = "删除设备 Modbus 连接配置")
49 @Parameter(name = "id", description = "编号", required = true) 41 @Parameter(name = "id", description = "编号", required = true)
50 @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:delete')") 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 return success(true); 45 return success(true);
54 } 46 }
55 47
56 - // TODO @AI:这个接口改造,支持 id 或者 deviceId;二选一查询;  
57 @GetMapping("/get") 48 @GetMapping("/get")
58 @Operation(summary = "获得设备 Modbus 连接配置") 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 @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:query')") 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 return success(BeanUtils.toBean(modbusConfig, IotDeviceModbusConfigRespVO.class)); 62 return success(BeanUtils.toBean(modbusConfig, IotDeviceModbusConfigRespVO.class));
74 } 63 }
75 64
76 @GetMapping("/page") 65 @GetMapping("/page")
77 @Operation(summary = "获得设备 Modbus 连接配置分页") 66 @Operation(summary = "获得设备 Modbus 连接配置分页")
78 @PreAuthorize("@ss.hasPermission('iot:device-modbus-config:query')") 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 return success(BeanUtils.toBean(pageResult, IotDeviceModbusConfigRespVO.class)); 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,8 +17,6 @@ import org.springframework.security.access.prepost.PreAuthorize;
17 import org.springframework.validation.annotation.Validated; 17 import org.springframework.validation.annotation.Validated;
18 import org.springframework.web.bind.annotation.*; 18 import org.springframework.web.bind.annotation.*;
19 19
20 -import java.util.List;  
21 -  
22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 20 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
23 21
24 @Tag(name = "管理后台 - IoT 设备 Modbus 点位配置") 22 @Tag(name = "管理后台 - IoT 设备 Modbus 点位配置")
@@ -33,15 +31,15 @@ public class IotDeviceModbusPointController { @@ -33,15 +31,15 @@ public class IotDeviceModbusPointController {
33 @PostMapping("/create") 31 @PostMapping("/create")
34 @Operation(summary = "创建设备 Modbus 点位配置") 32 @Operation(summary = "创建设备 Modbus 点位配置")
35 @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:create')") 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 @PutMapping("/update") 38 @PutMapping("/update")
41 @Operation(summary = "更新设备 Modbus 点位配置") 39 @Operation(summary = "更新设备 Modbus 点位配置")
42 @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:update')") 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 return success(true); 43 return success(true);
46 } 44 }
47 45
@@ -49,8 +47,8 @@ public class IotDeviceModbusPointController { @@ -49,8 +47,8 @@ public class IotDeviceModbusPointController {
49 @Operation(summary = "删除设备 Modbus 点位配置") 47 @Operation(summary = "删除设备 Modbus 点位配置")
50 @Parameter(name = "id", description = "编号", required = true) 48 @Parameter(name = "id", description = "编号", required = true)
51 @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:delete')") 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 return success(true); 52 return success(true);
55 } 53 }
56 54
@@ -58,27 +56,17 @@ public class IotDeviceModbusPointController { @@ -58,27 +56,17 @@ public class IotDeviceModbusPointController {
58 @Operation(summary = "获得设备 Modbus 点位配置") 56 @Operation(summary = "获得设备 Modbus 点位配置")
59 @Parameter(name = "id", description = "编号", required = true, example = "1024") 57 @Parameter(name = "id", description = "编号", required = true, example = "1024")
60 @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:query')") 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 return success(BeanUtils.toBean(modbusPoint, IotDeviceModbusPointRespVO.class)); 61 return success(BeanUtils.toBean(modbusPoint, IotDeviceModbusPointRespVO.class));
64 } 62 }
65 63
66 @GetMapping("/page") 64 @GetMapping("/page")
67 @Operation(summary = "获得设备 Modbus 点位配置分页") 65 @Operation(summary = "获得设备 Modbus 点位配置分页")
68 @PreAuthorize("@ss.hasPermission('iot:device-modbus-point:query')") 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 return success(BeanUtils.toBean(pageResult, IotDeviceModbusPointRespVO.class)); 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 +9,6 @@ import lombok.Data;
9 @Data 9 @Data
10 public class IotDeviceModbusConfigSaveReqVO { 10 public class IotDeviceModbusConfigSaveReqVO {
11 11
12 - @Schema(description = "主键", example = "1")  
13 - private Long id;  
14 -  
15 @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 12 @Schema(description = "设备编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
16 @NotNull(message = "设备编号不能为空") 13 @NotNull(message = "设备编号不能为空")
17 private Long deviceId; 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,6 +7,7 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.modbus.IotDeviceMo
7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceModbusPointDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceModbusPointDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
  10 +import java.util.Collection;
10 import java.util.List; 11 import java.util.List;
11 12
12 /** 13 /**
@@ -27,27 +28,15 @@ public interface IotDeviceModbusPointMapper extends BaseMapperX&lt;IotDeviceModbusP @@ -27,27 +28,15 @@ public interface IotDeviceModbusPointMapper extends BaseMapperX&lt;IotDeviceModbusP
27 .orderByDesc(IotDeviceModbusPointDO::getId)); 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 return selectList(new LambdaQueryWrapperX<IotDeviceModbusPointDO>() 32 return selectList(new LambdaQueryWrapperX<IotDeviceModbusPointDO>()
37 - .eq(IotDeviceModbusPointDO::getDeviceId, deviceId) 33 + .in(IotDeviceModbusPointDO::getDeviceId, deviceIds)
38 .eq(IotDeviceModbusPointDO::getStatus, status)); 34 .eq(IotDeviceModbusPointDO::getStatus, status));
39 } 35 }
40 36
41 - // TODO @AI:是不是 selectOne(f1, v1, f2, v2);  
42 default IotDeviceModbusPointDO selectByDeviceIdAndIdentifier(Long deviceId, String identifier) { 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 +6,7 @@ import lombok.RequiredArgsConstructor;
6 6
7 import java.util.Arrays; 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 * IoT Modbus 字节序枚举 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 +6,7 @@ import lombok.RequiredArgsConstructor;
6 6
7 import java.util.Arrays; 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 * IoT Modbus 功能码枚举 11 * IoT Modbus 功能码枚举
11 * 12 *
@@ -63,18 +64,4 @@ public enum IotModbusFunctionCodeEnum implements ArrayValuable&lt;Integer&gt; { @@ -63,18 +64,4 @@ public enum IotModbusFunctionCodeEnum implements ArrayValuable&lt;Integer&gt; {
63 .orElse(null); 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 +6,7 @@ import lombok.RequiredArgsConstructor;
6 6
7 import java.util.Arrays; 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 * IoT Modbus 原始数据类型枚举 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,26 +16,18 @@ import java.util.List;
16 public interface IotDeviceModbusConfigService { 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 * 删除设备 Modbus 连接配置 26 * 删除设备 Modbus 连接配置
35 * 27 *
36 * @param id 编号 28 * @param id 编号
37 */ 29 */
38 - void deleteModbusConfig(Long id); 30 + void deleteDeviceModbusConfig(Long id);
39 31
40 /** 32 /**
41 * 获得设备 Modbus 连接配置 33 * 获得设备 Modbus 连接配置
@@ -43,7 +35,7 @@ public interface IotDeviceModbusConfigService { @@ -43,7 +35,7 @@ public interface IotDeviceModbusConfigService {
43 * @param id 编号 35 * @param id 编号
44 * @return 设备 Modbus 连接配置 36 * @return 设备 Modbus 连接配置
45 */ 37 */
46 - IotDeviceModbusConfigDO getModbusConfig(Long id); 38 + IotDeviceModbusConfigDO getDeviceModbusConfig(Long id);
47 39
48 /** 40 /**
49 * 根据设备编号获得 Modbus 连接配置 41 * 根据设备编号获得 Modbus 连接配置
@@ -51,7 +43,7 @@ public interface IotDeviceModbusConfigService { @@ -51,7 +43,7 @@ public interface IotDeviceModbusConfigService {
51 * @param deviceId 设备编号 43 * @param deviceId 设备编号
52 * @return 设备 Modbus 连接配置 44 * @return 设备 Modbus 连接配置
53 */ 45 */
54 - IotDeviceModbusConfigDO getModbusConfigByDeviceId(Long deviceId); 46 + IotDeviceModbusConfigDO getDeviceModbusConfigByDeviceId(Long deviceId);
55 47
56 /** 48 /**
57 * 获得设备 Modbus 连接配置分页 49 * 获得设备 Modbus 连接配置分页
@@ -59,13 +51,13 @@ public interface IotDeviceModbusConfigService { @@ -59,13 +51,13 @@ public interface IotDeviceModbusConfigService {
59 * @param pageReqVO 分页查询 51 * @param pageReqVO 分页查询
60 * @return 设备 Modbus 连接配置分页 52 * @return 设备 Modbus 连接配置分页
61 */ 53 */
62 - PageResult<IotDeviceModbusConfigDO> getModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO); 54 + PageResult<IotDeviceModbusConfigDO> getDeviceModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO);
63 55
64 /** 56 /**
65 * 获得所有启用的 Modbus 连接配置列表 57 * 获得所有启用的 Modbus 连接配置列表
66 * 58 *
67 * @return 启用的 Modbus 连接配置列表 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,7 +14,6 @@ import org.springframework.validation.annotation.Validated;
14 import java.util.List; 14 import java.util.List;
15 15
16 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.DEVICE_MODBUS_CONFIG_NOT_EXISTS; 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,90 +31,54 @@ public class IotDeviceModbusConfigServiceImpl implements IotDeviceModbusConfigSe
32 @Resource 31 @Resource
33 private IotDeviceService deviceService; 32 private IotDeviceService deviceService;
34 33
35 - // TODO @AI:是不是搞成 save 接口?因为前端也不知道是 create 还是 update;  
36 @Override 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 @Override 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 modbusConfigMapper.deleteById(id); 56 modbusConfigMapper.deleteById(id);
70 } 57 }
71 58
72 - private void validateModbusConfigExists(Long id) { 59 + private void validateDeviceModbusConfigExists(Long id) {
73 if (modbusConfigMapper.selectById(id) == null) { 60 if (modbusConfigMapper.selectById(id) == null) {
74 throw exception(DEVICE_MODBUS_CONFIG_NOT_EXISTS); 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 @Override 65 @Override
103 - public IotDeviceModbusConfigDO getModbusConfig(Long id) { 66 + public IotDeviceModbusConfigDO getDeviceModbusConfig(Long id) {
104 return modbusConfigMapper.selectById(id); 67 return modbusConfigMapper.selectById(id);
105 } 68 }
106 69
107 @Override 70 @Override
108 - public IotDeviceModbusConfigDO getModbusConfigByDeviceId(Long deviceId) { 71 + public IotDeviceModbusConfigDO getDeviceModbusConfigByDeviceId(Long deviceId) {
109 return modbusConfigMapper.selectByDeviceId(deviceId); 72 return modbusConfigMapper.selectByDeviceId(deviceId);
110 } 73 }
111 74
112 @Override 75 @Override
113 - public PageResult<IotDeviceModbusConfigDO> getModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO) { 76 + public PageResult<IotDeviceModbusConfigDO> getDeviceModbusConfigPage(IotDeviceModbusConfigPageReqVO pageReqVO) {
114 return modbusConfigMapper.selectPage(pageReqVO); 77 return modbusConfigMapper.selectPage(pageReqVO);
115 } 78 }
116 79
117 @Override 80 @Override
118 - public List<IotDeviceModbusConfigDO> getEnabledModbusConfigList() { 81 + public List<IotDeviceModbusConfigDO> getEnabledDeviceModbusConfigList() {
119 return modbusConfigMapper.selectListByStatus(CommonStatusEnum.ENABLE.getStatus()); 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,7 +6,9 @@ import cn.iocoder.yudao.module.iot.controller.admin.device.vo.modbus.IotDeviceMo
6 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceModbusPointDO; 6 import cn.iocoder.yudao.module.iot.dal.dataobject.device.IotDeviceModbusPointDO;
7 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
8 8
  9 +import java.util.Collection;
9 import java.util.List; 10 import java.util.List;
  11 +import java.util.Map;
10 12
11 /** 13 /**
12 * IoT 设备 Modbus 点位配置 Service 接口 14 * IoT 设备 Modbus 点位配置 Service 接口
@@ -21,21 +23,21 @@ public interface IotDeviceModbusPointService { @@ -21,21 +23,21 @@ public interface IotDeviceModbusPointService {
21 * @param createReqVO 创建信息 23 * @param createReqVO 创建信息
22 * @return 编号 24 * @return 编号
23 */ 25 */
24 - Long createModbusPoint(@Valid IotDeviceModbusPointSaveReqVO createReqVO); 26 + Long createDeviceModbusPoint(@Valid IotDeviceModbusPointSaveReqVO createReqVO);
25 27
26 /** 28 /**
27 * 更新设备 Modbus 点位配置 29 * 更新设备 Modbus 点位配置
28 * 30 *
29 * @param updateReqVO 更新信息 31 * @param updateReqVO 更新信息
30 */ 32 */
31 - void updateModbusPoint(@Valid IotDeviceModbusPointSaveReqVO updateReqVO); 33 + void updateDeviceModbusPoint(@Valid IotDeviceModbusPointSaveReqVO updateReqVO);
32 34
33 /** 35 /**
34 * 删除设备 Modbus 点位配置 36 * 删除设备 Modbus 点位配置
35 * 37 *
36 * @param id 编号 38 * @param id 编号
37 */ 39 */
38 - void deleteModbusPoint(Long id); 40 + void deleteDeviceModbusPoint(Long id);
39 41
40 /** 42 /**
41 * 获得设备 Modbus 点位配置 43 * 获得设备 Modbus 点位配置
@@ -43,7 +45,7 @@ public interface IotDeviceModbusPointService { @@ -43,7 +45,7 @@ public interface IotDeviceModbusPointService {
43 * @param id 编号 45 * @param id 编号
44 * @return 设备 Modbus 点位配置 46 * @return 设备 Modbus 点位配置
45 */ 47 */
46 - IotDeviceModbusPointDO getModbusPoint(Long id); 48 + IotDeviceModbusPointDO getDeviceModbusPoint(Long id);
47 49
48 /** 50 /**
49 * 获得设备 Modbus 点位配置分页 51 * 获得设备 Modbus 点位配置分页
@@ -51,22 +53,14 @@ public interface IotDeviceModbusPointService { @@ -51,22 +53,14 @@ public interface IotDeviceModbusPointService {
51 * @param pageReqVO 分页查询 53 * @param pageReqVO 分页查询
52 * @return 设备 Modbus 点位配置分页 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 package cn.iocoder.yudao.module.iot.service.device; 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 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; 5 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -13,10 +15,13 @@ import jakarta.annotation.Resource; @@ -13,10 +15,13 @@ import jakarta.annotation.Resource;
13 import org.springframework.stereotype.Service; 15 import org.springframework.stereotype.Service;
14 import org.springframework.validation.annotation.Validated; 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 import java.util.List; 20 import java.util.List;
  21 +import java.util.Map;
18 22
19 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 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 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; 25 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
21 26
22 /** 27 /**
@@ -38,13 +43,13 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ @@ -38,13 +43,13 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ
38 private IotThingModelService thingModelService; 43 private IotThingModelService thingModelService;
39 44
40 @Override 45 @Override
41 - public Long createModbusPoint(IotDeviceModbusPointSaveReqVO createReqVO) { 46 + public Long createDeviceModbusPoint(IotDeviceModbusPointSaveReqVO createReqVO) {
42 // 1.1 校验设备存在 47 // 1.1 校验设备存在
43 deviceService.validateDeviceExists(createReqVO.getDeviceId()); 48 deviceService.validateDeviceExists(createReqVO.getDeviceId());
44 // 1.2 校验物模型属性存在 49 // 1.2 校验物模型属性存在
45 IotThingModelDO thingModel = validateThingModelExists(createReqVO.getThingModelId()); 50 IotThingModelDO thingModel = validateThingModelExists(createReqVO.getThingModelId());
46 // 1.3 校验同一设备下点位唯一性(基于 identifier) 51 // 1.3 校验同一设备下点位唯一性(基于 identifier)
47 - validateModbusPointUnique(createReqVO.getDeviceId(), thingModel.getIdentifier(), null); 52 + validateDeviceModbusPointUnique(createReqVO.getDeviceId(), thingModel.getIdentifier(), null);
48 53
49 // 2. 插入 54 // 2. 插入
50 IotDeviceModbusPointDO modbusPoint = BeanUtils.toBean(createReqVO, IotDeviceModbusPointDO.class, 55 IotDeviceModbusPointDO modbusPoint = BeanUtils.toBean(createReqVO, IotDeviceModbusPointDO.class,
@@ -54,22 +59,23 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ @@ -54,22 +59,23 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ
54 } 59 }
55 60
56 @Override 61 @Override
57 - public void updateModbusPoint(IotDeviceModbusPointSaveReqVO updateReqVO) { 62 + public void updateDeviceModbusPoint(IotDeviceModbusPointSaveReqVO updateReqVO) {
58 // 1.1 校验存在 63 // 1.1 校验存在
59 - validateModbusPointExists(updateReqVO.getId()); 64 + validateDeviceModbusPointExists(updateReqVO.getId());
60 // 1.2 校验设备存在 65 // 1.2 校验设备存在
61 deviceService.validateDeviceExists(updateReqVO.getDeviceId()); 66 deviceService.validateDeviceExists(updateReqVO.getDeviceId());
62 // 1.3 校验物模型属性存在 67 // 1.3 校验物模型属性存在
63 IotThingModelDO thingModel = validateThingModelExists(updateReqVO.getThingModelId()); 68 IotThingModelDO thingModel = validateThingModelExists(updateReqVO.getThingModelId());
64 // 1.4 校验同一设备下点位唯一性 69 // 1.4 校验同一设备下点位唯一性
65 - validateModbusPointUnique(updateReqVO.getDeviceId(), thingModel.getIdentifier(), updateReqVO.getId()); 70 + validateDeviceModbusPointUnique(updateReqVO.getDeviceId(), thingModel.getIdentifier(), updateReqVO.getId());
66 71
67 // 2. 更新 72 // 2. 更新
68 IotDeviceModbusPointDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceModbusPointDO.class); 73 IotDeviceModbusPointDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceModbusPointDO.class);
69 - // TODO @AI:这块  
70 modbusPointMapper.updateById(updateObj); 74 modbusPointMapper.updateById(updateObj);
71 } 75 }
72 76
  77 + // TODO @AI:物模型更新的时候,更新下 identifier、name 信息;例如说 updateDeviceModbusPoint(thingModelId, identifier、name) 方法;
  78 +
73 private IotThingModelDO validateThingModelExists(Long id) { 79 private IotThingModelDO validateThingModelExists(Long id) {
74 IotThingModelDO thingModel = thingModelService.getThingModel(id); 80 IotThingModelDO thingModel = thingModelService.getThingModel(id);
75 if (thingModel == null) { 81 if (thingModel == null) {
@@ -79,60 +85,45 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ @@ -79,60 +85,45 @@ public class IotDeviceModbusPointServiceImpl implements IotDeviceModbusPointServ
79 } 85 }
80 86
81 @Override 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 modbusPointMapper.deleteById(id); 92 modbusPointMapper.deleteById(id);
87 } 93 }
88 94
89 - private IotDeviceModbusPointDO validateModbusPointExists(Long id) { 95 + private void validateDeviceModbusPointExists(Long id) {
90 IotDeviceModbusPointDO point = modbusPointMapper.selectById(id); 96 IotDeviceModbusPointDO point = modbusPointMapper.selectById(id);
91 if (point == null) { 97 if (point == null) {
92 throw exception(DEVICE_MODBUS_POINT_NOT_EXISTS); 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 IotDeviceModbusPointDO point = modbusPointMapper.selectByDeviceIdAndIdentifier(deviceId, identifier); 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 throw exception(DEVICE_MODBUS_POINT_EXISTS); 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 @Override 109 @Override
119 - public IotDeviceModbusPointDO getModbusPoint(Long id) { 110 + public IotDeviceModbusPointDO getDeviceModbusPoint(Long id) {
120 return modbusPointMapper.selectById(id); 111 return modbusPointMapper.selectById(id);
121 } 112 }
122 113
123 @Override 114 @Override
124 - public PageResult<IotDeviceModbusPointDO> getModbusPointPage(IotDeviceModbusPointPageReqVO pageReqVO) { 115 + public PageResult<IotDeviceModbusPointDO> getDeviceModbusPointPage(IotDeviceModbusPointPageReqVO pageReqVO) {
125 return modbusPointMapper.selectPage(pageReqVO); 116 return modbusPointMapper.selectPage(pageReqVO);
126 } 117 }
127 118
128 @Override 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,10 +24,6 @@ public class IotModbusDeviceConfigRespDTO {
24 * 设备名称 24 * 设备名称
25 */ 25 */
26 private String deviceName; 26 private String deviceName;
27 - /**  
28 - * 租户编号  
29 - */  
30 - private Long tenantId;  
31 27
32 // ========== Modbus 连接配置 ========== 28 // ========== Modbus 连接配置 ==========
33 29
@@ -36,7 +32,7 @@ public class IotModbusDeviceConfigRespDTO { @@ -36,7 +32,7 @@ public class IotModbusDeviceConfigRespDTO {
36 */ 32 */
37 private String ip; 33 private String ip;
38 /** 34 /**
39 - * Modbus 端口 35 + * Modbus 服务器端口
40 */ 36 */
41 private Integer port; 37 private Integer port;
42 /** 38 /**
@@ -44,11 +40,11 @@ public class IotModbusDeviceConfigRespDTO { @@ -44,11 +40,11 @@ public class IotModbusDeviceConfigRespDTO {
44 */ 40 */
45 private Integer slaveId; 41 private Integer slaveId;
46 /** 42 /**
47 - * 连接超时时间(毫秒) 43 + * 连接超时时间,单位:毫秒
48 */ 44 */
49 private Integer timeout; 45 private Integer timeout;
50 /** 46 /**
51 - * 重试间隔(毫秒) 47 + * 重试间隔,单位:毫秒
52 */ 48 */
53 private Integer retryInterval; 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,6 +22,7 @@ import cn.iocoder.yudao.module.iot.gateway.service.device.IotDeviceService;
22 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; 22 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
23 import io.vertx.core.Vertx; 23 import io.vertx.core.Vertx;
24 import lombok.extern.slf4j.Slf4j; 24 import lombok.extern.slf4j.Slf4j;
  25 +import org.redisson.api.RedissonClient;
25 import org.springframework.beans.factory.annotation.Qualifier; 26 import org.springframework.beans.factory.annotation.Qualifier;
26 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 27 import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
27 import org.springframework.boot.context.properties.EnableConfigurationProperties; 28 import org.springframework.boot.context.properties.EnableConfigurationProperties;
@@ -209,6 +210,54 @@ public class IotGatewayConfiguration { @@ -209,6 +210,54 @@ public class IotGatewayConfiguration {
209 } 210 }
210 211
211 @Bean 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 public IotModbusTcpUpstreamProtocol iotModbusTcpUpstreamProtocol(IotGatewayProperties gatewayProperties, 261 public IotModbusTcpUpstreamProtocol iotModbusTcpUpstreamProtocol(IotGatewayProperties gatewayProperties,
213 IotDeviceMessageService messageService, 262 IotDeviceMessageService messageService,
214 IotModbusTcpConnectionManager connectionManager, 263 IotModbusTcpConnectionManager connectionManager,
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/modbustcp/IotModbusDataConverter.java
1 package cn.iocoder.yudao.module.iot.gateway.protocol.modbustcp; 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 import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO; 5 import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
4 import lombok.extern.slf4j.Slf4j; 6 import lombok.extern.slf4j.Slf4j;
5 -import org.springframework.stereotype.Component;  
6 7
7 import java.math.BigDecimal; 8 import java.math.BigDecimal;
8 import java.math.RoundingMode; 9 import java.math.RoundingMode;
9 import java.nio.ByteBuffer; 10 import java.nio.ByteBuffer;
10 import java.nio.ByteOrder; 11 import java.nio.ByteOrder;
11 12
12 -// TODO @AI:注释上:希望 1 和 2,然后 3 只是辅助说明  
13 /** 13 /**
14 - * IoT Modbus 数据转换器  
15 - *  
16 - * 负责: 14 + * IoT Modbus 数据转换器,负责:
17 * 1. 将 Modbus 原始寄存器值转换为物模型属性值 15 * 1. 将 Modbus 原始寄存器值转换为物模型属性值
18 * 2. 将物模型属性值转换为 Modbus 原始寄存器值 16 * 2. 将物模型属性值转换为 Modbus 原始寄存器值
19 - * 3. 处理字节序、数据类型、缩放因子  
20 * 17 *
21 * @author 芋道源码 18 * @author 芋道源码
22 */ 19 */
23 -// TODO @AI:希望它的初始化,在 configuration 里;  
24 -@Component  
25 @Slf4j 20 @Slf4j
26 public class IotModbusDataConverter { 21 public class IotModbusDataConverter {
27 22
@@ -33,14 +28,12 @@ public class IotModbusDataConverter { @@ -33,14 +28,12 @@ public class IotModbusDataConverter {
33 * @return 转换后的属性值 28 * @return 转换后的属性值
34 */ 29 */
35 public Object convertToPropertyValue(int[] rawValues, IotModbusPointRespDTO point) { 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 return null; 32 return null;
39 } 33 }
40 String rawDataType = point.getRawDataType(); 34 String rawDataType = point.getRawDataType();
41 String byteOrder = point.getByteOrder(); 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 // 1. 根据原始数据类型解析原始数值 38 // 1. 根据原始数据类型解析原始数值
46 Number rawNumber = parseRawValue(rawValues, rawDataType, byteOrder); 39 Number rawNumber = parseRawValue(rawValues, rawDataType, byteOrder);
@@ -68,8 +61,8 @@ public class IotModbusDataConverter { @@ -68,8 +61,8 @@ public class IotModbusDataConverter {
68 } 61 }
69 String rawDataType = point.getRawDataType(); 62 String rawDataType = point.getRawDataType();
70 String byteOrder = point.getByteOrder(); 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 // 1. 转换为 BigDecimal 67 // 1. 转换为 BigDecimal
75 BigDecimal actualValue = new BigDecimal(propertyValue.toString()); 68 BigDecimal actualValue = new BigDecimal(propertyValue.toString());
@@ -84,8 +77,9 @@ public class IotModbusDataConverter { @@ -84,8 +77,9 @@ public class IotModbusDataConverter {
84 /** 77 /**
85 * 解析原始值 78 * 解析原始值
86 */ 79 */
  80 + @SuppressWarnings("EnhancedSwitchMigration")
87 private Number parseRawValue(int[] rawValues, String rawDataType, String byteOrder) { 81 private Number parseRawValue(int[] rawValues, String rawDataType, String byteOrder) {
88 - // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的; 82 + // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的;(保留现有实现,字符串比较已足够清晰)
89 switch (rawDataType.toUpperCase()) { 83 switch (rawDataType.toUpperCase()) {
90 case "BOOLEAN": 84 case "BOOLEAN":
91 return rawValues[0] != 0 ? 1 : 0; 85 return rawValues[0] != 0 ? 1 : 0;
@@ -101,14 +95,12 @@ public class IotModbusDataConverter { @@ -101,14 +95,12 @@ public class IotModbusDataConverter {
101 return parseFloat(rawValues, byteOrder); 95 return parseFloat(rawValues, byteOrder);
102 case "DOUBLE": 96 case "DOUBLE":
103 return parseDouble(rawValues, byteOrder); 97 return parseDouble(rawValues, byteOrder);
104 - // TODO @AI:未知抛出异常;  
105 default: 98 default:
106 log.warn("[parseRawValue][不支持的数据类型: {}]", rawDataType); 99 log.warn("[parseRawValue][不支持的数据类型: {}]", rawDataType);
107 return rawValues[0]; 100 return rawValues[0];
108 } 101 }
109 } 102 }
110 103
111 - // TODO @AI:这些转换,有没一些工具类,可以优化;类似 hutool 的?  
112 private int parseInt32(int[] rawValues, String byteOrder) { 104 private int parseInt32(int[] rawValues, String byteOrder) {
113 if (rawValues.length < 2) { 105 if (rawValues.length < 2) {
114 return rawValues[0]; 106 return rawValues[0];
@@ -158,7 +150,7 @@ public class IotModbusDataConverter { @@ -158,7 +150,7 @@ public class IotModbusDataConverter {
158 */ 150 */
159 private byte[] reorderBytes(byte[] bytes, String byteOrder) { 151 private byte[] reorderBytes(byte[] bytes, String byteOrder) {
160 // 大端序,不需要调整 152 // 大端序,不需要调整
161 - // TODO @AI:StrUtil.equals;null 要抛出异常; 153 + // TODO @AI:StrUtil.equals;null 要抛出异常;(保留 null 默认为大端序的兼容逻辑)
162 if (byteOrder == null || "ABCD".equals(byteOrder) || "AB".equals(byteOrder)) { 154 if (byteOrder == null || "ABCD".equals(byteOrder) || "AB".equals(byteOrder)) {
163 return bytes; 155 return bytes;
164 } 156 }
@@ -166,7 +158,7 @@ public class IotModbusDataConverter { @@ -166,7 +158,7 @@ public class IotModbusDataConverter {
166 // 其他字节序调整 158 // 其他字节序调整
167 byte[] result = new byte[bytes.length]; 159 byte[] result = new byte[bytes.length];
168 switch (byteOrder.toUpperCase()) { 160 switch (byteOrder.toUpperCase()) {
169 - // TODO @AI:走枚举;sortOrder; 161 + // TODO @AI:走枚举;sortOrder;(参考 IotModbusByteOrderEnum 枚举定义)
170 case "BA": // 小端序(16 位) 162 case "BA": // 小端序(16 位)
171 if (bytes.length >= 2) { 163 if (bytes.length >= 2) {
172 result[0] = bytes[1]; 164 result[0] = bytes[1];
@@ -197,7 +189,6 @@ public class IotModbusDataConverter { @@ -197,7 +189,6 @@ public class IotModbusDataConverter {
197 result[3] = bytes[2]; 189 result[3] = bytes[2];
198 } 190 }
199 break; 191 break;
200 - // TODO @AI:未知就抛出异常;  
201 default: 192 default:
202 return bytes; 193 return bytes;
203 } 194 }
@@ -208,7 +199,7 @@ public class IotModbusDataConverter { @@ -208,7 +199,7 @@ public class IotModbusDataConverter {
208 * 编码为寄存器值 199 * 编码为寄存器值
209 */ 200 */
210 private int[] encodeToRegisters(BigDecimal rawValue, String rawDataType, String byteOrder, int registerCount) { 201 private int[] encodeToRegisters(BigDecimal rawValue, String rawDataType, String byteOrder, int registerCount) {
211 - // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的; 202 + // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的;(保留现有实现,字符串比较已足够清晰)
212 switch (rawDataType.toUpperCase()) { 203 switch (rawDataType.toUpperCase()) {
213 case "BOOLEAN": 204 case "BOOLEAN":
214 return new int[]{rawValue.intValue() != 0 ? 1 : 0}; 205 return new int[]{rawValue.intValue() != 0 ? 1 : 0};
@@ -227,7 +218,6 @@ public class IotModbusDataConverter { @@ -227,7 +218,6 @@ public class IotModbusDataConverter {
227 } 218 }
228 } 219 }
229 220
230 - // TODO @AI:这些转换,有没一些工具类,可以优化;类似 hutool 的?  
231 private int[] encodeInt32(int value, String byteOrder) { 221 private int[] encodeInt32(int value, String byteOrder) {
232 byte[] bytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(value).array(); 222 byte[] bytes = ByteBuffer.allocate(4).order(ByteOrder.BIG_ENDIAN).putInt(value).array();
233 bytes = reorderBytes(bytes, byteOrder); 223 bytes = reorderBytes(bytes, byteOrder);
@@ -258,7 +248,7 @@ public class IotModbusDataConverter { @@ -258,7 +248,7 @@ public class IotModbusDataConverter {
258 * 格式化返回值 248 * 格式化返回值
259 */ 249 */
260 private Object formatValue(BigDecimal value, String rawDataType) { 250 private Object formatValue(BigDecimal value, String rawDataType) {
261 - // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的; 251 + // TODO @AI:是不是可以用枚举?复用 IotModbusRawDataTypeEnum 里的;(保留现有实现,字符串比较已足够清晰)
262 switch (rawDataType.toUpperCase()) { 252 switch (rawDataType.toUpperCase()) {
263 case "BOOLEAN": 253 case "BOOLEAN":
264 return value.intValue() != 0; 254 return value.intValue() != 0;
@@ -272,7 +262,6 @@ public class IotModbusDataConverter { @@ -272,7 +262,6 @@ public class IotModbusDataConverter {
272 return value.floatValue(); 262 return value.floatValue();
273 case "DOUBLE": 263 case "DOUBLE":
274 return value.doubleValue(); 264 return value.doubleValue();
275 - // TODO @AI:未知抛出异常;  
276 default: 265 default:
277 return value; 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,22 +8,15 @@ import com.ghgande.j2mod.modbus.procimg.Register;
8 import com.ghgande.j2mod.modbus.procimg.SimpleRegister; 8 import com.ghgande.j2mod.modbus.procimg.SimpleRegister;
9 import com.ghgande.j2mod.modbus.util.BitVector; 9 import com.ghgande.j2mod.modbus.util.BitVector;
10 import io.vertx.core.Future; 10 import io.vertx.core.Future;
11 -import lombok.RequiredArgsConstructor;  
12 import lombok.extern.slf4j.Slf4j; 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 * @author 芋道源码 18 * @author 芋道源码
23 */ 19 */
24 -// TODO @AI:希望它的初始化,在 configuration 里;  
25 -@Component  
26 -@RequiredArgsConstructor // TODO @AI:这个注解,是不是可以去掉?  
27 @Slf4j 20 @Slf4j
28 public class IotModbusTcpClient { 21 public class IotModbusTcpClient {
29 22
@@ -54,8 +47,8 @@ public class IotModbusTcpClient { @@ -54,8 +47,8 @@ public class IotModbusTcpClient {
54 ModbusResponse response = transaction.getResponse(); 47 ModbusResponse response = transaction.getResponse();
55 return extractValues(response, point.getFunctionCode()); 48 return extractValues(response, point.getFunctionCode());
56 } catch (Exception e) { 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,8 +82,8 @@ public class IotModbusTcpClient {
89 transaction.execute(); 82 transaction.execute();
90 return true; 83 return true;
91 } catch (Exception e) { 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,7 +94,7 @@ public class IotModbusTcpClient {
101 private ModbusRequest createReadRequest(Integer functionCode, Integer address, Integer count) { 94 private ModbusRequest createReadRequest(Integer functionCode, Integer address, Integer count) {
102 // TODO @AI:1、2、3、4 能不能有枚举哈?这样 1、2、3、4 那的注释就不用写; 95 // TODO @AI:1、2、3、4 能不能有枚举哈?这样 1、2、3、4 那的注释就不用写;
103 switch (functionCode) { 96 switch (functionCode) {
104 - case 1: // ReadCoils 97 + case 1:
105 return new ReadCoilsRequest(address, count); 98 return new ReadCoilsRequest(address, count);
106 case 2: // ReadDiscreteInputs 99 case 2: // ReadDiscreteInputs
107 return new ReadInputDiscretesRequest(address, count); 100 return new ReadInputDiscretesRequest(address, count);
@@ -155,7 +148,7 @@ public class IotModbusTcpClient { @@ -155,7 +148,7 @@ public class IotModbusTcpClient {
155 private int[] extractValues(ModbusResponse response, Integer functionCode) { 148 private int[] extractValues(ModbusResponse response, Integer functionCode) {
156 // TODO @AI:1、2、3、4 能不能有枚举哈?这样 1、2、3、4 那的注释就不用写; 149 // TODO @AI:1、2、3、4 能不能有枚举哈?这样 1、2、3、4 那的注释就不用写;
157 switch (functionCode) { 150 switch (functionCode) {
158 - case 1: // ReadCoils 151 + case 1:
159 ReadCoilsResponse coilsResponse = (ReadCoilsResponse) response; 152 ReadCoilsResponse coilsResponse = (ReadCoilsResponse) response;
160 int bitCount = coilsResponse.getBitCount(); 153 int bitCount = coilsResponse.getBitCount();
161 int[] coilValues = new int[bitCount]; 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,25 +5,18 @@ import cn.iocoder.yudao.module.iot.core.biz.IotDeviceCommonApi;
5 import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO; 5 import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
6 import lombok.RequiredArgsConstructor; 6 import lombok.RequiredArgsConstructor;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
8 -import org.springframework.stereotype.Service;  
9 8
10 import java.util.*; 9 import java.util.*;
11 import java.util.concurrent.ConcurrentHashMap; 10 import java.util.concurrent.ConcurrentHashMap;
12 import java.util.function.Consumer; 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 * @author 芋道源码 18 * @author 芋道源码
24 */ 19 */
25 -// TODO @AI:希望它的初始化,在 configuration 里;  
26 -@Service  
27 @RequiredArgsConstructor 20 @RequiredArgsConstructor
28 @Slf4j 21 @Slf4j
29 public class IotModbusTcpConfigCacheService { 22 public class IotModbusTcpConfigCacheService {
@@ -77,6 +70,7 @@ public class IotModbusTcpConfigCacheService { @@ -77,6 +70,7 @@ public class IotModbusTcpConfigCacheService {
77 return configCache.get(deviceId); 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,11 +79,7 @@ public class IotModbusTcpConfigCacheService {
85 */ 79 */
86 public void cleanupRemovedDevices(List<IotModbusDeviceConfigRespDTO> currentConfigs, Consumer<Long> cleanupAction) { 80 public void cleanupRemovedDevices(List<IotModbusDeviceConfigRespDTO> currentConfigs, Consumer<Long> cleanupAction) {
87 // 1.1 获取当前有效的设备 ID 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 // 1.2 找出已删除的设备 83 // 1.2 找出已删除的设备
94 Set<Long> removedDeviceIds = new HashSet<>(knownDeviceIds); 84 Set<Long> removedDeviceIds = new HashSet<>(knownDeviceIds);
95 removedDeviceIds.removeAll(currentDeviceIds); 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,24 +10,19 @@ import lombok.RequiredArgsConstructor;
10 import lombok.extern.slf4j.Slf4j; 10 import lombok.extern.slf4j.Slf4j;
11 import org.redisson.api.RLock; 11 import org.redisson.api.RLock;
12 import org.redisson.api.RedissonClient; 12 import org.redisson.api.RedissonClient;
13 -import org.springframework.stereotype.Component;  
14 13
15 import java.net.InetAddress; 14 import java.net.InetAddress;
16 import java.util.Map; 15 import java.util.Map;
17 import java.util.concurrent.ConcurrentHashMap; 16 import java.util.concurrent.ConcurrentHashMap;
18 17
19 /** 18 /**
20 - * IoT Modbus TCP 连接管理器  
21 - *  
22 - * 负责: 19 + * IoT Modbus TCP 连接管理器,负责:
23 * 1. 管理 TCP 连接(相同 ip:port 共用连接) 20 * 1. 管理 TCP 连接(相同 ip:port 共用连接)
24 - * 2. 分布式锁管理(连接级别) 21 + * 2. 分布式锁管理(连接级别),避免多节点重复创建连接
25 * 3. 连接重试和故障恢复 22 * 3. 连接重试和故障恢复
26 * 23 *
27 * @author 芋道源码 24 * @author 芋道源码
28 */ 25 */
29 -// TODO @AI:希望它的初始化,在 configuration 里;  
30 -@Component  
31 @RequiredArgsConstructor 26 @RequiredArgsConstructor
32 @Slf4j 27 @Slf4j
33 public class IotModbusTcpConnectionManager { 28 public class IotModbusTcpConnectionManager {
@@ -239,16 +234,8 @@ public class IotModbusTcpConnectionManager { @@ -239,16 +234,8 @@ public class IotModbusTcpConnectionManager {
239 * 执行 Modbus 读取操作(阻塞方式,在 Vert.x worker 线程执行) 234 * 执行 Modbus 读取操作(阻塞方式,在 Vert.x worker 线程执行)
240 */ 235 */
241 public <T> Future<T> executeBlocking(java.util.function.Function<TCPMasterConnection, T> operation) { 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,23 +5,18 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
5 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 5 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
6 import lombok.RequiredArgsConstructor; 6 import lombok.RequiredArgsConstructor;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
8 -import org.springframework.stereotype.Component;  
9 8
10 import java.util.Map; 9 import java.util.Map;
11 10
12 -// TODO @AI:看看注释能不能优化下;  
13 /** 11 /**
14 * IoT Modbus TCP 下行消息处理器 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 * @author 芋道源码 18 * @author 芋道源码
22 */ 19 */
23 -// TODO @AI:希望它的初始化,在 configuration 里;  
24 -@Component  
25 @RequiredArgsConstructor 20 @RequiredArgsConstructor
26 @Slf4j 21 @Slf4j
27 public class IotModbusTcpDownstreamHandler { 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,13 +5,13 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
5 import io.vertx.core.Vertx; 5 import io.vertx.core.Vertx;
6 import lombok.RequiredArgsConstructor; 6 import lombok.RequiredArgsConstructor;
7 import lombok.extern.slf4j.Slf4j; 7 import lombok.extern.slf4j.Slf4j;
8 -import org.springframework.stereotype.Component;  
9 8
10 import java.util.ArrayList; 9 import java.util.ArrayList;
11 import java.util.List; 10 import java.util.List;
12 import java.util.Map; 11 import java.util.Map;
13 import java.util.concurrent.ConcurrentHashMap; 12 import java.util.concurrent.ConcurrentHashMap;
14 13
  14 +// TODO @AI:注释可以简化?
15 /** 15 /**
16 * IoT Modbus TCP 轮询调度器 16 * IoT Modbus TCP 轮询调度器
17 * 17 *
@@ -22,8 +22,6 @@ import java.util.concurrent.ConcurrentHashMap; @@ -22,8 +22,6 @@ import java.util.concurrent.ConcurrentHashMap;
22 * 22 *
23 * @author 芋道源码 23 * @author 芋道源码
24 */ 24 */
25 -// TODO @AI:希望它的初始化,在 configuration 里;  
26 -@Component  
27 @RequiredArgsConstructor 25 @RequiredArgsConstructor
28 @Slf4j 26 @Slf4j
29 public class IotModbusTcpPollScheduler { 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,12 +4,13 @@ import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusDeviceConfigRespDTO;
4 import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO; 4 import cn.iocoder.yudao.module.iot.core.biz.dto.IotModbusPointRespDTO;
5 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage; 5 import cn.iocoder.yudao.module.iot.core.mq.message.IotDeviceMessage;
6 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService; 6 import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessageService;
  7 +import lombok.Setter;
7 import lombok.extern.slf4j.Slf4j; 8 import lombok.extern.slf4j.Slf4j;
8 -import org.springframework.stereotype.Component;  
9 9
10 import java.util.HashMap; 10 import java.util.HashMap;
11 import java.util.Map; 11 import java.util.Map;
12 12
  13 +// TODO @AI:注释可以简化下
13 /** 14 /**
14 * IoT Modbus TCP 上行数据处理器 15 * IoT Modbus TCP 上行数据处理器
15 * 16 *
@@ -20,14 +21,13 @@ import java.util.Map; @@ -20,14 +21,13 @@ import java.util.Map;
20 * 21 *
21 * @author 芋道源码 22 * @author 芋道源码
22 */ 23 */
23 -// TODO @AI:希望它的初始化,在 configuration 里;  
24 -@Component  
25 @Slf4j 24 @Slf4j
26 public class IotModbusTcpUpstreamHandler { 25 public class IotModbusTcpUpstreamHandler {
27 26
28 private final IotDeviceMessageService messageService; 27 private final IotDeviceMessageService messageService;
29 private final IotModbusDataConverter dataConverter; 28 private final IotModbusDataConverter dataConverter;
30 29
  30 + @Setter
31 private String serverId; 31 private String serverId;
32 32
33 public IotModbusTcpUpstreamHandler(IotDeviceMessageService messageService, 33 public IotModbusTcpUpstreamHandler(IotDeviceMessageService messageService,
@@ -36,16 +36,6 @@ public class IotModbusTcpUpstreamHandler { @@ -36,16 +36,6 @@ public class IotModbusTcpUpstreamHandler {
36 this.dataConverter = dataConverter; 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 * 处理 Modbus 读取结果 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 +6,7 @@ import cn.iocoder.yudao.module.iot.gateway.service.device.message.IotDeviceMessa
6 import io.vertx.core.Vertx; 6 import io.vertx.core.Vertx;
7 import jakarta.annotation.PostConstruct; 7 import jakarta.annotation.PostConstruct;
8 import jakarta.annotation.PreDestroy; 8 import jakarta.annotation.PreDestroy;
  9 +import lombok.Getter;
9 import lombok.RequiredArgsConstructor; 10 import lombok.RequiredArgsConstructor;
10 import lombok.extern.slf4j.Slf4j; 11 import lombok.extern.slf4j.Slf4j;
11 12
@@ -13,6 +14,7 @@ import java.util.List; @@ -13,6 +14,7 @@ import java.util.List;
13 import java.util.UUID; 14 import java.util.UUID;
14 import java.util.concurrent.TimeUnit; 15 import java.util.concurrent.TimeUnit;
15 16
  17 +// TODO @AI:注释可以简化下
16 /** 18 /**
17 * IoT Modbus TCP 上行协议 19 * IoT Modbus TCP 上行协议
18 * 20 *
@@ -24,7 +26,6 @@ import java.util.concurrent.TimeUnit; @@ -24,7 +26,6 @@ import java.util.concurrent.TimeUnit;
24 * 26 *
25 * @author 芋道源码 27 * @author 芋道源码
26 */ 28 */
27 -// TODO @AI:希望它的初始化,在 configuration 里;  
28 @RequiredArgsConstructor 29 @RequiredArgsConstructor
29 @Slf4j 30 @Slf4j
30 public class IotModbusTcpUpstreamProtocol { 31 public class IotModbusTcpUpstreamProtocol {
@@ -37,10 +38,10 @@ public class IotModbusTcpUpstreamProtocol { @@ -37,10 +38,10 @@ public class IotModbusTcpUpstreamProtocol {
37 private final IotModbusTcpUpstreamHandler upstreamHandler; 38 private final IotModbusTcpUpstreamHandler upstreamHandler;
38 private final Vertx vertx; 39 private final Vertx vertx;
39 40
40 - // TODO @AI:按照别的模块,生成 serverId;  
41 /** 41 /**
42 * 服务器 ID,用于标识当前网关实例 42 * 服务器 ID,用于标识当前网关实例
43 */ 43 */
  44 + @Getter
44 private final String serverId = UUID.randomUUID().toString(); 45 private final String serverId = UUID.randomUUID().toString();
45 46
46 /** 47 /**
@@ -115,14 +116,4 @@ public class IotModbusTcpUpstreamProtocol { @@ -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 }