From 3ec596d8efdf92aa24428dce7e490815cb4affa5 Mon Sep 17 00:00:00 2001
From: zy <82248909@qq.com>
Date: Fri, 19 Dec 2025 19:20:30 +0800
Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=96=B0mqtt=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
zh-module-applet/zh-applet-admin/pom.xml | 11 +-
.../FIotVirtualDeviceGroupController.java | 143 ++++
.../FIotVirtualDeviceModuleController.java | 143 ++++
.../FIotVirtualDeviceNetController.java | 143 ++++
.../SurvDeviceDeployController.java | 2 +
.../SurvDeviceOprationController.java | 144 ++++
.../controller/SurvIotProtocolController.java | 143 ++++
.../SurvIotVirtualDeviceController.java | 143 ++++
.../appmana/mapper/FDeviceOprationMapper.java | 14 +
.../appmana/mapper/FIotProtocolMapper.java | 14 +
.../mapper/FIotVirtualDeviceGroupMapper.java | 14 +
.../mapper/FIotVirtualDeviceMapper.java | 16 +
.../mapper/FIotVirtualDeviceModuleMapper.java | 14 +
.../mapper/FIotVirtualDeviceNetMapper.java | 14 +
.../appmana/mapper/IOTStatisticMapper.java | 3 +
.../mapper/xml/FDeviceOprationMapper.xml | 5 +
.../appmana/mapper/xml/FIotProtocolMapper.xml | 5 +
.../xml/FIotVirtualDeviceGroupMapper.xml | 6 +
.../mapper/xml/FIotVirtualDeviceMapper.xml | 51 ++
.../xml/FIotVirtualDeviceModuleMapper.xml | 59 ++
.../mapper/xml/FIotVirtualDeviceNetMapper.xml | 5 +
.../appmana/mapper/xml/IOTStatisticMapper.xml | 3 +
.../appmana/o/vo/common/LoginUser.java | 128 +++
.../service/IFDeviceOprationService.java | 17 +
.../appmana/service/IFIotProtocolService.java | 14 +
.../IFIotVirtualDeviceGroupService.java | 14 +
.../IFIotVirtualDeviceModuleService.java | 14 +
.../service/IFIotVirtualDeviceNetService.java | 14 +
.../service/IFIotVirtualDeviceService.java | 71 ++
.../impl/FDeviceOprationServiceImpl.java | 73 ++
.../service/impl/FIotProtocolServiceImpl.java | 18 +
.../FIotVirtualDeviceGroupServiceImpl.java | 18 +
.../FIotVirtualDeviceModuleServiceImpl.java | 61 ++
.../impl/FIotVirtualDeviceNetServiceImpl.java | 28 +
.../impl/FIotVirtualDeviceServiceImpl.java | 764 ++++++++++++++++++
.../impl/SurvDeviceDeployServiceImpl.java | 12 +
.../appmana/utils/HttpRequestUtils.java | 1 +
.../appmana/utils/HttpServletRequestUtil.java | 152 ++++
.../modules/{appmana => }/mqtt/DTOMqtt.java | 0
.../modules/{appmana => }/mqtt/LhMqttMsg.java | 0
.../{appmana => }/mqtt/MqttConfig.java | 14 +-
.../{appmana => }/mqtt/MqttService.java | 0
.../{appmana => }/mqtt/MyMqttCallback.java | 16 +-
.../{appmana => }/mqtt/MyMqttClient.java | 0
.../{appmana => }/mqtt/MyMqttController.java | 0
.../mqtt/impl/MqttServiceImpl.java | 0
.../jeecg/common/constant/TopicConstant.java | 46 ++
.../jeecg/common/entity/FDeviceOpration.java | 218 +++++
.../org/jeecg/common/entity/FIotProtocol.java | 118 +++
.../common/entity/FIotVirtualDevice.java | 192 +++++
.../common/entity/FIotVirtualDeviceGroup.java | 106 +++
.../entity/FIotVirtualDeviceModule.java | 224 +++++
.../common/entity/FIotVirtualDeviceNet.java | 145 ++++
.../iot/Fertilizer/VOFertilizerStats.java | 124 +++
.../iot/Fertilizer/VOFertilizerStatsArr.java | 56 ++
.../jeecg/common/iot/common/DeviceLogVo.java | 27 +
.../jeecg/common/iot/common/LoginUser2.java | 138 ++++
.../common/iot/enums/DeviceActionType.java | 51 ++
.../jeecg/common/iot/enums/FunctionCode.java | 39 +
.../common/iot/enums/IotControlType.java | 51 ++
.../iot/enums/IotInerfaceTopicType.java | 52 ++
.../common/iot/enums/IotManufacturerEnum.java | 56 ++
.../common/iot/enums/IotProtocolType.java | 51 ++
.../org/jeecg/common/iot/enums/RWType.java | 9 +
.../jeecg/common/iot/enums/RegisterType.java | 52 ++
.../jeecg/common/iot/up/DeviceActionVo.java | 21 +
.../common/iot/up/ModuleStatusDetailVo.java | 12 +
.../common/iot/up/ModuleStatusResultVo.java | 10 +
.../common/iot/vo/DeviceControlResultVo.java | 16 +
.../org/jeecg/common/iot/vo/VOCmdPack.java | 11 +
.../org/jeecg/common/iot/vo/VOCmdPackQ.java | 8 +
.../org/jeecg/common/iot/vo/VODeviceCmd.java | 16 +
.../org/jeecg/common/iot/vo/VODeviceCmdQ.java | 17 +
.../jeecg/common/util/ModbusCommandUtil.java | 134 +++
.../common/util/ModbusResponseParser.java | 198 +++++
75 files changed, 4703 insertions(+), 19 deletions(-)
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceGroupController.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceModuleController.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceNetController.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvDeviceOprationController.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotProtocolController.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotVirtualDeviceController.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FDeviceOprationMapper.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotProtocolMapper.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceGroupMapper.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceMapper.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceModuleMapper.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceNetMapper.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FDeviceOprationMapper.xml
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotProtocolMapper.xml
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceGroupMapper.xml
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceMapper.xml
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceModuleMapper.xml
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceNetMapper.xml
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/o/vo/common/LoginUser.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFDeviceOprationService.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotProtocolService.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceGroupService.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceModuleService.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceNetService.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceService.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FDeviceOprationServiceImpl.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotProtocolServiceImpl.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceGroupServiceImpl.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceModuleServiceImpl.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceNetServiceImpl.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceServiceImpl.java
create mode 100644 zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpServletRequestUtil.java
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/DTOMqtt.java (100%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/LhMqttMsg.java (100%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/MqttConfig.java (87%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/MqttService.java (100%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/MyMqttCallback.java (90%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/MyMqttClient.java (100%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/MyMqttController.java (100%)
rename zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/{appmana => }/mqtt/impl/MqttServiceImpl.java (100%)
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/constant/TopicConstant.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FDeviceOpration.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotProtocol.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDevice.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceGroup.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceModule.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceNet.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStats.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStatsArr.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/DeviceLogVo.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/LoginUser2.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/DeviceActionType.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/FunctionCode.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotControlType.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotInerfaceTopicType.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotManufacturerEnum.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotProtocolType.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RWType.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RegisterType.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/DeviceActionVo.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusDetailVo.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusResultVo.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/DeviceControlResultVo.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPack.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPackQ.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmd.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmdQ.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusCommandUtil.java
create mode 100644 zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusResponseParser.java
diff --git a/zh-module-applet/zh-applet-admin/pom.xml b/zh-module-applet/zh-applet-admin/pom.xml
index c9e0e0e..02aed4a 100644
--- a/zh-module-applet/zh-applet-admin/pom.xml
+++ b/zh-module-applet/zh-applet-admin/pom.xml
@@ -68,6 +68,15 @@
org.springframework.security
spring-security-crypto
-
+
+ org.eclipse.paho
+ org.eclipse.paho.client.mqttv3
+ 1.2.5
+
+
+ org.redisson
+ redisson
+ 3.52.0
+
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceGroupController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceGroupController.java
new file mode 100644
index 0000000..340610d
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceGroupController.java
@@ -0,0 +1,143 @@
+package org.jeecg.modules.appmana.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.entity.FIotVirtualDeviceGroup;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceGroupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.Date;
+
+
+ /**
+ * @Description: 虚拟设备模块分组
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+@Api(tags="99. 虚拟设备模块分组 id")
+@RestController
+@RequestMapping("/api/iot/fIotVirtualDeviceGroup")
+@Slf4j
+public class FIotVirtualDeviceGroupController extends JeecgController {
+ @Autowired
+ private IFIotVirtualDeviceGroupService fIotVirtualDeviceGroupService;
+
+
+ //@AutoLog(value = "虚拟设备模块分组-分页列表查询")
+ @ApiOperation(value="01. 分页查询", notes="")
+ @ApiOperationSupport(order = 1)
+ @GetMapping(value = "/list")
+ public Result> queryPageList(FIotVirtualDeviceGroup fIotVirtualDeviceGroup,
+ @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+ @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(fIotVirtualDeviceGroup, req.getParameterMap());
+ Page page = new Page(pageNo, pageSize);
+ IPage pageList = fIotVirtualDeviceGroupService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+
+ @AutoLog(value = "虚拟设备模块分组-添加")
+ @ApiOperationSupport(order = 2)
+ @ApiOperation(value="02. 添加", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_group:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody FIotVirtualDeviceGroup fIotVirtualDeviceGroup, HttpServletRequest request) {
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDeviceGroup.setCreateBy(username);
+ fIotVirtualDeviceGroup.setCreateTime(new Date());
+ fIotVirtualDeviceGroupService.save(fIotVirtualDeviceGroup);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "虚拟设备模块分组-编辑")
+ @ApiOperationSupport(order = 3)
+ @ApiOperation(value="03. 编辑", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_group:edit")
+ @PostMapping(value = "/edit")
+ public Result edit(@RequestBody FIotVirtualDeviceGroup fIotVirtualDeviceGroup, HttpServletRequest request) {
+ //创建、更新时间不能编辑
+ fIotVirtualDeviceGroup.setCreateTime(null);
+ fIotVirtualDeviceGroup.setUpdateTime(null);
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDeviceGroup.setUpdateBy(username);
+ fIotVirtualDeviceGroupService.updateById(fIotVirtualDeviceGroup);
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 通过id删除
+ *
+ * @param id
+ * @return
+ */
+ @AutoLog(value = "虚拟设备模块分组-通过id删除")
+ @ApiOperation(value="04.通过id删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_group:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name="id",required=true) String id) {
+ fIotVirtualDeviceGroupService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+
+ @AutoLog(value = "虚拟设备模块分组-批量删除")
+ @ApiOperationSupport(order = 4)
+ @ApiOperation(value="04. 批量删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_group:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+ this.fIotVirtualDeviceGroupService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+
+ //@AutoLog(value = "虚拟设备模块分组-通过id查询")
+ @ApiOperationSupport(order = 5)
+ @ApiOperation(value="05. 通过id查询", notes="")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name="id",required=true) String id) {
+ FIotVirtualDeviceGroup fIotVirtualDeviceGroup = fIotVirtualDeviceGroupService.getById(id);
+ if(fIotVirtualDeviceGroup==null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(fIotVirtualDeviceGroup);
+ }
+
+
+ @ApiOperationSupport(order = 6)
+ @ApiOperation(value="06. 导出excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_group:exportXls")
+ @GetMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, FIotVirtualDeviceGroup fIotVirtualDeviceGroup) {
+ return super.exportXls(request, fIotVirtualDeviceGroup, FIotVirtualDeviceGroup.class, "虚拟设备模块分组");
+ }
+
+
+ @ApiOperationSupport(order = 7)
+ @ApiOperation(value="07. 导入excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_group:importExcel")
+ @PostMapping(value = "/importExcel")
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, FIotVirtualDeviceGroup.class);
+ }
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceModuleController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceModuleController.java
new file mode 100644
index 0000000..a96d59f
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceModuleController.java
@@ -0,0 +1,143 @@
+package org.jeecg.modules.appmana.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.entity.FIotVirtualDeviceModule;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceModuleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.Date;
+
+
+ /**
+ * @Description: 虚拟设备模组表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+@Api(tags="99. 虚拟设备模组表 id")
+@RestController
+@RequestMapping("/api/iot/fIotVirtualDeviceModule")
+@Slf4j
+public class FIotVirtualDeviceModuleController extends JeecgController {
+ @Autowired
+ private IFIotVirtualDeviceModuleService fIotVirtualDeviceModuleService;
+
+
+ //@AutoLog(value = "虚拟设备模组表-分页列表查询")
+ @ApiOperation(value="01. 分页查询", notes="")
+ @ApiOperationSupport(order = 1)
+ @GetMapping(value = "/list")
+ public Result> queryPageList(FIotVirtualDeviceModule fIotVirtualDeviceModule,
+ @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+ @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(fIotVirtualDeviceModule, req.getParameterMap());
+ Page page = new Page(pageNo, pageSize);
+ IPage pageList = fIotVirtualDeviceModuleService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+
+ @AutoLog(value = "虚拟设备模组表-添加")
+ @ApiOperationSupport(order = 2)
+ @ApiOperation(value="02. 添加", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_module:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody FIotVirtualDeviceModule fIotVirtualDeviceModule, HttpServletRequest request) {
+ String username =JwtUtil.getUserNameByToken(request);
+ fIotVirtualDeviceModule.setCreateBy(username);
+ fIotVirtualDeviceModule.setCreateTime(new Date());
+ fIotVirtualDeviceModuleService.save(fIotVirtualDeviceModule);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "虚拟设备模组表-编辑")
+ @ApiOperationSupport(order = 3)
+ @ApiOperation(value="03. 编辑", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_module:edit")
+ @PostMapping(value = "/edit")
+ public Result edit(@RequestBody FIotVirtualDeviceModule fIotVirtualDeviceModule, HttpServletRequest request) {
+ //创建、更新时间不能编辑
+ fIotVirtualDeviceModule.setCreateTime(null);
+ fIotVirtualDeviceModule.setUpdateTime(null);
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDeviceModule.setUpdateBy(username);
+ fIotVirtualDeviceModuleService.updateById(fIotVirtualDeviceModule);
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 通过id删除
+ *
+ * @param id
+ * @return
+ */
+ @AutoLog(value = "虚拟设备模组表-通过id删除")
+ @ApiOperation(value="04.通过id删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_module:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name="id",required=true) String id) {
+ fIotVirtualDeviceModuleService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+
+ @AutoLog(value = "虚拟设备模组表-批量删除")
+ @ApiOperationSupport(order = 4)
+ @ApiOperation(value="04. 批量删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_module:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+ this.fIotVirtualDeviceModuleService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+
+ //@AutoLog(value = "虚拟设备模组表-通过id查询")
+ @ApiOperationSupport(order = 5)
+ @ApiOperation(value="05. 通过id查询", notes="")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name="id",required=true) String id) {
+ FIotVirtualDeviceModule fIotVirtualDeviceModule = fIotVirtualDeviceModuleService.getById(id);
+ if(fIotVirtualDeviceModule==null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(fIotVirtualDeviceModule);
+ }
+
+
+ @ApiOperationSupport(order = 6)
+ @ApiOperation(value="06. 导出excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_module:exportXls")
+ @GetMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, FIotVirtualDeviceModule fIotVirtualDeviceModule) {
+ return super.exportXls(request, fIotVirtualDeviceModule, FIotVirtualDeviceModule.class, "虚拟设备模组表");
+ }
+
+
+ @ApiOperationSupport(order = 7)
+ @ApiOperation(value="07. 导入excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_module:importExcel")
+ @PostMapping(value = "/importExcel")
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, FIotVirtualDeviceModule.class);
+ }
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceNetController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceNetController.java
new file mode 100644
index 0000000..e8b889f
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/FIotVirtualDeviceNetController.java
@@ -0,0 +1,143 @@
+package org.jeecg.modules.appmana.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.entity.FIotVirtualDeviceNet;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceNetService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.Date;
+
+
+ /**
+ * @Description: 虚拟设备网络模块
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+@Api(tags="99. 虚拟设备网络模块 id")
+@RestController
+@RequestMapping("/api/iot/fIotVirtualDeviceNet")
+@Slf4j
+public class FIotVirtualDeviceNetController extends JeecgController {
+ @Autowired
+ private IFIotVirtualDeviceNetService fIotVirtualDeviceNetService;
+
+
+ //@AutoLog(value = "虚拟设备网络模块-分页列表查询")
+ @ApiOperation(value="01. 分页查询", notes="")
+ @ApiOperationSupport(order = 1)
+ @GetMapping(value = "/list")
+ public Result> queryPageList(FIotVirtualDeviceNet fIotVirtualDeviceNet,
+ @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+ @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(fIotVirtualDeviceNet, req.getParameterMap());
+ Page page = new Page(pageNo, pageSize);
+ IPage pageList = fIotVirtualDeviceNetService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+
+ @AutoLog(value = "虚拟设备网络模块-添加")
+ @ApiOperationSupport(order = 2)
+ @ApiOperation(value="02. 添加", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_net:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody FIotVirtualDeviceNet fIotVirtualDeviceNet, HttpServletRequest request) {
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDeviceNet.setCreateBy(username);
+ fIotVirtualDeviceNet.setCreateTime(new Date());
+ fIotVirtualDeviceNetService.save(fIotVirtualDeviceNet);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "虚拟设备网络模块-编辑")
+ @ApiOperationSupport(order = 3)
+ @ApiOperation(value="03. 编辑", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_net:edit")
+ @PostMapping(value = "/edit")
+ public Result edit(@RequestBody FIotVirtualDeviceNet fIotVirtualDeviceNet, HttpServletRequest request) {
+ //创建、更新时间不能编辑
+ fIotVirtualDeviceNet.setCreateTime(null);
+ fIotVirtualDeviceNet.setUpdateTime(null);
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDeviceNet.setUpdateBy(username);
+ fIotVirtualDeviceNetService.updateById(fIotVirtualDeviceNet);
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 通过id删除
+ *
+ * @param id
+ * @return
+ */
+ @AutoLog(value = "虚拟设备网络模块-通过id删除")
+ @ApiOperation(value="04.通过id删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_net:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name="id",required=true) String id) {
+ fIotVirtualDeviceNetService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+
+ @AutoLog(value = "虚拟设备网络模块-批量删除")
+ @ApiOperationSupport(order = 4)
+ @ApiOperation(value="04. 批量删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_net:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+ this.fIotVirtualDeviceNetService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+
+ //@AutoLog(value = "虚拟设备网络模块-通过id查询")
+ @ApiOperationSupport(order = 5)
+ @ApiOperation(value="05. 通过id查询", notes="")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name="id",required=true) String id) {
+ FIotVirtualDeviceNet fIotVirtualDeviceNet = fIotVirtualDeviceNetService.getById(id);
+ if(fIotVirtualDeviceNet==null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(fIotVirtualDeviceNet);
+ }
+
+
+ @ApiOperationSupport(order = 6)
+ @ApiOperation(value="06. 导出excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_net:exportXls")
+ @GetMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, FIotVirtualDeviceNet fIotVirtualDeviceNet) {
+ return super.exportXls(request, fIotVirtualDeviceNet, FIotVirtualDeviceNet.class, "虚拟设备网络模块");
+ }
+
+
+ @ApiOperationSupport(order = 7)
+ @ApiOperation(value="07. 导入excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device_net:importExcel")
+ @PostMapping(value = "/importExcel")
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, FIotVirtualDeviceNet.class);
+ }
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvDeviceDeployController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvDeviceDeployController.java
index db3541d..4a3a1bf 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvDeviceDeployController.java
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvDeviceDeployController.java
@@ -268,6 +268,8 @@ public class SurvDeviceDeployController extends JeecgController {
+ @Autowired
+ private IFDeviceOprationService fDeviceOprationService;
+
+
+ //@AutoLog(value = "设备操作记录-分页列表查询")
+ @ApiOperation(value = "01. 分页查询", notes = "")
+ @ApiOperationSupport(order = 1)
+ @GetMapping(value = "/list")
+ public Result> queryPageList(FDeviceOpration fDeviceOpration,
+ @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+ @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+ HttpServletRequest req) {
+
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(fDeviceOpration, req.getParameterMap());
+ DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ if (StringUtils.isNotBlank(fDeviceOpration.getAlertTimes())) {
+ String[] tims = fDeviceOpration.getAlertTimes().split(",");
+ LocalDateTime bTime = LocalDateTime.of(LocalDate.parse(tims[0], sdf), LocalTime.MIN);
+ LocalDateTime eTime = LocalDateTime.of(LocalDate.parse(tims[1], sdf), LocalTime.MAX).withNano(999999000);
+ queryWrapper.gt("OPERATOR_TIME", bTime);
+ queryWrapper.lt("OPERATOR_TIME", eTime);
+ }
+// if(fDeviceOpration.getEndTime()!=null){
+// LocalDateTime eTime =LocalDateTime.of(fDeviceOpration.getEndTime(),LocalTime.MAX).withNano(999999000);
+// queryWrapper.lt("OPERATOR_TIME", eTime);
+// }
+
+ Page page = new Page(pageNo, pageSize);
+ IPage pageList = fDeviceOprationService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+
+ @AutoLog(value = "设备操作记录-添加")
+ @ApiOperationSupport(order = 2)
+ @ApiOperation(value = "02. 添加", notes = "")
+ @RequiresPermissions("farm:f_device_opration:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody FDeviceOpration fDeviceOpration, HttpServletRequest request) {
+ String username = JwtUtil.getUserNameByToken(request);
+ fDeviceOpration.setCreateBy(username);
+ fDeviceOpration.setCreateTime(new Date());
+ fDeviceOprationService.save(fDeviceOpration);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "设备操作记录-编辑")
+ @ApiOperationSupport(order = 3)
+ @ApiOperation(value = "03. 编辑", notes = "")
+ @RequiresPermissions("farm:f_device_opration:edit")
+ @PostMapping(value = "/edit")
+ public Result edit(@RequestBody FDeviceOpration fDeviceOpration, HttpServletRequest request) {
+ //创建、更新时间不能编辑
+ fDeviceOpration.setCreateTime(null);
+ fDeviceOpration.setUpdateTime(null);
+ String username = JwtUtil.getUserNameByToken(request);
+ fDeviceOpration.setUpdateBy(username);
+ fDeviceOprationService.updateById(fDeviceOpration);
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 通过id删除
+ *
+ * @param id
+ * @return
+ */
+ @AutoLog(value = "设备操作记录-通过id删除")
+ @ApiOperation(value = "04.通过id删除", notes = "")
+ @RequiresPermissions("farm:f_device_opration:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name = "id", required = true) String id) {
+ fDeviceOprationService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+
+ @AutoLog(value = "设备操作记录-批量删除")
+ @ApiOperationSupport(order = 4)
+ @ApiOperation(value = "04. 批量删除", notes = "")
+ @RequiresPermissions("farm:f_device_opration:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+ this.fDeviceOprationService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+
+ //@AutoLog(value = "设备操作记录-通过id查询")
+ @ApiOperationSupport(order = 5)
+ @ApiOperation(value = "05. 通过id查询", notes = "")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name = "id", required = true) String id) {
+ FDeviceOpration fDeviceOpration = fDeviceOprationService.getById(id);
+ if (fDeviceOpration == null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(fDeviceOpration);
+ }
+
+
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotProtocolController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotProtocolController.java
new file mode 100644
index 0000000..467c32d
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotProtocolController.java
@@ -0,0 +1,143 @@
+package org.jeecg.modules.appmana.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.entity.FIotProtocol;
+import org.jeecg.modules.appmana.service.IFIotProtocolService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.Date;
+
+
+ /**
+ * @Description: 物联网设备协议表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+@Api(tags="99. 物联网设备协议表 id")
+@RestController
+@RequestMapping("/api/iot/fIotProtocol")
+@Slf4j
+public class SurvIotProtocolController extends JeecgController {
+ @Autowired
+ private IFIotProtocolService fIotProtocolService;
+
+
+ //@AutoLog(value = "物联网设备协议表-分页列表查询")
+ @ApiOperation(value="01. 分页查询", notes="")
+ @ApiOperationSupport(order = 1)
+ @GetMapping(value = "/list")
+ public Result> queryPageList(FIotProtocol fIotProtocol,
+ @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+ @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(fIotProtocol, req.getParameterMap());
+ Page page = new Page(pageNo, pageSize);
+ IPage pageList = fIotProtocolService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+
+ @AutoLog(value = "物联网设备协议表-添加")
+ @ApiOperationSupport(order = 2)
+ @ApiOperation(value="02. 添加", notes="")
+ @RequiresPermissions("iot:f_iot_protocol:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody FIotProtocol fIotProtocol, HttpServletRequest request) {
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotProtocol.setCreateBy(username);
+ fIotProtocol.setCreateTime(new Date());
+ fIotProtocolService.save(fIotProtocol);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "物联网设备协议表-编辑")
+ @ApiOperationSupport(order = 3)
+ @ApiOperation(value="03. 编辑", notes="")
+ @RequiresPermissions("iot:f_iot_protocol:edit")
+ @PostMapping(value = "/edit")
+ public Result edit(@RequestBody FIotProtocol fIotProtocol, HttpServletRequest request) {
+ //创建、更新时间不能编辑
+ fIotProtocol.setCreateTime(null);
+ fIotProtocol.setUpdateTime(null);
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotProtocol.setUpdateBy(username);
+ fIotProtocolService.updateById(fIotProtocol);
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 通过id删除
+ *
+ * @param id
+ * @return
+ */
+ @AutoLog(value = "物联网设备协议表-通过id删除")
+ @ApiOperation(value="04.通过id删除", notes="")
+ @RequiresPermissions("iot:f_iot_protocol:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name="id",required=true) String id) {
+ fIotProtocolService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+
+ @AutoLog(value = "物联网设备协议表-批量删除")
+ @ApiOperationSupport(order = 4)
+ @ApiOperation(value="04. 批量删除", notes="")
+ @RequiresPermissions("iot:f_iot_protocol:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+ this.fIotProtocolService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+
+ //@AutoLog(value = "物联网设备协议表-通过id查询")
+ @ApiOperationSupport(order = 5)
+ @ApiOperation(value="05. 通过id查询", notes="")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name="id",required=true) String id) {
+ FIotProtocol fIotProtocol = fIotProtocolService.getById(id);
+ if(fIotProtocol==null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(fIotProtocol);
+ }
+
+
+ @ApiOperationSupport(order = 6)
+ @ApiOperation(value="06. 导出excel", notes="")
+ @RequiresPermissions("iot:f_iot_protocol:exportXls")
+ @GetMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, FIotProtocol fIotProtocol) {
+ return super.exportXls(request, fIotProtocol, FIotProtocol.class, "物联网设备协议表");
+ }
+
+
+ @ApiOperationSupport(order = 7)
+ @ApiOperation(value="07. 导入excel", notes="")
+ @RequiresPermissions("iot:f_iot_protocol:importExcel")
+ @PostMapping(value = "/importExcel")
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, FIotProtocol.class);
+ }
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotVirtualDeviceController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotVirtualDeviceController.java
new file mode 100644
index 0000000..d4316f9
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/controller/SurvIotVirtualDeviceController.java
@@ -0,0 +1,143 @@
+package org.jeecg.modules.appmana.controller;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.jeecg.common.api.vo.Result;
+import org.jeecg.common.aspect.annotation.AutoLog;
+import org.jeecg.common.system.base.controller.JeecgController;
+import org.jeecg.common.system.query.QueryGenerator;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.entity.FIotVirtualDevice;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Arrays;
+import java.util.Date;
+
+
+ /**
+ * @Description: 虚拟设备表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+@Api(tags="99. 虚拟设备表 id")
+@RestController
+@RequestMapping("/api/iot/fIotVirtualDevice")
+@Slf4j
+public class SurvIotVirtualDeviceController extends JeecgController {
+ @Autowired
+ private IFIotVirtualDeviceService fIotVirtualDeviceService;
+
+
+ //@AutoLog(value = "虚拟设备表-分页列表查询")
+ @ApiOperation(value="01. 分页查询", notes="")
+ @ApiOperationSupport(order = 1)
+ @GetMapping(value = "/list")
+ public Result> queryPageList(FIotVirtualDevice fIotVirtualDevice,
+ @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
+ @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
+ HttpServletRequest req) {
+ QueryWrapper queryWrapper = QueryGenerator.initQueryWrapper(fIotVirtualDevice, req.getParameterMap());
+ Page page = new Page(pageNo, pageSize);
+ IPage pageList = fIotVirtualDeviceService.page(page, queryWrapper);
+ return Result.OK(pageList);
+ }
+
+
+ @AutoLog(value = "虚拟设备表-添加")
+ @ApiOperationSupport(order = 2)
+ @ApiOperation(value="02. 添加", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device:add")
+ @PostMapping(value = "/add")
+ public Result add(@RequestBody FIotVirtualDevice fIotVirtualDevice, HttpServletRequest request) {
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDevice.setCreateBy(username);
+ fIotVirtualDevice.setCreateTime(new Date());
+ fIotVirtualDeviceService.save(fIotVirtualDevice);
+ return Result.OK("添加成功!");
+ }
+
+ @AutoLog(value = "虚拟设备表-编辑")
+ @ApiOperationSupport(order = 3)
+ @ApiOperation(value="03. 编辑", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device:edit")
+ @PostMapping(value = "/edit")
+ public Result edit(@RequestBody FIotVirtualDevice fIotVirtualDevice, HttpServletRequest request) {
+ //创建、更新时间不能编辑
+ fIotVirtualDevice.setCreateTime(null);
+ fIotVirtualDevice.setUpdateTime(null);
+ String username = JwtUtil.getUserNameByToken(request);
+ fIotVirtualDevice.setUpdateBy(username);
+ fIotVirtualDeviceService.updateById(fIotVirtualDevice);
+ return Result.OK("编辑成功!");
+ }
+
+ /**
+ * 通过id删除
+ *
+ * @param id
+ * @return
+ */
+ @AutoLog(value = "虚拟设备表-通过id删除")
+ @ApiOperation(value="04.通过id删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device:delete")
+ @DeleteMapping(value = "/delete")
+ public Result delete(@RequestParam(name="id",required=true) String id) {
+ fIotVirtualDeviceService.removeById(id);
+ return Result.OK("删除成功!");
+ }
+
+
+ @AutoLog(value = "虚拟设备表-批量删除")
+ @ApiOperationSupport(order = 4)
+ @ApiOperation(value="04. 批量删除", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device:deleteBatch")
+ @DeleteMapping(value = "/deleteBatch")
+ public Result deleteBatch(@RequestParam(name="ids",required=true) String ids) {
+ this.fIotVirtualDeviceService.removeByIds(Arrays.asList(ids.split(",")));
+ return Result.OK("批量删除成功!");
+ }
+
+
+ //@AutoLog(value = "虚拟设备表-通过id查询")
+ @ApiOperationSupport(order = 5)
+ @ApiOperation(value="05. 通过id查询", notes="")
+ @GetMapping(value = "/queryById")
+ public Result queryById(@RequestParam(name="id",required=true) String id) {
+ FIotVirtualDevice fIotVirtualDevice = fIotVirtualDeviceService.getById(id);
+ if(fIotVirtualDevice==null) {
+ return Result.error("未找到对应数据");
+ }
+ return Result.OK(fIotVirtualDevice);
+ }
+
+
+ @ApiOperationSupport(order = 6)
+ @ApiOperation(value="06. 导出excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device:exportXls")
+ @GetMapping(value = "/exportXls")
+ public ModelAndView exportXls(HttpServletRequest request, FIotVirtualDevice fIotVirtualDevice) {
+ return super.exportXls(request, fIotVirtualDevice, FIotVirtualDevice.class, "虚拟设备表");
+ }
+
+
+ @ApiOperationSupport(order = 7)
+ @ApiOperation(value="07. 导入excel", notes="")
+ @RequiresPermissions("iot:f_iot_virtual_device:importExcel")
+ @PostMapping(value = "/importExcel")
+ public Result> importExcel(HttpServletRequest request, HttpServletResponse response) {
+ return super.importExcel(request, response, FIotVirtualDevice.class);
+ }
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FDeviceOprationMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FDeviceOprationMapper.java
new file mode 100644
index 0000000..f823e97
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FDeviceOprationMapper.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.common.entity.FDeviceOpration;
+
+/**
+ * @Description: 设备操作记录
+ * @Author: jeecg-boot
+ * @Date: 2023-11-04
+ * @Version: V1.0
+ */
+public interface FDeviceOprationMapper extends BaseMapper {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotProtocolMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotProtocolMapper.java
new file mode 100644
index 0000000..188ab56
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotProtocolMapper.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.common.entity.FIotProtocol;
+
+/**
+ * @Description: 物联网设备协议表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+public interface FIotProtocolMapper extends BaseMapper {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceGroupMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceGroupMapper.java
new file mode 100644
index 0000000..4c12c13
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceGroupMapper.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.common.entity.FIotVirtualDeviceGroup;
+
+/**
+ * @Description: 虚拟设备模块分组
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+public interface FIotVirtualDeviceGroupMapper extends BaseMapper {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceMapper.java
new file mode 100644
index 0000000..4e0bf6a
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceMapper.java
@@ -0,0 +1,16 @@
+package org.jeecg.modules.appmana.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Param;
+import org.jeecg.common.entity.FIotVirtualDevice;
+
+/**
+ * @Description: 虚拟设备表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+public interface FIotVirtualDeviceMapper extends BaseMapper {
+
+ FIotVirtualDevice getDeviceByCode(@Param("deployCode")String deployCode);
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceModuleMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceModuleMapper.java
new file mode 100644
index 0000000..faae256
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceModuleMapper.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.common.entity.FIotVirtualDeviceModule;
+
+/**
+ * @Description: 虚拟设备模组表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+public interface FIotVirtualDeviceModuleMapper extends BaseMapper {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceNetMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceNetMapper.java
new file mode 100644
index 0000000..ccc2655
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/FIotVirtualDeviceNetMapper.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.jeecg.common.entity.FIotVirtualDeviceNet;
+
+/**
+ * @Description: 虚拟设备网络模块
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+public interface FIotVirtualDeviceNetMapper extends BaseMapper {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/IOTStatisticMapper.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/IOTStatisticMapper.java
index c5b3b26..d9cf0ee 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/IOTStatisticMapper.java
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/IOTStatisticMapper.java
@@ -1,6 +1,7 @@
package org.jeecg.modules.appmana.mapper;
import org.apache.ibatis.annotations.Param;
+import org.jeecg.common.iot.common.LoginUser2;
import org.jeecg.common.vo.VOHisFormResult;
import org.jeecg.common.vo.statistic.DTOIotCusSummray;
import org.jeecg.common.vo.statistic.DTOIotSummray;
@@ -31,4 +32,6 @@ public interface IOTStatisticMapper {
List summaryMaxByDays(@Param("query") DTOIotSummray dtoIotSummray);
List summaryMaxYearMonth(@Param("deployCode") String deployCode, @Param("tables") String tables, @Param("survItem") String survItem, @Param("years") String years);
+
+ LoginUser2 getUserByUserName(@Param("username") String username);
}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FDeviceOprationMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FDeviceOprationMapper.xml
new file mode 100644
index 0000000..cce58c3
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FDeviceOprationMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotProtocolMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotProtocolMapper.xml
new file mode 100644
index 0000000..dc6b640
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotProtocolMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceGroupMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceGroupMapper.xml
new file mode 100644
index 0000000..2f0174e
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceGroupMapper.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceMapper.xml
new file mode 100644
index 0000000..b8a3093
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceMapper.xml
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID,COMPANY_ID,FARM_ID,GROUP_ID,BUS_ID,IOT_ID,IOT_PARAMS,DEVICE_NAME,DEVICE_TYPE,DEVICE_SEC_TYPE,PROTOCOL_ID,CMD_STR,DEVICE_LAT,DEVICE_LONG,DEVICE_LONGLAT,DEVICE_NOTES,STATUS_SUPPORT,CONTROL_SUPPORT,RECORD_SUPPORT,LOWER_URL,UPPER_URL,SORT_NO,IS_ENABLE,TENANT_ID,RE_VISION,CREATE_BY,CREATE_TIME,UPDATE_BY,IS_DEL,UPDATE_TIME
+
+
+
+
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceModuleMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceModuleMapper.xml
new file mode 100644
index 0000000..03e8830
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceModuleMapper.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ID,COMPANY_ID,FARM_ID,DEVICE_ID,MODULE_CODE,MODULE_NUM,MODULE_BUS_ID,MODULE_GROUP_ID,MODULE_NET_ID,MODULE_TYPE,MODULE_SEC_TYPE,MODULE_NAME,MODULE_NOTES,MODULE_MODE,MODULE_VIRTUAL_STATUS,MODULE_PATH,REGISTER_TYPE,REGISTER_NUM,REGISTER_CMD_ON,REGISTER_CMD_OFF,REGISTER_CMD_STOP,REGISTER_ON,REGISTER_OFF,REGISTER_STOP,SORT_NO,IS_ENABLE,TENANT_ID,RE_VISION,CREATE_BY,CREATE_TIME,UPDATE_BY,IS_DEL,UPDATE_TIME
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceNetMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceNetMapper.xml
new file mode 100644
index 0000000..5f072db
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/FIotVirtualDeviceNetMapper.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/IOTStatisticMapper.xml b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/IOTStatisticMapper.xml
index 531f64e..f5b6cd3 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/IOTStatisticMapper.xml
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mapper/xml/IOTStatisticMapper.xml
@@ -145,4 +145,7 @@
ON t1.index = t2.months
ORDER BY t1.index asc
+
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/o/vo/common/LoginUser.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/o/vo/common/LoginUser.java
new file mode 100644
index 0000000..457a8c0
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/o/vo/common/LoginUser.java
@@ -0,0 +1,128 @@
+package org.jeecg.modules.appmana.o.vo.common;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecg.common.desensitization.annotation.SensitiveField;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ *
+ * 在线用户信息
+ *
+ *
+ * @Author scott
+ * @since 2018-12-20
+ */
+@Data
+@EqualsAndHashCode(callSuper = false)
+@Accessors(chain = true)
+public class LoginUser {
+
+ /**
+ * 登录人id
+ */
+ @SensitiveField
+ private String id;
+
+ /**
+ * 登录人账号
+ */
+ @SensitiveField
+ private String username;
+
+ /**
+ * 登录人名字
+ */
+ @SensitiveField
+ private String realname;
+
+ /**
+ * 登录人密码
+ */
+ @SensitiveField
+ private String password;
+
+ /**
+ * 当前登录部门code
+ */
+ private String orgCode;
+ /**
+ * 头像
+ */
+ @SensitiveField
+ private String avatar;
+
+ /**
+ * 生日
+ */
+ @SensitiveField
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private Date birthday;
+
+ /**
+ * 性别(1:男 2:女)
+ */
+ private Integer sex;
+
+ /**
+ * 电子邮件
+ */
+ @SensitiveField
+ private String email;
+
+ /**
+ * 电话
+ */
+ @SensitiveField
+ private String phone;
+
+ /**
+ * 状态(1:正常 2:冻结 )
+ */
+ private Integer status;
+
+ private Integer delFlag;
+ /**
+ * 同步工作流引擎1同步0不同步
+ */
+ private Integer activitiSync;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+ /**
+ * 身份(1 普通员工 2 上级)
+ */
+ private Integer userIdentity;
+
+ /**
+ * 管理部门ids
+ */
+ private String departIds;
+
+ /**
+ * 职务,关联职务表
+ */
+ @SensitiveField
+ private String post;
+
+ /**
+ * 座机号
+ */
+ @SensitiveField
+ private String telephone;
+
+ /** 多租户ids临时用,不持久化数据库(数据库字段不存在) */
+ private String relTenantIds;
+
+ /**设备id uniapp推送用*/
+ private String clientId;
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFDeviceOprationService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFDeviceOprationService.java
new file mode 100644
index 0000000..527bd30
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFDeviceOprationService.java
@@ -0,0 +1,17 @@
+package org.jeecg.modules.appmana.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.entity.FDeviceOpration;
+import org.jeecg.common.iot.common.DeviceLogVo;
+
+/**
+ * @Description: 设备操作记录
+ * @Author: jeecg-boot
+ * @Date: 2023-11-04
+ * @Version: V1.0
+ */
+public interface IFDeviceOprationService extends IService {
+
+ boolean saveDeviceOpration(DeviceLogVo deviceLogVo);
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotProtocolService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotProtocolService.java
new file mode 100644
index 0000000..802ab1b
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotProtocolService.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.entity.FIotProtocol;
+
+/**
+ * @Description: 物联网设备协议表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+public interface IFIotProtocolService extends IService {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceGroupService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceGroupService.java
new file mode 100644
index 0000000..eb86197
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceGroupService.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.entity.FIotVirtualDeviceGroup;
+
+/**
+ * @Description: 虚拟设备模块分组
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+public interface IFIotVirtualDeviceGroupService extends IService {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceModuleService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceModuleService.java
new file mode 100644
index 0000000..f7585c9
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceModuleService.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.entity.FIotVirtualDeviceModule;
+
+/**
+ * @Description: 虚拟设备模组表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+public interface IFIotVirtualDeviceModuleService extends IService {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceNetService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceNetService.java
new file mode 100644
index 0000000..d059d20
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceNetService.java
@@ -0,0 +1,14 @@
+package org.jeecg.modules.appmana.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import org.jeecg.common.entity.FIotVirtualDeviceNet;
+
+/**
+ * @Description: 虚拟设备网络模块
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+public interface IFIotVirtualDeviceNetService extends IService {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceService.java
new file mode 100644
index 0000000..650bd58
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/IFIotVirtualDeviceService.java
@@ -0,0 +1,71 @@
+package org.jeecg.modules.appmana.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+
+import org.jeecg.common.entity.FIotVirtualDevice;
+import org.jeecg.common.entity.FIotVirtualDeviceModule;
+import org.jeecg.common.entity.SurvDeviceDeploy;
+import org.jeecg.common.iot.Fertilizer.VOFertilizerStats;
+import org.jeecg.common.iot.up.DeviceActionVo;
+import org.jeecg.common.iot.up.ModuleStatusResultVo;
+import org.jeecg.common.iot.vo.DeviceControlResultVo;
+import org.jeecg.common.iot.vo.VODeviceCmd;
+
+import java.util.List;
+
+/**
+ * @Description: 虚拟设备表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+public interface IFIotVirtualDeviceService extends IService {
+
+ FIotVirtualDevice getDeviceByCode(String deployCode);
+
+ VOFertilizerStats getDeviceStats(SurvDeviceDeploy deploy);
+
+ /**
+ * 单控寄存器
+ * @param deploy
+ * @param voDeviceCmd
+ * @return
+ */
+ DeviceControlResultVo sendControl(SurvDeviceDeploy deploy, VODeviceCmd voDeviceCmd);
+
+ /**
+ * 单查寄存器
+ */
+ boolean sendSingleQuery(SurvDeviceDeploy deploy, FIotVirtualDeviceModule module);
+
+ /**
+ * 多查寄存器
+ */
+ boolean sendMutiQuery(SurvDeviceDeploy deploy, List modules);
+
+ FIotVirtualDevice getDeviceByIotCode(String deployCode);
+
+ /**
+ * 处理内部mqtt服务中,设备行为
+ * @param deviceQueryActionVo
+ */
+ void processIotAction(DeviceActionVo deviceQueryActionVo);
+
+
+ ModuleStatusResultVo getDeviceCache(String deployCode);
+
+ void pubDeviceTopic(ModuleStatusResultVo moduleStatusResultVo,List devices);
+ /**
+ * 厂家对接mqtt处理
+ * @param topic
+ */
+ void processInterface(String topic, byte[] payload);
+
+ /**
+ * 获取所有需要订阅的mqtt主题
+ * @return
+ */
+ List getAllMqttTopic();
+
+ void processCache(DeviceActionVo deviceQueryActionVo);
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FDeviceOprationServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FDeviceOprationServiceImpl.java
new file mode 100644
index 0000000..c9b196d
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FDeviceOprationServiceImpl.java
@@ -0,0 +1,73 @@
+package org.jeecg.modules.appmana.service.impl;
+
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.entity.FDeviceOpration;
+import org.jeecg.common.entity.SurvDeviceDeploy;
+import org.jeecg.common.iot.common.DeviceLogVo;
+import org.jeecg.common.iot.common.LoginUser2;
+import org.jeecg.common.iot.vo.VOCmdPack;
+import org.jeecg.common.util.IpUtils;
+import org.jeecg.modules.appmana.mapper.FDeviceOprationMapper;
+import org.jeecg.modules.appmana.service.IFDeviceOprationService;
+import org.jeecg.modules.appmana.utils.HttpServletRequestUtil;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletRequest;
+import java.time.LocalDateTime;
+
+/**
+ * @Description: 设备操作记录
+ * @Author: jeecg-boot
+ * @Date: 2023-11-04
+ * @Version: V1.0
+ */
+@Service
+public class FDeviceOprationServiceImpl extends ServiceImpl implements IFDeviceOprationService {
+
+
+ @Override
+ public boolean saveDeviceOpration(DeviceLogVo deviceLogVo) {
+ if (deviceLogVo != null) {
+
+
+ LocalDateTime now = LocalDateTime.now();
+ SurvDeviceDeploy deploy = deviceLogVo.getDeploy();
+ LoginUser2 loginUser = deviceLogVo.getLoginUser();
+ if (deploy != null && loginUser != null) {
+ FDeviceOpration fDeviceOpration = new FDeviceOpration();
+ fDeviceOpration.setTenantId(deploy.getTenantId());
+ fDeviceOpration.setOperatorUserId(loginUser.getId());
+ fDeviceOpration.setOperatorUserName(loginUser.getRealname());
+ fDeviceOpration.setOperatorUserAvatar(loginUser.getAvatar());
+ fDeviceOpration.setCreateBy(loginUser.getId());
+
+ VOCmdPack voCmdPack = new VOCmdPack();
+ voCmdPack.setVariableName(deviceLogVo.getVariableName());
+ voCmdPack.setVariableValue(deviceLogVo.getVariableValue());
+ fDeviceOpration.setDeployId(deploy.getId());
+ fDeviceOpration.setOperatorTime(now);
+ fDeviceOpration.setOperatorContent(JSONUtil.parseObj(voCmdPack));
+
+ if(deviceLogVo.isProcessRequest()) {
+ HttpServletRequest request = HttpServletRequestUtil.getRequest();
+ String ipAddr = IpUtils.getIpAddr(request);
+ String header = request.getHeader("user-agent");
+ fDeviceOpration.setIp(ipAddr);
+ fDeviceOpration.setAgent(header);
+ }
+ fDeviceOpration.setOperatorDes(deviceLogVo.getOperationDetail());
+ fDeviceOpration.setVariableId(deviceLogVo.getVariableName());
+ fDeviceOpration.setVariableDes(deviceLogVo.getVariableDes());
+ fDeviceOpration.setOprationName(deviceLogVo.getActions());
+ fDeviceOpration.setVariableValue(deviceLogVo.getVariableValue());
+ fDeviceOpration.setOperationResult(deviceLogVo.isOperationResult() ? 1 : 0);
+ fDeviceOpration.setCalStatus(deviceLogVo.getCalStatus());
+ save(fDeviceOpration);
+ }
+ }
+ return false;
+ }
+
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotProtocolServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotProtocolServiceImpl.java
new file mode 100644
index 0000000..3b918c3
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotProtocolServiceImpl.java
@@ -0,0 +1,18 @@
+package org.jeecg.modules.appmana.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.entity.FIotProtocol;
+import org.jeecg.modules.appmana.mapper.FIotProtocolMapper;
+import org.jeecg.modules.appmana.service.IFIotProtocolService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: 物联网设备协议表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+@Service
+public class FIotProtocolServiceImpl extends ServiceImpl implements IFIotProtocolService {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceGroupServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceGroupServiceImpl.java
new file mode 100644
index 0000000..58adc14
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceGroupServiceImpl.java
@@ -0,0 +1,18 @@
+package org.jeecg.modules.appmana.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.entity.FIotVirtualDeviceGroup;
+import org.jeecg.modules.appmana.mapper.FIotVirtualDeviceGroupMapper;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceGroupService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: 虚拟设备模块分组
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+@Service
+public class FIotVirtualDeviceGroupServiceImpl extends ServiceImpl implements IFIotVirtualDeviceGroupService {
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceModuleServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceModuleServiceImpl.java
new file mode 100644
index 0000000..71140f9
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceModuleServiceImpl.java
@@ -0,0 +1,61 @@
+package org.jeecg.modules.appmana.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.jeecg.common.entity.FIotVirtualDevice;
+import org.jeecg.common.entity.FIotVirtualDeviceModule;
+import org.jeecg.modules.appmana.mapper.FIotVirtualDeviceModuleMapper;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceModuleService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @Description: 虚拟设备模组表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+@Service
+@Slf4j
+public class FIotVirtualDeviceModuleServiceImpl extends ServiceImpl implements IFIotVirtualDeviceModuleService {
+ @Autowired
+ @Lazy
+ private FIotVirtualDeviceServiceImpl deviceService;
+
+ public List getModulesByCode(String deployCode) {
+
+ FIotVirtualDevice device = deviceService.lambdaQuery()
+ .eq(FIotVirtualDevice::getIotCode,deployCode)
+ .eq(FIotVirtualDevice::getIsEnable,1)
+ .orderByDesc(FIotVirtualDevice::getCreateTime)
+ .last("limit 1")
+ .one();
+ if(device==null){
+ log.error("=======无效虚拟设备:{}======",deployCode);
+ return new ArrayList<>();
+ }
+ List modules = lambdaQuery()
+ .eq(FIotVirtualDeviceModule::getDeviceId,device.getId())
+ .eq(FIotVirtualDeviceModule::getIsEnable,1)
+ .orderByAsc(FIotVirtualDeviceModule::getSortNo)
+ .orderByDesc(FIotVirtualDeviceModule::getCreateTime)
+ .list()
+ ;
+ return modules;
+ }
+
+ public List getModulesByNet(String id) {
+ List modules = lambdaQuery()
+ .eq(FIotVirtualDeviceModule::getModuleNetId,id)
+ .eq(FIotVirtualDeviceModule::getIsEnable,1)
+ .orderByAsc(FIotVirtualDeviceModule::getSortNo)
+ .orderByDesc(FIotVirtualDeviceModule::getCreateTime)
+ .list()
+ ;
+ return modules;
+ }
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceNetServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceNetServiceImpl.java
new file mode 100644
index 0000000..f0311f8
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceNetServiceImpl.java
@@ -0,0 +1,28 @@
+package org.jeecg.modules.appmana.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.jeecg.common.entity.FIotVirtualDeviceNet;
+import org.jeecg.modules.appmana.mapper.FIotVirtualDeviceNetMapper;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceNetService;
+import org.springframework.stereotype.Service;
+
+/**
+ * @Description: 虚拟设备网络模块
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.0
+ */
+@Service
+public class FIotVirtualDeviceNetServiceImpl extends ServiceImpl implements IFIotVirtualDeviceNetService {
+
+ public FIotVirtualDeviceNet matchNetSet(String ident) {
+ FIotVirtualDeviceNet net = lambdaQuery()
+ .eq(FIotVirtualDeviceNet::getNetIdentCode, ident)
+ .eq(FIotVirtualDeviceNet::getIsEnable,1)
+ .orderByDesc(FIotVirtualDeviceNet::getCreateTime)
+ .last("limit 1")
+ .one()
+ ;
+ return net;
+ }
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceServiceImpl.java
new file mode 100644
index 0000000..4d7bd49
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/FIotVirtualDeviceServiceImpl.java
@@ -0,0 +1,764 @@
+package org.jeecg.modules.appmana.service.impl;
+
+import cn.hutool.core.lang.Assert;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.iot.Fertilizer.VOFertilizerStats;
+import org.jeecg.common.iot.Fertilizer.VOFertilizerStatsArr;
+import org.jeecg.common.iot.common.LoginUser2;
+import org.jeecg.common.iot.enums.*;
+import org.jeecg.common.iot.vo.VODeviceCmd;
+import org.jeecg.common.system.util.JwtUtil;
+import org.jeecg.common.util.RedisUtil;
+import org.jeecg.common.util.TokenUtils;
+import org.jeecg.common.constant.IotConstants;
+import org.jeecg.common.entity.SurvDeviceDeploy;
+import org.jeecg.common.iot.common.DeviceLogVo;
+import org.jeecg.modules.appmana.mapper.IOTStatisticMapper;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceService;
+import org.jeecg.modules.appmana.utils.CommonUtils;
+import org.jeecg.common.entity.FIotVirtualDevice;
+import org.jeecg.common.entity.FIotVirtualDeviceModule;
+import org.jeecg.common.entity.FIotVirtualDeviceNet;
+import org.jeecg.modules.appmana.mapper.FIotVirtualDeviceMapper;
+import org.jeecg.common.iot.up.DeviceActionVo;
+import org.jeecg.common.iot.up.ModuleStatusDetailVo;
+import org.jeecg.common.iot.up.ModuleStatusResultVo;
+import org.jeecg.common.iot.vo.DeviceControlResultVo;
+import org.jeecg.common.util.ModbusCommandUtil;
+import org.jeecg.common.util.ModbusResponseParser;
+import org.jeecg.modules.mqtt.MqttService;
+import org.jeecg.common.constant.TopicConstant;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Description: 虚拟设备表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.0
+ */
+@Service
+@Slf4j
+public class FIotVirtualDeviceServiceImpl extends ServiceImpl implements IFIotVirtualDeviceService {
+
+ @Autowired
+ private FIotVirtualDeviceModuleServiceImpl moduleService;
+ @Autowired
+ private FIotVirtualDeviceNetServiceImpl netService;
+ @Autowired(required = false)
+ private MqttService mqttCustomerClient;
+ @Autowired
+ @Lazy
+ private SurvDeviceDeployServiceImpl deviceDeployService;
+ @Autowired
+ @Lazy
+ private FDeviceOprationServiceImpl deviceOprationService;
+ @Resource
+ private IOTStatisticMapper iotStatisticMapper;
+ @Autowired
+ @Lazy
+ private RedisUtil redisUtil;
+
+
+ /**
+ * 设备缓存时间
+ */
+ private long cacheTime = 3600;//缓存3600秒
+
+
+ @Override
+ public FIotVirtualDevice getDeviceByCode(String deployCode) {
+ FIotVirtualDevice fIotVirtualDevice = baseMapper.getDeviceByCode(deployCode);
+ return fIotVirtualDevice;
+ }
+
+ @Override
+ public VOFertilizerStats getDeviceStats(SurvDeviceDeploy deploy) {
+
+ VOFertilizerStats voFertilizerStats = new VOFertilizerStats();
+ //获取设备信息 todo
+ FIotVirtualDevice fIotVirtualDevice = baseMapper.getDeviceByCode(deploy.getDeployCode());
+ Assert.notNull(fIotVirtualDevice,"无效设备。");
+ List arrList = new ArrayList();
+ if(fIotVirtualDevice.getModules()!= null && !fIotVirtualDevice.getModules().isEmpty()){
+ for (FIotVirtualDeviceModule module : fIotVirtualDevice.getModules()) {
+ VOFertilizerStatsArr voFertilizerStatsArr = new VOFertilizerStatsArr();
+ voFertilizerStatsArr.setDeployId(deploy.getId());
+ voFertilizerStatsArr.setEleType(IotConstants.FERTILIZER_DATA);
+ voFertilizerStatsArr.setEleName(module.getModuleName());
+ voFertilizerStatsArr.setEleItem("");
+ voFertilizerStatsArr.setEleIcon("");
+ voFertilizerStatsArr.setEleColor("");
+ voFertilizerStatsArr.setEleIconFolder("");
+// voFertilizerStatsArr.setEleValue(xphDeviceNewestDataEleVo.getEValue());
+// voFertilizerStatsArr.setEleUnit(sele.getEleUnit());
+ voFertilizerStatsArr.setLastUpdate(null);
+ voFertilizerStatsArr.setDataDateTime(null);
+ arrList.add(voFertilizerStatsArr);
+ }
+ }
+
+ voFertilizerStats.setStatsList(arrList);
+ voFertilizerStats.setStatusSupport(fIotVirtualDevice.getStatusSupport());
+ voFertilizerStats.setRecordSupport(fIotVirtualDevice.getRecordSupport());
+ voFertilizerStats.setControlSupport(fIotVirtualDevice.getControlSupport());
+ voFertilizerStats.setUpperUrl(fIotVirtualDevice.getUpperUrl());
+ voFertilizerStats.setLowerUrl(fIotVirtualDevice.getLowerUrl());
+ return voFertilizerStats;
+ }
+
+ public DeviceControlResultVo sendControl(SurvDeviceDeploy deploy, VODeviceCmd voDeviceCmd) {
+ DeviceControlResultVo deviceControlResultVo = new DeviceControlResultVo();
+ deviceControlResultVo.setDeviceStatus(voDeviceCmd.getVariableValue());
+ boolean result = false;
+ if(deploy!=null){
+ //获取寄存器位置
+ FIotVirtualDeviceModule module = moduleService.getById(voDeviceCmd.getVariableName());
+ Assert.notNull(module,"模组未正确配置");
+ FIotVirtualDeviceNet net = netService.getById(module.getModuleNetId());
+ Assert.notNull(net,"模组物联网模块未正确配置");
+ deviceControlResultVo.setDeviceName(module.getModuleName());
+ deviceControlResultVo.setDeviceKey(module.getRegisterNum()+"");
+ String cmdStr = ModbusCommandUtil.buildCommand(1, RegisterType.valueOfCode(module.getRegisterType()), RWType.WRITE, module.getRegisterNum(), HexTransToInteger(voDeviceCmd.getVariableValue(),module), null);
+ log.warn("设备:{},成功构造M控制指令:{},主题:{},即将发送",deploy.getDeployDes(),cmdStr,net.getNetDownTopic());
+
+ result = sendIt(net.getNetDownTopic(),cmdStr);
+ }
+ deviceControlResultVo.setActionResult(result);
+ return deviceControlResultVo;
+ }
+
+ @Override
+ public boolean sendSingleQuery(SurvDeviceDeploy deploy, FIotVirtualDeviceModule module) {
+ boolean result = false;
+ Assert.notNull(deploy,"设备未传入");
+ Assert.notNull(module,"模组未传入");
+ FIotVirtualDeviceNet net = netService.getById(module.getModuleNetId());
+ Assert.notNull(net,"模组物联网模块未正确配置");
+ String cmdStr = ModbusCommandUtil.buildCommand(1, RegisterType.valueOfCode(module.getRegisterType()), RWType.READ, module.getRegisterNum(), null, 1);
+ log.warn("设备:{},成功构造M单查询指令:{},即将发送至:{}",deploy.getDeployDes(),cmdStr,net.getNetDownTopic());
+ result = sendIt(net.getNetDownTopic(),cmdStr);
+ return false;
+ }
+
+ @Override
+ public boolean sendMutiQuery(SurvDeviceDeploy deploy, List modules) {
+ boolean result = false;
+ Assert.notNull(deploy,"设备未传入");
+ Assert.isTrue((modules!=null && !modules.isEmpty()),"模组列表未传入");
+ Map> moduleMap = modules.stream().collect(Collectors.groupingBy(FIotVirtualDeviceModule::getModuleNetId));
+ Comparator nameComparator = Comparator.comparing(FIotVirtualDeviceModule::getRegisterNum);
+ for (String netId : moduleMap.keySet()) {
+ List list = moduleMap.get(netId);
+ FIotVirtualDeviceNet net = netService.getById(netId);
+ if(net==null){
+ log.error("无效的物联网id:{},设备:{}",netId,deploy.getDeployDes());
+ continue;
+ }
+ //按寄存器类型分组
+ Map> regTypeList = list.stream().collect(Collectors.groupingBy(FIotVirtualDeviceModule::getRegisterType));
+ for (Integer keys : regTypeList.keySet()) {
+ List regs = regTypeList.get(keys);
+ regs.sort(nameComparator.reversed());//倒叙获取最大的寄存器
+ Integer maxRegister = regs.get(0).getRegisterNum() +1;//起始寄存器位置
+// Integer minRegister = regs.get(regs.size()-1).getRegisterNum();//查询寄存器数量
+ Integer minRegister = 0;//只能从0号开始,否则不清楚返回时是几号开始
+ Integer regType = regs.get(0).getRegisterType();
+ RegisterType typeEnum = RegisterType.valueOfCode(regType);
+ //构造查询参数
+ String cmdStr = ModbusCommandUtil.buildCommand(1, typeEnum, RWType.READ, minRegister, null, maxRegister);
+ log.warn("设备:{},成功构造M多查询指令:{},即将发送至:{}",deploy.getDeployDes(),cmdStr,net.getNetDownTopic());
+ result = sendIt(net.getNetDownTopic(),cmdStr);
+ }
+
+ }
+ return result;
+ }
+ @Override
+ public FIotVirtualDevice getDeviceByIotCode(String deployCode){
+ List devices = lambdaQuery()
+ .eq(FIotVirtualDevice::getIotCode, deployCode)
+ .eq(FIotVirtualDevice::getIsEnable,1)
+ .list();
+ if(!devices.isEmpty()){
+ return devices.get(0);
+ }
+ return null;
+ }
+
+ @Override
+ public void processIotAction(DeviceActionVo deviceActionVo) {
+ //token校验
+ boolean isOk = checkToken(deviceActionVo);
+ if(isOk){
+ DeviceActionType actionType = DeviceActionType.valueOfCode(deviceActionVo.getActionType());
+ SurvDeviceDeploy deploy = deviceDeployService.getById(deviceActionVo.getDeployId());
+ if(deploy!=null){
+ switch (actionType){
+ case DEVICE_QUERY_ALL:
+ //检查缓存
+ ModuleStatusResultVo deviceAllChache = getDeviceCache(deploy.getDeployCode());
+ log.warn("============={}===检查缓存======{}======",deploy.getDeployCode(),deviceAllChache);
+ if(deviceAllChache!=null){//缓存直接传入设备mqtt
+ FIotVirtualDevice device = getDeviceByIotCode(deploy.getDeployCode());
+ List devices = new ArrayList<>();
+ if(device!=null){
+ devices.add(device);
+ }
+ log.warn("============={}====缓存推入蓝海主题:{}=============",deviceAllChache,devices.size());
+ pubDeviceTopic(deviceAllChache, devices);
+ }else{//无缓存查询
+ List modules = moduleService.getModulesByCode(deploy.getDeployCode());
+ if(!modules.isEmpty()){
+ sendMutiQuery(deploy,modules);
+ }
+ }
+ break;
+ case DEVICE_QUERY_S:
+ //检查缓存
+ ModuleStatusResultVo deviceSCache = getDeviceCache(deploy.getDeployCode());
+ if(deviceSCache!=null){//缓存直接传入设备mqtt
+ FIotVirtualDevice device = getDeviceByIotCode(deploy.getDeployCode());
+ List devices = new ArrayList<>();
+ if(device!=null){
+ devices.add(device);
+ }
+ pubDeviceTopic(deviceSCache, devices);
+ }else {//无缓存查询
+ FIotVirtualDeviceModule module = moduleService.getById(deviceActionVo.getModuleId());
+ if (module != null) {
+ sendSingleQuery(deploy, module);
+ }
+ }
+ break;
+ case DEVICE_CONTROL:
+ VODeviceCmd voDeviceCmd = new VODeviceCmd();
+ voDeviceCmd.setDeployId(deploy.getId());
+ voDeviceCmd.setVariableName(deviceActionVo.getModuleId());
+ voDeviceCmd.setVariableValue(deviceActionVo.getCmdType());
+ DeviceControlResultVo resultVo = sendControl(deploy,voDeviceCmd);
+ //记录日志
+ String username = JwtUtil.getUsername(deviceActionVo.getToken());
+ LoginUser2 loginUser = iotStatisticMapper.getUserByUserName(username);
+ if(loginUser!=null){
+ DeviceLogVo deviceLogVo = new DeviceLogVo();
+ String formatStr = "用户%s,于 %s, 操作设备:%s,操作内容:%s,操作结果:%s";
+ deviceLogVo.setDeploy(deploy);
+ deviceLogVo.setLoginUser(loginUser);
+ deviceLogVo.setVariableDes(resultVo.getDeviceName());
+ deviceLogVo.setVariableName(resultVo.getDeviceKey());
+ deviceLogVo.setVariableValue(voDeviceCmd.getVariableValue());
+ deviceLogVo.setActions(CommonUtils.processRelayOprateName(resultVo.getDeviceName(), voDeviceCmd.getVariableValue()));
+ LocalDateTime now = LocalDateTime.now();
+ DateTimeFormatter sdf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+ deviceLogVo.setOperationDetail(String.format(formatStr, loginUser.getRealname(), now.format(sdf), deploy.getDeployDes(), resultVo.getDeviceName() + "->" + deviceLogVo.getActions(), resultVo.isActionResult() ? "成功" : "失败"));
+ deviceLogVo.setOperationResult(resultVo.isActionResult());
+ deviceLogVo.setCalStatus(0);
+ deviceLogVo.setProcessRequest(false);//不处理request
+ deviceOprationService.saveDeviceOpration(deviceLogVo);
+ }else{
+ log.error("=========记录日志失败,无效用户:{}============",username);
+ }
+ break;
+ }
+ }
+ }else{
+ log.error("非法的mqtt操作,设备:{},模组:{},类型:{},行为:{}",deviceActionVo.getDeployId(),deviceActionVo.getModuleId(),deviceActionVo.getActionType(),deviceActionVo.getCmdType());
+ }
+
+ }
+
+ public ModuleStatusResultVo getDeviceCache(String deployCode){
+ //检查缓存,如有直接返回
+ Object deviceCache = redisUtil.get(IotConstants.mqtt_device_status+deployCode);
+ if (deviceCache != null) {
+ log.warn("查询到 {} mqtt设备缓存缓存,直接返回", deployCode);
+ return JSONUtil.toBean(deviceCache.toString(), ModuleStatusResultVo.class);
+ }else{
+ log.error("xxxxxxxxxxxxxxxxxxxx未查询到mqtt缓存:{}xxxxxxxxxxxxxxxxx",deployCode);
+ }
+ return null;
+ }
+
+ public boolean checkToken(DeviceActionVo deviceActionVo){
+ boolean result = false;
+ if(deviceActionVo != null){
+ if(StringUtils.isNotBlank(deviceActionVo.getToken())){
+ // 验证Token有效性
+// result = TokenUtils.verifyToken(deviceActionVo.getToken(), sysBaseApi, redisUtil);//暂时无法验证,需要写一个内部调用校验
+ }
+ }
+ return result;
+ }
+
+
+ @Override
+ public void processInterface(String topic, byte[] payload) {
+
+ try {
+ String ident = topic.replace(IotInerfaceTopicType.DTU_TOPIC.getCode(), "");
+ ModbusResponseParser.ModbusResult res = org.jeecg.common.util.ModbusResponseParser.parse(payload);
+ String orgStr = ModbusResponseParser.bytesToHex(payload);
+ log.warn("主题:{},收到mqtt回执:{}=========,原文:{}", topic, res.toString(), orgStr);
+ if (res != null && res.isSuccess()) {
+ //查询网络模块
+ List modules = getModulesByIdent(ident);
+ if (!modules.isEmpty()) {
+ ModuleStatusResultVo moduleStatusResultVo = processHexToJson(res, modules);
+ //转发至设备的上下行主题
+ //模组关联的设备
+ List deviceId = modules.stream().map(FIotVirtualDeviceModule::getDeviceId).collect(Collectors.toList());
+ log.warn("转换modbus=========" + JSONUtil.toJsonStr(moduleStatusResultVo));
+ List devices = lambdaQuery().in(FIotVirtualDevice::getId, deviceId).list();
+ //推送蓝海设备主题
+ pubDeviceTopic(moduleStatusResultVo, devices);
+ //保存缓存
+ saveDeviceCache(moduleStatusResultVo,devices);
+ }
+ } else {
+ log.error("==================未能识别功能码,错误信息:{}:主题:{}===================", res != null ? res.getErrorMsg() : "", ident);
+ }
+ //如果是心跳,更新设备的时间
+ String infoStr = new String(payload);
+ log.error("========{}==========更新心跳:{}===================", infoStr, ident);
+ if ("www.usr.cn".equals(infoStr)) {
+ //查询网络模块
+ List modules = getModulesByIdent(ident);
+ if (!modules.isEmpty()) {
+ List deviceId = modules.stream().map(FIotVirtualDeviceModule::getDeviceId).collect(Collectors.toList());
+ List devices = lambdaQuery().in(FIotVirtualDevice::getId, deviceId).list();
+ List deploys = devices.stream().map(FIotVirtualDevice::getIotId).collect(Collectors.toList());
+ deviceDeployService.refreshLastSyncTimeByDeployCode(deploys);
+ }
+ }
+ }catch (Exception e){
+ e.printStackTrace();
+ log.error("处理厂家mqtt报文失败,"+e.getMessage());
+ }
+
+ }
+
+ /**
+ * 收到回执时,保存设备缓存
+ * @param devices
+ */
+ private void saveDeviceCache(ModuleStatusResultVo inComeStaus, List devices) {
+ if(!devices.isEmpty()){
+ for (FIotVirtualDevice device : devices) {
+ String redisKey = IotConstants.mqtt_device_status+device.getIotCode();
+
+ //首先检查缓存
+ ModuleStatusResultVo deviceCache = getDeviceCache(device.getIotCode());
+ if (deviceCache != null) {
+ List status = deviceCache.getStatus();
+ List finalList = new ArrayList<>();
+ Map cacheMap = new HashMap<>();
+ for (ModuleStatusDetailVo cache : status) {
+ cacheMap.put(cache.getModuleId(),cache);
+ }
+
+ for (ModuleStatusDetailVo inComeStausStatus : inComeStaus.getStatus()) {
+ ModuleStatusDetailVo cacheKey = cacheMap.get(inComeStausStatus.getModuleId());
+ if(cacheKey != null){//缓存存在,更新状态
+ status.remove(cacheKey);
+ cacheKey.setModuleStatus(inComeStausStatus.getModuleStatus());
+ finalList.add(cacheKey);
+ }else{//没有缓存,做补充
+ ModuleStatusDetailVo newStaus = new ModuleStatusDetailVo();
+ newStaus.setModuleId(inComeStausStatus.getModuleId());
+ newStaus.setModuleStatus(inComeStausStatus.getModuleStatus());
+ finalList.add(newStaus);
+ }
+ }
+ finalList.addAll(status);
+ deviceCache.setStatus(finalList);
+ redisUtil.set(redisKey, JSONUtil.parseObj(deviceCache), cacheTime);
+ log.warn("设备:{} 缓存更新成功", device.getDeviceName() + "-" + device.getIotCode());
+ } else {//否则直接覆盖或新增
+ cn.hutool.json.JSONObject newDeviceCache = JSONUtil.parseObj(inComeStaus);
+ redisUtil.set(redisKey, newDeviceCache, cacheTime);
+ log.warn("设备:{} 缓存创建成功", device.getDeviceName() + "-" + device.getIotCode());
+ }
+ }
+ }
+ }
+
+ /**
+ * 根据主题获取设备模组
+ */
+ private List getModulesByIdent(String identCode){
+ //查询网络模块
+ FIotVirtualDeviceNet net = netService.matchNetSet(identCode);
+ if (net != null) {
+ List modules = moduleService.getModulesByNet(net.getId());
+ if (!modules.isEmpty()) {
+ //模组关联的设备
+ return modules;
+ }else{
+ log.error("==================网络模块为空:{}:{}===================", identCode,net.getId());
+ }
+ } else {
+ log.error("==================网络模块未识别:{}===================", identCode);
+ }
+ return new ArrayList<>();
+ }
+
+ /**
+ * 推送消息至设备的主题
+ * @param moduleStatusResultVo
+ */
+ public void pubDeviceTopic(ModuleStatusResultVo moduleStatusResultVo,List devices) {
+ if(moduleStatusResultVo.getStatus()!=null && !moduleStatusResultVo.getStatus().isEmpty()){
+ if(!devices.isEmpty()){
+ for (FIotVirtualDevice device : devices) {
+ //推送至设别的上行主题
+ sendModbus(device.getUpperUrl(),null,JSONObject.toJSONString(moduleStatusResultVo));
+ }
+ }else{
+ log.error("xxxxxxxx设备为空,跳过发送xxxxxxxxxx");
+ }
+ }else{
+ log.error("<==================trans数据为空,跳过发送=================>");
+ }
+
+ }
+
+ @Override
+ public List getAllMqttTopic() {
+ List topics = new ArrayList<>();
+ //已部署设备中配置的主题
+ List deploys = deviceDeployService.lambdaQuery()
+ .eq(SurvDeviceDeploy::getIsDel,0)
+ .eq(SurvDeviceDeploy::getRunStatus,0)
+ .eq(SurvDeviceDeploy::getProtocolType, IotProtocolType.MQTT.getCode())
+ .list();
+ if(!deploys.isEmpty()){
+ for (SurvDeviceDeploy deploy : deploys) {
+ if(StringUtils.isNotBlank(deploy.getDeviceUrl())){
+ topics.add(deploy.getDeviceUrl());
+ }
+ if(StringUtils.isNotBlank(deploy.getDeviceIotUrl())){
+ topics.add(deploy.getDeviceIotUrl());
+ }
+ }
+ }
+ //虚拟设备中需要订阅的主题
+ List devices = lambdaQuery().nested(wrapper->
+ wrapper.isNotNull(FIotVirtualDevice::getUpperUrl)
+ .or()
+ .isNotNull(FIotVirtualDevice::getLowerUrl)
+ ).list();
+ if(!devices.isEmpty()){
+ for (FIotVirtualDevice device : devices) {
+ if(StringUtils.isNotBlank(device.getUpperUrl())){
+ topics.add(device.getUpperUrl());
+ }
+ if(StringUtils.isNotBlank(device.getLowerUrl())){
+ topics.add(device.getLowerUrl());
+ }
+ }
+ }
+ //物联网模块中的主题
+ List nets = netService.lambdaQuery()
+ .nested(wrapper->
+ wrapper.isNotNull(FIotVirtualDeviceNet::getNetUpTopic)
+ .or()
+ .isNotNull(FIotVirtualDeviceNet::getNetDownTopic)
+ ).list();
+ ;
+ if(!nets.isEmpty()){
+ for (FIotVirtualDeviceNet net : nets) {
+ if(StringUtils.isNotBlank(net.getNetUpTopic())){
+ topics.add(net.getNetUpTopic());
+ }
+ if(StringUtils.isNotBlank(net.getNetDownTopic())){
+ topics.add(net.getNetDownTopic());
+ }
+ }
+ }
+ return topics;
+ }
+
+ @Override
+ public void processCache(DeviceActionVo deviceActionVo) {
+ //token校验
+ boolean isOk = checkToken(deviceActionVo);
+ if(isOk){
+ DeviceActionType actionType = DeviceActionType.valueOfCode(deviceActionVo.getActionType());
+ SurvDeviceDeploy deploy = deviceDeployService.getById(deviceActionVo.getDeployId());
+ if(deploy!=null){
+ switch (actionType){
+ case DEVICE_QUERY_ALL:
+ //检查缓存
+ ModuleStatusResultVo deviceAllChache = getDeviceCache(deploy.getDeployCode());
+ log.warn("============={}===检查间隔缓存======{}======",deploy.getDeployCode(),deviceAllChache);
+ if(deviceAllChache!=null){//缓存直接传入设备mqtt
+ FIotVirtualDevice device = getDeviceByIotCode(deploy.getDeployCode());
+ List devices = new ArrayList<>();
+ if(device!=null){
+ devices.add(device);
+ }
+ log.warn("============={}====间隔缓存推入蓝海主题:{}=============",deviceAllChache,devices.size());
+ pubDeviceTopic(deviceAllChache, devices);
+ }
+ break;
+ }
+ }
+ }else{
+ log.error("间隔非法的mqtt操作,设备:{},模组:{},类型:{},行为:{}",deviceActionVo.getDeployId(),deviceActionVo.getModuleId(),deviceActionVo.getActionType(),deviceActionVo.getCmdType());
+ }
+ }
+
+ //将modus处理为json
+ public ModuleStatusResultVo processHexToJson(ModbusResponseParser.ModbusResult modbusResult, List modules){
+ FunctionCode functionCode = FunctionCode.valueOfCode(modbusResult.getFunctionCode());
+ ModuleStatusResultVo moduleStatusResultVo = null;
+ switch (functionCode){
+ case READ_COIL:
+ case READ_DISCRETE_INPUT:
+ moduleStatusResultVo = BitsToHex(modbusResult.getBits(),modules);
+ break;
+ case READ_HOLDING_REGISTER:
+ case READ_INPUT_REGISTER:
+ moduleStatusResultVo = ByteArrToHex(modbusResult.getValues(),modules);
+ break;
+ case WRITE_COIL:
+ case WRITE_HOLDING_REGISTER:
+ moduleStatusResultVo = ByteToHex(modbusResult.getAddress(),modbusResult.getValue(),modules);
+ break;
+ }
+ return moduleStatusResultVo;
+ }
+ public ModuleStatusResultVo BitsToHex(boolean[] bits,List modules){
+ ModuleStatusResultVo moduleStatusResultVo = new ModuleStatusResultVo();
+ if(bits!=null && bits.length>0){
+ List detailVos = new ArrayList<>();
+ log.warn("开始解析modbus_bits为json,数据长度:{},模组数量:{}",bits.length ,modules.size());
+ //遍历对应 模组和寄存器对应关系
+ if(!modules.isEmpty()){
+ Map moduleMap = new HashMap<>();
+ for (FIotVirtualDeviceModule module : modules) {
+ moduleMap.put(module.getRegisterNum(),module.getId());
+ }
+ for (int i = 0; i < bits.length; i++) {
+ String modbusId = moduleMap.get(i);
+ if(StringUtils.isNotBlank(modbusId)){
+ log.warn("==========bits寄存器序列:{},id:{}===========",i,modbusId);
+ ModuleStatusDetailVo moduleStatusDetailVo = new ModuleStatusDetailVo();
+ moduleStatusDetailVo.setModuleId(modbusId);
+ moduleStatusDetailVo.setModuleStatus(transBitsToStatus(bits[i]));
+ detailVos.add(moduleStatusDetailVo);
+ }else{
+ log.warn("bits跳过未配置的寄存器序列:{}",i);
+ }
+ }
+ }
+ moduleStatusResultVo.setStatus(detailVos);
+ }else{
+ log.error("跳过无数据bits解析");
+ }
+ return moduleStatusResultVo;
+ }
+
+
+ public ModuleStatusResultVo ByteToHex(Integer address,Integer bytes,List modules){
+ ModuleStatusResultVo moduleStatusResultVo = new ModuleStatusResultVo();
+ if(bytes!=null){
+ List detailVos = new ArrayList<>();
+ ModuleStatusDetailVo moduleStatusDetailVo = new ModuleStatusDetailVo();
+ //遍历对应 模组和寄存器对应关系
+ if(!modules.isEmpty()){
+ Map moduleMap = new HashMap<>();
+ for (FIotVirtualDeviceModule module : modules) {
+ moduleMap.put(module.getRegisterNum(),module.getId());
+ }
+ String modbusId = moduleMap.get(address);
+ if(StringUtils.isNotBlank(modbusId)){
+ moduleStatusDetailVo.setModuleId(modbusId);
+ moduleStatusDetailVo.setModuleStatus(transIntToStatus(bytes));
+ detailVos.add(moduleStatusDetailVo);
+ moduleStatusResultVo.setStatus(detailVos);
+ }else{
+ log.error("byte跳过未配置的寄存器序列 :{}",address);
+ }
+
+ }
+
+ }
+ return moduleStatusResultVo;
+ }
+
+
+
+
+ public ModuleStatusResultVo ByteArrToHex(int[] modbusBytes,List modules){
+ ModuleStatusResultVo moduleStatusResultVo = new ModuleStatusResultVo();
+ if(modbusBytes!=null && modbusBytes.length>0){
+ List detailVos = new ArrayList<>();
+ log.warn("开始解析modbus为json,数据长度:{},模组数量:{}",modbusBytes.length ,modules.size());
+ //遍历对应 模组和寄存器对应关系
+ if(!modules.isEmpty()){
+ Map moduleMap = new HashMap<>();
+ for (FIotVirtualDeviceModule module : modules) {
+ moduleMap.put(module.getRegisterNum(),module.getId());
+ }
+ for (int i = 0; i < modbusBytes.length; i++) {
+ String modbusId = moduleMap.get(i);
+ if(StringUtils.isNotBlank(modbusId)){
+ log.warn("==========寄存器序列:{},id:{}===========",i,modbusId);
+ ModuleStatusDetailVo moduleStatusDetailVo = new ModuleStatusDetailVo();
+ moduleStatusDetailVo.setModuleId(modbusId);
+ moduleStatusDetailVo.setModuleStatus(transIntToStatus(modbusBytes[i]));
+ detailVos.add(moduleStatusDetailVo);
+ }else{
+ log.warn("跳过未配置的寄存器序列:{}",i);
+ }
+ }
+ }
+ moduleStatusResultVo.setStatus(detailVos);
+ }else{
+ log.error("跳过无数据modbus解析");
+ }
+ return moduleStatusResultVo;
+ }
+
+ /**
+ * 将modbus十六进制 转为可读的模块状态
+ * @param hexStatus
+ * @return
+ */
+ public String transIntToStatus(int hexStatus){
+ String status = IotControlType.valueOfCode(hexStatus+"").getCode();
+ return status;
+ }
+ private String transBitsToStatus(boolean bits) {
+ if(bits){
+ return IotControlType.EQ_ON.getCode();
+ }else {
+ return IotControlType.EQ_OFF.getCode();
+ }
+ }
+
+ /**
+ * 将十六进制的字符串值转为Integer
+ * @param variableValue
+ * @param module
+ * @return
+ */
+ public Integer HexTransToInteger(String variableValue,FIotVirtualDeviceModule module){
+ Integer result = null;
+ IotControlType controlType = IotControlType.valueOfCode(variableValue);
+ switch (controlType){
+ case EQ_ON://开
+ result = Integer.decode(module.getRegisterCmdOn());
+ break;
+ case EQ_OFF://关
+ result = Integer.decode(module.getRegisterCmdOff());
+ break;
+ case EQ_STOP://停
+ result = Integer.decode(module.getRegisterCmdStop());
+ break;
+ }
+ return result;
+
+ }
+
+ public boolean sendIt(String topic,String cmd){
+ boolean result = false;
+ try {
+ byte[] modbusFrame = Hex.decodeHex(cmd.replaceAll("\\s", ""));
+ result = sendModbus(topic,modbusFrame,null);
+ }catch (Exception e){
+ e.printStackTrace();
+ }
+ return result;
+ }
+
+ public boolean sendModbus(String topic,byte[] msgContent,String content){
+ try {
+ log.warn("modbus指令发送======主题:{}========指令:{}",topic,msgContent);
+ String cmdId = "";
+ if(StringUtils.isNotBlank(content)){
+ cmdId = toUniqueString(content);
+ }else if(msgContent!=null){
+ cmdId = toUniqueString(new String(msgContent));
+ }
+ int expireSeconds=3000;//锁3秒
+ String lockerId = TopicConstant.MQTT_CMD_LOCKER + cmdId;
+
+ if(StringUtils.isNotBlank(content)){
+ mqttCustomerClient.publish(topic,content);
+ }else if(msgContent!=null){
+ mqttCustomerClient.publish(topic,msgContent);
+ }
+
+ }catch (Exception e){
+ log.error("=====mqtt指令发送失败========{}",e.getMessage());
+ e.printStackTrace();
+ }
+ return Boolean.TRUE;
+ }
+
+ // 转换为大写十六进制(无分隔)
+ public static String stringToHexUpperCase(String input) {
+ StringBuilder hexBuilder = new StringBuilder();
+ byte[] bytes = input.getBytes(StandardCharsets.UTF_8);
+
+ for (byte b : bytes) {
+ hexBuilder.append(String.format("%02X", b));
+ }
+ return hexBuilder.toString();
+ }
+
+ /**
+ * 将字节数组转换为带空格的十六进制字符串(便于阅读)
+ */
+ public static String bytesToHexWithSpaces(byte[] bytes) {
+ StringBuilder hexBuilder = new StringBuilder();
+ for (int i = 0; i < bytes.length; i++) {
+ if (i > 0) {
+ hexBuilder.append(" ");
+ }
+ hexBuilder.append(String.format("%02X", bytes[i]));
+ }
+ return hexBuilder.toString();
+ }
+
+
+ public static String toUniqueString(String jsonString) {
+ try {
+ ObjectMapper mapper = new ObjectMapper();
+ // 2. 生成MD5哈希作为唯一标识
+ MessageDigest md = MessageDigest.getInstance("MD5");
+ byte[] hash = md.digest(jsonString.getBytes());
+
+ // 3. 转换为十六进制字符串
+ StringBuilder hexString = new StringBuilder();
+ for (byte b : hash) {
+ hexString.append(String.format("%02x", b));
+ }
+
+ return hexString.toString();
+
+ } catch (Exception e) {
+ throw new RuntimeException("生成唯一字符串失败", e);
+ }
+ }
+
+}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/SurvDeviceDeployServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/SurvDeviceDeployServiceImpl.java
index 284bf94..f304771 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/SurvDeviceDeployServiceImpl.java
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/service/impl/SurvDeviceDeployServiceImpl.java
@@ -611,4 +611,16 @@ public class SurvDeviceDeployServiceImpl extends ServiceImpl deploys) {
+ if (!deploys.isEmpty()) {
+ lambdaUpdate()
+ .eq(SurvDeviceDeploy::getRunStatus, 0)
+ .in(SurvDeviceDeploy::getDeployCode, deploys).set(SurvDeviceDeploy::getLastsyncTime, new Date()).update();
+ }
+ }
}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpRequestUtils.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpRequestUtils.java
index 6e7c35c..55cdb2f 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpRequestUtils.java
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpRequestUtils.java
@@ -479,4 +479,5 @@ public class HttpRequestUtils {
HttpHeaders headers1 = responseEntity.getHeaders();//获取到头信息
return responseEntity.getBody();
}
+
}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpServletRequestUtil.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpServletRequestUtil.java
new file mode 100644
index 0000000..657f11e
--- /dev/null
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/utils/HttpServletRequestUtil.java
@@ -0,0 +1,152 @@
+package org.jeecg.modules.appmana.utils;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.useragent.UserAgent;
+import cn.hutool.http.useragent.UserAgentUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StreamUtils;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.Charset;
+import java.util.*;
+
+/**
+ * request 工具类
+ */
+@Slf4j
+public class HttpServletRequestUtil {
+
+ /**
+ * 获取request对象
+ *
+ * @return
+ */
+ public static HttpServletRequest getRequest() {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ return request;
+
+ }
+
+ /**
+ * 获取getRequestURI
+ *
+ * @return /sys/user/getInfo?id=1
+ */
+ public static String getRequestURI() {
+ HttpServletRequest request = getRequest();
+ String queryString = request.getQueryString();
+ if (StrUtil.isBlank(queryString)) {
+ return request.getRequestURI();
+ }
+ return request.getRequestURI() + "?" + queryString;
+
+ }
+
+ /**
+ * 获取getRequestURI
+ *
+ * @return
+ */
+ public static UserAgent getRequestUserAgent() {
+ HttpServletRequest request = getRequest();
+ UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
+ return userAgent;
+
+ }
+
+ public static String getRemoteIP() {
+ return getRemoteIP(getRequest());
+ }
+
+ public static String getRemoteIP(HttpServletRequest request) {
+
+ if (request == null) {
+ return "unknown";
+ }
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("X-Forwarded-For");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("X-Real-IP");
+ }
+
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ // 多次反向代理后会有多个IP值,第一个为真实IP。
+ int index = ip.indexOf(',');
+ if (index != -1) {
+ ip = ip.substring(0, index);
+ }
+ return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
+ }
+
+ /**
+ * 取得请求头信息 name:value
+ */
+ public static Map getHeaders() {
+ HttpServletRequest request = getRequest();
+ Map map = new HashMap<>(32);
+ Enumeration headerNames = request.getHeaderNames();
+ while (headerNames.hasMoreElements()) {
+ String key = (String) headerNames.nextElement();
+ String value = request.getHeader(key);
+ map.put(key, value);
+ }
+ return map;
+ }
+
+ /**
+ * 获取请求体信息
+ */
+ public static String getBody() {
+ HttpServletRequest request = getRequest();
+ InputStream inputStream = null;
+ try {
+ inputStream = request.getInputStream();
+ return StreamUtils.copyToString(inputStream, Charset.forName("utf-8"));
+ } catch (IOException e) {
+ e.printStackTrace();
+ log.error("HttpServletRequest.getBody", e);
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ log.error("HttpServletRequest.getBody", e);
+ }
+ }
+ }
+ return StrUtil.EMPTY;
+ }
+
+ public static String getAllRequestInfo() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("请求详情为:").append(StrUtil.CRLF);
+ sb.append("RemoteAddress: ").append(getRemoteIP()).append(StrUtil.CRLF);
+ sb.append("Method: ").append(getRequest().getMethod()).append(StrUtil.CRLF);
+ sb.append("URI: ").append(getRequestURI()).append(StrUtil.CRLF);
+ sb.append("Headers: ").append(StrUtil.join(StrUtil.CRLF + " ", mapToList(getHeaders()))).append(StrUtil.CRLF);
+ sb.append("Body: ").append(getBody()).append(StrUtil.CRLF);
+ return sb.toString();
+ }
+
+ private static List mapToList(Map parameters) {
+ List parametersList = new ArrayList();
+ parameters.forEach((name, value) -> {
+ parametersList.add(name + "=" + value);
+ });
+ return parametersList;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/DTOMqtt.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/DTOMqtt.java
similarity index 100%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/DTOMqtt.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/DTOMqtt.java
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/LhMqttMsg.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/LhMqttMsg.java
similarity index 100%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/LhMqttMsg.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/LhMqttMsg.java
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MqttConfig.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MqttConfig.java
similarity index 87%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MqttConfig.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MqttConfig.java
index 88a827e..a12fb60 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MqttConfig.java
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MqttConfig.java
@@ -10,13 +10,15 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
+import java.util.Arrays;
+
@Slf4j
@Configuration
@ConditionalOnProperty(
prefix = "iot.mq",
name = "enabled",
havingValue = "true",
- matchIfMissing = false // 默认注册,除非显式设置为 false
+ matchIfMissing = true // 默认注册,除非显式设置为 false
)
public class MqttConfig {
@@ -42,9 +44,9 @@ public class MqttConfig {
@Bean//注入Spring
public MyMqttClient myMqttClient() {
MyMqttClient myMqttClient = new MyMqttClient(host, username, password, clientId, timeOut, keepAlive, clearSession);
- String activeProfile = env.getActiveProfiles()[0];
+// String activeProfile = env.getActiveProfiles()[0];
//正式环境才连接mqtt
- if(activeProfile.contains("prod")){
+// if(activeProfile.contains("prod")){
log.warn("-------------正式环境,MQTT启动初始化---------");
for (int i = 0; i < 10; i++) {
try {
@@ -62,9 +64,9 @@ public class MqttConfig {
}
}
}
- }else{
- log.warn("-------------非正式环境跳过Mqtt订阅---------");
- }
+// }else{
+// log.warn("-------------非正式环境跳过Mqtt订阅---------");
+// }
return myMqttClient;
}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MqttService.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MqttService.java
similarity index 100%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MqttService.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MqttService.java
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttCallback.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttCallback.java
similarity index 90%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttCallback.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttCallback.java
index f616caf..d1f1ce6 100644
--- a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttCallback.java
+++ b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttCallback.java
@@ -7,12 +7,9 @@ import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.jeecg.common.util.SpringContextUtils;
-import org.jeecg.modules.config.RedisDistributedLock2;
-import org.jeecg.modules.iot.enums.IotInerfaceTopicType;
-import org.jeecg.modules.iot.o.dto.DTOMqttMessage;
-import org.jeecg.modules.iot.o.mqtt.up.DeviceActionVo;
-import org.jeecg.modules.iot.service.IFIotVirtualDeviceService;
-import org.jeecg.modules.rocketmq.service.RocketMqService;
+import org.jeecg.modules.appmana.service.IFIotVirtualDeviceService;
+import org.jeecg.common.iot.enums.IotInerfaceTopicType;
+import org.jeecg.common.iot.up.DeviceActionVo;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.List;
@@ -29,7 +26,6 @@ public class MyMqttCallback implements MqttCallbackExtended {
private static RedisTemplate redisTemplate = SpringContextUtils.getBean("redisTemplate", RedisTemplate.class);
- private static RocketMqService rocketMqService = SpringContextUtils.getBean(RocketMqService.class);
private MyMqttClient myMqttClient;
@@ -126,11 +122,7 @@ public class MyMqttCallback implements MqttCallbackExtended {
DeviceActionVo deviceQueryActionVo = JSONObject.toJavaObject(JSONObject.parseObject(message), DeviceActionVo.class);
//设备响应处理,查询、控制
deviceService.processIotAction(deviceQueryActionVo);
- //MQ模式
-// DTOMqttMessage dtoMqttMessage = new DTOMqttMessage();
-// dtoMqttMessage.setTopic(topic);
-// dtoMqttMessage.setMessage(message);
-// rocketMqService.sendMqttMessage(dtoMqttMessage);
+
}catch (Exception e){
log.error("======处理蓝海主题设备报错================"+e.getMessage());
}
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttClient.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttClient.java
similarity index 100%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttClient.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttClient.java
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttController.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttController.java
similarity index 100%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/MyMqttController.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/MyMqttController.java
diff --git a/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/impl/MqttServiceImpl.java b/zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/impl/MqttServiceImpl.java
similarity index 100%
rename from zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/appmana/mqtt/impl/MqttServiceImpl.java
rename to zh-module-applet/zh-applet-admin/src/main/java/org/jeecg/modules/mqtt/impl/MqttServiceImpl.java
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/constant/TopicConstant.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/constant/TopicConstant.java
new file mode 100644
index 0000000..58bd952
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/constant/TopicConstant.java
@@ -0,0 +1,46 @@
+package org.jeecg.common.constant;
+
+
+public interface TopicConstant {
+
+ /**
+ * AI统计消费主题
+ */
+ String AI_DISPATCH_TOPIC = "ai_dispatch_topic";
+
+ /**
+ * AI统计消费标签
+ */
+ String AI_DISPATCH_TAG = "ai_dispatch_tag";
+
+ /**
+ * AI消费组
+ */
+ String AI_DISPATCH_GROUP = "ai_dispatch_group";
+
+ /**
+ * mqtt消费主题
+ */
+ String MQTT_DISPATCH_TOPIC = "mqtt_dispatch_topic";
+
+ /**
+ * mqtt消费标签
+ */
+ String MQTT_DISPATCH_TAG = "mqtt_dispatch_tag";
+
+ /**
+ * mqtt消费组
+ */
+ String MQTT_DISPATCH_GROUP = "mqtt_dispatch_group";
+
+
+ /**
+ * redis 指令过滤头
+ */
+ String MQTT_MESSAGE_FILTER = "mqtt_message_filter:";
+
+ /**
+ * redis 指令过滤头
+ */
+ String MQTT_CMD_LOCKER = "mqtt_cmd_locker:";
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FDeviceOpration.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FDeviceOpration.java
new file mode 100644
index 0000000..fb0337e
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FDeviceOpration.java
@@ -0,0 +1,218 @@
+package org.jeecg.common.entity;
+
+import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.ibatis.type.JdbcType;
+import org.jeecg.common.mybatis.typehandler.JsonTypeHandler;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * @Description: 设备操作记录
+ * @Author: jeecg-boot
+ * @Date: 2023-11-04
+ * @Version: V1.06
+ */
+@Data
+@TableName("surv_device_opration")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value = "设备操作记录", description = "设备操作记录")
+public class FDeviceOpration implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+
+ /**
+ * 主键
+ */
+ @TableId(type = IdType.ASSIGN_ID)
+ @ApiModelProperty(value = "主键")
+ private String id;
+
+ /**
+ * 公司ID
+ */
+ @Excel(name = "公司ID", width = 15)
+ @ApiModelProperty(value = "公司ID")
+ private String companyId;
+
+ /**
+ * 农场ID
+ */
+ @Excel(name = "农场ID", width = 15)
+ @ApiModelProperty(value = "农场ID")
+ private String farmId;
+
+ /**
+ * 设备部署ID
+ */
+ @Excel(name = "设备部署ID", width = 15)
+ @ApiModelProperty(value = "设备部署ID")
+ private String deployId;
+
+ /**
+ * 采集id
+ */
+ @Excel(name = "采集id", width = 15)
+ @ApiModelProperty(value = "采集id")
+ private String gatherId;
+
+ /**
+ * 变量Id
+ */
+ @Excel(name = "变量id", width = 15)
+ @ApiModelProperty(value = "变量Id")
+ private String variableId;
+
+ @Excel(name = "变量中文", width = 15)
+ @ApiModelProperty(value = "变量中文")
+ private String variableDes;
+
+ @Excel(name = "操作值", width = 15)
+ @ApiModelProperty(value = "操作值,0断开,1闭合")
+ private String variableValue;
+
+ @Excel(name = "操作标记", width = 15)
+ @ApiModelProperty(value = "操作标记,launch=启动,function=功能,参数=params")
+ private String variableMark;
+
+ /**
+ * 操作名称
+ */
+ @Excel(name = "操作名称", width = 15)
+ @ApiModelProperty(value = "操作名称")
+ private String oprationName;
+
+ /**
+ * 操作结果 0失败,1成功
+ */
+ @Excel(name = "操作名称", width = 15)
+ @ApiModelProperty(value = "操作名称")
+ private Integer operationResult;
+
+ /**
+ * 操作人ID
+ */
+ @Excel(name = "操作人ID", width = 15)
+ @ApiModelProperty(value = "操作人ID")
+ private String operatorUserId;
+
+ /**
+ * 操作人名称
+ */
+ @Excel(name = "操作人名称", width = 15)
+ @ApiModelProperty(value = "操作人名称")
+ private String operatorUserName;
+
+ /**
+ * 操作人头像
+ */
+ @Excel(name = "操作人头像", width = 15)
+ @ApiModelProperty(value = "操作人头像")
+ private String operatorUserAvatar;
+
+ /**
+ * 操作时间
+ */
+ @Excel(name = "操作时间", width = 15)
+ @ApiModelProperty(value = "操作时间")
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime operatorTime;
+
+ /**
+ * 指令原文
+ */
+ @ApiModelProperty(value = "指令原文")
+ @TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR, value = "OPERATOR_CONTENT")
+ private JSONObject operatorContent;
+
+ /**
+ * 操作描述
+ */
+ @Excel(name = "操作描述", width = 15)
+ @ApiModelProperty(value = "操作描述")
+ private String operatorDes;
+
+
+ /**
+ * 日志是否已经核算,0否,1是
+ */
+ @Excel(name = "是否已经核算", width = 15)
+ @ApiModelProperty(value = "是否已经核算")
+ private Integer calStatus;
+
+ /**
+ * 租户号
+ */
+ @ApiModelProperty(value = "租户号")
+ private String tenantId;
+
+ /**
+ * 乐观锁
+ */
+ @ApiModelProperty(value = "乐观锁")
+ private Integer reVision;
+
+ /**
+ * 创建人
+ */
+ @ApiModelProperty(value = "创建人")
+ private String createBy;
+
+ /**
+ * 创建时间
+ */
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "创建时间")
+ private java.util.Date createTime;
+
+ /**
+ * 更新人
+ */
+ @ApiModelProperty(value = "更新人")
+ private String updateBy;
+
+ /**
+ * 逻辑删除
+ */
+ @ApiModelProperty(value = "逻辑删除")
+ private Integer isDel;
+
+ /**
+ * 更新时间
+ */
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "更新时间")
+ private java.util.Date updateTime;
+
+ @ApiModelProperty(value = "IP")
+ private String ip;
+ @ApiModelProperty(value = "浏览器标识")
+ private String agent;
+
+// @TableField(exist = false)
+// @DateTimeFormat(pattern="yyyy-MM-dd")
+// private LocalDate beginTime;
+//
+// @TableField(exist = false)
+// @DateTimeFormat(pattern="yyyy-MM-dd")
+// private LocalDate endTime;
+
+ @TableField(exist = false)
+ private String alertTimes;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotProtocol.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotProtocol.java
new file mode 100644
index 0000000..b1b99c4
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotProtocol.java
@@ -0,0 +1,118 @@
+package org.jeecg.common.entity;
+
+import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.ibatis.type.JdbcType;
+import org.jeecg.common.mybatis.typehandler.JsonTypeHandler;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+/**
+ * @Description: 物联网设备协议表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.06
+ */
+@Data
+@TableName("surv_iot_protocol")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="物联网设备协议表", description="物联网设备协议表")
+public class FIotProtocol implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+
+ /**主键*/
+ @TableId(type = IdType.ASSIGN_ID)
+ @ApiModelProperty(value = "主键")
+ private String id;
+
+ /**协议名称*/
+ @Excel(name = "协议名称", width = 15)
+ @ApiModelProperty(value = "协议名称")
+ private String protocolName;
+
+ /**所属厂家*/
+ @Excel(name = "所属厂家", width = 15)
+ @ApiModelProperty(value = "所属厂家")
+ private String manufacturerId;
+
+ /**协议类型;1=设备协议*/
+ @Excel(name = "协议类型;1=设备协议", width = 15)
+ @ApiModelProperty(value = "协议类型;1=设备协议")
+ private Integer protocolType;
+
+ /**对接方式;mqtt,http,tcp*/
+ @Excel(name = "对接方式;mqtt,http,tcp", width = 15)
+ @ApiModelProperty(value = "对接方式;mqtt,http,tcp")
+ private String integrateType;
+
+ /**参数指令模板*/
+ @Excel(name = "参数指令模板", width = 15)
+ @ApiModelProperty(value = "参数指令模板")
+ @TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR, value = "CMD_STR")
+ private JSONObject cmdStr;
+
+ /**启动指令模板*/
+ @Excel(name = "启动指令模板", width = 15)
+ @ApiModelProperty(value = "启动指令模板")
+ @TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR, value = "LAUNCH_CMD_STR")
+ private JSONObject launchCmdStr;
+
+ /**停止指令模板*/
+ @Excel(name = "停止指令模板", width = 15)
+ @ApiModelProperty(value = "停止指令模板")
+ @TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR, value = "STOP_CMD_STR")
+ private JSONObject stopCmdStr;
+
+ /**排序*/
+ @Excel(name = "排序", width = 15)
+ @ApiModelProperty(value = "排序")
+ private Integer sortNo;
+
+ /**租户号*/
+ @Excel(name = "租户号", width = 15)
+ @ApiModelProperty(value = "租户号")
+ private String tenantId;
+
+ /**乐观锁*/
+ @Excel(name = "乐观锁", width = 15)
+ @ApiModelProperty(value = "乐观锁")
+ private Integer reVision;
+
+ /**创建人*/
+ @ApiModelProperty(value = "创建人")
+ private String createBy;
+
+ /**创建时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+ /**更新人*/
+ @ApiModelProperty(value = "更新人")
+ private String updateBy;
+
+ /**逻辑删除*/
+ @Excel(name = "逻辑删除", width = 15)
+ @ApiModelProperty(value = "逻辑删除")
+ private Integer isDel;
+
+ /**更新时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "更新时间")
+ private Date updateTime;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDevice.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDevice.java
new file mode 100644
index 0000000..f27c5f5
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDevice.java
@@ -0,0 +1,192 @@
+package org.jeecg.common.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+/**
+ * @Description: 虚拟设备表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.06
+ */
+@Data
+@TableName("surv_iot_virtual_device")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="虚拟设备表", description="虚拟设备表")
+public class FIotVirtualDevice implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+
+ /**主键*/
+ @TableId(type = IdType.ASSIGN_ID)
+ @ApiModelProperty(value = "主键")
+ private String id;
+
+ /**企业id*/
+ @Excel(name = "企业id", width = 15)
+ @ApiModelProperty(value = "企业id")
+ private String companyId;
+
+ /**农场ID*/
+ @Excel(name = "农场ID", width = 15)
+ @ApiModelProperty(value = "农场ID")
+ private String farmId;
+
+ /**分组*/
+ @Excel(name = "分组", width = 15)
+ @ApiModelProperty(value = "分组")
+ private String groupId;
+
+ /**业务关联id*/
+ @Excel(name = "业务关联id", width = 15)
+ @ApiModelProperty(value = "业务关联id")
+ private String busId;
+
+ /**设备物联网ID*/
+ @Excel(name = "设备物联网ID", width = 15)
+ @ApiModelProperty(value = "设备物联网ID")
+ private String iotId;
+
+ /**设备物联网编号*/
+ @Excel(name = "设备物联网编号", width = 15)
+ @ApiModelProperty(value = "设备物联网编号")
+ private String iotCode;
+
+ /**备用配置项*/
+ @Excel(name = "备用配置项", width = 15)
+ @ApiModelProperty(value = "备用配置项")
+ private String iotParams;
+
+ /**设备名称*/
+ @Excel(name = "设备名称", width = 15)
+ @ApiModelProperty(value = "设备名称")
+ private String deviceName;
+
+ /**设备主类型*/
+ @Excel(name = "设备主类型", width = 15)
+ @ApiModelProperty(value = "设备主类型")
+ private String deviceType;
+
+ /**设备副类型*/
+ @Excel(name = "设备副类型", width = 15)
+ @ApiModelProperty(value = "设备副类型")
+ private String deviceSecType;
+
+ /**协议ID*/
+ @Excel(name = "协议ID", width = 15)
+ @ApiModelProperty(value = "协议ID")
+ private String protocolId;
+
+ /**启动指令模板*/
+ @Excel(name = "启动指令模板", width = 15)
+ @ApiModelProperty(value = "启动指令模板")
+ private String cmdStr;
+
+ /**纬度*/
+ @Excel(name = "纬度", width = 15)
+ @ApiModelProperty(value = "纬度")
+ private String deviceLat;
+
+ /**经度*/
+ @Excel(name = "经度", width = 15)
+ @ApiModelProperty(value = "经度")
+ private String deviceLong;
+
+ /**经纬度*/
+ @Excel(name = "经纬度", width = 15)
+ @ApiModelProperty(value = "经纬度")
+ private String deviceLonglat;
+
+ /**备注*/
+ @Excel(name = "备注", width = 15)
+ @ApiModelProperty(value = "备注")
+ private String deviceNotes;
+
+ /**运行状态支持*/
+ @Excel(name = "运行状态支持", width = 15)
+ @ApiModelProperty(value = "运行状态支持")
+ private Integer statusSupport;
+
+ /**控制支持*/
+ @Excel(name = "控制支持", width = 15)
+ @ApiModelProperty(value = "控制支持")
+ private Integer controlSupport;
+ /**灌溉记录支持*/
+ @Excel(name = "灌溉记录支持", width = 15)
+ @ApiModelProperty(value = "灌溉记录支持")
+ private Integer recordSupport;
+
+ /**下行mqtt主题*/
+ @Excel(name = "下行mqtt主题", width = 15)
+ @ApiModelProperty(value = "下行mqtt主题")
+ private String lowerUrl;
+
+ /**上行mqtt主题*/
+ @Excel(name = "上行mqtt主题", width = 15)
+ @ApiModelProperty(value = "上行mqtt主题")
+ private String upperUrl;
+
+
+ /**排序值*/
+ @Excel(name = "排序值", width = 15)
+ @ApiModelProperty(value = "排序值")
+ private Integer sortNo;
+
+ /**
+ * 是否启用
+ */
+ @Excel(name = "是否启用", width = 15)
+ @ApiModelProperty(value = "是否启用")
+ private Integer isEnable;
+
+ /**租户号*/
+ @Excel(name = "租户号", width = 15)
+ @ApiModelProperty(value = "租户号")
+ private String tenantId;
+
+ /**乐观锁*/
+ @Excel(name = "乐观锁", width = 15)
+ @ApiModelProperty(value = "乐观锁")
+ private Integer reVision;
+
+ /**创建人*/
+ @ApiModelProperty(value = "创建人")
+ private String createBy;
+
+ /**创建时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+ /**更新人*/
+ @ApiModelProperty(value = "更新人")
+ private String updateBy;
+
+ /**逻辑删除*/
+ @Excel(name = "逻辑删除", width = 15)
+ @ApiModelProperty(value = "逻辑删除")
+ @TableLogic
+ private Integer isDel;
+
+
+ @TableField(exist = false)
+ private List modules;
+
+ /**更新时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "更新时间")
+ private Date updateTime;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceGroup.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceGroup.java
new file mode 100644
index 0000000..93efbca
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceGroup.java
@@ -0,0 +1,106 @@
+package org.jeecg.common.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+/**
+ * @Description: 虚拟设备模块分组
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.06
+ */
+@Data
+@TableName("surv_iot_virtual_device_group")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="虚拟设备模块分组", description="虚拟设备模块分组")
+public class FIotVirtualDeviceGroup implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+
+ /**主键*/
+ @TableId(type = IdType.ASSIGN_ID)
+ @ApiModelProperty(value = "主键")
+ private String id;
+
+ /**企业id*/
+ @Excel(name = "企业id", width = 15)
+ @ApiModelProperty(value = "企业id")
+ private String companyId;
+
+ /**农场ID*/
+ @Excel(name = "农场ID", width = 15)
+ @ApiModelProperty(value = "农场ID")
+ private String farmId;
+
+ /**分组类型;module=模块分组*/
+ @Excel(name = "分组类型;module=模块分组", width = 15)
+ @ApiModelProperty(value = "分组类型;module=模块分组")
+ private String groupType;
+
+ /**设备分组*/
+ @Excel(name = "设备分组", width = 15)
+ @ApiModelProperty(value = "设备分组")
+ private String groupName;
+
+ /**分组图标*/
+ @Excel(name = "分组图标", width = 15)
+ @ApiModelProperty(value = "分组图标")
+ private String groupIcon;
+
+ /**分组图标*/
+ @Excel(name = "分组图标", width = 15)
+ @ApiModelProperty(value = "分组图标")
+ private String groupNotes;
+
+ /**排序值*/
+ @Excel(name = "排序值", width = 15)
+ @ApiModelProperty(value = "排序值")
+ private Integer sortNo;
+
+ /**租户号*/
+ @Excel(name = "租户号", width = 15)
+ @ApiModelProperty(value = "租户号")
+ private String tenantId;
+
+ /**乐观锁*/
+ @Excel(name = "乐观锁", width = 15)
+ @ApiModelProperty(value = "乐观锁")
+ private Integer reVision;
+
+ /**创建人*/
+ @ApiModelProperty(value = "创建人")
+ private String createBy;
+
+ /**创建时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+ /**更新人*/
+ @ApiModelProperty(value = "更新人")
+ private String updateBy;
+
+ /**逻辑删除*/
+ @Excel(name = "逻辑删除", width = 15)
+ @ApiModelProperty(value = "逻辑删除")
+ private Integer isDel;
+
+ /**更新时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "更新时间")
+ private Date updateTime;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceModule.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceModule.java
new file mode 100644
index 0000000..dc7859e
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceModule.java
@@ -0,0 +1,224 @@
+package org.jeecg.common.entity;
+
+import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.apache.ibatis.type.JdbcType;
+import org.jeecg.common.mybatis.typehandler.JsonTypeHandler;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+/**
+ * @Description: 虚拟设备模组表
+ * @Author: jeecg-boot
+ * @Date: 2025-05-15
+ * @Version: V1.06
+ */
+@Data
+@TableName("surv_iot_virtual_device_module")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="虚拟设备模组表", description="虚拟设备模组表")
+public class FIotVirtualDeviceModule implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+
+ /**主键*/
+ @TableId(type = IdType.ASSIGN_ID)
+ @ApiModelProperty(value = "主键")
+ private String id;
+
+ /**企业id*/
+ @Excel(name = "企业id", width = 15)
+ @ApiModelProperty(value = "企业id")
+ private String companyId;
+
+ /**农场ID*/
+ @Excel(name = "农场ID", width = 15)
+ @ApiModelProperty(value = "农场ID")
+ private String farmId;
+
+ /**设备ID*/
+ @Excel(name = "设备ID", width = 15)
+ @ApiModelProperty(value = "设备ID")
+ private String deviceId;
+
+ /**模块编号*/
+ @Excel(name = "模块编号", width = 15)
+ @ApiModelProperty(value = "模块编号")
+ private String moduleCode;
+
+ /**模块序号*/
+ @Excel(name = "模块序号", width = 15)
+ @ApiModelProperty(value = "模块序号")
+ private String moduleNum;
+
+ /**模组业务ID*/
+ @Excel(name = "模组业务ID", width = 15)
+ @ApiModelProperty(value = "模组业务ID")
+ private String moduleBusId;
+
+ /**模块分组id*/
+ @Excel(name = "模块分组id", width = 15)
+ @ApiModelProperty(value = "模块分组id")
+ private String moduleGroupId;
+
+ /**模块网络id*/
+ @Excel(name = "模块网络id", width = 15)
+ @ApiModelProperty(value = "模块网络id")
+ private String moduleNetId;
+
+ /**模块主类型;sensor=传感器,meter=测量仪*/
+ @Excel(name = "模块主类型;sensor=传感器,meter=测量仪", width = 15)
+ @ApiModelProperty(value = "模块主类型;sensor=传感器,meter=测量仪")
+ private String moduleType;
+
+ /**模块类型;flows=流量计,valve=电磁阀*/
+ @Excel(name = "模块类型;flows=流量计,valve=电磁阀", width = 15)
+ @ApiModelProperty(value = "模块类型;flows=流量计,valve=电磁阀")
+ private String moduleSecType;
+
+ /**模块名称*/
+ @Excel(name = "模块名称", width = 15)
+ @ApiModelProperty(value = "模块名称")
+ private String moduleName;
+
+ /**模块备注*/
+ @Excel(name = "模块备注", width = 15)
+ @ApiModelProperty(value = "模块备注")
+ private String moduleNotes;
+
+ /**1=虚拟模块,2=物理模块*/
+ @Excel(name = "模块模式", width = 15)
+ @ApiModelProperty(value = "模块模式")
+ private String moduleMode;
+
+ /**模块虚拟状态*/
+ @Excel(name = "模块虚拟状态", width = 15)
+ @ApiModelProperty(value = "模块虚拟状态")
+ private String moduleVirtualStatus;
+
+ /**模块配置*/
+ @Excel(name = "模块配置", width = 15)
+ @ApiModelProperty(value = "模块配置")
+ @TableField(typeHandler = JsonTypeHandler.class, jdbcType = JdbcType.VARCHAR, value = "MODULE_PATH")
+ private JSONObject modulePath;
+
+
+ /**
+ * 寄存器类型 4=保持寄存器,0=线圈,1=离散输入
+ */
+ @Excel(name = "寄存器类型", width = 15)
+ @ApiModelProperty(value = "寄存器类型")
+ private Integer registerType;
+
+
+
+ /**
+ * 寄存器序号 通讯地址
+ */
+ @Excel(name = "寄存器序号(通讯地址)", width = 15)
+ @ApiModelProperty(value = "寄存器序号(通讯地址)")
+ private Integer registerNum;
+
+ /**
+ * 开指令
+ */
+ @Excel(name = "开指令", width = 15)
+ @ApiModelProperty(value = "开指令")
+ private String registerCmdOn;
+
+ /**
+ * 关指令
+ */
+ @Excel(name = "关指令", width = 15)
+ @ApiModelProperty(value = "关指令")
+ private String registerCmdOff;
+
+ /**
+ * 停指令
+ */
+ @Excel(name = "停指令", width = 15)
+ @ApiModelProperty(value = "停指令")
+ private String registerCmdStop;
+
+ /**
+ * 回执状态开
+ */
+ @Excel(name = "回执状态开", width = 15)
+ @ApiModelProperty(value = "回执状态开")
+ private String registerOn;
+
+ /**
+ * 回执状态关
+ */
+ @Excel(name = "回执状态关", width = 15)
+ @ApiModelProperty(value = "回执状态关")
+ private String registerOff;
+
+ /**
+ * 回执状态停
+ */
+ @Excel(name = "回执状态停", width = 15)
+ @ApiModelProperty(value = "回执状态停")
+ private String registerStop;
+
+ /**排序值*/
+ @Excel(name = "排序值", width = 15)
+ @ApiModelProperty(value = "排序值")
+ private Integer sortNo;
+
+ /**
+ * 是否启用
+ */
+ @Excel(name = "是否启用", width = 15)
+ @ApiModelProperty(value = "是否启用")
+ private Integer isEnable;
+
+ /**租户号*/
+ @Excel(name = "租户号", width = 15)
+ @ApiModelProperty(value = "租户号")
+ private String tenantId;
+
+ /**乐观锁*/
+ @Excel(name = "乐观锁", width = 15)
+ @ApiModelProperty(value = "乐观锁")
+ private Integer reVision;
+
+ /**创建人*/
+ @ApiModelProperty(value = "创建人")
+ private String createBy;
+
+ /**创建时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+ /**更新人*/
+ @ApiModelProperty(value = "更新人")
+ private String updateBy;
+
+ /**逻辑删除*/
+ @Excel(name = "逻辑删除", width = 15)
+ @ApiModelProperty(value = "逻辑删除")
+ @TableLogic
+ private Integer isDel;
+
+ /**更新时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "更新时间")
+ private Date updateTime;
+
+ @TableField(exist = false)
+ @ApiModelProperty("设备状态,-1=获取失败,0=关闭,1=开启,2=异常")
+ private String moduleStatus;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceNet.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceNet.java
new file mode 100644
index 0000000..221b8de
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/entity/FIotVirtualDeviceNet.java
@@ -0,0 +1,145 @@
+package org.jeecg.common.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.jeecgframework.poi.excel.annotation.Excel;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+/**
+ * @Description: 虚拟设备网络模块
+ * @Author: jeecg-boot
+ * @Date: 2025-09-06
+ * @Version: V1.06
+ */
+@Data
+@TableName("surv_iot_virtual_device_net")
+@Accessors(chain = true)
+@EqualsAndHashCode(callSuper = false)
+@ApiModel(value="虚拟设备网络模块", description="虚拟设备网络模块")
+public class FIotVirtualDeviceNet implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+
+ /**主键*/
+ @TableId(type = IdType.ASSIGN_ID)
+ @ApiModelProperty(value = "主键")
+ private String id;
+
+ /**企业id*/
+ @Excel(name = "企业id", width = 15)
+ @ApiModelProperty(value = "企业id")
+ private String companyId;
+
+ /**农场ID*/
+ @Excel(name = "农场ID", width = 15)
+ @ApiModelProperty(value = "农场ID")
+ private String farmId;
+
+ /**入网方式;dtu=数据传输单元,wifi=无线网络,cable=有线网络,mobile=移动网络*/
+ @Excel(name = "入网方式;dtu=数据传输单元,wifi=无线网络,cable=有线网络,mobile=移动网络", width = 15)
+ @ApiModelProperty(value = "入网方式;dtu=数据传输单元,wifi=无线网络,cable=有线网络,mobile=移动网络")
+ private String netType;
+
+ /**网络名称*/
+ @Excel(name = "网络名称", width = 15)
+ @ApiModelProperty(value = "网络名称")
+ private String netName;
+
+ /**网络识别码,用于识别对应的物联网单元*/
+ @Excel(name = "网络识别码", width = 15)
+ @ApiModelProperty(value = "网络识别码")
+ private String netIdentCode;
+
+ /**备注*/
+ @Excel(name = "备注", width = 15)
+ @ApiModelProperty(value = "备注")
+ private String netNotes;
+
+ /**上行mqtt主题*/
+ @Excel(name = "上行mqtt主题", width = 15)
+ @ApiModelProperty(value = "上行mqtt主题")
+ private String netUpTopic;
+
+ /**下行mqtt主题*/
+ @Excel(name = "下行mqtt主题", width = 15)
+ @ApiModelProperty(value = "下行mqtt主题")
+ private String netDownTopic;
+
+ /**传输口令*/
+ @Excel(name = "传输口令", width = 15)
+ @ApiModelProperty(value = "传输口令")
+ private String netPass;
+
+ /**传输密钥*/
+ @Excel(name = "传输密钥", width = 15)
+ @ApiModelProperty(value = "传输密钥")
+ private String netSecret;
+
+ /**备用配置1*/
+ @Excel(name = "备用配置1", width = 15)
+ @ApiModelProperty(value = "备用配置1")
+ private String netSetOne;
+
+ /**备用配置2*/
+ @Excel(name = "备用配置2", width = 15)
+ @ApiModelProperty(value = "备用配置2")
+ private String netSetTwo;
+
+ /**排序*/
+ @Excel(name = "排序", width = 15)
+ @ApiModelProperty(value = "排序")
+ private Integer sortNo;
+
+ /**
+ * 是否启用
+ */
+ @Excel(name = "是否启用", width = 15)
+ @ApiModelProperty(value = "是否启用")
+ private Integer isEnable;
+
+ /**租户号*/
+ @Excel(name = "租户号", width = 15)
+ @ApiModelProperty(value = "租户号")
+ private String tenantId;
+
+ /**乐观锁*/
+ @Excel(name = "乐观锁", width = 15)
+ @ApiModelProperty(value = "乐观锁")
+ private Integer reVision;
+
+ /**创建人*/
+ @ApiModelProperty(value = "创建人")
+ private String createBy;
+
+ /**创建时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "创建时间")
+ private Date createTime;
+
+ /**更新人*/
+ @ApiModelProperty(value = "更新人")
+ private String updateBy;
+
+ /**逻辑删除*/
+ @Excel(name = "逻辑删除", width = 15)
+ @ApiModelProperty(value = "逻辑删除")
+ @TableLogic
+ private Integer isDel;
+
+ /**更新时间*/
+ @JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "更新时间")
+ private Date updateTime;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStats.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStats.java
new file mode 100644
index 0000000..55bf708
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStats.java
@@ -0,0 +1,124 @@
+package org.jeecg.common.iot.Fertilizer;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Data
+public class VOFertilizerStats {
+ @ApiModelProperty(value = "是否在线")
+ private Integer isOnline;
+
+ /**施肥压力*/
+ @ApiModelProperty(value = "施肥压力")
+ private String fePressure;
+
+ /**注肥流量*/
+ @ApiModelProperty(value = "注肥流量")
+ private String feInjectFlows;
+
+ /**pH值*/
+ @ApiModelProperty(value = "pH值")
+ private String fePh;
+
+ /**电导率*/
+ @ApiModelProperty(value = "电导率")
+ private String feDdl;
+
+ /**瞬时流量*/
+ @ApiModelProperty(value = "瞬时流量")
+ private String feInstantFlows;
+
+ /**累计流量*/
+ @ApiModelProperty(value = "累计流量")
+ private String feTotalFlows;
+
+ /**流量1*/
+ @ApiModelProperty(value = "流量1")
+ private String feFlowsOne;
+
+ /**流量2*/
+ @ApiModelProperty(value = "流量2")
+ private String feFlowsTwo;
+
+ /**流量3*/
+ @ApiModelProperty(value = "流量3")
+ private String feFlowsThree;
+
+ /**流量4*/
+ @ApiModelProperty(value = "流量4")
+ private String feFlowsFour;
+
+ /**流量5*/
+ @ApiModelProperty(value = "流量5")
+ private String feFlowsFive;
+
+ /**流量6*/
+ @ApiModelProperty(value = "流量6")
+ private String feFlowsSix;
+
+ /**流量7*/
+ @ApiModelProperty(value = "流量7")
+ private String feFlowsSeven;
+
+ /**流量8*/
+ @ApiModelProperty(value = "流量8")
+ private String feFlowsEight;
+
+ /**流量9*/
+ @ApiModelProperty(value = "流量9")
+ private String feFlowsNine;
+
+ /**流量10*/
+ @ApiModelProperty(value = "流量10")
+ private String feFlowsTen;
+
+ /**监测数据*/
+ @ApiModelProperty(value = "监测数据")
+ private List statsList;
+
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JSONField(format = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "数据更新时间")
+ @JsonDeserialize(using = LocalDateTimeDeserializer.class) // 反序列化
+ @JsonSerialize(using = LocalDateTimeSerializer.class) // 序列化
+ private LocalDateTime dataDateTime;
+
+
+ /**运行状态支持*/
+ @ApiModelProperty(value = "运行状态支持")
+ private Integer statusSupport = 1;
+
+ /**控制支持*/
+ @ApiModelProperty(value = "控制支持")
+ private Integer controlSupport = 1;
+
+ /**灌溉记录支持*/
+ @ApiModelProperty(value = "灌溉记录支持")
+ private Integer recordSupport = 1;
+
+ /**上行mqtt主题*/
+ @ApiModelProperty(value = "上行mqtt主题")
+ private String upperUrl;
+
+ /**下行mqtt主题*/
+ @ApiModelProperty(value = "下行mqtt主题")
+ private String lowerUrl;
+
+
+ @ApiModelProperty(value = "协议编号,用于识别对接方式")
+ private String protocolCode;
+
+ @ApiModelProperty(value = "协议类型,http=http,mqtt=mqtt")
+ private String protocolType;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStatsArr.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStatsArr.java
new file mode 100644
index 0000000..a3175e5
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/Fertilizer/VOFertilizerStatsArr.java
@@ -0,0 +1,56 @@
+package org.jeecg.common.iot.Fertilizer;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+@Data
+public class VOFertilizerStatsArr {
+ @ApiModelProperty("设备编号")
+ private String deployId;
+ @ApiModelProperty("监测类型")
+ private String eleType;
+ @ApiModelProperty("监测项名称")
+ private String eleName;
+ @ApiModelProperty("监测项字段名")
+ private String eleItem;
+ @ApiModelProperty("监测项图标名称")
+ private String eleIcon;
+ @ApiModelProperty("颜色")
+ private String eleColor;
+ @ApiModelProperty("监测项图标文件夹")
+ private String eleIconFolder;
+ @ApiModelProperty("监测项值")
+ private String eleValue;
+ @ApiModelProperty("监测项单位")
+ private String eleUnit;
+ @ApiModelProperty("更新时间")
+ private String lastUpdate;
+ @ApiModelProperty("h5图标路径")
+ private String h5IconPath;
+ @ApiModelProperty("中台图标路径")
+ private String midIconPath;
+ @ApiModelProperty("app图标路径")
+ private String appIconPath;
+ @ApiModelProperty("大屏图标路径")
+ private String bsIconPath;
+ @ApiModelProperty("大屏图标路径2")
+ private String bsIconPath2;
+
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @JSONField(format = "yyyy-MM-dd HH:mm:ss")
+ @ApiModelProperty(value = "数据更新时间")
+ @JsonDeserialize(using = LocalDateTimeDeserializer.class) // 反序列化
+ @JsonSerialize(using = LocalDateTimeSerializer.class) // 序列化
+ private LocalDateTime dataDateTime;
+
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/DeviceLogVo.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/DeviceLogVo.java
new file mode 100644
index 0000000..fdf6212
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/DeviceLogVo.java
@@ -0,0 +1,27 @@
+package org.jeecg.common.iot.common;
+
+import lombok.Data;
+import org.jeecg.common.entity.SurvDeviceDeploy;
+@Data
+public class DeviceLogVo {
+ /*设备id*/
+ private SurvDeviceDeploy deploy;
+ /*操作人*/
+ private LoginUser2 loginUser;
+ /*指令key*/
+ private String variableName;
+ /*指令中文*/
+ private String variableDes;
+ /*指令值*/
+ private String variableValue;
+ /*指令简单说明,如设备x 开*/
+ private String actions;
+ /*详细日志,如用户xx x点x分 操作设备 x 开*/
+ private String operationDetail;
+ /*操作结果*/
+ private boolean operationResult;
+ /*核算结果*/
+ private Integer calStatus = 0;
+ /*是否处理request mqtt等连接*/
+ private boolean processRequest = true;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/LoginUser2.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/LoginUser2.java
new file mode 100644
index 0000000..579a287
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/common/LoginUser2.java
@@ -0,0 +1,138 @@
+package org.jeecg.common.iot.common;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.experimental.Accessors;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.util.Date;
+
+/**
+ *
+ * 在线用户信息
+ *
+ *
+ * @Author scott
+ * @since 2018-12-20
+ */
+@Data
+public class LoginUser2 {
+
+ /**
+ * 登录人id
+ */
+ private String id;
+
+ /**
+ * 登录人账号
+ */
+ private String username;
+
+ /**
+ * 登录人名字
+ */
+ private String realname;
+
+ /**
+ * 登录人密码
+ */
+ private String password;
+
+ /**
+ * 当前登录部门code
+ */
+ private String orgCode;
+ /**
+ * 头像
+ */
+ private String avatar;
+
+ /**
+ * 生日
+ */
+ @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd")
+ @DateTimeFormat(pattern = "yyyy-MM-dd")
+ private Date birthday;
+
+ /**
+ * 性别(1:男 2:女)
+ */
+ private Integer sex;
+
+ /**
+ * 电子邮件
+ */
+ private String email;
+
+ /**
+ * 电话
+ */
+ private String phone;
+
+ /**
+ * 状态(1:正常 2:冻结 )
+ */
+ private Integer status;
+
+ private Integer delFlag;
+ /**
+ * 同步工作流引擎1同步0不同步
+ */
+ private Integer activitiSync;
+
+ /**
+ * 创建时间
+ */
+ private Date createTime;
+
+ /**
+ * 身份(1 普通员工 2 上级)
+ */
+ private Integer userIdentity;
+
+ /**
+ * 管理部门ids
+ */
+ private String departIds;
+
+ /**
+ * 职务,关联职务表
+ */
+ private String post;
+
+ /**
+ * 座机号
+ */
+ private String telephone;
+
+ /** 多租户ids临时用,不持久化数据库(数据库字段不存在) */
+ private String relTenantIds;
+
+ /**设备id uniapp推送用*/
+ private String clientId;
+ /**
+ * 当前登录租户
+ */
+ private Integer loginTenantId;
+
+ //(name = "用户类型(1系统,2农业前端,3专家)", width = 15)
+ private Integer type;
+
+ //腾讯IM同步状态
+ private Boolean imstatus = false;
+
+
+ //农业角色ID
+ //角色ID
+ private String roleId;
+ //角色名称
+ private String roleName;
+ //企业系统logo
+ private String companySystemLogo;
+
+// /**
+// * 当前登录租户
+// */
+// private String companyName;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/DeviceActionType.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/DeviceActionType.java
new file mode 100644
index 0000000..b4f962b
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/DeviceActionType.java
@@ -0,0 +1,51 @@
+package org.jeecg.common.iot.enums;
+
+
+/**
+ * 设备操作类型枚举
+ */
+public enum DeviceActionType {
+ DEVICE_QUERY_ALL("1","查询所有"),
+ DEVICE_QUERY_S("2","查询单个"),
+ DEVICE_CONTROL("3","控制设备"),
+ OTHER("99","其他")
+ ;
+
+ DeviceActionType(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private String code;
+ private String desc;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static DeviceActionType valueOfCode(String code) {
+ for (DeviceActionType e : DeviceActionType.values()) {
+ if (e.getCode().equals(code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/FunctionCode.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/FunctionCode.java
new file mode 100644
index 0000000..0fed680
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/FunctionCode.java
@@ -0,0 +1,39 @@
+package org.jeecg.common.iot.enums;
+
+import java.util.Objects;
+
+/**
+ * 功能码枚举
+ */
+public enum FunctionCode {
+ READ_COIL(0x01), // 读线圈
+ READ_DISCRETE_INPUT(0x02), // 读离散输入
+ READ_HOLDING_REGISTER(0x03), // 读保持寄存器
+ READ_INPUT_REGISTER(0x04), // 读输入寄存器
+ WRITE_COIL(0x05), // 写单个线圈
+ WRITE_HOLDING_REGISTER(0x06), // 写单个保持寄存器
+ OTHER(0x99);
+ private final int code;
+
+ FunctionCode(int code) {
+ this.code = code;
+ }
+
+ public byte getCode() {
+ return (byte) code;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static FunctionCode valueOfCode(int code) {
+ for (FunctionCode e : FunctionCode.values()) {
+ if (Objects.equals(e.code, code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotControlType.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotControlType.java
new file mode 100644
index 0000000..adf4e5e
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotControlType.java
@@ -0,0 +1,51 @@
+package org.jeecg.common.iot.enums;
+
+
+/**
+ * 物联网设备控制枚举
+ */
+public enum IotControlType {
+ EQ_OFF("0","关"),
+ EQ_ON("1","开"),
+ EQ_STOP("2","停"),
+ OTHER("other","其他")
+ ;
+
+ IotControlType(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private String code;
+ private String desc;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static IotControlType valueOfCode(String code) {
+ for (IotControlType e : IotControlType.values()) {
+ if (e.getCode().equals(code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotInerfaceTopicType.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotInerfaceTopicType.java
new file mode 100644
index 0000000..8cf097f
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotInerfaceTopicType.java
@@ -0,0 +1,52 @@
+package org.jeecg.common.iot.enums;
+
+
+/**
+ * 物联网设备主题头类型枚举
+ */
+public enum IotInerfaceTopicType {
+ DTU_TOPIC("/pub-","厂家DTU模块头上行"),
+ LH_IOT_TOPIC_UP("/lh-iot-up","蓝海虚拟设备头上行"),
+ LH_IOT_TOPIC_DOWN("/lh-iot-down","蓝海虚拟设备头下行"),
+ API_TOPIC("/api-","厂家api头"),
+ OTHER("other","其他")
+ ;
+
+ IotInerfaceTopicType(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private String code;
+ private String desc;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static IotInerfaceTopicType valueOfCode(String code) {
+ for (IotInerfaceTopicType e : IotInerfaceTopicType.values()) {
+ if (e.getCode().equals(code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotManufacturerEnum.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotManufacturerEnum.java
new file mode 100644
index 0000000..dd0e019
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotManufacturerEnum.java
@@ -0,0 +1,56 @@
+package org.jeecg.common.iot.enums;
+
+
+/**
+ * 物联网厂家枚举
+ */
+public enum IotManufacturerEnum {
+ XPH("xph","武汉新普惠科技有限公司"),
+ OKQ("okq","郑州欧柯奇仪器制造有限公司"),
+ YunFei("yf","河南云飞科技发展有限公司"),
+ BoYun("by","南通博云物联网技术有限公司"),
+ Flexem("flexem","上海繁易信息科技股份有限公司"),
+ YouRen("YouRen","山东有人物联网股份有限公司"),
+ TuYa("TuYa","杭州涂鸦信息技术有限公司"),
+ RenKe("RenKe","山东仁科测控技术有限公司"),
+ OTHER("other","其他")
+ ;
+
+ IotManufacturerEnum(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private String code;
+ private String desc;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static IotManufacturerEnum valueOfCode(String code) {
+ for (IotManufacturerEnum e : IotManufacturerEnum.values()) {
+ if (e.getCode().equals(code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotProtocolType.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotProtocolType.java
new file mode 100644
index 0000000..8fcf6c8
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/IotProtocolType.java
@@ -0,0 +1,51 @@
+package org.jeecg.common.iot.enums;
+
+
+/**
+ * 物联网设备协议类型枚举
+ */
+public enum IotProtocolType {
+ MQTT("mqtt","mqtt协议"),
+ HTTP("http","http协议"),
+ BLANK("local","无协议"),
+ OTHER("other","其他")
+ ;
+
+ IotProtocolType(String code, String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private String code;
+ private String desc;
+
+ public String getCode() {
+ return code;
+ }
+
+ public void setCode(String code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static IotProtocolType valueOfCode(String code) {
+ for (IotProtocolType e : IotProtocolType.values()) {
+ if (e.getCode().equals(code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RWType.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RWType.java
new file mode 100644
index 0000000..fadc489
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RWType.java
@@ -0,0 +1,9 @@
+package org.jeecg.common.iot.enums;
+
+/**
+ * 读写类型枚举
+ */
+public enum RWType {
+ READ, // 读操作
+ WRITE // 写操作
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RegisterType.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RegisterType.java
new file mode 100644
index 0000000..e4c606b
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/enums/RegisterType.java
@@ -0,0 +1,52 @@
+package org.jeecg.common.iot.enums;
+
+
+/**
+ * 寄存器类型枚举
+ */
+public enum RegisterType {
+ COIL(0,"线圈"), // 线圈(可读写,单个位)
+ DISCRETE_INPUT(1,"离散输入"), // 离散输入(只读,单个位)
+ INPUT_REGISTER(3,"输入寄存器"), // 输入寄存器(只读,2字节)
+ HOLDING_REGISTER(4,"保持寄存器"), // 保持寄存器(可读写,2字节)
+ OTHER(99,"其他")
+ ;
+
+ RegisterType(Integer code,String desc) {
+ this.code = code;
+ this.desc = desc;
+ }
+
+ private Integer code;
+ private String desc;
+
+ public Integer getCode() {
+ return code;
+ }
+
+ public void setCode(Integer code) {
+ this.code = code;
+ }
+
+ public String getDesc() {
+ return desc;
+ }
+
+ public void setDesc(String desc) {
+ this.desc = desc;
+ }
+
+ /**
+ * 根据type获取枚举
+ *
+ * @return
+ */
+ public static RegisterType valueOfCode(Integer code) {
+ for (RegisterType e : RegisterType.values()) {
+ if (e.getCode().equals(code)) {
+ return e;
+ }
+ }
+ return OTHER;
+ }
+}
\ No newline at end of file
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/DeviceActionVo.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/DeviceActionVo.java
new file mode 100644
index 0000000..8913040
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/DeviceActionVo.java
@@ -0,0 +1,21 @@
+package org.jeecg.common.iot.up;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * 设备查询实体
+ */
+@Data
+public class DeviceActionVo {
+ @ApiModelProperty("设备ID")
+ private String deployId;
+ @ApiModelProperty("行为类型,查询所有=1,查询单个=2,控制设备=3")
+ private String actionType;
+ @ApiModelProperty("控制类型,actionType=3时传入,0=关,1=开,2=停")
+ private String cmdType;
+ @ApiModelProperty("模组id,actionType=2或3时传入")
+ private String moduleId;
+ @ApiModelProperty("token")
+ private String token;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusDetailVo.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusDetailVo.java
new file mode 100644
index 0000000..09e94c6
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusDetailVo.java
@@ -0,0 +1,12 @@
+package org.jeecg.common.iot.up;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class ModuleStatusDetailVo {
+ @ApiModelProperty("模组id")
+ private String moduleId;
+ @ApiModelProperty("开关状态")
+ private String moduleStatus;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusResultVo.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusResultVo.java
new file mode 100644
index 0000000..c37916b
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/up/ModuleStatusResultVo.java
@@ -0,0 +1,10 @@
+package org.jeecg.common.iot.up;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class ModuleStatusResultVo {
+ List status;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/DeviceControlResultVo.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/DeviceControlResultVo.java
new file mode 100644
index 0000000..b04652b
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/DeviceControlResultVo.java
@@ -0,0 +1,16 @@
+package org.jeecg.common.iot.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class DeviceControlResultVo {
+ @ApiModelProperty("设备执行结果")
+ private boolean actionResult;
+ @ApiModelProperty("设备信息")
+ private String deviceName;
+ @ApiModelProperty("设备键值")
+ private String deviceKey;
+ @ApiModelProperty("设备状态")
+ private String deviceStatus;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPack.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPack.java
new file mode 100644
index 0000000..bde393a
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPack.java
@@ -0,0 +1,11 @@
+package org.jeecg.common.iot.vo;
+
+import lombok.Data;
+import org.jeecg.common.entity.SurvDeviceDeploy;
+
+@Data
+public class VOCmdPack {
+ private SurvDeviceDeploy deploy;
+ private String variableName;
+ private String variableValue;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPackQ.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPackQ.java
new file mode 100644
index 0000000..3027e17
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VOCmdPackQ.java
@@ -0,0 +1,8 @@
+package org.jeecg.common.iot.vo;
+
+import lombok.Data;
+
+@Data
+public class VOCmdPackQ {
+ private String variableName;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmd.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmd.java
new file mode 100644
index 0000000..1db0837
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmd.java
@@ -0,0 +1,16 @@
+package org.jeecg.common.iot.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@Data
+public class VODeviceCmd {
+ @ApiModelProperty("设备部署id")
+ private String deployId;
+ @ApiModelProperty("指令")
+ private String variableName;
+ @ApiModelProperty("指令值")
+ private String variableValue;
+ @ApiModelProperty("授权密钥,除大屏外勿传")
+ private String auths;
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmdQ.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmdQ.java
new file mode 100644
index 0000000..633cf10
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/iot/vo/VODeviceCmdQ.java
@@ -0,0 +1,17 @@
+package org.jeecg.common.iot.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class VODeviceCmdQ {
+ @ApiModelProperty("设备部署id")
+ private String deployId;
+ @ApiModelProperty("指令集合")
+ private List cmdPacks;
+ @ApiModelProperty("授权密钥,除大屏外勿传")
+ private String auths;
+
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusCommandUtil.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusCommandUtil.java
new file mode 100644
index 0000000..9fecaf1
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusCommandUtil.java
@@ -0,0 +1,134 @@
+package org.jeecg.common.util;
+
+
+import org.jeecg.common.iot.enums.FunctionCode;
+import org.jeecg.common.iot.enums.RWType;
+import org.jeecg.common.iot.enums.RegisterType;
+
+public class ModbusCommandUtil {
+
+ /**
+ * 通过枚举获取功能码
+ */
+ public static FunctionCode getFunctionCode(RegisterType regType, RWType rwType) {
+ switch (regType) {
+ case COIL:
+ return rwType == RWType.READ ? FunctionCode.READ_COIL : FunctionCode.WRITE_COIL;
+ case DISCRETE_INPUT:
+ if (rwType == RWType.READ) return FunctionCode.READ_DISCRETE_INPUT;
+ break;
+ case INPUT_REGISTER:
+ if (rwType == RWType.READ) return FunctionCode.READ_INPUT_REGISTER;
+ break;
+ case HOLDING_REGISTER:
+ return rwType == RWType.READ ? FunctionCode.READ_HOLDING_REGISTER : FunctionCode.WRITE_HOLDING_REGISTER;
+ }
+ throw new IllegalArgumentException("不支持的寄存器类型或读写类型");
+ }
+
+ /**
+ * 构建数据区
+ */
+ private static byte[] buildDataArea(RWType rwType, int regAddr, Integer value, Integer quantity) {
+ if (rwType == RWType.READ) {
+ int qty = (quantity == null) ? 1 : quantity;
+ return new byte[]{
+ (byte) ((regAddr >> 8) & 0xFF),
+ (byte) (regAddr & 0xFF),
+ (byte) ((qty >> 8) & 0xFF),
+ (byte) (qty & 0xFF)
+ };
+ } else {
+ if (value == null)
+ throw new IllegalArgumentException("写操作必须提供value");
+ return new byte[]{
+ (byte) ((regAddr >> 8) & 0xFF),
+ (byte) (regAddr & 0xFF),
+ (byte) ((value >> 8) & 0xFF),
+ (byte) (value & 0xFF)
+ };
+ }
+ }
+
+ /**
+ * 构建报文(不带CRC)
+ */
+ private static byte[] buildFrame(int slaveAddr, FunctionCode funcCode, byte[] data) {
+ byte[] frame = new byte[2 + data.length];
+ frame[0] = (byte) (slaveAddr & 0xFF);
+ frame[1] = funcCode.getCode();
+ System.arraycopy(data, 0, frame, 2, data.length);
+ return frame;
+ }
+
+ /**
+ * 添加CRC校验
+ */
+ private static byte[] addCRC(byte[] frame) {
+ byte[] crc = crc16(frame);
+ byte[] command = new byte[frame.length + 2];
+ System.arraycopy(frame, 0, command, 0, frame.length);
+ command[command.length - 2] = crc[0];
+ command[command.length - 1] = crc[1];
+ return command;
+ }
+
+ /**
+ * 计算MODBUS CRC16
+ */
+ public static byte[] crc16(byte[] data) {
+ int crc = 0xFFFF;
+ for (byte b : data) {
+ crc ^= (b & 0xFF);
+ for (int i = 0; i < 8; i++) {
+ if ((crc & 0x0001) != 0) {
+ crc >>= 1;
+ crc ^= 0xA001;
+ } else {
+ crc >>= 1;
+ }
+ }
+ }
+ return new byte[]{(byte) (crc & 0xFF), (byte) ((crc >> 8) & 0xFF)};
+ }
+
+ public static String buildCommand(
+ int slaveAddr,
+ RegisterType regType,
+ RWType rwType,
+ int regAddr,
+ Integer value,
+ Integer quantity
+ ) {
+ FunctionCode funcCode = getFunctionCode(regType, rwType);
+ byte[] data = buildDataArea(rwType, regAddr, value, quantity);
+ byte[] frame = buildFrame(slaveAddr, funcCode, data);
+ return bytesToHex(addCRC(frame));
+ }
+
+ public static String bytesToHex(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02X ", b));
+ }
+ return sb.toString().trim();
+ }
+
+ // 示例
+ public static void main(String[] args) {
+// // 读保持寄存器
+// byte[] cmd1 = buildCommand(1, RegisterType.HOLDING_REGISTER, RWType.READ, 1, null, 2);
+// System.out.println("读保持寄存器: " + bytesToHex(cmd1));
+// // 写线圈
+// byte[] cmd2 = buildCommand(1, RegisterType.COIL, RWType.WRITE, 5, 0xFF00, null);
+// System.out.println("写线圈: " + bytesToHex(cmd2));
+ String hexString = "0xFF00";
+ int value = Integer.decode(hexString);
+
+ String cmd1 = buildCommand(1, RegisterType.HOLDING_REGISTER, RWType.READ, 1, null, 2);
+ System.out.println("读保持寄存器: " + cmd1);
+ // 写线圈
+ String cmd2 = buildCommand(1, RegisterType.COIL, RWType.WRITE, 0, value, null);
+ System.out.println("写线圈: " + cmd2);
+ }
+}
diff --git a/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusResponseParser.java b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusResponseParser.java
new file mode 100644
index 0000000..ea2a901
--- /dev/null
+++ b/zh-module-applet/zh-applet-common/src/main/java/org/jeecg/common/util/ModbusResponseParser.java
@@ -0,0 +1,198 @@
+package org.jeecg.common.util;
+
+import java.util.Arrays;
+
+public class ModbusResponseParser {
+ /**
+ * 解析Modbus响应报文
+ * @param response modbus响应字节数组
+ * @return 解析结果ModbusResult对象
+ */
+ public static ModbusResult parse(byte[] response) {
+ if (response == null || response.length < 5) {
+ return ModbusResult.error("响应数据过短或为null");
+ }
+
+ int slaveId = response[0] & 0xFF;
+ int functionCode = response[1] & 0xFF;
+
+ // 检查异常响应
+ if ((functionCode & 0x80) != 0) {
+ int exceptionCode = response[2] & 0xFF;
+ return ModbusResult.error("从站返回异常响应,异常码:" + exceptionCode);
+ }
+
+ // 处理读保持寄存器(0x03)和输入寄存器(0x04)
+ if (functionCode == 0x03 || functionCode == 0x04) {
+ int byteCount = response[2] & 0xFF;
+ if (response.length != byteCount + 5) {
+ return ModbusResult.error("字节数或响应长度无效");
+ }
+ int registerCount = byteCount / 2;
+ int[] values = new int[registerCount];
+ for (int i = 0; i < registerCount; i++) {
+ int hi = response[3 + i * 2] & 0xFF;
+ int lo = response[4 + i * 2] & 0xFF;
+ values[i] = (hi << 8) | lo;
+ }
+ if (registerCount == 1) {
+ return ModbusResult.success(slaveId, functionCode, new int[]{values[0]});
+ } else {
+ return ModbusResult.success(slaveId, functionCode, values);
+ }
+ }
+
+ // 处理读线圈(0x01)和离散输入(0x02)
+ if (functionCode == 0x01 || functionCode == 0x02) {
+ int byteCount = response[2] & 0xFF;
+ if (response.length != byteCount + 5) {
+ return ModbusResult.error("字节数或响应长度无效");
+ }
+ boolean[] bits = new boolean[byteCount * 8];
+ for (int i = 0; i < byteCount; i++) {
+ for (int bit = 0; bit < 8; bit++) {
+ bits[i * 8 + bit] = ((response[3 + i] >> bit) & 0x01) != 0;
+ }
+ }
+ return ModbusResult.success(slaveId, functionCode, bits);
+ }
+
+ // 处理写单个线圈(0x05)或写单个寄存器(0x06)
+ if (functionCode == 0x05 || functionCode == 0x06) {
+ int address = ((response[2] & 0xFF) << 8) | (response[3] & 0xFF);
+ int value = ((response[4] & 0xFF) << 8) | (response[5] & 0xFF);
+ return ModbusResult.successValue(slaveId, functionCode,address, value);
+ }
+
+ // 处理写多个线圈/寄存器(0x0F, 0x10)
+ if (functionCode == 0x0F || functionCode == 0x10) {
+ int address = ((response[2] & 0xFF) << 8) | (response[3] & 0xFF);
+ int count = ((response[4] & 0xFF) << 8) | (response[5] & 0xFF);
+ return ModbusResult.success(slaveId, functionCode, address, count);
+ }
+
+ return ModbusResult.error("不支持的功能码:" + functionCode);
+ }
+
+ /**
+ * Modbus结果实体类
+ */
+ public static class ModbusResult {
+ private boolean success;
+ private String errorMsg;
+ private int slaveId;
+ private int functionCode;
+ private Integer value; // 单个寄存器值
+ private int[] values; // 多个寄存器值
+ private boolean[] bits; // bit数组
+ private Integer address;
+ private Integer count;
+
+ public static ModbusResult successValue(int slaveId, int functionCode,int address, int value) {
+ ModbusResult r = new ModbusResult();
+ r.success = true;
+ r.slaveId = slaveId;
+ r.functionCode = functionCode;
+ r.value = value;
+ r.address = address;
+ return r;
+ }
+
+ public static ModbusResult success(int slaveId, int functionCode, int[] values) {
+ ModbusResult r = new ModbusResult();
+ r.success = true;
+ r.slaveId = slaveId;
+ r.functionCode = functionCode;
+ r.values = values;
+ return r;
+ }
+
+ public static ModbusResult success(int slaveId, int functionCode, boolean[] bits) {
+ ModbusResult r = new ModbusResult();
+ r.success = true;
+ r.slaveId = slaveId;
+ r.functionCode = functionCode;
+ r.bits = bits;
+ return r;
+ }
+
+ public static ModbusResult success(int slaveId, int functionCode, int address, int count) {
+ ModbusResult r = new ModbusResult();
+ r.success = true;
+ r.slaveId = slaveId;
+ r.functionCode = functionCode;
+ r.address = address;
+ r.count = count;
+ return r;
+ }
+
+ public static ModbusResult error(String msg) {
+ ModbusResult r = new ModbusResult();
+ r.success = false;
+ r.errorMsg = msg;
+ return r;
+ }
+
+ // Getter与toString方法
+ public boolean isSuccess() { return success; }
+ public String getErrorMsg() { return errorMsg; }
+ public int getSlaveId() { return slaveId; }
+ public int getFunctionCode() { return functionCode; }
+ public Integer getValue() { return value; }
+ public int[] getValues() { return values; }
+ public boolean[] getBits() { return bits; }
+ public Integer getAddress() { return address; }
+ public Integer getCount() { return count; }
+
+ @Override
+ public String toString() {
+ if (!success) {
+ return "ModbusResult{error='" + errorMsg + "'}";
+ }
+ StringBuilder sb = new StringBuilder("ModbusResult{slaveId=" + slaveId + ", functionCode=" + functionCode);
+ if (value != null) sb.append(", value=").append(value);
+ if (values != null) sb.append(", values=").append(Arrays.toString(values));
+ if (bits != null) sb.append(", bits=").append(Arrays.toString(bits));
+ if (address != null) sb.append(", address=").append(address);
+ if (count != null) sb.append(", count=").append(count);
+ sb.append('}');
+ return sb.toString();
+ }
+ }
+
+ public static String bytesToHex(byte[] bytes) {
+ StringBuilder sb = new StringBuilder();
+ for (byte b : bytes) {
+ sb.append(String.format("%02X", b));
+ }
+ return sb.toString();
+ }
+
+ /**
+ * 测试主方法
+ */
+ public static void main(String[] args) {
+ // 示例1:读单个寄存器响应 01 03 02 00 0A CRC CRC
+// byte[] response1 = new byte[]{0x01, 0x03, 0x02, 0x00, 0x0A, 0x00, 0x00};
+// System.out.println("读单个寄存器:" + parse(response1));
+//
+// // 示例2:读多个寄存器响应 01 03 04 00 0A 01 02 CRC CRC
+// // 0103 0800 0000 0000 0000 0095 d7
+// byte[] response2 = new byte[]{0x01, 0x03, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,(byte)0x95,(byte)0xd7};
+// System.out.println("读多个寄存器:" + parse(response2));
+//
+// // 示例3:异常响应 01 83 02 CRC CRC
+//
+// byte[] response3 = new byte[]{0x01, (byte)0x83, 0x02, 0x00, 0x00};
+// System.out.println("异常响应:" + parse(response3));
+//
+// // 示例4:读多个线圈响应 01 01 01 55 CRC CRC
+// byte[] response4 = new byte[]{0x01, 0x01, 0x01, 0x55, 0x00, 0x00};
+// System.out.println("读多个线圈:" + parse(response4));
+
+
+ // 示例1:读单个寄存器响应 01 03 02 00 0A CRC CRC
+ byte[] response1 = new byte[]{0x01, 0x06, (byte) 0xCA, 0x00, 0x00, (byte) 0x89, (byte) 0xCA};
+ System.out.println("读单个寄存器:" + bytesToHex(response1));
+ }
+}