From 46f9bd6cb9c9c7468728af93180819bf69c4e9dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=BE=BE=E5=AF=8C=E6=96=8C?= Date: Fri, 19 Sep 2025 17:32:24 +0800 Subject: [PATCH] =?UTF-8?q?feat=20(farm):=20=E8=AE=BE=E5=A4=87=E7=AE=A1?= =?UTF-8?q?=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 本服务接口 - 对接第三方设备商 --- .../admin/baseinfo/BaseInfoController.java | 17 +- .../admin/baseinfo/vo/BaseNamesRespVO.java | 20 ++ .../DeviceClassifyController.java | 18 +- .../deviceclassify/vo/DeviceModelRespVO.java | 25 ++ .../deviceclassify/vo/DeviceTypeRespVO.java | 29 +++ .../deviceinfo/DeviceInfoController.java | 39 +++- .../deviceinfo/vo/DeviceInfoPageReqVO.java | 6 +- .../admin/deviceinfo/vo/DeviceInfoRespVO.java | 7 +- .../deviceinfo/vo/DeviceInfoSaveReqVO.java | 6 +- .../vo/v2/DeviceInfoDetailV2RespVO.java | 73 ++++++ .../vo/v2/DeviceInfoPageV2ReqVO.java | 27 +++ .../vo/v2/DeviceInfoPageV2RespVO.java | 49 ++++ .../vo/v2/DeviceInfoSaveV2ReqVO.java | 45 ++++ .../vo/v2/DeviceStatisticsRespVO.java | 27 +++ .../devicestatus/DeviceStatusController.java | 6 +- .../dataobject/deviceinfo/DeviceInfoDO.java | 25 +- .../mysql/deviceinfo/DeviceInfoMapper.java | 16 +- .../module/farm/enums/ErrorCodeConstants.java | 6 + .../farm/manager/devices/DeviceManager.java | 13 ++ .../manager/devices/commons/DeviceConst.java | 79 +++++++ .../farm/manager/devices/conf/DeviceConf.java | 62 +++++ .../devices/conf/SchedulingConfig.java | 15 ++ .../devices/soil/BaseTokenCacheService.java | 204 +++++++++++++++++ .../manager/devices/soil/SoilService.java | 194 ++++++++++++++++ .../soil/dto/AlarmNoticeRecordReqVO.java | 53 +++++ .../soil/dto/AlarmNoticeRecordRespVO.java | 54 +++++ .../devices/soil/dto/DeviceAllInfoReqVO.java | 21 ++ .../devices/soil/dto/DeviceAllInfoRespVO.java | 154 +++++++++++++ .../soil/dto/HistoryDataListPageReqVO.java | 46 ++++ .../soil/dto/HistoryDataListPageRespVO.java | 62 +++++ .../devices/soil/dto/RealTimeDataReqVO.java | 23 ++ .../devices/soil/dto/RealTimeDataRespVO.java | 68 ++++++ .../devices/soil/dto/SysUserDeviceReqVO.java | 24 ++ .../devices/soil/dto/SysUserDeviceRespVO.java | 45 ++++ .../devices/soil/dto/UpdateDeviceReqVO.java | 33 +++ .../devices/soil/dto/UpdateNodeInfoReqVO.java | 81 +++++++ .../devices/soil/dto/UserLoginReqVO.java | 18 ++ .../devices/soil/dto/UserLoginRespVO.java | 32 +++ .../devices/wf/WaterFertilizerService.java | 90 ++++++++ .../devices/wf/dto/DevicePageRespVO.java | 51 +++++ .../manager/devices/wf/dto/LoginReqVO.java | 18 ++ .../manager/devices/wf/dto/LoginRespVO.java | 19 ++ .../wf/dto/RealTimeDeviceDataRespVO.java | 35 +++ .../wf/dto/UpdateDeviceStatusRespVO.java | 18 ++ .../service/baseinfo/BaseInfoServiceImpl.java | 3 + .../deviceclassify/DeviceClassifyService.java | 3 + .../DeviceClassifyServiceImpl.java | 38 ++++ .../service/deviceinfo/DeviceInfoService.java | 7 + .../deviceinfo/DeviceInfoServiceImpl.java | 6 + .../devicestatus/DeviceStatusServiceImpl.java | 14 +- .../farm/service/home/HomeServiceImpl.java | 3 + .../module/farm/utils/HttpClientUtils.java | 215 ++++++++++++++++++ .../mapper/deviceinfo/DeviceInfoMapper.xml | 20 ++ .../src/main/resources/application.yaml | 35 ++- 54 files changed, 2256 insertions(+), 41 deletions(-) create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/vo/BaseNamesRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceModelRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceTypeRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoDetailV2RespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2ReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2RespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoSaveV2ReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceStatisticsRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/DeviceManager.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/commons/DeviceConst.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/DeviceConf.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/SchedulingConfig.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/BaseTokenCacheService.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/SoilService.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateDeviceReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateNodeInfoReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/WaterFertilizerService.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/DevicePageRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginReqVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/RealTimeDeviceDataRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/UpdateDeviceStatusRespVO.java create mode 100644 yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/HttpClientUtils.java diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/BaseInfoController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/BaseInfoController.java index 2d9da630..225997c9 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/BaseInfoController.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/BaseInfoController.java @@ -109,11 +109,24 @@ public class BaseInfoController { BeanUtils.toBean(list, BaseInfoRespVO.class)); } + @GetMapping("/base/plot/list") + @Operation(summary = "基地-地块列表") + public CommonResult> getBasePlotList() { + List res = baseInfoService.getBaseListForWx(); + return success(res); + } + + @GetMapping("/base/list") + @Operation(summary = "基地列表") + public CommonResult> getBaseList() { + List baseInfos = baseInfoService.getBaseInfos(); + List res = baseInfos.stream().map(e -> new BaseNamesRespVO(e.getId(),e.getName())).toList(); + return success(res); + } + /** * === === 微信端 === === */ -// @GetMapping("/wx/base/list") -// @Operation(summary = "微信端-常用地块集合") @GetMapping("/wx/base/list") @Operation(summary = "基地列表(微信端)") public CommonResult> getBaseListForWx() { diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/vo/BaseNamesRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/vo/BaseNamesRespVO.java new file mode 100644 index 00000000..051d9343 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/baseinfo/vo/BaseNamesRespVO.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.farm.controller.admin.baseinfo.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: binda + * @date: 2025/9/19 16:08 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class BaseNamesRespVO { + + private String baseId; + private String baseName; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/DeviceClassifyController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/DeviceClassifyController.java index 16e03843..66cf06df 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/DeviceClassifyController.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/DeviceClassifyController.java @@ -6,9 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; -import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceClassifyPageReqVO; -import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceClassifyRespVO; -import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceClassifySaveReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.*; import cn.iocoder.yudao.module.farm.dal.dataobject.deviceclassify.DeviceClassifyDO; import cn.iocoder.yudao.module.farm.service.deviceclassify.DeviceClassifyService; import io.swagger.v3.oas.annotations.Operation; @@ -106,4 +104,18 @@ public class DeviceClassifyController { BeanUtils.toBean(list, DeviceClassifyRespVO.class)); } + @GetMapping("/device-type/list") + @Operation(summary = "设备类型列表") + public CommonResult> getDeviceTypeList() { + List res = deviceClassifyService.getDeviceTypeList(); + return success(res); + } + + @GetMapping("/device-model/list") + @Operation(summary = "设备型号列表") + public CommonResult> getDeviceModelList(String deviceTypeId) { + List res = deviceClassifyService.getDeviceModelList(deviceTypeId); + return success(res); + } + } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceModelRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceModelRespVO.java new file mode 100644 index 00000000..072df085 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceModelRespVO.java @@ -0,0 +1,25 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 设备型号 + * @author: binda + * @date: 2025/9/19 16:12 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceModelRespVO { + + @Schema(description = "设备型号ID") + private String deviceModelId; + @Schema(description = "设备型号名称") + private String deviceModelName; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceTypeRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceTypeRespVO.java new file mode 100644 index 00000000..2e8add7b --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceclassify/vo/DeviceTypeRespVO.java @@ -0,0 +1,29 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 设备类型 + * @author: binda + * @date: 2025/9/19 16:12 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceTypeRespVO { + + @Schema(description = "设备类型ID") + private String deviceTypeId; + @Schema(description = "设备类型名称") + private String deviceTypeName; + @Schema(description = "设备类型图片") + private String image; + @Schema(description = "设备类型图片集合") + private List imageList; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/DeviceInfoController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/DeviceInfoController.java index 93623b0d..6619c485 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/DeviceInfoController.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/DeviceInfoController.java @@ -9,6 +9,7 @@ import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoRespVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.*; import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO; import cn.iocoder.yudao.module.farm.dal.dataobject.mqtt.MqttConnectionDO; import cn.iocoder.yudao.module.farm.service.deviceinfo.DeviceInfoService; @@ -43,14 +44,16 @@ public class DeviceInfoController { @PostMapping("/create") @Operation(summary = "创建设备信息") - public CommonResult createDeviceInfo(@Valid @RequestBody DeviceInfoSaveReqVO createReqVO) { - return success(deviceInfoService.createDeviceInfo(createReqVO)); + public CommonResult createDeviceInfo(@Valid @RequestBody DeviceInfoSaveV2ReqVO createReqVO) { + DeviceInfoSaveReqVO targetObj = BeanUtils.toBean(createReqVO, DeviceInfoSaveReqVO.class); + return success(deviceInfoService.createDeviceInfo(targetObj)); } @PutMapping("/update") @Operation(summary = "更新设备信息") - public CommonResult updateDeviceInfo(@Valid @RequestBody DeviceInfoSaveReqVO updateReqVO) { - deviceInfoService.updateDeviceInfo(updateReqVO); + public CommonResult updateDeviceInfo(@Valid @RequestBody DeviceInfoSaveV2ReqVO updateReqVO) { + DeviceInfoSaveReqVO targetObj = BeanUtils.toBean(updateReqVO, DeviceInfoSaveReqVO.class); + deviceInfoService.updateDeviceInfo(targetObj); return success(true); } @@ -73,16 +76,24 @@ public class DeviceInfoController { @GetMapping("/get") @Operation(summary = "获得设备信息") @Parameter(name = "id", description = "编号", required = true, example = "1024") - public CommonResult getDeviceInfo(@RequestParam("id") String id) { + public CommonResult getDeviceInfo(@RequestParam("id") String id) { DeviceInfoDO deviceInfo = deviceInfoService.getDeviceInfo(id); - return success(BeanUtils.toBean(deviceInfo, DeviceInfoRespVO.class)); + return success(BeanUtils.toBean(deviceInfo, DeviceInfoDetailV2RespVO.class)); } @GetMapping("/page") @Operation(summary = "获得设备信息分页") - public CommonResult> getDeviceInfoPage(@Valid DeviceInfoPageReqVO pageReqVO) { - PageResult pageResult = deviceInfoService.getDeviceInfoPage(pageReqVO); - return success(BeanUtils.toBean(pageResult, DeviceInfoRespVO.class)); + public CommonResult> getDeviceInfoPage(@Valid DeviceInfoPageV2ReqVO pageReqVO) { + + DeviceInfoPageReqVO targetObj = new DeviceInfoPageReqVO(); + targetObj.setBaseId(pageReqVO.getBaseId()); + targetObj.setDeviceType(pageReqVO.getDeviceTypeId()); + targetObj.setDeviceName(pageReqVO.getDeviceName()); + PageResult pageResult = deviceInfoService.getDeviceInfoPage(targetObj); + + PageResult deviceInfoRespVOPageResult = BeanUtils.toBean(pageResult, DeviceInfoPageV2RespVO.class); + return success(deviceInfoRespVOPageResult); + } @GetMapping("/export-excel") @@ -106,6 +117,14 @@ public class DeviceInfoController { } catch (MqttException e) { return error(500, "设备连接失败"); } - } + + @GetMapping("/statistics") + @Operation(summary = "订阅设备上报并持久化") + @Parameter(name = "baseId", description = "基地编号") + public CommonResult getStatisticsInfo(@RequestParam("baseId") String baseId) { + DeviceStatisticsRespVO res = deviceInfoService.getStatisticsInfo(baseId); + return success(res); + } + } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoPageReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoPageReqVO.java index ae539680..8e54f527 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoPageReqVO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoPageReqVO.java @@ -40,8 +40,10 @@ public class DeviceInfoPageReqVO extends PageParam { @Schema(description = "LP产品唯一ID", example = "10175") private String lpProductUniqueId; - @Schema(description = "设备状态", example = "2") - private Integer status; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + @Schema(description = "绑定状态:1: 绑定; 0: 未绑定") + private Integer bindingState; @Schema(description = "设备类型", example = "2") private String deviceType; diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoRespVO.java index 1373496b..f18e5623 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoRespVO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoRespVO.java @@ -52,9 +52,10 @@ public class DeviceInfoRespVO { @ExcelProperty("LP产品唯一ID") private String lpProductUniqueId; - @Schema(description = "设备状态", example = "2") - @ExcelProperty("设备状态") - private Integer status; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + @Schema(description = "绑定状态:1: 绑定; 0: 未绑定") + private Integer bindingState; @Schema(description = "设备类型", example = "2") @ExcelProperty("设备类型") diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoSaveReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoSaveReqVO.java index 00c11fc4..a0af35db 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoSaveReqVO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/DeviceInfoSaveReqVO.java @@ -42,8 +42,10 @@ public class DeviceInfoSaveReqVO { @Schema(description = "LP产品唯一ID", example = "10175") private String lpProductUniqueId; - @Schema(description = "设备状态", example = "2") - private Integer status; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + @Schema(description = "绑定状态:1: 绑定; 0: 未绑定") + private Integer bindingState; @Schema(description = "设备类型", example = "2") private String deviceType; diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoDetailV2RespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoDetailV2RespVO.java new file mode 100644 index 00000000..6cb716bb --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoDetailV2RespVO.java @@ -0,0 +1,73 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 设备详情 请求实体 + * @author: binda + * @date: 2025/9/19 09:47 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceInfoDetailV2RespVO { + + private String id; + + @Schema(description = "设备全局唯一标识(设备厂商提供)", requiredMode = Schema.RequiredMode.REQUIRED) + private String deviceUniqueId; + + @Schema(description = "设备类型 (设备类型ID)") + private String deviceType; + + @Schema(description = "设备分类名称 (设备型号,字符拼接)") + private String deviceCategoryName; + + @Schema(description = "设备名称(本服务自定义名称)") + private String deviceName; + + @Schema(description = "负责人") + private String managerId; + @Schema(description = "是否存在物联网卡 (1:有;2:无;)") + private Boolean isIotCardExisted; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + @Schema(description = "绑定状态:1: 绑定; 0: 未绑定") + private Integer bindingState; + @Schema(description = "设备坐标") + private String point; + + @Schema(description = "基地iD") + private String baseId; + @Schema(description = "基地坐标") + private String basePoint; + @Schema(description = "地块ID") + private String plotId; + @Schema(description = "地块坐标") + private String plotPoint; + + @Schema(description = "土壤墒情") + private SoilInfo soilInfo; + @Schema(description = "水肥机") + private WfInfo wfInfo; + + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class SoilInfo{ + private String deviceUniqueId; + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class WfInfo{ + private String deviceUniqueId; + } + + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2ReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2ReqVO.java new file mode 100644 index 00000000..9586b275 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2ReqVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: + * @author: binda + * @date: 2025/9/19 15:35 + */ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class DeviceInfoPageV2ReqVO { + + @Schema(description = "基地ID") + private String baseId; + @Schema(description = "设备类型ID") + private String deviceTypeId; + @Schema(description = "设备名称") + private String deviceName; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2RespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2RespVO.java new file mode 100644 index 00000000..7818c279 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoPageV2RespVO.java @@ -0,0 +1,49 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * @description: 分页查询 + * @author: binda + * @date: 2025/9/19 14:22 + */ +@Data +public class DeviceInfoPageV2RespVO extends PageParam { + + private String id; + + @Schema(description = "设备全局唯一标识(设备厂商提供)", requiredMode = Schema.RequiredMode.REQUIRED) + private String deviceUniqueId; + + @Schema(description = "设备类型 (设备类型ID)") + private String deviceType; + + @Schema(description = "设备分类名称 (设备型号,字符拼接)") + private String deviceCategoryName; + + @Schema(description = "设备名称(本服务自定义名称)") + private String deviceName; + + @Schema(description = "负责人") + private String managerId; + @Schema(description = "是否存在物联网卡 (1:有;2:无;)") + private Boolean isIotCardExisted; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + @Schema(description = "绑定状态:1: 绑定; 0: 未绑定") + private Integer bindingState; + @Schema(description = "设备坐标") + private String point; + + @Schema(description = "基地iD") + private String baseId; + @Schema(description = "基地坐标") + private String basePoint; + @Schema(description = "地块ID") + private String plotId; + @Schema(description = "地块坐标") + private String plotPoint; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoSaveV2ReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoSaveV2ReqVO.java new file mode 100644 index 00000000..6f86a7f1 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceInfoSaveV2ReqVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 新增设备 请求实体 + * @author: binda + * @date: 2025/9/19 09:47 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceInfoSaveV2ReqVO { + + private String id; + + @Schema(description = "设备全局唯一标识(设备厂商提供)", requiredMode = Schema.RequiredMode.REQUIRED) + private String deviceUniqueId; + + @Schema(description = "设备类型 (设备类型ID)") + private String deviceType; + + @Schema(description = "设备分类名称 (设备型号,字符拼接)") + private String deviceCategoryName; + + @Schema(description = "设备名称(本服务自定义名称)") + private String deviceName; + + @Schema(description = "负责人") + private String managerId; + @Schema(description = "是否存在物联网卡 (1:有;0:无;)") + private Boolean isIotCardExisted; + @Schema(description = "设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障") + private Integer deviceState; + @Schema(description = "绑定状态:1: 绑定; 0: 未绑定") + private Integer bindingState; + private String baseId; + private String plotId; + @Schema(description = "设备坐标") + private String point; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceStatisticsRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceStatisticsRespVO.java new file mode 100644 index 00000000..24bac373 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/deviceinfo/vo/v2/DeviceStatisticsRespVO.java @@ -0,0 +1,27 @@ +package cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 设备统计 + * @author: binda + * @date: 2025/9/19 15:48 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceStatisticsRespVO { + + @Schema(description = "设备总数") + private Integer deviceTotal; + @Schema(description = "在线总数") + private Integer deviceOnline; + @Schema(description = "离线总数") + private Integer deviceOffline; + @Schema(description = "异常总数") + private Integer deviceWarning; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/devicestatus/DeviceStatusController.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/devicestatus/DeviceStatusController.java index b21ea3bc..ed0e16ef 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/devicestatus/DeviceStatusController.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/controller/admin/devicestatus/DeviceStatusController.java @@ -54,11 +54,11 @@ public class DeviceStatusController { } DeviceStatusRespVO respVO = BeanUtils.toBean(device, DeviceStatusRespVO.class); - if (device.getState() != null) { - DeviceStateEnum stateEnum = DeviceStateEnum.valueOf(device.getState()); + if (device.getDeviceState() != null) { + DeviceStateEnum stateEnum = DeviceStateEnum.valueOf(device.getDeviceState()); if (stateEnum != null) { respVO.setStateName(stateEnum.getName()); - respVO.setOnline(DeviceStateEnum.isOnline(device.getState())); + respVO.setOnline(DeviceStateEnum.isOnline(device.getDeviceState())); } } return success(respVO); diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java index a4c632b4..99f05273 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/dataobject/deviceinfo/DeviceInfoDO.java @@ -23,12 +23,11 @@ import cn.iocoder.yudao.module.farm.framework.util.ImageCollectionUtil; @NoArgsConstructor @AllArgsConstructor public class DeviceInfoDO extends BaseDO { - + @TableId(type = IdType.INPUT) private String id; /** - * 设备全局唯一标识 + * 设备全局唯一标识 (设备商提供) */ - @TableId(type = IdType.INPUT) private String deviceUniqueId; /** * 设备名称 @@ -166,7 +165,11 @@ public class DeviceInfoDO extends BaseDO { /** * 设备状态:0-未激活,1-在线,2-离线,3-维护中,4-故障 */ - private Integer state; + private Integer deviceState; + /** + * 绑定状态:1: 绑定; 0: 未绑定 + */ + private Integer bindingState; /** * 设备激活时间 @@ -212,6 +215,20 @@ public class DeviceInfoDO extends BaseDO { private String tenantId; private String point; + /** + * 负责人 + */ + private String managerId; + + + + + + + + + + /** * 获取设备图片集合 */ diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/deviceinfo/DeviceInfoMapper.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/deviceinfo/DeviceInfoMapper.java index ff96269c..18bc2e63 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/deviceinfo/DeviceInfoMapper.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/dal/mysql/deviceinfo/DeviceInfoMapper.java @@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceStatisticsRespVO; import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -30,7 +31,7 @@ public interface DeviceInfoMapper extends BaseMapperX { .eqIfPresent(DeviceInfoDO::getLpProductKey, reqVO.getLpProductKey()) .likeIfPresent(DeviceInfoDO::getLpProductName, reqVO.getLpProductName()) .eqIfPresent(DeviceInfoDO::getLpProductUniqueId, reqVO.getLpProductUniqueId()) - .eqIfPresent(DeviceInfoDO::getStatus, reqVO.getStatus()) + .eqIfPresent(DeviceInfoDO::getStatus, reqVO.getDeviceState()) .eqIfPresent(DeviceInfoDO::getDeviceType, reqVO.getDeviceType()) .eqIfPresent(DeviceInfoDO::getType, reqVO.getType()) .eqIfPresent(DeviceInfoDO::getVendor, reqVO.getVendor()) @@ -62,7 +63,7 @@ public interface DeviceInfoMapper extends BaseMapperX { */ default List selectListByState(Integer state) { return selectList(new LambdaQueryWrapperX() - .eq(DeviceInfoDO::getState, state)); + .eq(DeviceInfoDO::getDeviceState, state)); } /** @@ -70,7 +71,7 @@ public interface DeviceInfoMapper extends BaseMapperX { */ default List selectTimeoutDevices(@Param("timeoutTime") LocalDateTime timeoutTime) { return selectList(new LambdaQueryWrapperX() - .eq(DeviceInfoDO::getState, 1) // 只查询在线状态的设备 + .eq(DeviceInfoDO::getDeviceState, 1) // 只查询在线状态的设备 .and(wrapper -> wrapper .isNull(DeviceInfoDO::getLastMessageTime) // 从未上报过消息 .or() @@ -83,7 +84,14 @@ public interface DeviceInfoMapper extends BaseMapperX { */ default Long selectCountByState(Integer state) { return selectCount(new LambdaQueryWrapperX() - .eq(DeviceInfoDO::getState, state)); + .eq(DeviceInfoDO::getDeviceState, state)); } + /** + * 设备统计信息 + * @param baseId + * @return + */ + DeviceStatisticsRespVO getStatisticsInfo(@Param("baseId") String baseId, + @Param("tenantId") String tenantId); } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/enums/ErrorCodeConstants.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/enums/ErrorCodeConstants.java index 74a9ec57..2bbc54ca 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/enums/ErrorCodeConstants.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/enums/ErrorCodeConstants.java @@ -26,6 +26,12 @@ public interface ErrorCodeConstants { // ========== 设备信息 1-050-004-000 ========== ErrorCode DEVICE_INFO_NOT_EXISTS = new ErrorCode(1_050_004_000, "设备信息不存在"); + ErrorCode DEVICE_INFO_NOT_EXISTS_FOR_USER_LOGIN = new ErrorCode(1_050_004_001, "物连网农业四情采集,登录失败"); + ErrorCode DEVICE_INFO_NOT_EXISTS_FOR_USER_DEVICE = new ErrorCode(1_050_004_002, "获取用户设备失败"); + ErrorCode DEVICE_INFO_NOT_EXISTS_FOR_REAL_TIME_DATA= new ErrorCode(1_050_004_003, "获取设备实时数据失败"); + ErrorCode DEVICE_INFO_NOT_EXISTS_FOR_ALARM_NOTICE_RECORD= new ErrorCode(1_050_004_004, "获取设备报警通知记录失败"); + ErrorCode DEVICE_INFO_NOT_EXISTS_FOR_WF_LOGIN= new ErrorCode(1_050_004_005, "水肥机登录失败"); + ErrorCode DEVICE_TYPE_ERROR= new ErrorCode(1_050_004_006, "未找到对应的设备类型"); // ========== 设备地块关系 1-050-005-000 ========== ErrorCode DEVICE_PLOT_RELATION_NOT_EXISTS = new ErrorCode(1_050_005_000, "设备地块关系不存在"); diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/DeviceManager.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/DeviceManager.java new file mode 100644 index 00000000..61e70d9c --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/DeviceManager.java @@ -0,0 +1,13 @@ +package cn.iocoder.yudao.module.farm.manager.devices; + +import org.springframework.stereotype.Service; + +/** + * @description: 设备管理 + * 参考文档: 物连网农业四情采集api协议.pdf 版本:v2.0.3 日期:2022.08.16 + * @author: binda + * @date: 2025/9/17 10:50 + */ +@Service +public class DeviceManager { +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/commons/DeviceConst.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/commons/DeviceConst.java new file mode 100644 index 00000000..143cacc0 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/commons/DeviceConst.java @@ -0,0 +1,79 @@ +package cn.iocoder.yudao.module.farm.manager.devices.commons; + +/** + * @description: 设备常量 + * @author: binda + * @date: 2025/9/17 15:24 + */ +public class DeviceConst { + + /** + * 四情 设备类型 + */ + public final String DEVICE_TYPE_IRRIGATION = "irrigation"; // 灌溉 + public final String DEVICE_TYPE_WORM = "worm"; // 虫害 + public final String DEVICE_TYPE_WORM_FLAG_SHIP = "wormFlagship"; + public final String DEVICE_TYPE_SOIL = "soil"; // 土壤 + public final String DEVICE_TYPE_MET = "met"; // 重金属 + public final String DEVICE_TYPE_SPORE = "spore"; // 孢子 + public final String DEVICE_TYPE_CAMERA = "camera"; // 监控 + + /** + * 四情 设备状态 + */ + public final String DEVICE_STATUS_ONLINE = "online"; + public final String DEVICE_STATUS_OFFLINE = "offline"; + public final String DEVICE_STATUS_ALARM = "alarm"; + + /** + * 四情 http 状态 + */ + public final String HTTP_STATUS_1000 = "1000"; // 成功 + public final String HTTP_STATUS_1001 = "1001"; // 失败 (执行错误) + public final String HTTP_STATUS_1002 = "1002"; // 失败 (验证失败) + public final String HTTP_STATUS_1003 = "1003"; // 服务端异常 + public final String HTTP_STATUS_1004 = "1004"; // 登录过期 + public final String HTTP_STATUS_2000 = "2000"; // 登录超时 + public final String HTTP_STATUS_4000 = "4000"; // 未登录或登录失败 + public final String HTTP_STATUS_5000 = "5000"; // 操作失败 + + /** + * 四情-墒情 设备实时数据 - 节点类型 + */ + public final int NODE_TYPE_1 = 1; // 模拟量 + public final int NODE_TYPE_1_1 = 1; // 模拟量 使能模拟量 + public final int NODE_TYPE_1_2 = 2; // 模拟量 使能 + + public final int NODE_TYPE_2 = 2; // 模拟量 + public final int NODE_TYPE_2_1 = 1; // 模拟量 使能模拟量 + public final int NODE_TYPE_2_2 = 2; // 模拟量 禁用 + + public final int NODE_TYPE_3 = 3; // 模拟量 + public final int NODE_TYPE_3_1 = 1; // 模拟量 禁用模拟量 + public final int NODE_TYPE_3_2 = 2; // 模拟量 使能 + + public final int NODE_TYPE_4 = 4; // 浮点型设备 + public final int NODE_TYPE_5 = 5; // 开关量型设备 + public final int NODE_TYPE_6 = 6; // 32位有符号整型 + public final int NODE_TYPE_7 = 7; // 32位无符号整型 + public final int NODE_TYPE_8 = 8; // 遥调设备 + + /** + * 四情-墒情 设备实时数据 - 节点报警等级 + */ + public final int ALARM_STATUS_0 = 0; // 正常 + public final int ALARM_STATUS_1 = 1; // 超上限报警 + public final int ALARM_STATUS_2 = 2; // 超下限报警 + public final int ALARM_STATUS_3 = 3; // 开关闭合报警 + public final int ALARM_STATUS_4 = 4; // 开关断开报警 + public final int ALARM_STATUS_5 = 5; // 遥调报警 + + /** + * 四情-设备报警通知记录 - 通知类型 + */ + public final int NOTICE_TYPE_0 = 0; // 邮箱 + public final int NOTICE_TYPE_1 = 1; // 短信 + + // TODO: 2025/9/17 UpdateNodeInfoReqVO + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/DeviceConf.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/DeviceConf.java new file mode 100644 index 00000000..f8e9e447 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/DeviceConf.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.farm.manager.devices.conf; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * @description: 设备配置 + * @author: binda + * @date: 2025/9/17 10:55 + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "device-manager") +public class DeviceConf { + + private FourSituations fourSituations; + private WaterAndFertilizer waterAndFertilizer; + + @Data + public static class FourSituations { + private String hosts; + private String username; + private String password; + private Global global; + private Soil soil; + } + + @Data + public static class Global { + private String url21; // 用户登录 + private String url22; // 获取登录用户信息 + private String url23; // 获取子用户信息 + private String url24; // 设备报警通知记录 + private String url25; // 获取用户区域 + private String url26; // 获取用户设备 + private String url27; // 批量获取摄像头设备信息 + private String url28; // 获取设备实时数据 + private String url29; // 区域绑定设备 + } + + @Data + public static class Soil { + private String url41; // 墒情设备, 获取设备全部信息 + private String url42; // 墒情设备, 更新设备信息 + private String url43; // 墒情设备, 更新节点信息 + private String url44; // 墒情设备, 获取历史数据 + } + + @Data + public static class WaterAndFertilizer { + private String hosts; + private String username; + private String password; + private String url1; + private String url2; + private String url3; + private String url4; + } + + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/SchedulingConfig.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/SchedulingConfig.java new file mode 100644 index 00000000..2b3cc9a1 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/conf/SchedulingConfig.java @@ -0,0 +1,15 @@ +package cn.iocoder.yudao.module.farm.manager.devices.conf; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; + +/** + * @description: + * @author: binda + * @date: 2025/9/17 14:42 + */ +@Configuration +@EnableScheduling +public class SchedulingConfig { + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/BaseTokenCacheService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/BaseTokenCacheService.java new file mode 100644 index 00000000..ef0a6f6f --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/BaseTokenCacheService.java @@ -0,0 +1,204 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil; + +import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.UserLoginRespVO; +import lombok.extern.slf4j.Slf4j; +import org.springframework.scheduling.annotation.Scheduled; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + + +/** + * @description: 缓存token + * @author: binda + * @date: 2025/9/17 14:33 + */ +@Slf4j +public abstract class BaseTokenCacheService { + + // 使用ConcurrentHashMap存储token信息,key: tenantId, value: token + private final Map tokenCache = new ConcurrentHashMap<>(); + // 存储token详细信息,key: token, value: UserLoginRespVO + private final Map tokenDetailCache = new ConcurrentHashMap<>(); + + /** + * 每30分钟清理一次过期token + */ + @Scheduled(fixedRate = 30 * 60 * 1000) // 30分钟,单位毫秒 + public void cleanExpiredTokens() { + long currentTime = System.currentTimeMillis() / 1000; + int initialTokenCount = tokenDetailCache.size(); + int initialTenantCount = tokenCache.size(); + + // 清理过期的token详情 + tokenDetailCache.entrySet().removeIf(entry -> + entry.getValue() != null && entry.getValue().expDate <= currentTime + ); + + // 同步清理租户ID映射 + tokenCache.entrySet().removeIf(entry -> { + String token = entry.getValue(); + UserLoginRespVO tokenInfo = tokenDetailCache.get(token); + return tokenInfo == null || tokenInfo.expDate <= currentTime; + }); + + int finalTokenCount = tokenDetailCache.size(); + int finalTenantCount = tokenCache.size(); + int removedTokenCount = initialTokenCount - finalTokenCount; + int removedTenantCount = initialTenantCount - finalTenantCount; + + log.info("Token缓存清理完成: 清理前 {} 个token({} 租户), 清理后 {} 个token({} 租户), 移除 {} 个过期token({} 租户)", + initialTokenCount, initialTenantCount, + finalTokenCount, finalTenantCount, + removedTokenCount, removedTenantCount); + } + + /** + * 缓存token(基于租户ID) + */ + protected void cacheToken(String tenantId, UserLoginRespVO loginRespVO) { + if (tenantId != null && loginRespVO != null && loginRespVO.token != null) { + // 存储租户ID到token的映射 + tokenCache.put(tenantId, loginRespVO.token); + // 存储token详细信息 + tokenDetailCache.put(loginRespVO.token, loginRespVO); + log.debug("租户 {} 的Token已缓存: {}", tenantId, loginRespVO.token); + } + } + + protected void cacheToken(String tenantId, String token) { + tokenCache.put(tenantId, token); + } + + /** + * 根据租户ID获取token + */ + protected String getTokenByTenantId(String tenantId) { + String token = tokenCache.get(tenantId); + if (token != null && isTokenValid(token)) { + log.debug("获取租户 {} 的Token: {}", tenantId, token); + return token; + } + // 如果token过期,移除映射 + if (token != null) { + tokenCache.remove(tenantId); + tokenDetailCache.remove(token); + log.debug("租户 {} 的Token已过期,已移除", tenantId); + } + return null; + } + + /** + * 根据租户ID获取token详细信息 + */ + protected UserLoginRespVO getTokenInfoByTenantId(String tenantId) { + String token = getTokenByTenantId(tenantId); + if (token != null) { + return tokenDetailCache.get(token); + } + return null; + } + + /** + * 根据token获取详细信息 + */ + protected UserLoginRespVO getTokenInfo(String token) { + UserLoginRespVO tokenInfo = tokenDetailCache.get(token); + if (tokenInfo != null && isTokenValid(tokenInfo)) { + return tokenInfo; + } + // 如果token过期,移除 + if (tokenInfo != null) { + removeTokenByValue(token); + } + return null; + } + + /** + * 检查租户的token是否有效 + */ + protected boolean isTokenValidByTenantId(String tenantId) { + String token = tokenCache.get(tenantId); + boolean isValid = token != null && isTokenValid(token); + log.debug("租户 {} 的Token验证结果: {}", tenantId, isValid ? "有效" : "无效"); + return isValid; + } + + /** + * 检查token是否有效 + */ + protected boolean isTokenValid(String token) { + UserLoginRespVO tokenInfo = tokenDetailCache.get(token); + boolean isValid = tokenInfo != null && isTokenValid(tokenInfo); + log.debug("Token验证结果: {} -> {}", token, isValid ? "有效" : "无效"); + return isValid; + } + + /** + * 检查token是否有效(内部方法) + */ + private boolean isTokenValid(UserLoginRespVO tokenInfo) { + long currentTime = System.currentTimeMillis() / 1000; + return tokenInfo.expDate > currentTime; + } + + /** + * 根据租户ID移除token + */ + protected void removeTokenByTenantId(String tenantId) { + String token = tokenCache.remove(tenantId); + if (token != null) { + tokenDetailCache.remove(token); + log.debug("租户 {} 的Token已移除: {}", tenantId, token); + } + } + + /** + * 根据token值移除 + */ + protected void removeTokenByValue(String token) { + // 需要找到对应的租户ID + tokenDetailCache.remove(token); + tokenCache.entrySet().removeIf(entry -> entry.getValue().equals(token)); + log.debug("Token已移除: {}", token); + } + + /** + * 获取所有租户的token数量 + */ + protected int getTenantTokenCount() { + return tokenCache.size(); + } + + /** + * 获取所有token的数量 + */ + protected int getTotalTokenCount() { + return tokenDetailCache.size(); + } + + /** + * 清理所有token + */ + protected void clearAllTokens() { + int tenantCount = tokenCache.size(); + int tokenCount = tokenDetailCache.size(); + tokenCache.clear(); + tokenDetailCache.clear(); + log.info("所有Token已清除,共清除 {} 个租户的 {} 个token", tenantCount, tokenCount); + } + + /** + * 获取租户ID列表 + */ + protected java.util.Set getAllTenantIds() { + return new java.util.HashSet<>(tokenCache.keySet()); + } + + /** + * 获取所有token信息(调试用) + */ + protected Map getTokenCache() { + return new ConcurrentHashMap<>(tokenCache); + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/SoilService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/SoilService.java new file mode 100644 index 00000000..20780c0c --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/SoilService.java @@ -0,0 +1,194 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil; + +import cn.iocoder.yudao.module.farm.manager.devices.conf.DeviceConf; +import cn.iocoder.yudao.module.farm.manager.devices.soil.dto.*; +import cn.iocoder.yudao.module.farm.utils.HttpClientUtils; +import cn.iocoder.yudao.module.farm.utils.HttpClientUtils.ApiResponse; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; +import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.*; + +/** + * @description: 土壤墒情 + * @author: binda + * @date: 2025/9/17 10:57 + */ +@Slf4j +@Service +public class SoilService extends BaseTokenCacheService { + + private final DeviceConf deviceConf; + private final HttpClientUtils httpClientUtils; + + public SoilService(DeviceConf deviceConf, HttpClientUtils httpClientUtils) { + this.deviceConf = deviceConf; + this.httpClientUtils = httpClientUtils; + } + + private final String SOIL = "soil_"; + + /** + * 登录获取token + * + * @param req + * @return + */ + public UserLoginRespVO userLogin(UserLoginReqVO req) { + String tenantId = getLoginUser().getTenantId().toString(); + String hosts = deviceConf.getFourSituations().getHosts(); + String userLoginURL = deviceConf.getFourSituations().getGlobal().getUrl21(); + + try { + ApiResponse response = httpClientUtils.postRequest(hosts, userLoginURL, req, null, UserLoginRespVO.class); + + if (response.isSuccess()) { + UserLoginRespVO data = response.getData(); + // TODO: 2025/9/17 持久化 + cacheToken(SOIL+tenantId, data); + } + + return response.getData(); + } catch (Exception e) { + log.error("租户 {} 登录失败: {}", tenantId, e.getMessage(), e); + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_USER_LOGIN); + } + } + + /** + * 验证租户token有效性 + */ + public boolean validateUserToken(String tenantId) { + log.debug("验证租户 {} 的Token", tenantId); + return isTokenValidByTenantId(SOIL+tenantId); + } + + /** + * 获取用户设备 + */ + public List getSysUserDevice(SysUserDeviceReqVO req) { + + String tenantId = getLoginUser().getTenantId().toString(); + String token = getTokenByTenantId(tenantId); + String hosts = deviceConf.getFourSituations().getHosts(); + String getSysUserDeviceURL = deviceConf.getFourSituations().getGlobal().getUrl26(); + + Map headers = new HashMap<>(); + headers.put("token", token); + + Map params = new HashMap<>(); + params.put("groupId", StringUtils.defaultString(req.getGroupId())); + params.put("deviceType", StringUtils.defaultString(req.getDeviceType())); + + try { + + ApiResponse> response = httpClientUtils.getRequestAsList(hosts, getSysUserDeviceURL, params, headers, SysUserDeviceRespVO.class); + if (!response.isSuccess()) { + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_USER_DEVICE); + } + return response.getData(); + } catch (Exception e) { + e.printStackTrace(); + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_USER_DEVICE); + } + + } + + /** + * 获取设备实时数据 + */ + public List getRealTimeData(RealTimeDataReqVO req) { + String tenantId = getLoginUser().getTenantId().toString(); + String token = getTokenByTenantId(tenantId); + String hosts = deviceConf.getFourSituations().getHosts(); + String getSysUserDeviceURL = deviceConf.getFourSituations().getGlobal().getUrl27(); + + Map headers = new HashMap<>(); + headers.put("token", token); + Map params = new HashMap<>(); + params.put("deviceAddrs", req.getDeviceAddrs()); + + try { + ApiResponse> response = httpClientUtils.getRequestAsList(hosts, getSysUserDeviceURL, params, headers, RealTimeDataRespVO.class); + if (!response.isSuccess()) { + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_REAL_TIME_DATA); + } + return response.getData(); + } catch (Exception e) { + e.printStackTrace(); + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_REAL_TIME_DATA); + } + + } + + /** + * 设备报请通知记录 + */ + public List getAlarmNoticeRecord(AlarmNoticeRecordReqVO req) { + + String tenantId = getLoginUser().getTenantId().toString(); + String token = getTokenByTenantId(tenantId); + String hosts = deviceConf.getFourSituations().getHosts(); + String getAlarmNoticeRecord = deviceConf.getFourSituations().getGlobal().getUrl24(); + + Map headers = new HashMap<>(); + headers.put("token", token); + Map params = req.toFieldValueMap(); + + try { + ApiResponse> response = httpClientUtils.getRequestAsList(hosts, getAlarmNoticeRecord, params, headers, AlarmNoticeRecordRespVO.class); + if (!response.isSuccess()) { + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_ALARM_NOTICE_RECORD); + } + return response.getData(); + } catch (Exception e) { + e.printStackTrace(); + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_ALARM_NOTICE_RECORD); + } + + } + + /** + * 墒情设备, 获取设备全部信息 + */ + public List getDeviceAllInfo(DeviceAllInfoReqVO req) { + + + return null; + } + + /** + * 墒情设备, 更新设备信息 + */ + public Boolean updateDevice(UpdateDeviceReqVO req) { + + + return false; + } + + /** + * 墒情设备, 更新节点信息 + */ + public Boolean updateNodeInfo(UpdateNodeInfoReqVO req) { + + + return false; + } + + /** + * 墒情设备, 获取历史数据 + */ + public HistoryDataListPageRespVO getHistoryDataList(HistoryDataListPageReqVO req) { + + return null; + } + + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordReqVO.java new file mode 100644 index 00000000..08173b9d --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordReqVO.java @@ -0,0 +1,53 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.HashMap; +import java.util.Map; + +/** + * @description: 设备报请通知记录 请求实体 + * @author: binda + * @date: 2025/9/17 19:51 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AlarmNoticeRecordReqVO { + /** + * 开始时间(yyyy-MM-dd HH:mm:ss) + * tips: 必选 + */ + private String beginTime; + /** + * 结束时间(yyyy-MM-dd HH:mm:ss) + * tips: 必选 + */ + private String endTime; + /** + * 设备地址码 + * tips: 必选 + */ + private String deviceAddr; + /** + * 节点ID (多个节点使用","分隔) + * tips: 非必选 + */ + private String factorIds; + /** + * 通知类型 0 邮件 1 短信 + */ + private String noticeType; + + public Map toFieldValueMap() { + Map map = new HashMap<>(); + map.put("beginTime", this.getBeginTime()); + map.put("endTime", this.getEndTime()); + map.put("deviceAddr", this.getDeviceAddr()); + map.put("factorIds", this.getFactorIds()); + map.put("noticeType", this.getNoticeType()); + return map; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordRespVO.java new file mode 100644 index 00000000..db1c90f4 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/AlarmNoticeRecordRespVO.java @@ -0,0 +1,54 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 设备报请通知记录 响应实体 + * @author: binda + * @date: 2025/9/17 19:51 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class AlarmNoticeRecordRespVO { + /** + * 通知记录表 id + */ + private Integer noticeID; + /** + * 类型 0 邮件 1 短信 + */ + private Integer noticeIType; + /** + * 设备地址 + */ + private String deviceAddr; + /** + * 节点ID + */ + private String factorId; + /** + * 节点名称 + */ + private String factorName; + /** + * 联系人 + */ + private String contact; + /** + * 通知内容 + */ + private String noticeIContent; + /** + * 备注 + */ + private String remark; + /** + * 创建时间 + */ + private String createTime; + + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoReqVO.java new file mode 100644 index 00000000..14e082ad --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoReqVO.java @@ -0,0 +1,21 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 墒情设备, 设备全部信息 请求实体 + * @author: binda + * @date: 2025/9/17 20:13 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceAllInfoReqVO { + /** + * 必选 + * 设备地址(多个用英文逗号分隔,最多同时获取 5 个设备信息) + */ + private String deviceStr; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoRespVO.java new file mode 100644 index 00000000..f7d71dd2 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/DeviceAllInfoRespVO.java @@ -0,0 +1,154 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 墒情设备, 设备全部信息 响应实体 + * @author: binda + * @date: 2025/9/17 20:13 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DeviceAllInfoRespVO { + /** 设备地址 */ + private String deviceAddr; + + /** 设备名称 */ + private String deviceName; + + /** 经度 */ + private double lng; + + /** 纬度 */ + private double lat; + + /** 数据保存间隔(分钟) */ + private Integer saveDataInterval; + + /** 离线判断间隔(分钟) */ + private Integer offlineInterval; + + /** 节点信息列表 */ + private List nodeInfoList; + + /** 遥调信息列表 */ + private List regulatingInfoList; + + /** + * 节点信息内部类 + */ + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class NodeInfo { + /** 节点编号 */ + private Integer nodeId; + + /** 设备地址 */ + private String deviceAddr; + + /** 节点名称 */ + private String nodeName; + + /** 节点是否开启 0:关闭 1:开启 */ + private Integer enable; + + /** 0 常规 ;1 雨量 ;2 蒸发量 */ + private Integer nodeMold; + + /** + * 节点类型: + * 1: 模拟量 1 使能模拟量 2 使能 + * 2: 模拟量 1 使能模拟量 2 禁用 + * 3: 模拟量 1 禁用模拟量 2 使能 + * 4: 浮点型设备 + * 5: 开关量型设备 + * 6: 32 位有符号整形 + * 7: 32 位无符号整形 + * 8: 遥调设备 + */ + private Integer nodeType; + + /** 优先级 */ + private Integer priority; + + /** 小数位 */ + private Integer digits; + + /** 模拟量 1 名称 */ + private String temName; + + /** 模拟量 1 单位 */ + private String temUnit; + + /** 模拟量 1 系数 */ + private double temRatio; + + /** 模拟量 1 偏差 */ + private double temOffset; + + /** 模拟量 1 上限 */ + private double temUpperLimit; + + /** 模拟量 1 下限 */ + private double temLowerLimit; + + /** 模拟量 2 名称 */ + private String humName; + + /** 模拟量 2 单位 */ + private String humUnit; + + /** 模拟量 2 系数 */ + private double humRatio; + + /** 模拟量 2 偏差 */ + private double humOffset; + + /** 模拟量 2 上限 */ + private double humUpperLimit; + + /** 模拟量 2 下限 */ + private double humLowerLimit; + + /** 开关量闭合显示内容 */ + private String switchOnContent; + + /** 开关量断开显示内容 */ + private String switchOffContent; + + /** 开关量报警类型(0 不报警 1 闭合报警 2 断开报警) */ + private Integer switchAlarmType; + } + + /** + * 遥调信息内部类 + */ + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class RegulatingInfo { + /** 遥调编号(8 位或 15 位) */ + private String regularId; + + /** 节点编号 */ + private Integer nodeId; + + /** 设备地址 */ + private String deviceAddr; + + /** 遥调档位值 */ + private double regularValue; + + /** 遥调档位内容 */ + private String regularText; + + /** 是否开启报警 0:不开启 1:开启 */ + private Integer alarmEnable; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageReqVO.java new file mode 100644 index 00000000..578ce155 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageReqVO.java @@ -0,0 +1,46 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 墒情设备, 获取历史数据 请求实体 + * @author: binda + * @date: 2025/9/17 20:53 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class HistoryDataListPageReqVO { + /** + * 必选 + * 开始时间 (时间戳) + */ + private String beginTime; + /** + * 必选 + * 结束时间 (时间戳) + */ + private String endTime; + /** + * 必选 + * 设备地址 + */ + private String deviceAddr; + /** + * 非必选 + * 节点ID + */ + private String nodeId; + /** + * 必选 + * 页码 + */ + private Integer pages; + /** + * 必选 + * 每页数量 + */ + private Integer limit; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageRespVO.java new file mode 100644 index 00000000..3e4a582a --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/HistoryDataListPageRespVO.java @@ -0,0 +1,62 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 墒情设备, 获取历史数据 响应实体 + * @author: binda + * @date: 2025/9/17 20:53 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class HistoryDataListPageRespVO { + /** + * 页码,每页数量,总页数,总条数 + */ + private Integer pages; + private Integer limit; + private Integer totalPages; + private Integer total; + private List rows; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class Row{ + /** + * 记录表 id + */ + private Integer historyId; + /** + * 节点编号 + */ + private Integer nodeId; + /** + * 设备地址 + */ + private String deviceAddress; + /** + * 模拟量 1 + */ + private String temStr; + private Double temValue; + /** + * 模拟狼 2 + */ + private String humStr; + private Double humValue; + /** + * 是否是报警数据 0:正常 1:报警 + */ + private Integer alarmStatus; + /** + * 保存时间(时间戳) + */ + private Long recordTime; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataReqVO.java new file mode 100644 index 00000000..1ae60224 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataReqVO.java @@ -0,0 +1,23 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 设备实时数据 请求实体 + * @author: binda + * @date: 2025/9/17 19:02 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RealTimeDataReqVO { + /** + * 设备地址 非必定 + * tips: 多个用英文逗号分隔,空为获取当前用户下的所有设备 + */ + private String deviceAddrs; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataRespVO.java new file mode 100644 index 00000000..eaaec0e8 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/RealTimeDataRespVO.java @@ -0,0 +1,68 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 设备实时数据 相应试题 + * @author: binda + * @date: 2025/9/17 19:01 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RealTimeDataRespVO { + /** + * 设备地址 + */ + private String deviceAddr; + /** + * 设备名称 + */ + private String deviceName; + /** + * 经度 + */ + private Double lat; + /** + * 维度 + */ + private Double lng; + /** + * 设备状态 + */ + private String status; + /** + * 设备类型 + */ + private String deviceType; + + private List data; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class RealTimeData { + // 节点编号 + private Integer nodeId; + // 节点名称 + private String nodeName; + // 节点类型 + private Integer nodeType; + // 模拟量1 名称,单位,原值,显示值,报警等级 + private String temName; + private String temUnit; + private Double temValue; + private String temValueStr; + private Integer temAlarmStatus; + // 模拟量2 名称,单位,原值,显示值,报警等级 + private String humName; + private String humUnit; + private String humValue; + private String humValueStr; + private String humAlarmStatus; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceReqVO.java new file mode 100644 index 00000000..b9054816 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 获取用户设备 请求实体 + * @author: binda + * @date: 2025/9/17 15:28 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysUserDeviceReqVO { + /** + * 区域ID 非必填 + */ + private String groupId; + /** + * 设备类型 非必填 + */ + private String deviceType; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceRespVO.java new file mode 100644 index 00000000..8166901f --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/SysUserDeviceRespVO.java @@ -0,0 +1,45 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 获取用户设备 响应实体 + * @author: binda + * @date: 2025/9/17 15:31 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class SysUserDeviceRespVO { + /** + * 设备地址 + */ + public String deviceAddr; + /** + * 区域ID + */ + public String groupId; + /** + * 设备类型 + */ + public String deviceType; + /** + * 设备名称 + */ + public String deviceName; + /** + * 设备的经度 + */ + public String deviceLng; + /** + * 设备的维度 + */ + public String deviceLat; + /** + * 设备iccid + */ + public String deviceIccId; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateDeviceReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateDeviceReqVO.java new file mode 100644 index 00000000..ad4c0ea1 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateDeviceReqVO.java @@ -0,0 +1,33 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 墒情设备, 更新设备信息 请求实体 + * @author: binda + * @date: 2025/9/17 20:29 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UpdateDeviceReqVO { + /** + * 设备地址 + */ + private String deviceAddr; + private String deviceName; + private Double lat; + private Double lng; + /** + * 离线判断间隔 + */ + private Integer offlineInterval; + /** + * 数据保存间隔 + */ + private Integer saveDataInterval; + + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateNodeInfoReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateNodeInfoReqVO.java new file mode 100644 index 00000000..ea449b6e --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UpdateNodeInfoReqVO.java @@ -0,0 +1,81 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 墒情设备, 更新节点信息 请求实体 + * @author: binda + * @date: 2025/9/17 20:34 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UpdateNodeInfoReqVO { + + /** + * 必选 + * 设备地址 + */ + private String deviceAddr; + /** + * 必选 + * 节点编号 + */ + private String nodeId; + private String nodeName; + /** + * 参考 cn.iocoder.yudao.module.farm.manager.devices.commons.DeviceConst: 四情-墒情 设备实时数据 - 节点类型 + */ + private Integer nodeType; + /** + * 0 常规 ;1 雨量 ;2 蒸发量 + */ + private Integer nodeMold; + /** + * 小数位数 + */ + private Integer digits; + /** + * 节点是否开启 0:关闭 1:开启 + */ + private Integer enable; + /** + * 优先级 + */ + private Integer priority; + /** + * 开关量报警类型 (0 不报警 1 闭合报警 2 断开报警) + */ + private Integer switchAlarmType; + /** + * 开关量闭合显示内容 + */ + private String switchOnContent; + /** + * 开关量断开显示内容 + */ + private String switchOffContent; + + /** + * 模拟量2 : 名称,单位,上限,下限,偏差,系数 + */ + private String humName; + private String humUnit; + private Double humUpperLimit; + private Double humLowerLimit; + private Double humOffset; + private Double humRatio; + + /** + * 模拟量2 : 名称,单位,上限,下限,偏差,系数 + */ + private String temName; + private String temUnit; + private Double temUpperLimit; + private Double temLowerLimit; + private Double temOffset; + private Double temRatio; + +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginReqVO.java new file mode 100644 index 00000000..6550372f --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 登录请求实体 + * @author: binda + * @date: 2025/9/17 13:46 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserLoginReqVO { + public String loginName; + public String loginPwd; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginRespVO.java new file mode 100644 index 00000000..1062527d --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/soil/dto/UserLoginRespVO.java @@ -0,0 +1,32 @@ +package cn.iocoder.yudao.module.farm.manager.devices.soil.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 登录响应实体 + * @author: binda + * @date: 2025/9/17 13:46 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UserLoginRespVO { + /** + * 登录标识 + */ + public String loginSign; + /** + * token 生成时间 + */ + public long currDate; + /** + * 过期时间 + */ + public long expDate; + /** + * 令牌 + */ + public String token; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/WaterFertilizerService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/WaterFertilizerService.java new file mode 100644 index 00000000..0122db68 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/WaterFertilizerService.java @@ -0,0 +1,90 @@ +package cn.iocoder.yudao.module.farm.manager.devices.wf; + +import cn.iocoder.yudao.module.farm.manager.devices.conf.DeviceConf; +import cn.iocoder.yudao.module.farm.manager.devices.soil.BaseTokenCacheService; +import cn.iocoder.yudao.module.farm.manager.devices.wf.dto.*; +import cn.iocoder.yudao.module.farm.utils.HttpClientUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Service; + + +import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; +import static cn.iocoder.yudao.module.farm.enums.ErrorCodeConstants.DEVICE_INFO_NOT_EXISTS_FOR_WF_LOGIN; + +/** + * @description: 水肥机 + * @author: binda + * @date: 2025/9/17 10:59 + */ +@Slf4j +@Service +public class WaterFertilizerService extends BaseTokenCacheService { + + private final DeviceConf deviceConf; + private final HttpClientUtils httpClientUtils; + + public WaterFertilizerService(DeviceConf deviceConf, HttpClientUtils httpClientUtils) { + this.deviceConf = deviceConf; + this.httpClientUtils = httpClientUtils; + } + + private final String Authorization = "Authorization"; + private final String Bearer = "Bearer "; + private final String WF = "wf_"; + + /** + * 获取公钥 + */ + public LoginRespVO login() { + String tenantId = getLoginUser().getTenantId().toString(); + String hosts = deviceConf.getWaterAndFertilizer().getHosts(); + String loginURL = deviceConf.getWaterAndFertilizer().getUrl1(); + LoginReqVO req = new LoginReqVO(deviceConf.getWaterAndFertilizer().getUsername(), + deviceConf.getWaterAndFertilizer().getPassword()); + + try { + HttpClientUtils.ApiResponse response = httpClientUtils.postRequest(hosts, loginURL, req, null, LoginRespVO.class); + if (!response.isSuccess()) { + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_WF_LOGIN); + } + LoginRespVO data = response.getData(); + cacheToken(WF+tenantId, data.getToken()); + return response.getData(); + } catch (Exception e) { + e.printStackTrace(); + throw exception(DEVICE_INFO_NOT_EXISTS_FOR_WF_LOGIN); + } + + } + + /** + * 获取设备列表 + * @param userCode 用户名 + * @return + */ + public DevicePageRespVO getDeviceList(String userCode) { + + return null; + } + + /** + * 获取设备实时状态 + * @param deviceId 设备ID + * @return + */ + public RealTimeDeviceDataRespVO getRealTimeDeviceData(String deviceId) { + return null; + } + + /** + * 更改设备属性 + * @param deviceId 设备ID + * @param paramStr 更改值: true: 打开,false: 关闭 + * @return + */ + public UpdateDeviceStatusRespVO updateDeviceStatus(String deviceId, String paramStr) { + + return null; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/DevicePageRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/DevicePageRespVO.java new file mode 100644 index 00000000..85b10775 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/DevicePageRespVO.java @@ -0,0 +1,51 @@ +package cn.iocoder.yudao.module.farm.manager.devices.wf.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; +import java.util.List; + +/** + * @description: 获取设备列表 分页响应实体 + * @author: binda + * @date: 2025/9/18 14:30 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class DevicePageRespVO { + private Integer code; + private String msg; + private Integer total; + private List rows; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class Row{ + private Long deviceId; + private Long deptId; + private String productCode; + private String productName; + private String modelCode; + private String deviceCode; + private String code; // 设备编号 + private String name; + private String farmland; + private String modelName; + private String userCode; + private Double lng; + private Double lat; + private Long farmlandId; + private String delFlag; + private String loginIp; + private Date loginDate; + private String createBy; + private Date createTime; + private String updateBy; + private Date updateTime; + private String remark; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginReqVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginReqVO.java new file mode 100644 index 00000000..46e135eb --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginReqVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.farm.manager.devices.wf.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 获取公钥 请求实体 + * @author: binda + * @date: 2025/9/18 14:19 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginReqVO { + private String username; + private String password; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginRespVO.java new file mode 100644 index 00000000..7646a1d3 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/LoginRespVO.java @@ -0,0 +1,19 @@ +package cn.iocoder.yudao.module.farm.manager.devices.wf.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 获取公钥 响应实体 + * @author: binda + * @date: 2025/9/18 14:26 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class LoginRespVO { + private Integer code; + private String msg; + private String token; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/RealTimeDeviceDataRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/RealTimeDeviceDataRespVO.java new file mode 100644 index 00000000..223ed3f0 --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/RealTimeDeviceDataRespVO.java @@ -0,0 +1,35 @@ +package cn.iocoder.yudao.module.farm.manager.devices.wf.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + +/** + * @description: 设备实时数据 + * @author: binda + * @date: 2025/9/18 14:38 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class RealTimeDeviceDataRespVO { + private String deviceId; + private String name; + private String stateText; // 是否在线 中文 + private String stateValue; // 是否在线 编码 online + private List controlProperties; + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class ControlProperty { + private String id; // 开关标识 + private String name; + private String operateType; // 设备类型 + private String operateValue; + private String value; + private String formatValue; + } +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/UpdateDeviceStatusRespVO.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/UpdateDeviceStatusRespVO.java new file mode 100644 index 00000000..9ad6e88c --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/manager/devices/wf/dto/UpdateDeviceStatusRespVO.java @@ -0,0 +1,18 @@ +package cn.iocoder.yudao.module.farm.manager.devices.wf.dto; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @description: 更改设备属性 响应实体 + * @author: binda + * @date: 2025/9/18 14:45 + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UpdateDeviceStatusRespVO { + private Integer code; + private String msg; +} diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/baseinfo/BaseInfoServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/baseinfo/BaseInfoServiceImpl.java index aaca4f68..f50b4f5c 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/baseinfo/BaseInfoServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/baseinfo/BaseInfoServiceImpl.java @@ -352,6 +352,9 @@ public class BaseInfoServiceImpl implements BaseInfoService { @Override public Double getBaseTotalArea(String tenantId) { BigDecimal d = baseInfoMapper.getTotalBaseArea(null, Long.valueOf(tenantId)); + if (d == null) { + return 0.00; + } return d.doubleValue(); } diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyService.java index c1d31d10..42c190ff 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyService.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyService.java @@ -61,4 +61,7 @@ public interface DeviceClassifyService { List getDeviceClassifyList(); + List getDeviceTypeList(); + + List getDeviceModelList(String deviceTypeId); } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyServiceImpl.java index 9f4f6745..aee1943a 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceclassify/DeviceClassifyServiceImpl.java @@ -6,6 +6,8 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceClassifyPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceClassifySaveReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceModelRespVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceclassify.vo.DeviceTypeRespVO; import cn.iocoder.yudao.module.farm.dal.dataobject.deviceclassify.DeviceClassifyDO; import cn.iocoder.yudao.module.farm.dal.mysql.deviceclassify.DeviceClassifyMapper; import jakarta.annotation.Resource; @@ -15,6 +17,7 @@ import org.springframework.validation.annotation.Validated; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; @@ -108,6 +111,41 @@ public class DeviceClassifyServiceImpl implements DeviceClassifyService { return deviceClassifyDOS; } + @Override + public List getDeviceTypeList() { + List list = this.getDeviceClassifyList(); + return list.stream() + .filter(device -> device.getParentId() != null && device.getParentId() == 0L) + .map(device -> new DeviceTypeRespVO( + String.valueOf(device.getId()), + device.getName(), + device.getImage(), + device.getImageList() + )) + .collect(Collectors.toList()); + } + + @Override + public List getDeviceModelList(String deviceTypeId) { + + List list = this.getDeviceClassifyList(); + Long parentId = Long.valueOf(deviceTypeId); + + DeviceClassifyDO parentDevice = list.stream() + .filter(device -> device.getId().equals(parentId)) + .findFirst() + .orElseThrow(() -> {throw exception(DEVICE_TYPE_ERROR);}); + + return list.stream() + .filter(device -> device.getParentId() != null && device.getParentId().equals(parentId)) + .map(childDevice -> new DeviceModelRespVO( + String.valueOf(childDevice.getId()), + parentDevice.getName() + "/" + childDevice.getName() + )) + .collect(Collectors.toList()); + + } + /** * 处理图片集合转换 * 支持从 imageList 或 image 字段获取图片,优先使用 imageList diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoService.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoService.java index 288a13ef..dd1b06d5 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoService.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoService.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.farm.service.deviceinfo; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceStatisticsRespVO; import cn.iocoder.yudao.module.farm.dal.dataobject.deviceinfo.DeviceInfoDO; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageParam; @@ -61,4 +62,10 @@ public interface DeviceInfoService { */ PageResult getDeviceInfoPage(DeviceInfoPageReqVO pageReqVO); + /** + * 设备统计 + * @param baseId + * @return + */ + DeviceStatisticsRespVO getStatisticsInfo(String baseId); } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoServiceImpl.java index 3b8e69d9..48facd86 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/deviceinfo/DeviceInfoServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoPageReqVO; import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.DeviceInfoSaveReqVO; +import cn.iocoder.yudao.module.farm.controller.admin.deviceinfo.vo.v2.DeviceStatisticsRespVO; import org.springframework.stereotype.Service; import jakarta.annotation.Resource; import org.springframework.validation.annotation.Validated; @@ -107,4 +108,9 @@ private void validateDeviceInfoExists(String id) { return pageResult; } + @Override + public DeviceStatisticsRespVO getStatisticsInfo(String baseId) { + return deviceInfoMapper.getStatisticsInfo(baseId,String.valueOf(getLoginUser().getTenantId())); + } + } \ No newline at end of file diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/devicestatus/DeviceStatusServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/devicestatus/DeviceStatusServiceImpl.java index 3481a431..342c9d9b 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/devicestatus/DeviceStatusServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/devicestatus/DeviceStatusServiceImpl.java @@ -41,7 +41,7 @@ public class DeviceStatusServiceImpl implements DeviceStatusService { // 构建更新对象 DeviceInfoDO updateObj = new DeviceInfoDO(); updateObj.setId(device.getId()); - updateObj.setState(state); + updateObj.setDeviceState(state); updateObj.setLastMessageTime(messageTime); // 根据状态设置相应的时间字段 @@ -84,8 +84,8 @@ public class DeviceStatusServiceImpl implements DeviceStatusService { updateObj.setLastMessageTime(messageTime); // 如果设备当前是离线状态,收到消息后自动上线 - if (DeviceStateEnum.isOffline(device.getState()) || device.getState() == null) { - updateObj.setState(DeviceStateEnum.ONLINE.getState()); + if (DeviceStateEnum.isOffline(device.getDeviceState()) || device.getDeviceState() == null) { + updateObj.setDeviceState(DeviceStateEnum.ONLINE.getState()); updateObj.setOnlineTime(messageTime); // 如果是首次激活,设置激活时间 if (device.getActiveTime() == null) { @@ -99,16 +99,16 @@ public class DeviceStatusServiceImpl implements DeviceStatusService { @Override public boolean isDeviceOnline(String deviceUniqueId) { DeviceInfoDO device = deviceInfoMapper.selectOne(DeviceInfoDO::getDeviceUniqueId, deviceUniqueId); - return device != null && DeviceStateEnum.isOnline(device.getState()); + return device != null && DeviceStateEnum.isOnline(device.getDeviceState()); } @Override public DeviceStateEnum getDeviceState(String deviceUniqueId) { DeviceInfoDO device = deviceInfoMapper.selectOne(DeviceInfoDO::getDeviceUniqueId, deviceUniqueId); - if (device == null || device.getState() == null) { + if (device == null || device.getDeviceState() == null) { return DeviceStateEnum.INACTIVE; } - return DeviceStateEnum.valueOf(device.getState()); + return DeviceStateEnum.valueOf(device.getDeviceState()); } @Override @@ -140,7 +140,7 @@ public class DeviceStatusServiceImpl implements DeviceStatusService { for (DeviceInfoDO device : timeoutDevices) { // 只处理当前在线的设备 - if (DeviceStateEnum.isOnline(device.getState())) { + if (DeviceStateEnum.isOnline(device.getDeviceState())) { deviceOffline(device.getDeviceUniqueId()); count++; log.info("设备超时离线:{}", device.getDeviceUniqueId()); diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/home/HomeServiceImpl.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/home/HomeServiceImpl.java index 30f54a92..f3f24d13 100644 --- a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/home/HomeServiceImpl.java +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/service/home/HomeServiceImpl.java @@ -244,6 +244,9 @@ public class HomeServiceImpl implements HomeService { @Override public List getBaseNameList() { List baseNameList = baseInfoService.getBaseInfos(); + if (ObjectUtils.isEmpty(baseNameList)) { + return new ArrayList<>(); + } return baseNameList.stream().map(e -> new BaseNameVO(e.getId(), e.getName())).collect(Collectors.toList()); } diff --git a/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/HttpClientUtils.java b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/HttpClientUtils.java new file mode 100644 index 00000000..7366bc5e --- /dev/null +++ b/yudao-module-farm/src/main/java/cn/iocoder/yudao/module/farm/utils/HttpClientUtils.java @@ -0,0 +1,215 @@ +package cn.iocoder.yudao.module.farm.utils; + +import com.fasterxml.jackson.databind.JavaType; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.springframework.stereotype.Component; + +import java.io.UnsupportedEncodingException; +import java.net.URI; +import java.net.http.HttpClient; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; +import java.time.Duration; +import java.util.List; +import java.util.Map; + +/** + * @description: http client + * @author: binda + * @date: 2025/9/16 16:46 + */ +@Component +public class HttpClientUtils { + private final HttpClient httpClient; + private final ObjectMapper objectMapper; + + public HttpClientUtils(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + this.httpClient = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(); + } + + private String getBaseUrl(String hosts) { + if (hosts.startsWith("http")) { + return hosts; + } + return "https://" + hosts; + } + + // 通用GET请求 - 返回原始JsonNode,让调用方自己解析 + public JsonNode getRequestRaw(String hosts, + String path, + Map params, + Map headers) throws Exception { + + String queryString = buildQueryString(params); + HttpRequest request = buildRequest(hosts, path + queryString, "GET", null, headers); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + return objectMapper.readTree(response.body()); + } else { + throw new RuntimeException("HTTP request failed with status: " + response.statusCode()); + } + + } + + // 通用GET请求 - 自动解析为指定类型 + public ApiResponse getRequest(String hosts, + String path, + Map params, + Map headers, + Class dataType) throws Exception { + + JsonNode responseJson = getRequestRaw(hosts, path, params, headers); + return parseResponse(responseJson, dataType); + + } + + // 通用GET请求 - 自动解析为List类型 + public ApiResponse> getRequestAsList(String hosts, + String path, + Map params, + Map headers, + Class itemType) throws Exception { + + JsonNode responseJson = getRequestRaw(hosts, path, params, headers); + return parseResponseAsList(responseJson, itemType); + + } + + // 通用POST请求 - 返回原始JsonNode + public JsonNode postRequestRaw(String hosts, + String path, + Object requestBody, + Map headers) throws Exception { + + String requestBodyJson = objectMapper.writeValueAsString(requestBody); + + HttpRequest request = buildRequest(hosts, path, "POST", requestBodyJson, headers); + HttpResponse response = httpClient.send(request, HttpResponse.BodyHandlers.ofString()); + + if (response.statusCode() == 200) { + return objectMapper.readTree(response.body()); + } else { + throw new RuntimeException("HTTP request failed with status: " + response.statusCode()); + } + + } + + // 通用POST请求 - 自动解析为指定类型 + public ApiResponse postRequest(String hosts, + String path, + Object requestBody, + Map headers, + Class dataType) throws Exception { + + JsonNode responseJson = postRequestRaw(hosts, path, requestBody, headers); + return parseResponse(responseJson, dataType); + + } + + // 通用POST请求 - 自动解析为List类型 + public ApiResponse> postRequestAsList(String hosts, + String path, + Object requestBody, + Map headers, + Class itemType) throws Exception { + + JsonNode responseJson = postRequestRaw(hosts, path, requestBody, headers); + return parseResponseAsList(responseJson, itemType); + + } + + + // 构建查询字符串 + private String buildQueryString(Map params) throws UnsupportedEncodingException { + if (params == null || params.isEmpty()) { + return ""; + } + + StringBuilder queryBuilder = new StringBuilder("?"); + for (Map.Entry entry : params.entrySet()) { + if (queryBuilder.length() > 1) { + queryBuilder.append("&"); + } + queryBuilder.append(entry.getKey()) + .append("=") + .append(java.net.URLEncoder.encode(entry.getValue(), "UTF-8")); + } + return queryBuilder.toString(); + } + + // 构建HTTP请求 + private HttpRequest buildRequest(String hosts, + String path, + String method, + String requestBody, + Map headers) throws Exception { + + HttpRequest.Builder builder = HttpRequest.newBuilder() + .uri(URI.create(this.getBaseUrl(hosts) + "/" + path)) + .header("Content-Type", "application/json") + .timeout(Duration.ofSeconds(10)); + + if ("GET".equals(method)) { + builder.GET(); + } else if ("POST".equals(method)) { + builder.POST(HttpRequest.BodyPublishers.ofString(requestBody)); + } + + if (headers != null) { + for (Map.Entry entry : headers.entrySet()) { + builder.header(entry.getKey(), entry.getValue()); + } + } + + return builder.build(); + } + + // 解析响应为单个对象 + private ApiResponse parseResponse(JsonNode responseJson, Class dataType) { + String code = responseJson.get("code").asText(); + String message = responseJson.get("message").asText(); + JsonNode dataNode = responseJson.get("data"); + + T data = null; + if (dataNode != null && !dataNode.isNull()) { + data = objectMapper.convertValue(dataNode, dataType); + } + + return new ApiResponse<>(code, message, data); + } + + // 解析响应为List + private ApiResponse> parseResponseAsList(JsonNode responseJson, Class itemType) { + String code = responseJson.get("code").asText(); + String message = responseJson.get("message").asText(); + JsonNode dataNode = responseJson.get("data"); + + List data = null; + if (dataNode != null && !dataNode.isNull() && dataNode.isArray()) { + JavaType listType = objectMapper.getTypeFactory().constructCollectionType(List.class, itemType); + data = objectMapper.convertValue(dataNode, listType); + } + + return new ApiResponse<>(code, message, data); + } + + @Data + @AllArgsConstructor + @NoArgsConstructor + public static class ApiResponse { + private String code; + private String message; + private T data; + + public boolean isSuccess() { + return "1000".equals(code); + } + } + +} diff --git a/yudao-module-farm/src/main/resources/mapper/deviceinfo/DeviceInfoMapper.xml b/yudao-module-farm/src/main/resources/mapper/deviceinfo/DeviceInfoMapper.xml index 8999af5d..feeb01fe 100644 --- a/yudao-module-farm/src/main/resources/mapper/deviceinfo/DeviceInfoMapper.xml +++ b/yudao-module-farm/src/main/resources/mapper/deviceinfo/DeviceInfoMapper.xml @@ -9,4 +9,24 @@ 文档可见:https://www.iocoder.cn/MyBatis/x-plugins/ --> + \ No newline at end of file diff --git a/yudao-server/src/main/resources/application.yaml b/yudao-server/src/main/resources/application.yaml index 34c1f121..b492bacd 100644 --- a/yudao-server/src/main/resources/application.yaml +++ b/yudao-server/src/main/resources/application.yaml @@ -343,4 +343,37 @@ spring: # 万懋wms系统 wms: hosts: 47.111.15.9:8074/prod-api - url_1: getTenantByMobile \ No newline at end of file + url_1: getTenantByMobile + +# 万懋设备管理 +device-manager: + # 四情 (文档来源: 物连网农业四情采集api协议.pdf 版本:v2.0.3 日期:2022.08.16) + four-situations: + hosts: http://farm.0531yun.cn/#/ # http://farm.0531yun.cn/#/ + username: cq250904jxtr + password: cq250904jxtr + global: + url-2-1: /api/v2.0/entrance/user/userLogin #用户登录 POST + url-2-2: /api/v2.0/entrance/user/getUser #获取登录用户信息 + url-2-3: /api/v2.0/entrance/user/getChildUser #获取子用户信息 + url-2-4: /api/v2.0/entrance/device/getAlarmNoticeRecord #设备报请通知记录 GET + url-2-5: /api/v2.0/entrance/group/getsysUserGroup #获取用户区域 + url-2-6: /api/v2.0/entrance/device/getsysUserDevice #获取用户设备 GET + url-2-7: /api/v2.0/entrance/device/getDeviceCamera #批量获取摄像头设备信息 + url-2-8: /api/v2.0/entrance/device/getRealTimeData #获取设备实时数据 GET + url-2-9: /api/v2.0/entrance/device/groupBoundDevice #区域绑定设备 + # 土壤墒情 + soil: + url-4-1: /api/v2.0/soil/device/getDeviceAllInfo # 墒情设备, 获取设备全部信息 GET + url-4-2: /api/v2.0/soil/device/updateDevice # 墒情设备, 更新设备信息 POST + url-4-3: /api/v2.0/soil/device/updateNodeInfo # 墒情设备, 更新节点信息 POST + url-4-4: /api/v2.0/soil/history/getHistoryDataList # 墒情设备, 获取历史数据 GET + # 水费机 (文档参考: 智慧物联 HTTPS通讯协议说明书 版本:1.0.1 日期:2025.06.08) + water-and-fertilizer: + hosts: https://ryy.mythiot.com + username: jishui + password: jishui@888@ + url-1: /prod-api/login # 获取公钥 POST + url-2: /prod-api/agriculture/deviceMain/list # 获取设备列表 GET + url-3: /prod-api/agriculture/deviceMain/getDeviceAllPropertyAndDataSimple/{0} # 获取设备实时状态 GET {0}: deviceId + url-4: /prod-api/agriculture/deviceMain/updateDeviceStatus # 更改设备属性 POST