Compare commits

...

24 Commits

Author SHA1 Message Date
3067418132@qq.com bde7a2669c 1、参数设置改成可以设置小数 1 day ago
3067418132@qq.com 9e0bf9b7ee 1、添加日志 4 weeks ago
3067418132@qq.com 440eab0f8c 1、优化微信异常数据推送 1 month ago
3067418132@qq.com 455bc79c5a 1、增加收益分析相关接口逻辑处理 2 months ago
3067418132@qq.com 364886f4cc 1、热泵运行记录存储过程、查询接口、导出接口编写 2 months ago
3067418132@qq.com 668f8e3fb2 1、冷量修改成五分钟存储一次 2 months ago
3067418132@qq.com 1150bf4cac 1、温湿度传感器解析代码修复 2 months ago
3067418132@qq.com e43244596a 1、netty添加工厂策略。 2 months ago
3067418132@qq.com cc19ab5afd 1、修复液位控制 2 months ago
3067418132@qq.com 7dd7b9866d 1、水表接入系统 2 months ago
3067418132@qq.com 4a00010e3e 1、netty液位控制器采集解析程序; 2 months ago
3067418132@qq.com a12030c83c 1、PLC相关参数 2 months ago
3067418132@qq.com 9854414719 1、增加温湿度采集解析 2 months ago
3067418132@qq.com 63985b2bd8 1、增加循环泵相关数据展示; 3 months ago
3067418132@qq.com beb4bc866e 1、去掉log.info; 3 months ago
3067418132@qq.com 837e662c8d 1、热水系统监控界面显示内容接口更改; 3 months ago
3067418132@qq.com 2ceb622eb6 1、添加中央热水系统相关api; 3 months ago
25604 4fd5c674b5 1、主机监控、详情页数据优化 4 months ago
25604 1871e06353 1、减少日志打印; 6 months ago
25604 fc98e3bd6d 1、修复定时报警,数据处理问题; 10 months ago
25604 c83403c4cd 1、优化策略管理排序问题。 1 year ago
25604 5210bcdd58 1、报警添加微信通知功能,增加模板。 1 year ago
25604 ebabe3d17a 1、报警添加微信通知功能,增加模板。 1 year ago
25604 c4eaa3b97b 1、报警添加微信通知功能。 1 year ago
  1. 33
      mh-admin/src/main/java/com/mh/MHRunner.java
  2. 11
      mh-admin/src/main/java/com/mh/web/controller/device/ChillersParamsController.java
  3. 10
      mh-admin/src/main/java/com/mh/web/controller/device/CollectionParamsManageController.java
  4. 26
      mh-admin/src/main/java/com/mh/web/controller/device/OperationController.java
  5. 109
      mh-admin/src/main/java/com/mh/web/controller/energy/HotWaterEnergyController.java
  6. 58
      mh-admin/src/main/java/com/mh/web/controller/energy/HowWaterRevenueEnergyController.java
  7. 20
      mh-admin/src/main/java/com/mh/web/controller/monitor/HotWaterMonitorController.java
  8. 178
      mh-admin/src/main/java/com/mh/web/controller/report/ReportHotWaterController.java
  9. 18
      mh-admin/src/main/java/com/mh/web/controller/space/BuildingInfoController.java
  10. 5
      mh-admin/src/main/java/com/mh/web/controller/space/SpaceController.java
  11. 30
      mh-admin/src/main/resources/application-dev.yml
  12. 30
      mh-admin/src/main/resources/application-prod.yml
  13. 14
      mh-admin/src/main/resources/application-test.yml
  14. 2
      mh-admin/src/main/resources/application.yml
  15. 2
      mh-admin/src/main/resources/logback.xml
  16. 65
      mh-admin/src/test/java/com/mh/MHApplicationTest.java
  17. 7
      mh-common/pom.xml
  18. 28
      mh-common/src/main/java/com/mh/common/config/wechat/RestTemplateConfig.java
  19. 94
      mh-common/src/main/java/com/mh/common/config/wechat/WechatMpConfig.java
  20. 62
      mh-common/src/main/java/com/mh/common/config/wechat/WechatSignUtil.java
  21. 25
      mh-common/src/main/java/com/mh/common/constant/EnergyType.java
  22. 338
      mh-common/src/main/java/com/mh/common/core/domain/dto/BFloorReportHotWaterDTO.java
  23. 68
      mh-common/src/main/java/com/mh/common/core/domain/dto/DataResultDTO.java
  24. 19
      mh-common/src/main/java/com/mh/common/core/domain/dto/HotWaterNowDataDTO.java
  25. 77
      mh-common/src/main/java/com/mh/common/core/domain/dto/HotWaterRevenueSumDTO.java
  26. 220
      mh-common/src/main/java/com/mh/common/core/domain/dto/ThreeFloorReportHotWaterDTO.java
  27. 63
      mh-common/src/main/java/com/mh/common/core/domain/dto/WeatherDataDTO.java
  28. 13
      mh-common/src/main/java/com/mh/common/core/domain/entity/AlarmRecords.java
  29. 46
      mh-common/src/main/java/com/mh/common/core/domain/entity/AnalysisMonth.java
  30. 27
      mh-common/src/main/java/com/mh/common/core/domain/entity/AnalysisYear.java
  31. 81
      mh-common/src/main/java/com/mh/common/core/domain/entity/CollectionParamsManage.java
  32. 8
      mh-common/src/main/java/com/mh/common/core/domain/entity/CpmSpaceRelation.java
  33. 84
      mh-common/src/main/java/com/mh/common/core/domain/entity/DeviceState.java
  34. 70
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyBaseSum.java
  35. 89
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyDay.java
  36. 26
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyDaySum.java
  37. 220
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyHour.java
  38. 89
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyMonth.java
  39. 26
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyMonthSum.java
  40. 89
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyYear.java
  41. 26
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyYearSum.java
  42. 9
      mh-common/src/main/java/com/mh/common/core/domain/entity/GatewayManage.java
  43. 15
      mh-common/src/main/java/com/mh/common/core/domain/entity/HouseInfo.java
  44. 286
      mh-common/src/main/java/com/mh/common/core/domain/entity/ReportHotWaterParamHis.java
  45. 310
      mh-common/src/main/java/com/mh/common/core/domain/entity/ReportSysRunParamHis.java
  46. 117
      mh-common/src/main/java/com/mh/common/core/domain/entity/WaterLevel.java
  47. 117
      mh-common/src/main/java/com/mh/common/core/domain/entity/WaterTemp.java
  48. 20
      mh-common/src/main/java/com/mh/common/core/domain/entity/WeatherData.java
  49. 3
      mh-common/src/main/java/com/mh/common/core/domain/vo/DeviceMonitorVO.java
  50. 69
      mh-common/src/main/java/com/mh/common/core/domain/vo/HotWaterControlVO.java
  51. 35
      mh-common/src/main/java/com/mh/common/core/domain/wechat/First.java
  52. 35
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key1.java
  53. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key2.java
  54. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key3.java
  55. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key4.java
  56. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key5.java
  57. 115
      mh-common/src/main/java/com/mh/common/core/domain/wechat/PushMsgEntity.java
  58. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Remark.java
  59. 70
      mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatTemplate.java
  60. 52
      mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatTemplateProject.java
  61. 172
      mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatUserInfo.java
  62. 63
      mh-common/src/main/java/com/mh/common/core/redis/RedisLock.java
  63. 55
      mh-common/src/main/java/com/mh/common/enums/ComputeEnum.java
  64. 5
      mh-common/src/main/java/com/mh/common/model/request/AdvantechDatas.java
  65. 39
      mh-common/src/main/java/com/mh/common/model/response/ParseResult.java
  66. 446
      mh-common/src/main/java/com/mh/common/utils/AnalysisReceiveOrder485.java
  67. 1
      mh-common/src/main/java/com/mh/common/utils/BigDecimalUtils.java
  68. 253
      mh-common/src/main/java/com/mh/common/utils/CRC16.java
  69. 108
      mh-common/src/main/java/com/mh/common/utils/DateUtils.java
  70. 1350
      mh-common/src/main/java/com/mh/common/utils/ExchangeStringUtil.java
  71. 99
      mh-common/src/main/java/com/mh/common/utils/ModbusUtils.java
  72. 77
      mh-common/src/main/java/com/mh/common/utils/NettyTools.java
  73. 64
      mh-common/src/main/java/com/mh/common/utils/SendOrderUtils.java
  74. 81
      mh-common/src/main/java/com/mh/common/utils/file/handle/ExcelFillCellMergeHandler.java
  75. 46
      mh-common/src/main/java/com/mh/common/utils/file/handle/ReportSysParamHandler.java
  76. 25
      mh-common/src/main/java/com/mh/common/utils/file/handle/RowHeightStyleHandler.java
  77. 12
      mh-common/src/main/java/com/mh/common/utils/http/HttpUtils.java
  78. 14
      mh-framework/src/main/java/com/mh/framework/aspectj/ControlDeviceAspect.java
  79. 2
      mh-framework/src/main/java/com/mh/framework/aspectj/RateLimiterAspect.java
  80. 2
      mh-framework/src/main/java/com/mh/framework/datasource/DynamicDataSourceContextHolder.java
  81. 137
      mh-framework/src/main/java/com/mh/framework/dealdata/impl/DataProcessServiceImpl.java
  82. 2
      mh-framework/src/main/java/com/mh/framework/manager/factory/AsyncFactory.java
  83. 4
      mh-framework/src/main/java/com/mh/framework/mqtt/handler/InboundMessageRouter.java
  84. 8
      mh-framework/src/main/java/com/mh/framework/mqtt/service/impl/EventsServiceImpl.java
  85. 4
      mh-framework/src/main/java/com/mh/framework/mqtt/service/impl/MqttMsgSenderServiceImpl.java
  86. 57
      mh-framework/src/main/java/com/mh/framework/netty/EchoServer.java
  87. 498
      mh-framework/src/main/java/com/mh/framework/netty/EchoServerHandler.java
  88. 18
      mh-framework/src/main/java/com/mh/framework/netty/INettyService.java
  89. 147
      mh-framework/src/main/java/com/mh/framework/netty/NettyServiceImpl.java
  90. 495
      mh-framework/src/main/java/com/mh/framework/netty/NewEchoServerHandler.java
  91. 33
      mh-framework/src/main/java/com/mh/framework/netty/ServerChannelInitializer.java
  92. 66
      mh-framework/src/main/java/com/mh/framework/netty/session/ServerSession.java
  93. 96
      mh-framework/src/main/java/com/mh/framework/netty/session/SessionMap.java
  94. 20
      mh-framework/src/main/java/com/mh/framework/netty/task/CallbackTask.java
  95. 78
      mh-framework/src/main/java/com/mh/framework/netty/task/CallbackTaskScheduler.java
  96. 6
      mh-framework/src/main/java/com/mh/framework/netty/task/ExecuteTask.java
  97. 67
      mh-framework/src/main/java/com/mh/framework/netty/task/FutureTaskScheduler.java
  98. 8
      mh-framework/src/main/java/com/mh/framework/rabbitmq/consumer/ReceiveHandler.java
  99. 6
      mh-framework/src/main/java/com/mh/framework/web/service/UserDetailsServiceImpl.java
  100. 2
      mh-quartz/src/main/java/com/mh/quartz/task/CreateAlarmTask.java
  101. Some files were not shown because too many files have changed in this diff Show More

33
mh-admin/src/main/java/com/mh/MHRunner.java

@ -1,14 +1,19 @@
package com.mh;
import com.mh.common.core.domain.entity.GatewayManage;
import com.mh.common.core.domain.entity.MqttSubscription;
import com.mh.common.utils.StringUtils;
import com.mh.framework.mqtt.service.IMqttTopicService;
import com.mh.framework.netty.EchoServer;
import com.mh.system.service.device.ICollectionParamsManageService;
import com.mh.system.service.device.IGatewayManageService;
import com.mh.system.service.mqtt.IMqttSubscriptionService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author LJF
@ -24,15 +29,41 @@ public class MHRunner implements ApplicationRunner {
private final IMqttTopicService iMqttTopicService;
public MHRunner(IMqttSubscriptionService iMqttSubscriptionService, IMqttTopicService iMqttTopicService) {
private final ICollectionParamsManageService collectionParamsManageService;
private final IGatewayManageService gatewayManageService;
public MHRunner(IMqttSubscriptionService iMqttSubscriptionService, IMqttTopicService iMqttTopicService, ICollectionParamsManageService collectionParamsManageService, IGatewayManageService gatewayManageService) {
this.iMqttSubscriptionService = iMqttSubscriptionService;
this.iMqttTopicService = iMqttTopicService;
this.collectionParamsManageService = collectionParamsManageService;
this.gatewayManageService = gatewayManageService;
}
@Override
public void run(ApplicationArguments args) throws Exception {
// 初始化mqtt订阅记录
initializeMqttSubscription();
// 生成DTU采集参数
createDtuCollectionParams();
// 启动netty服务端
startNettyServer();
}
private void startNettyServer() {
List<GatewayManage> gatewayManages = gatewayManageService.selectGwManageList(new GatewayManage());
if (gatewayManages != null && !gatewayManages.isEmpty()) {
// 根据端口号分组
gatewayManages.stream().collect(Collectors.groupingBy(GatewayManage::getPort)).forEach((k, v) -> {
// 启动网关
GatewayManage gatewayManage = v.getFirst();
new Thread(() -> new EchoServer(gatewayManage.getPort()).start()).start();
});
}
}
private void createDtuCollectionParams() {
collectionParamsManageService.createDtuCollectionParams();
}
/**

11
mh-admin/src/main/java/com/mh/web/controller/device/ChillersParamsController.java

@ -18,6 +18,7 @@ import com.mh.system.service.device.ICommunicationParamsService;
import com.mh.system.service.energy.IEnergyService;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -71,27 +72,27 @@ public class ChillersParamsController extends BaseController {
switch (vo.getParamType()) {
case "1": // 运行状态
if (!StringUtils.isEmpty(vo.getCurValue())) {
vo.setCurValue(vo.getCurValue().equals("1") ? "运行" : "停止");
vo.setCurValue(new BigDecimal(vo.getCurValue()).intValue() == 1 ? "运行" : "停止");
}
break;
case "2": // 启停
if (!StringUtils.isEmpty(vo.getCurValue())) {
vo.setCurValue(vo.getCurValue().equals("1") ? "启动" : "停止");
vo.setCurValue(new BigDecimal(vo.getCurValue()).intValue() == 1 ? "启动" : "停止");
}
break;
case "5": // 故障
if (!StringUtils.isEmpty(vo.getCurValue())) {
vo.setCurValue(vo.getCurValue().equals("1") ? "故障" : "正常");
vo.setCurValue(new BigDecimal(vo.getCurValue()).intValue() == 1 ? "故障" : "正常");
}
break;
case "6": // 手自动切换
if (!StringUtils.isEmpty(vo.getCurValue())) {
vo.setCurValue(vo.getCurValue().equals("1") ? "手动" : "自动");
vo.setCurValue(new BigDecimal(vo.getCurValue()).intValue() == 1 ? "手动" : "自动");
}
break;
case "22": // 本地远程切换
if (!StringUtils.isEmpty(vo.getCurValue())) {
vo.setCurValue(vo.getCurValue().equals("1") ? "远程" : "本地");
vo.setCurValue(new BigDecimal(vo.getCurValue()).intValue() == 1 ? "远程" : "本地");
}
break;
default:

10
mh-admin/src/main/java/com/mh/web/controller/device/CollectionParamsManageController.java

@ -88,4 +88,14 @@ public class CollectionParamsManageController extends BaseController {
return toAjax(iCollectionParamsManageService.deleteCommunicationByIds(cpmIds));
}
/**
* 删除设备采集参数管理
*/
@Log(title = "设备采集参数管理")
@GetMapping("/list/{deviceLegerIds}")
public TableDataInfo queryList(@PathVariable String[] deviceLegerIds)
{
return getDataTable(iCollectionParamsManageService.selectCollectionParamsManageListByIds(deviceLegerIds));
}
}

26
mh-admin/src/main/java/com/mh/web/controller/device/OperationController.java

@ -11,6 +11,7 @@ import com.mh.common.core.domain.vo.DeviceOperateMonitorVO;
import com.mh.common.core.page.TableDataInfo;
import com.mh.common.enums.BusinessType;
import com.mh.framework.mqtt.service.IMqttGatewayService;
import com.mh.framework.netty.INettyService;
import com.mh.system.service.device.ICollectionParamsManageService;
import com.mh.system.service.operation.IOperationDeviceService;
import lombok.extern.slf4j.Slf4j;
@ -45,13 +46,16 @@ public class OperationController extends BaseController {
private final IMqttGatewayService iMqttGatewayService;
private final INettyService nettyService;
@Autowired
public OperationController(ICollectionParamsManageService iCollectionParamsManageService,
IOperationDeviceService iOperationService,
IMqttGatewayService iMqttGatewayService) {
IMqttGatewayService iMqttGatewayService, INettyService nettyService) {
this.iCollectionParamsManageService = iCollectionParamsManageService;
this.iOperationService = iOperationService;
this.iMqttGatewayService = iMqttGatewayService;
this.nettyService = nettyService;
}
/**
@ -95,11 +99,21 @@ public class OperationController extends BaseController {
@ControlDeviceAno(value = "设备操作")
public AjaxResult operationDevice(@RequestBody List<OrderEntity> changeValues) {
try {
String sendOrder = iOperationService.operationDevice(changeValues);
String name = mhConfig.getName();
// 获取mqtt操作队列(后期通过mqtt队列配置发送主题)
log.info("发送主题:{},消息:{}", name + "/"+ controlTopic, sendOrder);
iMqttGatewayService.publish(name + "/"+ controlTopic, sendOrder, 1);
// 判断id是否是DTU设备类型
if (!iOperationService.isAdvanTech(changeValues)) {
String sendOrder = iOperationService.operationDevice(changeValues);
String name = mhConfig.getName();
// 获取mqtt操作队列(后期通过mqtt队列配置发送主题)
log.info("发送主题:{},消息:{}", name + "/" + controlTopic, sendOrder);
iMqttGatewayService.publish(name + "/" + controlTopic, sendOrder, 1);
} else {
// 目前只有DTU设备需要发送4G指令
if (nettyService.sendOrder(changeValues)) {
return AjaxResult.success();
} else {
return AjaxResult.error();
}
}
} catch (Exception e) {
log.error("设备操作失败", e);
return AjaxResult.error();

109
mh-admin/src/main/java/com/mh/web/controller/energy/HotWaterEnergyController.java

@ -0,0 +1,109 @@
package com.mh.web.controller.energy;
import com.mh.common.core.controller.BaseController;
import com.mh.common.core.domain.entity.WaterLevel;
import com.mh.common.core.domain.entity.WaterTemp;
import com.mh.common.core.page.TableDataInfo;
import com.mh.system.service.energy.IEnergyQueryService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 生活热水能耗分析
* @date 2025-06-18 17:49:49
*/
@RestController
@RequestMapping("/hot_energy")
public class HotWaterEnergyController extends BaseController {
private final IEnergyQueryService energyQueryService;
public HotWaterEnergyController(IEnergyQueryService iEnergyQueryService) {
this.energyQueryService = iEnergyQueryService;
}
@GetMapping("/query")
public TableDataInfo queryEnergy(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "startDate", required = false) String startDate,
@RequestParam(value = "endDate", required = false) String endDate,
@RequestParam(value = "type") int type) {
startPage();
List<?> result = energyQueryService.queryEnergyDataList(buildingId, startDate, endDate, type);
return getDataTable(result);
}
//查询日月年用量汇总
@GetMapping(value = "/energySum")
public TableDataInfo queryEnergySum(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "curDate", required = false) String curDate,
@RequestParam(value = "type", required = true) Integer type) {
startPage();
List<?> result = energyQueryService.queryEnergyDataSumList(buildingId, curDate, type);
return getDataTable(result);
}
/**
* 温度变化表
*
* @param buildingId
* @param curDate
* @return
*/
@GetMapping("/waterTemp")
public TableDataInfo queryWaterTemp(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "curDate", required = false) String curDate) {
startPage();
List<WaterTemp> result = energyQueryService.queryWaterTemp(buildingId, curDate);
return getDataTable(result);
}
/**
* 水位变化表
*
* @param buildingId
* @param curDate
* @return
*/
@GetMapping("/waterLevel")
public TableDataInfo queryWaterLevel(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "curDate", required = false) String curDate) {
startPage();
List<WaterLevel> result = energyQueryService.queryWaterLevel(buildingId, curDate);
return getDataTable(result);
}
@GetMapping("/queryDeviceDatas")
public TableDataInfo queryDeviceDatas(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "startDate", required = false) String startDate,
@RequestParam(value = "endDate", required = false) String endDate,
@RequestParam(value = "deviceType", required = false) String deviceType) {
startPage();
List<?> result = energyQueryService.queryDeviceDatas(buildingId, startDate, endDate, deviceType);
return getDataTable(result);
}
@GetMapping("/analysis/queryYear") //type=1(水),2(电),3(能耗),4(维保)
public TableDataInfo queryAnalysisYear(@RequestParam(value = "curDate",required = true) String curDate,
@RequestParam(value = "buildingId",required = true) String buildingId,
@RequestParam(value = "type",defaultValue = "3") int type) {
startPage();
List<?> result = energyQueryService.queryAnalysisYear(curDate, buildingId, type);
return getDataTable(result);
}
@GetMapping("/analysis/queryMonth") //type=1(水),2(电),3(能耗),4(维保),5(使用时间)
public TableDataInfo queryAnalysisMonth(@RequestParam(value = "curDate",required = true) String curDate,
@RequestParam(value = "buildingId",required = true) String buildingId,
@RequestParam(value = "type",defaultValue = "3") int type) {
startPage();
List<?> result = energyQueryService.queryAnalysisMonth(curDate, buildingId, type);
return getDataTable(result);
}
}

58
mh-admin/src/main/java/com/mh/web/controller/energy/HowWaterRevenueEnergyController.java

@ -0,0 +1,58 @@
package com.mh.web.controller.energy;
import com.mh.common.core.controller.BaseController;
import com.mh.common.core.page.PageDomain;
import com.mh.common.core.page.TableDataInfo;
import com.mh.common.core.page.TableSupport;
import com.mh.system.service.energy.IEnergyQueryService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 中央热水收益分析
* @date 2026-05-13 08:37:12
*/
@RestController
@RequestMapping("/hot_water_revenue")
public class HowWaterRevenueEnergyController extends BaseController {
private final IEnergyQueryService energyQueryService;
public HowWaterRevenueEnergyController(IEnergyQueryService iEnergyQueryService) {
this.energyQueryService = iEnergyQueryService;
}
@GetMapping(value = "/energySum")
public TableDataInfo queryEnergySum(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "startDate", required = false) String startDate,
@RequestParam(value = "endDate", required = false) String endDate,
@RequestParam(value = "type", required = true) Integer type) {
startPage();
List<?> result = energyQueryService.queryRevenueEnergyDataSumList(buildingId, startDate, endDate, type);
return getDataTable(result);
}
@GetMapping("/query")
public TableDataInfo queryEnergy(@RequestParam(value = "buildingId", required = false) String buildingId,
@RequestParam(value = "startDate", required = false) String startDate,
@RequestParam(value = "endDate", required = false) String endDate,
@RequestParam(value = "type") int type) {
startPage();
List<?> result = energyQueryService.queryRevenueEnergyDataList(buildingId, startDate, endDate, type);
TableDataInfo dataTable = getDataTable(result);
// 或者总条数数据
PageDomain pageDomain = TableSupport.buildPageRequest();
pageDomain.setPageNum(0);
List<?> result1 = energyQueryService.queryRevenueEnergyDataList(buildingId, startDate, endDate, type);
dataTable.setTotal(result1.size());
return dataTable;
}
}

20
mh-admin/src/main/java/com/mh/web/controller/monitor/HotWaterMonitorController.java

@ -1,14 +1,15 @@
package com.mh.web.controller.monitor;
import com.mh.common.core.controller.BaseController;
import com.mh.common.core.domain.ColumnData;
import com.mh.common.core.domain.ColumnFilter;
import com.mh.common.core.domain.entity.DeviceState;
import com.mh.common.core.domain.dto.HotWaterControlDTO;
import com.mh.common.core.domain.dto.HotWaterNowDataDTO;
import com.mh.common.core.domain.dto.PumpInfoDTO;
import com.mh.common.core.domain.entity.ChillersEntity;
import com.mh.common.core.page.TableDataInfo;
import com.mh.system.service.device.ICollectionParamsManageService;
import com.mh.system.service.device.IDeviceLedgerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
@ -30,9 +31,12 @@ public class HotWaterMonitorController extends BaseController {
private final ICollectionParamsManageService iCollectionParamsManageService;
private final IDeviceLedgerService deviceLedgerService;
@Autowired
public HotWaterMonitorController(ICollectionParamsManageService iCollectionParamsManageService) {
public HotWaterMonitorController(ICollectionParamsManageService iCollectionParamsManageService, IDeviceLedgerService deviceLedgerService) {
this.iCollectionParamsManageService = iCollectionParamsManageService;
this.deviceLedgerService = deviceLedgerService;
}
/**
@ -89,4 +93,16 @@ public class HotWaterMonitorController extends BaseController {
return getDataTable(list);
}
/**
* 获取设备状态信息数据
* @param systemType
* @return
*/
@GetMapping("/deviceState")
public TableDataInfo deviceState(@RequestParam("systemType") String systemType) {
startPage();
List<DeviceState> list = deviceLedgerService.deviceState(systemType);
return getDataTable(list);
}
}

178
mh-admin/src/main/java/com/mh/web/controller/report/ReportHotWaterController.java

@ -0,0 +1,178 @@
package com.mh.web.controller.report;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import com.mh.common.core.controller.BaseController;
import com.mh.common.core.domain.AjaxResult;
import com.mh.common.core.domain.dto.BFloorReportHotWaterDTO;
import com.mh.common.core.domain.dto.ThreeFloorReportHotWaterDTO;
import com.mh.common.core.domain.entity.FloorInfo;
import com.mh.common.core.domain.entity.ReportHotWaterParamHis;
import com.mh.common.core.domain.entity.ReportSysRunParamHis;
import com.mh.common.core.page.TableDataInfo;
import com.mh.common.utils.StringUtils;
import com.mh.common.utils.file.handle.ExcelFillCellMergeHandler;
import com.mh.common.utils.file.handle.ReportSysParamHandler;
import com.mh.common.utils.file.handle.RowHeightStyleHandler;
import com.mh.system.service.report.IReportHotWaterService;
import com.mh.system.service.space.IFloorInfoService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.List;
import java.util.stream.Collectors;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 热泵系统运行参数报表
* @date 2024-05-30 08:45:57
*/
@RestController
@RequestMapping("/reportHotWater")
@Slf4j
public class ReportHotWaterController extends BaseController {
private final IReportHotWaterService reportHotWaterService;
private final IFloorInfoService floorInfoService;
private ReportHotWaterController(IReportHotWaterService reportHotWaterService, IFloorInfoService floorInfoService) {
this.reportHotWaterService = reportHotWaterService;
this.floorInfoService = floorInfoService;
}
@PostMapping("/list")
public TableDataInfo list(@RequestBody ReportHotWaterParamHis reportHotWaterParamHis)
{
if (reportHotWaterParamHis.getPageNum() != 0) {
PageHelper.startPage(reportHotWaterParamHis.getPageNum(), reportHotWaterParamHis.getPageSize());
}
FloorInfo floorInfo = floorInfoService.selectFloorInfoById(reportHotWaterParamHis.getFloorId());
if (floorInfo == null) {
throw new IllegalArgumentException("Floor not found");
} else {
reportHotWaterParamHis.setFloorId(reportHotWaterParamHis.getFloorId() + "_" + floorInfo.getFloorName());
}
List<ReportHotWaterParamHis> list = reportHotWaterService.selectList(reportHotWaterParamHis);
return getDataTable(list);
}
@PutMapping("/edit")
public AjaxResult edit(@RequestBody ReportHotWaterParamHis reportHotWaterParamHis)
{
// FloorInfo floorInfo = floorInfoService.selectFloorInfoById(reportHotWaterParamHis.getFloorId());
// if (floorInfo == null) {
// throw new IllegalArgumentException("Floor not found");
// } else {
// reportHotWaterParamHis.setFloorId(reportHotWaterParamHis.getFloorId() + "_" + floorInfo.getFloorName());
// }
return toAjax(reportHotWaterService.updateRunParams(reportHotWaterParamHis));
}
@PostMapping("/export")
public void exportExcel(@RequestBody ReportHotWaterParamHis reportHotWaterParamHis, HttpServletResponse response) {
// 文件名
try {
String fileName = "热水热泵运行记录表.xlsx";
String floorId = reportHotWaterParamHis.getFloorId();
FloorInfo floorInfo = floorInfoService.selectFloorInfoById(floorId);
if (floorInfo == null) {
throw new IllegalArgumentException("Floor not found");
} else {
floorId = floorId + "_" + floorInfo.getFloorName();
reportHotWaterParamHis.setFloorId(floorId);
}
String headTitle = "热水热泵运行记录表";
if (!StringUtils.isBlank(floorId)) {
if (floorId.contains("主楼")) {
fileName = "主楼热水热泵运行记录表.xlsx";
headTitle = "主楼热水热泵运行记录表";
} else {
fileName = "贵宾楼热水热泵运行记录表.xlsx";
headTitle = "贵宾楼热水热泵运行记录表";
}
}
// 从数据库获取数据
List<ReportHotWaterParamHis> list = reportHotWaterService.selectList(reportHotWaterParamHis);
if (list != null) {
// 设置响应格式
response.setContentType("application/vdn.ms-excel;charset=utf-8");
response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName, "UTF-8") + "\"");
response.setCharacterEncoding("UTF-8");
ExcelFillCellMergeHandler mergePrevCol = new ExcelFillCellMergeHandler();
int headSize = 3;
if (floorId.contains("贵宾楼")) {
List<BFloorReportHotWaterDTO> infoDTOS = list.stream().map(info -> {
BFloorReportHotWaterDTO deviceInfoDTO = new BFloorReportHotWaterDTO();
BeanUtils.copyProperties(info, deviceInfoDTO);
// 单独处理启停和运行状态
deviceInfoDTO.setStatusRunHotPumpOneStr(info.getStatusRunHotPumpOne() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpOneStr(info.getStatusSwitchHotPumpOne() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpTwoStr(info.getStatusRunHotPumpTwo() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpTwoStr(info.getStatusSwitchHotPumpTwo() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpThreeStr(info.getStatusRunHotPumpThree() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpThreeStr(info.getStatusSwitchHotPumpThree() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpFourStr(info.getStatusRunHotPumpFour() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpFourStr(info.getStatusSwitchHotPumpFour() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpFiveStr(info.getStatusRunHotPumpFive() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpFiveStr(info.getStatusSwitchHotPumpFive() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpSixStr(info.getStatusRunHotPumpSix() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpSixStr(info.getStatusSwitchHotPumpSix() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpSevenStr(info.getStatusRunHotPumpSeven() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpSevenStr(info.getStatusSwitchHotPumpSeven() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpEightStr(info.getStatusRunHotPumpEight() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpEightStr(info.getStatusSwitchHotPumpEight() == 1 ? "开机" : "关机");
return deviceInfoDTO;
}).collect(Collectors.toList());
// 内容格式
EasyExcel.write(response.getOutputStream(), BFloorReportHotWaterDTO.class)
.registerWriteHandler(new ReportSysParamHandler(headTitle))
.registerWriteHandler(mergePrevCol)
.registerWriteHandler(new RowHeightStyleHandler())
.sheet(fileName.replace(".xlsx", ""))
.doWrite(infoDTOS);
} else {
List<ThreeFloorReportHotWaterDTO> infoDTOS = list.stream().map(info -> {
ThreeFloorReportHotWaterDTO deviceInfoDTO = new ThreeFloorReportHotWaterDTO();
BeanUtils.copyProperties(info, deviceInfoDTO);
// 单独处理启停和运行状态
deviceInfoDTO.setStatusRunHotPumpOneStr(info.getStatusRunHotPumpOne() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpOneStr(info.getStatusSwitchHotPumpOne() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunHotPumpTwoStr(info.getStatusRunHotPumpTwo() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusSwitchHotPumpTwoStr(info.getStatusSwitchHotPumpTwo() == 1 ? "开机" : "关机");
deviceInfoDTO.setStatusRunCyclePumpOneStr(info.getStatusRunCyclePumpOne() == 1 ? "运行" : "不运行");
deviceInfoDTO.setStatusRunCyclePumpTwoStr(info.getStatusRunCyclePumpTwo() == 1 ? "运行" : "不运行");
// deviceInfoDTO.setStatusRunHotPumpThreeStr(info.getStatusRunHotPumpThree() == 1 ? "运行" : "不运行");
// deviceInfoDTO.setStatusSwitchHotPumpThreeStr(info.getStatusSwitchHotPumpThree() == 1 ? "开机" : "关机");
// deviceInfoDTO.setStatusRunHotPumpFourStr(info.getStatusRunHotPumpFour() == 1 ? "运行" : "不运行");
// deviceInfoDTO.setStatusSwitchHotPumpFourStr(info.getStatusSwitchHotPumpFour() == 1 ? "开机" : "关机");
// deviceInfoDTO.setStatusRunSupplyPumpOneStr(info.getStatusRunSupplyPumpOne() == 1 ? "运行" : "不运行");
// deviceInfoDTO.setStatusRunSupplyPumpTwoStr(info.getStatusRunSupplyPumpTwo() == 1 ? "运行" : "不运行");
// deviceInfoDTO.setStatusRunSupplyPumpThreeStr(info.getStatusRunSupplyPumpThree() == 1 ? "运行" : "不运行");
// deviceInfoDTO.setStatusRunSupplyPumpFourStr(info.getStatusRunSupplyPumpFour() == 1 ? "运行" : "不运行");
return deviceInfoDTO;
}).collect(Collectors.toList());
// 内容格式
EasyExcel.write(response.getOutputStream(), ThreeFloorReportHotWaterDTO.class)
.registerWriteHandler(new ReportSysParamHandler(headTitle))
.registerWriteHandler(mergePrevCol)
.registerWriteHandler(new RowHeightStyleHandler())
.sheet(fileName.replace(".xlsx", ""))
.doWrite(infoDTOS);
}
}
} catch (IOException e) {
throw new RuntimeException("下载报表异常");
}
}
}

18
mh-admin/src/main/java/com/mh/web/controller/space/BuildingInfoController.java

@ -6,6 +6,7 @@ import com.mh.common.core.domain.AjaxResult;
import com.mh.common.core.domain.entity.BuildingInfo;
import com.mh.common.core.page.TableDataInfo;
import com.mh.common.enums.BusinessType;
import com.mh.system.service.energy.IEnergyQueryService;
import com.mh.system.service.space.IBuildingInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
@ -13,6 +14,7 @@ import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* @author LJF
@ -28,6 +30,9 @@ public class BuildingInfoController extends BaseController {
@Autowired
private IBuildingInfoService buildingInfoService;
@Autowired
private IEnergyQueryService energyQueryService;
/**
* 获取楼栋管理列表内容数据
*/
@ -85,4 +90,17 @@ public class BuildingInfoController extends BaseController {
return toAjax(buildingInfoService.deleteBuildingInfoByIds(buildingIds));
}
/**
* 获取楼栋管理列表内容数据
*/
@GetMapping("/hot_list")
public TableDataInfo hotWaterList()
{
List<Map<String, Object>> list = energyQueryService.queryFloorInfo();
// 在当前list首个坐标加个值
list.addFirst(Map.of("id", "所有", "building_name", "所有"));
return getDataTable(list);
}
}

5
mh-admin/src/main/java/com/mh/web/controller/space/SpaceController.java

@ -29,4 +29,9 @@ public class SpaceController extends BaseController {
return AjaxResult.success(houseInfoService.buildTree(systemType));
}
@GetMapping("/floorTree")
public AjaxResult floorTree(@RequestParam(value = "systemType", required = false) String systemType) {
return AjaxResult.success(houseInfoService.buildFloorTree(systemType));
}
}

30
mh-admin/src/main/resources/application-dev.yml

@ -1,7 +1,7 @@
# 项目相关配置
mh:
# 名称
name: mz
name: MH
# 版本
version: 1.0.0
# 版权年份
@ -98,8 +98,8 @@ spring:
# 主库数据源
master:
#添加allowMultiQueries=true 在批量更新时才不会出错
# url: jdbc:postgresql://127.0.0.1:5432/eemcs_hw_dev
url: jdbc:postgresql://127.0.0.1:5432/eemcs
url: jdbc:postgresql://127.0.0.1:5432/eemcs_hw_dev
# url: jdbc:postgresql://127.0.0.1:5432/eemcs
username: postgres
password: mh@803
# 从库数据源
@ -191,10 +191,10 @@ mqttSpring:
# BASIC parameters are required.
BASIC:
protocol: MQTT
host: 127.0.0.1
port: 2883
username: mh
password: mhtech@803
host: 192.168.1.79
port: 1883
username: test123456
password: test123456
# protocol: MQTT
# host: mqtt.mhito.net
# port: 1883
@ -209,10 +209,24 @@ mqttSpring:
# 无人机远程控制模式(drone remote control)
DRC:
protocol: WS
host: 127.0.0.1
host: 192.168.1.79
port: 8083
path: /mqtt
control:
topic: mh_control/events_upload/devices/dev
amap:
key: fc4e79719daca2d0b8a11ba3124e1bd5
wechat:
mpAppId: wx5653d0f930e98414
mpAppSecret: 3473cbd80e891e4e7da1b1b71ae3a5a2
redirectUri: https://35gm72cu2458.vicp.fun/wechat/userInfo
# 生成微信授权
authorizedUrl: https://open.weixin.qq.com/connect/oauth2/authorize?appid=mpAppId&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
# 获取code后,请求以下链接获取access_token
access_token: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET
# 拉取用户信息(需scope为 snsapi_userinfo)
userinfo: https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
# 消息推送url
pushUrl: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
baseUrl: https://35gm72cu2458.vicp.fun

30
mh-admin/src/main/resources/application-prod.yml

@ -1,7 +1,7 @@
# 项目相关配置
mh:
# 名称
name: mz
name: hw
# 版本
version: 1.0.0
# 版权年份
@ -16,7 +16,7 @@ mh:
# 开发环境配置
server:
# 服务器的HTTP端口,默认为8080
port: 8091
port: 8090
servlet:
# 应用的访问路径
context-path: /
@ -63,7 +63,7 @@ spring:
# 端口,默认为6379
port: 6379
# 数据库索引
database: 14
database: 0
# 密码
password:
# 连接超时时间
@ -82,9 +82,9 @@ spring:
rabbitmq:
host: 127.0.0.1
port: 5672
username: eemcs_mz
username: eemcs
password: mh@803
virtual-host: /eemcs_mz
virtual-host: /eemcs
listener:
direct:
prefetch: 2
@ -98,8 +98,8 @@ spring:
# 主库数据源
master:
#添加allowMultiQueries=true 在批量更新时才不会出错
url: jdbc:postgresql://127.0.0.1:5505/eemcs
# url: jdbc:postgresql://127.0.0.1:5505/eemcs
url: jdbc:postgresql://127.0.0.1:5505/eemcs_hw
# url: jdbc:postgresql://127.0.0.1:5505/eemcs
username: postgres
password: mhtech@803
# 从库数据源
@ -195,7 +195,7 @@ mqttSpring:
port: 1883
username: sa
password: sa123
client-id: eemcs_mz_mqtt_pro
client-id: eemcs_hw_mqtt_pro
# If the protocol is ws/wss, this value is required.
path:
# Topics that need to be subscribed when initially connecting to mqtt, multiple topics are divided by ",".
@ -211,3 +211,17 @@ control:
topic: mh_control/events_upload/devices
amap:
key: fc4e79719daca2d0b8a11ba3124e1bd5
wechat:
mpAppId: wx5653d0f930e98414
mpAppSecret: 3473cbd80e891e4e7da1b1b71ae3a5a2
redirectUri: http://jnd2.mhwsh.net:8766/wechat/userInfo
# 生成微信授权
authorizedUrl: https://open.weixin.qq.com/connect/oauth2/authorize?appid=mpAppId&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
# 获取code后,请求以下链接获取access_token
access_token: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET
# 拉取用户信息(需scope为 snsapi_userinfo)
userinfo: https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
# 消息推送url
pushUrl: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
baseUrl: http://jnd2.mhwsh.net:8766

14
mh-admin/src/main/resources/application-test.yml

@ -210,3 +210,17 @@ control:
topic: mh_control/events_upload/devices/test
amap:
key: fc4e79719daca2d0b8a11ba3124e1bd5
wechat:
mpAppId: wx5653d0f930e98414
mpAppSecret: 3473cbd80e891e4e7da1b1b71ae3a5a2
redirectUri: https://35gm72cu2458.vicp.fun/wechat/userInfo
# 生成微信授权
authorizedUrl: https://open.weixin.qq.com/connect/oauth2/authorize?appid=mpAppId&redirect_uri=REDIRECT_URI&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect
# 获取code后,请求以下链接获取access_token
access_token: https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=SECRET
# 拉取用户信息(需scope为 snsapi_userinfo)
userinfo: https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
# 消息推送url
pushUrl: https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=ACCESS_TOKEN
baseUrl: https://35gm72cu2458.vicp.fun

2
mh-admin/src/main/resources/application.yml

@ -1,6 +1,6 @@
spring:
profiles:
active: dev
active: prod
# 用户配置
user:

2
mh-admin/src/main/resources/logback.xml

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!-- 日志存放路径 -->
<property name="log.path" value="/home/mh/mz/logs" />
<property name="log.path" value="/home/mh/hw/logs" />
<!-- 日志输出格式 -->
<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />

65
mh-admin/src/test/java/com/mh/MHApplicationTest.java

@ -9,7 +9,9 @@ import com.mh.common.core.domain.entity.WeatherData;
import com.mh.common.utils.DateUtils;
import com.mh.common.utils.StringUtils;
import com.mh.quartz.task.DealDataTask;
import com.mh.quartz.task.GGDataTask;
import com.mh.quartz.task.GetWeatherDataTask;
import com.mh.quartz.task.HotWaterTask;
import com.mh.system.mapper.device.DataProcessMapper;
import com.mh.system.service.ISysParamsService;
import com.mh.system.service.ISysUserService;
@ -21,6 +23,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.web.client.RestTemplate;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
@ -40,6 +43,53 @@ public class MHApplicationTest {
@Autowired
private ISysUserService sysUserService;
@Autowired
private HotWaterTask hotWaterTask;
@Test
public void hotWaterTask() {
hotWaterTask.calcEnergyData("2026-04-10 11:00:00");
}
@Test
public void hotWaterTaskWithTimeRange() {
// 定义起始时间和结束时间
String startTimeStr = "2026-05-12 00:00:00";
String endTimeStr = "2026-05-12 23:00:00";
try {
java.time.LocalDateTime startTime = java.time.LocalDateTime.parse(startTimeStr,
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
java.time.LocalDateTime endTime = java.time.LocalDateTime.parse(endTimeStr,
java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
java.time.LocalDateTime currentTime = startTime;
int count = 0;
while (!currentTime.isAfter(endTime)) {
String timeStr = currentTime.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println("正在处理时间: " + timeStr);
try {
hotWaterTask.calcFloorEnergyData(timeStr);
count++;
} catch (Exception e) {
System.err.println("处理时间 " + timeStr + " 时发生错误: " + e.getMessage());
e.printStackTrace();
}
// 增加一小时
currentTime = currentTime.plusHours(1);
}
System.out.println("完成!共处理了 " + count + " 个时间点的数据");
} catch (Exception e) {
System.err.println("时间范围处理过程中发生错误: " + e.getMessage());
e.printStackTrace();
}
}
@Test
public void test() throws Exception {
SysUser sysUser = sysUserService.selectUserById(1L);
@ -50,6 +100,14 @@ public class MHApplicationTest {
@Autowired
private DealDataTask dealDeviceData;
@Autowired
private GGDataTask gGDataTask;
@Test
public void gGDataTask() {
gGDataTask.calcWeatherData();
}
@Test
public void dealDeviceData() {
dealDeviceData.dealDeviceData();
@ -71,6 +129,13 @@ public class MHApplicationTest {
@Autowired
private ISysParamsService sysParamsService;
@Test
public void test1() {
BigDecimal bigDecimal = new BigDecimal(165);
bigDecimal = bigDecimal.multiply(new BigDecimal(550)).divide(new BigDecimal(1650)).subtract(new BigDecimal(40));
System.out.println(bigDecimal);
}
@Test
public void getWeatherInfo() {
getWeatherDataTask.getWeatherInfo();

7
mh-common/pom.xml

@ -160,6 +160,13 @@
<artifactId>lombok</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.binarywang/weixin-java-mp -->
<dependency>
<groupId>com.github.binarywang</groupId>
<artifactId>weixin-java-mp</artifactId>
<version>4.7.6.B</version>
</dependency>
</dependencies>
</project>

28
mh-common/src/main/java/com/mh/common/config/wechat/RestTemplateConfig.java

@ -0,0 +1,28 @@
package com.mh.common.config.wechat;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description restTemplate配置
* @date 2025-06-30 14:35:10
*/
@Configuration
public class RestTemplateConfig {
// 配置类中定义Bean(全局禁用分块传输)
@Bean
public RestTemplate restTemplate() {
return new RestTemplateBuilder()
.requestFactory(() -> new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory()))
.build();
}
}

94
mh-common/src/main/java/com/mh/common/config/wechat/WechatMpConfig.java

@ -0,0 +1,94 @@
package com.mh.common.config.wechat;
import me.chanjar.weixin.mp.api.WxMpService;
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
import me.chanjar.weixin.mp.config.WxMpConfigStorage;
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import java.net.URLEncoder;
/**
* @author chison
* @date 2020-04-03 15:42
* @Description 微信网页授权信息配置类
*/
@Component
@Configuration
public class WechatMpConfig {
@Value("${wechat.mpAppId}")
private String mpAppId;
@Value("${wechat.mpAppSecret}")
private String mpAppSecret;
@Value("${wechat.redirectUri}")
private String redirectUri;
@Value("${wechat.authorizedUrl}")
private String authorizedUrl;
@Value("${wechat.access_token}")
private String accessToken;
@Value("${wechat.userinfo}")
private String userinfo;
@Value("${wechat.pushUrl}")
private String pushUrl;
@Value("${wechat.baseUrl}")
private String baseUrl;
public String getBaseUrl() {
return baseUrl;
}
public void setBaseUrl(String baseUrl) {
this.baseUrl = baseUrl;
}
public String getAuthorizedUrl() {
return authorizedUrl.replace("mpAppId", mpAppId).replace("REDIRECT_URI", URLEncoder.encode(redirectUri));
}
public String getAccessTokenUrl() {
return accessToken.replace("APPID", mpAppId).replace("SECRET", mpAppSecret);
}
public String getUserInfo(String accessToken, String openId) {
return userinfo.replace("ACCESS_TOKEN", accessToken).replace("OPENID", openId);
}
public String getPushMsgUrl(String accessToken) {
return pushUrl.replace("ACCESS_TOKEN", accessToken);
}
public String getMpAppId() {
return mpAppId;
}
public String getMpAppSecret() {
return mpAppSecret;
}
/**
* 配置WxMpService所需信息
*
* @return
*/
@Bean // 此注解指定在Spring容器启动时,就执行该方法并将该方法返回的对象交由Spring容器管理
public WxMpService wxMpService() {
WxMpService wxMpService = new WxMpServiceImpl();
// 设置配置信息的存储位置
wxMpService.setWxMpConfigStorage(wxMpConfigStorage());
return wxMpService;
}
public WxMpConfigStorage wxMpConfigStorage() {
// 使用这个实现类则表示将配置信息存储在内存中
WxMpDefaultConfigImpl wxMpInMemoryConfigStorage = new WxMpDefaultConfigImpl();
wxMpInMemoryConfigStorage.setAppId(getMpAppId());
wxMpInMemoryConfigStorage.setSecret(getMpAppSecret());
return wxMpInMemoryConfigStorage;
}
}

62
mh-common/src/main/java/com/mh/common/config/wechat/WechatSignUtil.java

@ -0,0 +1,62 @@
package com.mh.common.config.wechat;
import lombok.extern.slf4j.Slf4j;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
/**
* @Author : Rainbow
* @date : 2024-09-14
*/
@Slf4j
public class WechatSignUtil {
/**
* SHA-1加密
* @param params
* @return
*/
public static String generateSignature(Map<String, String> params) {
// 使用TreeMap进行自然排序(按照key的ASCII码排序)
TreeMap<String, String> sortedParams = new TreeMap<>(params);
// 拼接字符串
StringBuilder stringBuilder = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
if (stringBuilder.length() > 0) {
stringBuilder.append("&");
}
stringBuilder.append(entry.getKey()).append("=").append(entry.getValue());
}
String string1 = stringBuilder.toString();
// SHA-1加密
try {
// 获取SHA-1实例
MessageDigest digest = MessageDigest.getInstance("SHA-1");
// 将输入字符串转换为字节数组
byte[] encodedHash = digest.digest(string1.getBytes());
// 可选:将字节数组转换为Base64字符串,便于显示和传输
String base64Encoded = Base64.getEncoder().encodeToString(encodedHash);
// log.info("SHA-1 (Base64 Encoded): {}", base64Encoded);
// 或者,直接以16进制形式输出
StringBuilder hexString = new StringBuilder();
for (byte b : encodedHash) {
String hex = Integer.toHexString(0xff & b);
if(hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
// log.info("SHA-1 (Hexadecimal): {}", hexString);
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("SHA-1 algorithm not found", e);
}
}
}

25
mh-common/src/main/java/com/mh/common/constant/EnergyType.java

@ -0,0 +1,25 @@
package com.mh.common.constant;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description
* @date 2025-06-18 16:32:56
*/
public enum EnergyType {
HOUR("hour"),
DAY("day"),
MONTH("month"),
YEAR("year");
private final String code;
EnergyType(String code) {
this.code = code;
}
public String getCode() {
return code;
}
}

338
mh-common/src/main/java/com/mh/common/core/domain/dto/BFloorReportHotWaterDTO.java

@ -0,0 +1,338 @@
package com.mh.common.core.domain.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.BorderStyleEnum;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
//import java.math.String;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 三楼热水系统参数报表
* @date 2024-05-30 11:00:12
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
@HeadRowHeight(25)
@HeadFontStyle(fontHeightInPoints = 14)
@ContentFontStyle(fontHeightInPoints = 13)
@ContentRowHeight(25)
@ContentStyle(
horizontalAlignment = HorizontalAlignmentEnum.CENTER,
borderBottom = BorderStyleEnum.THIN,
borderLeft = BorderStyleEnum.THIN,
borderRight = BorderStyleEnum.THIN,
borderTop = BorderStyleEnum.THIN
)
@ColumnWidth(10)
public class BFloorReportHotWaterDTO {
/**
* 当前时间
*/
@ColumnWidth(17)
@ExcelProperty(value = {"${deviceType}", "时间", "时间"}, index = 0)
private String curTime;
// /**
// * 班次
// */
// @ColumnWidth(10)
// @ExcelProperty(value = {"${deviceType}", "班次", "班次"}, index = 1)
// private String classes;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "1号热泵", "设定温度℃"}, index = 1)
private BigDecimal tempSetHotPumpOne;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "1号热泵", "实际温度℃"}, index = 2)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpOne;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "1号热泵", "设备开关机"}, index = 3)
@ColumnWidth(10)
private String statusSwitchHotPumpOneStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "1号热泵", "设备运行状态"}, index = 4)
@ColumnWidth(10)
private String statusRunHotPumpOneStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "2号热泵", "设定温度℃"}, index = 5)
private BigDecimal tempSetHotPumpTwo;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "2号热泵", "实际温度℃"}, index = 6)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpTwo;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "2号热泵", "设备开关机"}, index = 7)
@ColumnWidth(10)
private String statusSwitchHotPumpTwoStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "2号热泵", "设备运行状态"}, index = 8)
@ColumnWidth(10)
private String statusRunHotPumpTwoStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "3号热泵", "设定温度℃"}, index = 9)
private BigDecimal tempSetHotPumpThree;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "3号热泵", "实际温度℃"}, index = 10)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpThree;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "3号热泵", "设备开关机"}, index = 11)
@ColumnWidth(10)
private String statusSwitchHotPumpThreeStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "3号热泵", "设备运行状态"}, index = 12)
@ColumnWidth(10)
private String statusRunHotPumpThreeStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "4号热泵", "设定温度℃"}, index = 13)
private BigDecimal tempSetHotPumpFour;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "4号热泵", "实际温度℃"}, index = 14)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpFour;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "4号热泵", "设备开关机"}, index = 15)
@ColumnWidth(10)
private String statusSwitchHotPumpFourStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "4号热泵", "设备运行状态"}, index = 16)
@ColumnWidth(10)
private String statusRunHotPumpFourStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "5号热泵", "设定温度℃"}, index = 17)
private BigDecimal tempSetHotPumpFive;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "5号热泵", "实际温度℃"}, index = 18)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpFive;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "5号热泵", "设备开关机"}, index = 19)
@ColumnWidth(10)
private String statusSwitchHotPumpFiveStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "5号热泵", "设备运行状态"}, index = 20)
@ColumnWidth(10)
private String statusRunHotPumpFiveStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "6号热泵", "设定温度℃"}, index = 21)
private BigDecimal tempSetHotPumpSix;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "6号热泵", "实际温度℃"}, index = 22)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpSix;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "6号热泵", "设备开关机"}, index = 23)
@ColumnWidth(10)
private String statusSwitchHotPumpSixStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "6号热泵", "设备运行状态"}, index = 24)
@ColumnWidth(10)
private String statusRunHotPumpSixStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "7号热泵", "设定温度℃"}, index = 25)
private BigDecimal tempSetHotPumpSeven;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "7号热泵", "实际温度℃"}, index = 26)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpSeven;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "7号热泵", "设备开关机"}, index = 27)
@ColumnWidth(10)
private String statusSwitchHotPumpSevenStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "7号热泵", "设备运行状态"}, index = 28)
@ColumnWidth(10)
private String statusRunHotPumpSevenStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "8号热泵", "设定温度℃"}, index = 29)
private BigDecimal tempSetHotPumpEight;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "8号热泵", "实际温度℃"}, index = 30)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpEight;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "8号热泵", "设备开关机"}, index = 31)
@ColumnWidth(10)
private String statusSwitchHotPumpEightStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "8号热泵", "设备运行状态"}, index = 32)
@ColumnWidth(10)
private String statusRunHotPumpEightStr;
// // 高区/裙楼设定压力(bar)
// @ExcelProperty(value = {"${deviceType}", "裙楼变频泵", "设定压力bar"}, index = 9)
// @ColumnWidth(10)
// private BigDecimal presSetSupplyPumpAreaOne;
//
// // 高区/裙楼实际压力(bar)
// @ExcelProperty(value = {"${deviceType}", "裙楼变频泵", "实际压力bar"}, index = 10)
// @ColumnWidth(10)
// private BigDecimal presRealSupplyPumpAreaOne;
//
// // 高区/裙楼1号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "裙楼变频泵", "1号泵运行状态"}, index = 11)
// @ColumnWidth(10)
// private String statusRunSupplyPumpOneStr;
//
// // 高区/裙楼2号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "裙楼变频泵", "2号泵运行状态"}, index = 12)
// @ColumnWidth(10)
// private String statusRunSupplyPumpTwoStr;
//
// // 中区/中厨设定压力(bar)
// @ExcelProperty(value = {"${deviceType}", "中厨变频泵", "设定压力bar"}, index = 13)
// @ColumnWidth(10)
// private BigDecimal presSetSupplyPumpAreaTwo;
//
// // 中区/中厨实际压力(bar)
// @ExcelProperty(value = {"${deviceType}", "中厨变频泵", "实际压力bar"}, index = 14)
// @ColumnWidth(10)
// private BigDecimal presRealSupplyPumpAreaTwo;
//
// // 中区/中厨1号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "中厨变频泵", "1号泵运行状态"}, index = 15)
// @ColumnWidth(10)
// private String statusRunSupplyPumpThreeStr;
//
// // 中区/中厨2号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "中厨变频泵", "2号泵运行状态"}, index = 16)
// @ColumnWidth(10)
// private String statusRunSupplyPumpFourStr;
// 贵宾楼液位1(米)
@ExcelProperty(value = {"${deviceType}", "水箱液位", "水箱1液位(米)"}, index = 33)
@ColumnWidth(10)
private BigDecimal levelWaterTankOne;
// 主楼液位2(米)
// @ExcelProperty(value = {"${deviceType}", "水箱液位", "水箱2液位(米)"}, index = 34)
// @ColumnWidth(10)
// private BigDecimal levelWaterTankTwo;
// 巡查记录人
@ExcelProperty(value = {"${deviceType}", "巡查记录人", "巡查记录人"}, index = 34)
@ColumnWidth(20)
private String recorder;
// 备注信息
@ExcelProperty(value = {"${deviceType}", "备注", "备注"}, index = 35)
@ColumnWidth(20)
private String remark;
}

68
mh-common/src/main/java/com/mh/common/core/domain/dto/DataResultDTO.java

@ -0,0 +1,68 @@
package com.mh.common.core.domain.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.math.BigDecimal;
import java.util.Date;
@Data
public class DataResultDTO {
private Long id;
private String buildingId;
private String buildingName;
private String deviceNum;
private String deviceName;
private String deviceCode;
private String deviceType;
private BigDecimal lastValue;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date lastTime;
private double curValue;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date curTime;
private BigDecimal usedValue;
private int ratio;
private BigDecimal calcValue;
private int grade;
private String registerAddr;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("buildingId", buildingId)
.append("buildingName", buildingName)
.append("deviceNum", deviceNum)
.append("deviceName", deviceName)
.append("deviceCode", deviceCode)
.append("deviceType", deviceType)
.append("lastValue", lastValue)
.append("lastTime", lastTime)
.append("curValue", curValue)
.append("curTime", curTime)
.append("usedValue", usedValue)
.append("ratio", ratio)
.append("calcValue", calcValue)
.append("grade", grade)
.append("registerAddr", registerAddr)
.toString();
}
}

19
mh-common/src/main/java/com/mh/common/core/domain/dto/HotWaterNowDataDTO.java

@ -20,12 +20,19 @@ public class HotWaterNowDataDTO {
private String pumpName; //热泵名称
private String tempSet; //水温设定
private String waterTemp; //水箱水温
private String runState; //运行状态
private String runState; //运行状态:0:关机,4:运行,9:待机
private String openCloseState;// 开关机状态 0:关机,4:制热
private String isFault; //是否故障
private String levelSet; //水位设置
private String waterLevel; //实际水位
private String levelSet; //水位1设置
private String levelSet2; //水位2设置
private String waterLevel1; //实际1水位
private String waterLevel2; //实际2水位
private String tankId; //水箱编号
private String tankName; //水箱名称
private String tankWaterTemp; // 水箱1温度
private String tankWaterTemp2; // 水箱2温度
private String tankId2; //水箱2编号
private String tankName2; //水箱2名称
private String envTemp; //环境温度
private String upWaterState1; // 供水1泵状态
@ -40,6 +47,12 @@ public class HotWaterNowDataDTO {
private String backWaterState; // 回水状态
private String loopPumpState1; // 1循环泵状态:0:关机 1:运行 2:故障
private String loopPumpState2; // 2循环泵状态:0:关机 1:运行 2:故障
private String gatewayStatus; // 网关状态 0:离线,1:在线
private int orderNum;
}

77
mh-common/src/main/java/com/mh/common/core/domain/dto/HotWaterRevenueSumDTO.java

@ -0,0 +1,77 @@
package com.mh.common.core.domain.dto;
import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
import java.util.StringJoiner;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水收益总的收益情况
* @date 2026-05-13 09:33:27
*/
@Setter
@Getter
public class HotWaterRevenueSumDTO {
/**
* 时间
*/
private String curDate;
/**
* 建筑id
*/
private String buildingId;
// 电表用量
private BigDecimal totalUseEleAmount;
// 电量单价
private BigDecimal electPrice;
// 用电金额
private BigDecimal totalUseEle;
// 水表用量
private BigDecimal totalUseWaterAmount;
// 水价
private BigDecimal waterPrice;
// 用水金额
private BigDecimal totalUseWater;
// 平均电表用量
private BigDecimal avgUseEle;
// 平均水表用量
private BigDecimal avgUseWater;
// 单耗
private BigDecimal unitConsumption;
// 收益总额
private BigDecimal totalIncome;
@Override
public String toString() {
return new StringJoiner(", ", HotWaterRevenueSumDTO.class.getSimpleName() + "[", "]")
.add("curDate='" + curDate + "'")
.add("buildingId='" + buildingId + "'")
.add("totalUseEleAmount=" + totalUseEleAmount)
.add("electPrice=" + electPrice)
.add("totalUseEle=" + totalUseEle)
.add("totalUseWaterAmount=" + totalUseWaterAmount)
.add("waterPrice=" + waterPrice)
.add("totalUseWater=" + totalUseWater)
.add("avgUseEle=" + avgUseEle)
.add("avgUseWater=" + avgUseWater)
.add("unitConsumption=" + unitConsumption)
.add("totalIncome=" + totalIncome)
.toString();
}
}

220
mh-common/src/main/java/com/mh/common/core/domain/dto/ThreeFloorReportHotWaterDTO.java

@ -0,0 +1,220 @@
package com.mh.common.core.domain.dto;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.*;
import com.alibaba.excel.enums.poi.BorderStyleEnum;
import com.alibaba.excel.enums.poi.HorizontalAlignmentEnum;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
//import java.math.String;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 三楼热水系统参数报表
* @date 2024-05-30 11:00:12
*/
@Data
@NoArgsConstructor
@Accessors(chain = true)
@HeadRowHeight(25)
@HeadFontStyle(fontHeightInPoints = 14)
@ContentFontStyle(fontHeightInPoints = 13)
@ContentRowHeight(25)
@ContentStyle(
horizontalAlignment = HorizontalAlignmentEnum.CENTER,
borderBottom = BorderStyleEnum.THIN,
borderLeft = BorderStyleEnum.THIN,
borderRight = BorderStyleEnum.THIN,
borderTop = BorderStyleEnum.THIN
)
@ColumnWidth(10)
public class ThreeFloorReportHotWaterDTO {
/**
* 当前时间
*/
@ColumnWidth(17)
@ExcelProperty(value = {"${deviceType}", "时间", "时间"}, index = 0)
private String curTime;
// /**
// * 班次
// */
// @ColumnWidth(10)
// @ExcelProperty(value = {"${deviceType}", "班次", "班次"}, index = 1)
// private String classes;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "1号热泵", "设定温度℃"}, index = 1)
private BigDecimal tempSetHotPumpOne;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "1号热泵", "实际温度℃"}, index = 2)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpOne;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "1号热泵", "设备开关机"}, index = 3)
@ColumnWidth(10)
private String statusSwitchHotPumpOneStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "1号热泵", "设备运行状态"}, index = 4)
@ColumnWidth(10)
private String statusRunHotPumpOneStr;
/**
* 设定温度
*/
@ColumnWidth(10)
@ExcelProperty(value = {"${deviceType}", "2号热泵", "设定温度℃"}, index = 5)
private BigDecimal tempSetHotPumpTwo;
/**
* 实际温度
*/
@ExcelProperty(value = {"${deviceType}", "2号热泵", "实际温度℃"}, index = 6)
@ColumnWidth(10)
private BigDecimal tempRealHotPumpTwo;
/**
* 设备开关机
*/
@ExcelProperty(value = {"${deviceType}", "2号热泵", "设备开关机"}, index = 7)
@ColumnWidth(10)
private String statusSwitchHotPumpTwoStr;
/**
* 设备运行状态
*/
@ExcelProperty(value = {"${deviceType}", "2号热泵", "设备运行状态"}, index = 8)
@ColumnWidth(10)
private String statusRunHotPumpTwoStr;
// // 3号热泵设定温度(℃)
// @ColumnWidth(10)
// @ExcelProperty(value = {"${deviceType}", "3号热泵", "设定温度℃"}, index = 9)
// private BigDecimal tempSetHotPumpThree;
//
// // 3号热泵实际温度(℃)
// @ExcelProperty(value = {"${deviceType}", "3号热泵", "实际温度℃"}, index = 10)
// @ColumnWidth(10)
// private BigDecimal tempRealHotPumpThree;
//
// // 3号热泵启停状态
// @ExcelProperty(value = {"${deviceType}", "3号热泵", "设备开关机"}, index = 11)
// @ColumnWidth(10)
// private String statusSwitchHotPumpThreeStr;
//
// // 3号热泵运行状态
// @ExcelProperty(value = {"${deviceType}", "3号热泵", "设备运行状态"}, index = 12)
// @ColumnWidth(10)
// private String statusRunHotPumpThreeStr;
//
// // 4号热泵设定温度(℃)
// @ColumnWidth(10)
// @ExcelProperty(value = {"${deviceType}", "4号热泵", "设定温度℃"}, index = 13)
// private BigDecimal tempSetHotPumpFour;
//
// // 4号热泵实际温度(℃)
// @ExcelProperty(value = {"${deviceType}", "4号热泵", "实际温度℃"}, index = 14)
// @ColumnWidth(10)
// private BigDecimal tempRealHotPumpFour;
//
// // 4号热泵启停状态
// @ExcelProperty(value = {"${deviceType}", "4号热泵", "设备开关机"}, index = 15)
// @ColumnWidth(10)
// private String statusSwitchHotPumpFourStr;
//
// // 4号热泵运行状态
// @ExcelProperty(value = {"${deviceType}", "4号热泵", "设备运行状态"}, index = 16)
// @ColumnWidth(10)
// private String statusRunHotPumpFourStr;
//
// // 高区/高区设定压力(bar)
// @ExcelProperty(value = {"${deviceType}", "高区变频泵", "设定压力bar"}, index = 17)
// @ColumnWidth(10)
// private BigDecimal presSetSupplyPumpAreaOne;
//
// // 高区/高区实际压力(bar)
// @ExcelProperty(value = {"${deviceType}", "高区变频泵", "实际压力bar"}, index = 18)
// @ColumnWidth(10)
// private BigDecimal presRealSupplyPumpAreaOne;
//
// // 高区/高区1号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "高区变频泵", "1号泵运行状态"}, index = 19)
// @ColumnWidth(10)
// private String statusRunSupplyPumpOneStr;
//
// // 高区/高区2号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "高区变频泵", "2号泵运行状态"}, index = 20)
// @ColumnWidth(10)
// private String statusRunSupplyPumpTwoStr;
//
// // 中区/中区设定压力(bar)
// @ExcelProperty(value = {"${deviceType}", "中区变频泵", "设定压力bar"}, index = 21)
// @ColumnWidth(10)
// private BigDecimal presSetSupplyPumpAreaTwo;
//
// // 中区/中区实际压力(bar)
// @ExcelProperty(value = {"${deviceType}", "中区变频泵", "实际压力bar"}, index = 22)
// @ColumnWidth(10)
// private BigDecimal presRealSupplyPumpAreaTwo;
//
// // 中区/中区1号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "中区变频泵", "1号泵运行状态"}, index = 23)
// @ColumnWidth(10)
// private String statusRunSupplyPumpThreeStr;
//
// // 中区/中区2号泵运行状态
// @ExcelProperty(value = {"${deviceType}", "中区变频泵", "2号泵运行状态"}, index = 24)
// @ColumnWidth(10)
// private String statusRunSupplyPumpFourStr;
// 主楼与贵宾楼1号循环泵运行状态
@ExcelProperty(value = {"${deviceType}", "主楼与贵宾楼循环泵", "1号循环泵运行状态"}, index = 9)
@ColumnWidth(10)
private String statusRunCyclePumpOneStr;
// 主楼与贵宾楼2号循环泵运行状态
@ExcelProperty(value = {"${deviceType}", "主楼与贵宾楼循环泵", "2号循环泵运行状态"}, index = 10)
@ColumnWidth(10)
private String statusRunCyclePumpTwoStr;
// 主楼水箱1
@ExcelProperty(value = {"${deviceType}", "水箱液位", "水箱1液位(米)"}, index = 11)
@ColumnWidth(10)
private BigDecimal levelWaterTankOne;
// 主楼水箱2
@ExcelProperty(value = {"${deviceType}", "水箱液位", "水箱2液位(米)"}, index = 12)
@ColumnWidth(10)
private BigDecimal levelWaterTankTwo;
// 巡查记录人
@ExcelProperty(value = {"${deviceType}", "巡查记录人", "巡查记录人"}, index = 13)
@ColumnWidth(20)
private String recorder;
// 备注信息
@ExcelProperty(value = {"${deviceType}", "备注", "备注"}, index = 14)
@ColumnWidth(20)
private String remark;
}

63
mh-common/src/main/java/com/mh/common/core/domain/dto/WeatherDataDTO.java

@ -0,0 +1,63 @@
package com.mh.common.core.domain.dto;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 天气温度历史记录查询
* @date 2025-06-16 11:21:48
*/
@Data
public class WeatherDataDTO {
/**
* 时间
*/
private String weatherDate;
/**
* 日期和星期
*/
private String dateAndWeek;
/**
* 最高温度
*/
private String maxTemp;
/**
* 最低温度
*/
private String minTemp;
/**
* 天气
*/
private String weatherConditions;
/**
* 风向
*/
private String windDirection;
/**
* 风速
*/
private String windPower;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("weatherDate", weatherDate)
.append("dateAndWeek", dateAndWeek)
.append("maxTemp", maxTemp)
.append("minTemp", minTemp)
.append("weatherConditions", weatherConditions)
.append("windDirection", windDirection)
.append("windPower", windPower)
.toString();
}
}

13
mh-common/src/main/java/com/mh/common/core/domain/entity/AlarmRecords.java

@ -83,6 +83,19 @@ public class AlarmRecords implements Serializable {
*/
private int status;
/**
* 是否发送通知 0未发送 1已发送
*/
private Integer isSend;
public Integer getIsSend() {
return isSend;
}
public void setIsSend(Integer isSend) {
this.isSend = isSend;
}
public int getStatus() {
return status;
}

46
mh-common/src/main/java/com/mh/common/core/domain/entity/AnalysisMonth.java

@ -0,0 +1,46 @@
package com.mh.common.core.domain.entity;
import lombok.Data;
@Data
public class AnalysisMonth {
private Long id;
private String curDate;
private String itemType;
private String day01;
private String day02;
private String day03;
private String day04;
private String day05;
private String day06;
private String day07;
private String day08;
private String day09;
private String day10;
private String day11;
private String day12;
private String day13;
private String day14;
private String day15;
private String day16;
private String day17;
private String day18;
private String day19;
private String day20;
private String day21;
private String day22;
private String day23;
private String day24;
private String day25;
private String day26;
private String day27;
private String day28;
private String day29;
private String day30;
private String day31;
private String day32;
private String totalValue;
private String buildingId;
private String buildingName;
}

27
mh-common/src/main/java/com/mh/common/core/domain/entity/AnalysisYear.java

@ -0,0 +1,27 @@
package com.mh.common.core.domain.entity;
import lombok.Data;
@Data
public class AnalysisYear {
private Long id;
private String curDate;
private String itemType;
private String month01;
private String month02;
private String month03;
private String month04;
private String month05;
private String month06;
private String month07;
private String month08;
private String month09;
private String month10;
private String month11;
private String month12;
private String totalValue;
private String buildingId;
private String buildingName;
}

81
mh-common/src/main/java/com/mh/common/core/domain/entity/CollectionParamsManage.java

@ -14,6 +14,7 @@ import org.apache.commons.lang3.builder.ToStringBuilder;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;
import java.util.StringJoiner;
/**
* @author LJF
@ -144,6 +145,11 @@ public class CollectionParamsManage extends BaseEntity {
*/
private String communicationType;
/**
* 通信质量
*/
private String quality;
/**
* 读取响应的寄存器大小创建指令的时候需要
*/
@ -192,42 +198,49 @@ public class CollectionParamsManage extends BaseEntity {
*/
private String terminalDeviceType;
/**
* 价格
*/
private BigDecimal price;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("deviceLedgerId", deviceLedgerId)
.append("mtType", mtType)
.append("mtNum", mtNum)
.append("mtCode", mtCode)
.append("registerAddr", registerAddr)
.append("funcCode", funcCode)
.append("identifyCode", identifyCode)
.append("mtCaliberPulse", mtCaliberPulse)
.append("mtRange", mtRange)
.append("mtRatio", mtRatio)
.append("mtInitValue", mtInitValue)
.append("digits", digits)
.append("dataType", dataType)
.append("curValue", curValue)
.append("curTime", curTime)
.append("mtIsSum", mtIsSum)
.append("unit", unit)
.append("orderNum", orderNum)
.append("gatewayId", gatewayId)
.append("communicationParamId", communicationParamId)
.append("protocolType", protocolType)
.append("communicationType", communicationType)
.append("registerSize", registerSize)
.append("isUse", isUse)
.append("otherName", otherName)
.append("grade", grade)
.append("searchValue", searchValue)
.append("params", params)
.append("paramType", paramType)
.append("systemType", systemType)
.append("collectionType", collectionType)
.append("terminalDeviceType", terminalDeviceType)
return new StringJoiner(", ", CollectionParamsManage.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("deviceLedgerId='" + deviceLedgerId + "'")
.add("mtType='" + mtType + "'")
.add("mtNum='" + mtNum + "'")
.add("mtCode='" + mtCode + "'")
.add("registerAddr='" + registerAddr + "'")
.add("funcCode='" + funcCode + "'")
.add("identifyCode='" + identifyCode + "'")
.add("mtCaliberPulse='" + mtCaliberPulse + "'")
.add("mtRange=" + mtRange)
.add("mtRatio=" + mtRatio)
.add("mtInitValue=" + mtInitValue)
.add("digits=" + digits)
.add("dataType=" + dataType)
.add("curValue=" + curValue)
.add("curTime=" + curTime)
.add("mtIsSum=" + mtIsSum)
.add("unit='" + unit + "'")
.add("orderNum=" + orderNum)
.add("gatewayId='" + gatewayId + "'")
.add("communicationParamId='" + communicationParamId + "'")
.add("protocolType='" + protocolType + "'")
.add("communicationType='" + communicationType + "'")
.add("quality='" + quality + "'")
.add("registerSize=" + registerSize)
.add("isUse=" + isUse)
.add("otherName='" + otherName + "'")
.add("grade=" + grade)
.add("searchValue='" + searchValue + "'")
.add("params=" + params)
.add("paramType='" + paramType + "'")
.add("systemType='" + systemType + "'")
.add("collectionType='" + collectionType + "'")
.add("terminalDeviceType='" + terminalDeviceType + "'")
.add("price=" + price)
.toString();
}
}

8
mh-common/src/main/java/com/mh/common/core/domain/entity/CpmSpaceRelation.java

@ -30,6 +30,14 @@ public class CpmSpaceRelation extends BaseEntity {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
/** 删除标志(0代表存在 2代表删除) */
private String delFlag;
/**
* 台账id
*/
private String ledgerId;
/**
* 采集参数id
*/

84
mh-common/src/main/java/com/mh/common/core/domain/entity/DeviceState.java

@ -0,0 +1,84 @@
package com.mh.common.core.domain.entity;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
/**
* @author LJF
* @version 1.0
* @date 2025-02-14 09:30:47
* @description 设备统计状态表
*/
@Data
public class DeviceState {
/**
* 当前时间
*/
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date curDate;
/**
* 设备数目
*/
private int deviceNum;
/**
* 电表数目
*/
private int electNum;
/**
* 水表数目
*/
private int waterNum;
/**
* 泵数目
*/
private int pumpNum;
/**
* 压力表数目
*/
private int pressureNum;
/**
* 在线设备数目
*/
private int onlineNum;
/**
* 离线设备数目
*/
private int offlineNum;
/**
* 故障设备数目
*/
private int faultNum;
/**
* 上次故障数目
*/
private int lastFaultNum;
/**
* 故障环比
*/
private String faultP;
/**
* 热泵正在运行的数目
*/
private int pumpOnline;
/**
* 其他设备数目
*/
private int otherNum;
}

70
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyBaseSum.java

@ -0,0 +1,70 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水Sum基础类
* @date 2026-05-13 09:50:45
*/
@Data
public class EnergyBaseSum {
private String id;
/**
* 时间
*/
private String curDate;
/**
* 建筑id
*/
private String buildingId;
/**
* 补水
*/
private BigDecimal fillWater;
/**
* 补水与昨日比
*/
private String fillWaterP;
/**
* 用水
*/
private BigDecimal waterValue;
/**
* 用水与昨日比
*/
private String waterP;
/**
* 用电量
*/
private BigDecimal electValue;
/**
* 用电与昨日比
*/
private String electP;
/**
* 单耗
*/
private BigDecimal electWater;
/**
* 单耗与昨日比
*/
private String electWaterP;
}

89
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyDay.java

@ -0,0 +1,89 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@Data
@TableName("energy_day")
public class EnergyDay {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
/**
* 时间
*/
private String curDate;
/**
* 建筑id
*/
private String buildingId;
/**
* 产热量
*/
private BigDecimal hotWaterValue;
/**
* 使用用量
*/
private BigDecimal useHotWater;
/**
* 用电量
*/
private BigDecimal electValue;
/**
* 单耗
*/
private BigDecimal electWater;
/**
* 入住人数
*/
private int checkInCount;
/**
* 人均用电
*/
private BigDecimal perElect;
/**
* 人均用水
*/
private BigDecimal perWater;
/**
* 更新标志
*/
private String updateFlag;
/**
* 建筑名称
*/
private String buildingName;
/**
* 当前电表读数
*/
private BigDecimal electCurValue;
/**
* 当前水表读数
*/
private BigDecimal wtCurValue;
}

26
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyDaySum.java

@ -0,0 +1,26 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("energy_day_sum")
public class EnergyDaySum extends EnergyBaseSum {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
}

220
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyHour.java

@ -0,0 +1,220 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@TableName("energy_hour")
public class EnergyHour {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
/**
* 时间
*/
private String curDate;
/**
* 建筑id
*/
private String buildingId;
/**
* 产热量
*/
private BigDecimal hotWaterValue;
/**
* 使用用量
*/
private BigDecimal useHotWater;
/**
* 用电量
*/
private BigDecimal electValue;
/**
* 单耗
*/
private BigDecimal electWater;
/**
* 入住人数
*/
private int checkInCount;
/**
* 人均用电
*/
private BigDecimal perElect;
/**
* 人均用水
*/
private BigDecimal perWater;
/**
* 更新标志
*/
private String updateFlag;
/**
* 建筑名称
*/
private String buildingName;
/**
* 当前电表读数
*/
private BigDecimal electCurValue;
/**
* 当前水表读数
*/
private BigDecimal wtCurValue;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCurDate() {
return curDate;
}
public void setCurDate(String curDate) {
this.curDate = curDate;
}
public String getBuildingId() {
return buildingId;
}
public void setBuildingId(String buildingId) {
this.buildingId = buildingId;
}
public BigDecimal getHotWaterValue() {
return hotWaterValue;
}
public void setHotWaterValue(BigDecimal hotWaterValue) {
this.hotWaterValue = hotWaterValue;
}
public BigDecimal getUseHotWater() {
return useHotWater;
}
public void setUseHotWater(BigDecimal useHotWater) {
this.useHotWater = useHotWater;
}
public BigDecimal getElectValue() {
return electValue;
}
public void setElectValue(BigDecimal electValue) {
this.electValue = electValue;
}
public BigDecimal getElectWater() {
return electWater;
}
public void setElectWater(BigDecimal electWater) {
this.electWater = electWater;
}
public int getCheckInCount() {
return checkInCount;
}
public void setCheckInCount(int checkInCount) {
this.checkInCount = checkInCount;
}
public BigDecimal getPerElect() {
return perElect;
}
public void setPerElect(BigDecimal perElect) {
this.perElect = perElect;
}
public BigDecimal getPerWater() {
return perWater;
}
public void setPerWater(BigDecimal perWater) {
this.perWater = perWater;
}
public String getUpdateFlag() {
return updateFlag;
}
public void setUpdateFlag(String updateFlag) {
this.updateFlag = updateFlag;
}
public String getBuildingName() {
return buildingName;
}
public void setBuildingName(String buildingName) {
this.buildingName = buildingName;
}
public BigDecimal getElectCurValue() {
return electCurValue;
}
public void setElectCurValue(BigDecimal electCurValue) {
this.electCurValue = electCurValue;
}
public BigDecimal getWtCurValue() {
return wtCurValue;
}
public void setWtCurValue(BigDecimal wtCurValue) {
this.wtCurValue = wtCurValue;
}
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("curDate", curDate)
.append("buildingId", buildingId)
.append("hotWaterValue", hotWaterValue)
.append("useHotWater", useHotWater)
.append("electValue", electValue)
.append("electWater", electWater)
.append("checkInCount", checkInCount)
.append("perElect", perElect)
.append("perWater", perWater)
.append("updateFlag", updateFlag)
.append("buildingName", buildingName)
.append("electCurValue", electCurValue)
.append("wtCurValue", wtCurValue)
.toString();
}
}

89
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyMonth.java

@ -0,0 +1,89 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@Data
@TableName("energy_month")
public class EnergyMonth {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
/**
* 时间
*/
private String curDate;
/**
* 建筑id
*/
private String buildingId;
/**
* 产热量
*/
private BigDecimal hotWaterValue;
/**
* 使用用量
*/
private BigDecimal useHotWater;
/**
* 用电量
*/
private BigDecimal electValue;
/**
* 单耗
*/
private BigDecimal electWater;
/**
* 入住人数
*/
private int checkInCount;
/**
* 人均用电
*/
private BigDecimal perElect;
/**
* 人均用水
*/
private BigDecimal perWater;
/**
* 更新标志
*/
private String updateFlag;
/**
* 建筑名称
*/
private String buildingName;
/**
* 当前电表读数
*/
private BigDecimal electCurValue;
/**
* 当前水表读数
*/
private BigDecimal wtCurValue;
}

26
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyMonthSum.java

@ -0,0 +1,26 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("energy_month_sum")
public class EnergyMonthSum extends EnergyBaseSum {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
}

89
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyYear.java

@ -0,0 +1,89 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@Data
@TableName("energy_year")
public class EnergyYear {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
/**
* 时间
*/
private String curDate;
/**
* 建筑id
*/
private String buildingId;
/**
* 产热量
*/
private BigDecimal hotWaterValue;
/**
* 使用用量
*/
private BigDecimal useHotWater;
/**
* 用电量
*/
private BigDecimal electValue;
/**
* 单耗
*/
private BigDecimal electWater;
/**
* 入住人数
*/
private int checkInCount;
/**
* 人均用电
*/
private BigDecimal perElect;
/**
* 人均用水
*/
private BigDecimal perWater;
/**
* 更新标志
*/
private String updateFlag;
/**
* 建筑名称
*/
private String buildingName;
/**
* 当前电表读数
*/
private BigDecimal electCurValue;
/**
* 当前水表读数
*/
private BigDecimal wtCurValue;
}

26
mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyYearSum.java

@ -0,0 +1,26 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水时间能耗实体类
* @date 2025-06-18 14:28:30
*/
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("energy_month_sum")
public class EnergyYearSum extends EnergyBaseSum {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
}

9
mh-common/src/main/java/com/mh/common/core/domain/entity/GatewayManage.java

@ -35,6 +35,7 @@ public class GatewayManage extends BaseEntity {
private int communicationType; // 通讯类型
private int grade; // 标志位(连接状态) 0:正常;1:不在线;2:异常
private Integer status; // (连接状态) 0:正常;1:不在线;2:异常
private String heartBeat; // 心跳包
@JsonIgnore
@TableField(exist = false)
@ -47,6 +48,14 @@ public class GatewayManage extends BaseEntity {
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
public String getHeartBeat() {
return heartBeat;
}
public void setHeartBeat(String heartBeat) {
this.heartBeat = heartBeat;
}
public Integer getStatus() {
return status;
}

15
mh-common/src/main/java/com/mh/common/core/domain/entity/HouseInfo.java

@ -12,6 +12,7 @@ import lombok.Setter;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
@ -92,6 +93,20 @@ public class HouseInfo extends BaseEntity {
private int orderNum;
/**
* 台账id
*/
// @JsonIgnore
@TableField(exist = false)
private List<String> ledgerId;
/**
* 采集节点id
*/
// @JsonIgnore
@TableField(exist = false)
private List<String> cpmId;
@Override
public String toString() {
return new ToStringBuilder(this)

286
mh-common/src/main/java/com/mh/common/core/domain/entity/ReportHotWaterParamHis.java

@ -0,0 +1,286 @@
package com.mh.common.core.domain.entity;
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 com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.mh.common.core.domain.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Map;
import java.util.StringJoiner;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 生活热水供水热泵运行情况
* @date 2025-10-22 17:40:03
*/
@Setter
@Getter
@TableName("report_hot_water_param_his")
public class ReportHotWaterParamHis extends BaseEntity implements Serializable {
// 主键
@Serial
private static final long serialVersionUID = 1L;
@TableId(value = "id", type = IdType.ASSIGN_UUID)
private String id;
// 楼层ID
private String floorId;
// 记录日期
private LocalDate curDate;
// 记录时间(varchar格式)
private String curTime;
// 班次
private String classes;
// 1号热泵设定温度(℃)
private BigDecimal tempSetHotPumpOne;
// 1号热泵实际温度(℃)
private BigDecimal tempRealHotPumpOne;
// 1号热泵启停状态(0-关闭,1-开启)
private Integer statusSwitchHotPumpOne;
// 1号热泵运行状态(0-故障,1-正常)
private Integer statusRunHotPumpOne;
// 2号热泵设定温度(℃)
private BigDecimal tempSetHotPumpTwo;
// 2号热泵实际温度(℃)
private BigDecimal tempRealHotPumpTwo;
// 2号热泵启停状态
private Integer statusSwitchHotPumpTwo;
// 2号热泵运行状态
private Integer statusRunHotPumpTwo;
// 3号热泵设定温度(℃)
private BigDecimal tempSetHotPumpThree;
// 3号热泵实际温度(℃)
private BigDecimal tempRealHotPumpThree;
// 3号热泵启停状态
private Integer statusSwitchHotPumpThree;
// 3号热泵运行状态
private Integer statusRunHotPumpThree;
// 4号热泵设定温度(℃)
private BigDecimal tempSetHotPumpFour;
// 4号热泵实际温度(℃)
private BigDecimal tempRealHotPumpFour;
// 4号热泵启停状态
private Integer statusSwitchHotPumpFour;
// 4号热泵运行状态
private Integer statusRunHotPumpFour;
// 5号热泵设定温度(℃)
private BigDecimal tempSetHotPumpFive;
// 5号热泵实际温度(℃)
private BigDecimal tempRealHotPumpFive;
// 5号热泵启停状态(0-关闭,1-开启)
private Integer statusSwitchHotPumpFive;
// 5号热泵运行状态(0-故障,1-正常)
private Integer statusRunHotPumpFive;
// 6号热泵设定温度(℃)
private BigDecimal tempSetHotPumpSix;
// 6号热泵实际温度(℃)
private BigDecimal tempRealHotPumpSix;
// 6号热泵启停状态
private Integer statusSwitchHotPumpSix;
// 6号热泵运行状态
private Integer statusRunHotPumpSix;
// 7号热泵设定温度(℃)
private BigDecimal tempSetHotPumpSeven;
// 7号热泵实际温度(℃)
private BigDecimal tempRealHotPumpSeven;
// 7号热泵启停状态
private Integer statusSwitchHotPumpSeven;
// 7号热泵运行状态
private Integer statusRunHotPumpSeven;
// 8号热泵设定温度(℃)
private BigDecimal tempSetHotPumpEight;
// 8号热泵实际温度(℃)
private BigDecimal tempRealHotPumpEight;
// 8号热泵启停状态
private Integer statusSwitchHotPumpEight;
// 8号热泵运行状态
private Integer statusRunHotPumpEight;
// 高区/裙楼设定压力(MPa)
private BigDecimal presSetSupplyPumpAreaOne;
// 高区/裙楼实际压力(MPa)
private BigDecimal presRealSupplyPumpAreaOne;
// 高区/裙楼1号泵运行状态
private Integer statusRunSupplyPumpOne;
// 高区/裙楼2号泵运行状态
private Integer statusRunSupplyPumpTwo;
// 中区/中厨设定压力(MPa)
private BigDecimal presSetSupplyPumpAreaTwo;
// 中区/中厨实际压力(MPa)
private BigDecimal presRealSupplyPumpAreaTwo;
// 中区/中厨1号泵运行状态
private Integer statusRunSupplyPumpThree;
// 中区/中厨2号泵运行状态
private Integer statusRunSupplyPumpFour;
// 高区/裙楼液位(米)
private BigDecimal levelWaterTankOne;
// 中区/中厨液位(米)
private BigDecimal levelWaterTankTwo;
// 主楼与贵宾楼循环泵1
private Integer statusRunCyclePumpOne;
// 主楼与贵宾楼循环泵2
private Integer statusRunCyclePumpTwo;
// 巡查记录人
private String recorder;
// 备注信息
private String remark;
@JsonIgnore
@TableField(exist = false)
private String searchValue;
/**
* 请求参数
*/
@TableField(exist = false)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
/** 创建者 */
@JsonIgnore
@TableField(exist = false)
private String createBy;
/** 创建时间 */
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** 更新者 */
@JsonIgnore
@TableField(exist = false)
private String updateBy;
/** 更新时间 */
@JsonIgnore
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 更新者 */
@TableField(exist = false)
private int pageNum;
/** 更新者 */
@TableField(exist = false)
private int pageSize;
// 无参构造
public ReportHotWaterParamHis() {
}
// Getter/Setter 方法(此处省略,实际开发中建议使用 Lombok @Data)
// 业务方法示例:判断热泵1是否正常运行
public boolean isHotPump1Normal() {
return statusRunHotPumpOne != null && statusRunHotPumpOne == 1;
}
// 业务方法示例:获取当前压力差值(高区)
public BigDecimal getHighAreaPressureDiff() {
return presRealSupplyPumpAreaOne.subtract(presSetSupplyPumpAreaOne);
}
@Override
public String toString() {
return new StringJoiner(", ", ReportHotWaterParamHis.class.getSimpleName() + "[", "]")
.add("id='" + id + "'")
.add("floorId='" + floorId + "'")
.add("curDate=" + curDate)
.add("curTime='" + curTime + "'")
.add("classes='" + classes + "'")
.add("tempSetHotPumpOne=" + tempSetHotPumpOne)
.add("tempRealHotPumpOne=" + tempRealHotPumpOne)
.add("statusSwitchHotPumpOne=" + statusSwitchHotPumpOne)
.add("statusRunHotPumpOne=" + statusRunHotPumpOne)
.add("tempSetHotPumpTwo=" + tempSetHotPumpTwo)
.add("tempRealHotPumpTwo=" + tempRealHotPumpTwo)
.add("statusSwitchHotPumpTwo=" + statusSwitchHotPumpTwo)
.add("statusRunHotPumpTwo=" + statusRunHotPumpTwo)
.add("tempSetHotPumpThree=" + tempSetHotPumpThree)
.add("tempRealHotPumpThree=" + tempRealHotPumpThree)
.add("statusSwitchHotPumpThree=" + statusSwitchHotPumpThree)
.add("statusRunHotPumpThree=" + statusRunHotPumpThree)
.add("tempSetHotPumpFour=" + tempSetHotPumpFour)
.add("tempRealHotPumpFour=" + tempRealHotPumpFour)
.add("statusSwitchHotPumpFour=" + statusSwitchHotPumpFour)
.add("statusRunHotPumpFour=" + statusRunHotPumpFour)
.add("presSetSupplyPumpAreaOne=" + presSetSupplyPumpAreaOne)
.add("presRealSupplyPumpAreaOne=" + presRealSupplyPumpAreaOne)
.add("statusRunSupplyPumpOne=" + statusRunSupplyPumpOne)
.add("statusRunSupplyPumpTwo=" + statusRunSupplyPumpTwo)
.add("presSetSupplyPumpAreaTwo=" + presSetSupplyPumpAreaTwo)
.add("presRealSupplyPumpAreaTwo=" + presRealSupplyPumpAreaTwo)
.add("statusRunSupplyPumpThree=" + statusRunSupplyPumpThree)
.add("statusRunSupplyPumpFour=" + statusRunSupplyPumpFour)
.add("levelWaterTankOne=" + levelWaterTankOne)
.add("levelWaterTankTwo=" + levelWaterTankTwo)
.add("recorder='" + recorder + "'")
.add("remark='" + remark + "'")
.toString();
}
}

310
mh-common/src/main/java/com/mh/common/core/domain/entity/ReportSysRunParamHis.java

@ -0,0 +1,310 @@
package com.mh.common.core.domain.entity;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
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 com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.mh.common.core.domain.BaseEntity;
import lombok.*;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.springframework.data.annotation.Id;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.Date;
import java.util.Map;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 系统参数设备运行历史记录
* @date 2025-08-12 10:44:36
*/
@Data
@TableName("report_sys_run_param_his")
public class ReportSysRunParamHis extends BaseEntity {
/**
* 自增主键
*/
@Id
@TableId(value = "id", type = IdType.AUTO)
private Long id;
/**
* 主机id
*/
private String deviceNum;
/**
* 日期
*/
private LocalDate curDate;
/**
* 时间格式建议与数据库存储一致 "HH:mm:ss" "yyyy-MM-dd HH:mm:ss"
*/
private String curTime;
// /**
// * 班次
// */
// private String classes;
/**
* 冷冻水进水温度
*/
private BigDecimal tempInChillerWater;
/**
* 冷冻水出水温度
*/
private BigDecimal tempOutChillerWater;
/**
* 设计流量%修正列名 "design flow" 含空格
*/
private BigDecimal designFlow;
/**
* 蒸发器压力kpa--磁悬浮
*/
private BigDecimal pressEvapSaturation;
/**
* 蒸发器饱和温度
*/
private BigDecimal tempEvapSaturation;
/**
* 蒸发器趋近温度
*/
private BigDecimal tempEvapApproaching;
/**
* 冷却水进水温度
*/
private BigDecimal tempInCoolingWater;
/**
* 冷却水出水温度
*/
private BigDecimal tempOutCoolingWater;
/**
* 冷凝器压力kpa--磁悬浮
*/
private BigDecimal pressCondenserSaturation;
/**
* 冷凝器饱和温度
*/
private BigDecimal tempCondenserSaturation;
/**
* 冷凝器趋近温度
*/
private BigDecimal tempCondenserApproaching;
/**
* 冷冻水设定值
*/
private BigDecimal setChillerWater;
/**
* 冷水机需求%
*/
private BigDecimal setLoad;
/**
* 总电流%
*/
private BigDecimal currentTotal;
/**
* 总输入功率kw
*/
private BigDecimal inputPowerTotal;
/**
* 压缩比1
*/
private BigDecimal ratioCompOne;
/**
* 压缩比1
*/
private BigDecimal ratioCompTwo;
/**
* 压缩比1
*/
private BigDecimal ratioCompThree;
/**
* 膨胀阀开度%
*/
private BigDecimal openExv;
/**
* 运行中的压缩机数量
*/
private Integer runCompNum;
/**
* 冷冻水泵频率hz
*/
private BigDecimal frequencyChiller;
/**
* 冷冻水出水压力kpa
*/
private BigDecimal pressOutChillerWater;
/**
* 冷冻水进水压力kpa
*/
private BigDecimal pressInChillerWater;
/**
* 冷却水泵频率hz
*/
private BigDecimal frequencyCooling;
/**
* 冷却水出水压力kpa
*/
private BigDecimal pressOutCoolingWater;
/**
* 冷却水进水压力kpa
*/
private BigDecimal pressInCoolingWater;
/**
* 冷却塔水泵频率hz
*/
private BigDecimal frequencyCoolingTower;
/**
* 冷却塔运行数量原注释可能有误根据列名调整
*/
private Integer runCoolingTower;
/**
* 恒压补水罐压力
*/
private BigDecimal pressConstantWaterTank;
/**
* 室外温度
*/
private BigDecimal tempOutdoor;
/**
* 室外湿度%
*/
private BigDecimal humidityOutdoor;
/**
* 巡查记录人
*/
private String recorder;
/**
* 备注
*/
private String remark;
@JsonIgnore
@TableField(exist = false)
private String searchValue;
/**
* 请求参数
*/
@TableField(exist = false)
@JsonInclude(JsonInclude.Include.NON_EMPTY)
private Map<String, Object> params;
/** 创建者 */
@TableField(exist = false)
private String createBy;
/** 创建时间 */
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createTime;
/** 更新者 */
@TableField(exist = false)
private String updateBy;
/** 更新时间 */
@TableField(exist = false)
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date updateTime;
/** 更新者 */
@TableField(exist = false)
private int pageNum;
/** 更新者 */
@TableField(exist = false)
private int pageSize;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("deviceNum", deviceNum)
.append("curDate", curDate)
.append("curTime", curTime)
.append("tempInChillerWater", tempInChillerWater)
.append("tempOutChillerWater", tempOutChillerWater)
.append("designFlow", designFlow)
.append("pressEvapSaturation", pressEvapSaturation)
.append("tempEvapSaturation", tempEvapSaturation)
.append("tempEvapApproaching", tempEvapApproaching)
.append("tempInCoolingWater", tempInCoolingWater)
.append("tempOutCoolingWater", tempOutCoolingWater)
.append("pressCondenserSaturation", pressCondenserSaturation)
.append("tempCondenserSaturation", tempCondenserSaturation)
.append("tempCondenserApproaching", tempCondenserApproaching)
.append("setChillerWater", setChillerWater)
.append("setLoad", setLoad)
.append("currentTotal", currentTotal)
.append("inputPowerTotal", inputPowerTotal)
.append("ratioCompOne", ratioCompOne)
.append("ratioCompTwo", ratioCompTwo)
.append("ratioCompThree", ratioCompThree)
.append("openExv", openExv)
.append("runCompNum", runCompNum)
.append("frequencyChiller", frequencyChiller)
.append("pressOutChillerWater", pressOutChillerWater)
.append("pressInChillerWater", pressInChillerWater)
.append("frequencyCooling", frequencyCooling)
.append("pressOutCoolingWater", pressOutCoolingWater)
.append("pressInCoolingWater", pressInCoolingWater)
.append("frequencyCoolingTower", frequencyCoolingTower)
.append("runCoolingTower", runCoolingTower)
.append("pressConstantWaterTank", pressConstantWaterTank)
.append("tempOutdoor", tempOutdoor)
.append("humidityOutdoor", humidityOutdoor)
.append("recorder", recorder)
.append("remark", remark)
.append("searchValue", searchValue)
.append("params", params)
.append("createBy", createBy)
.append("createTime", createTime)
.append("updateBy", updateBy)
.append("updateTime", updateTime)
.toString();
}
}

117
mh-common/src/main/java/com/mh/common/core/domain/entity/WaterLevel.java

@ -0,0 +1,117 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Date;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水液位
* @date 2025-06-19 16:18:12
*/
@Data
@TableName("water_level")
public class WaterLevel {
private String id;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date curDate;
private String buildingId;
private String buildingName;
private String deviceNum;
private String deviceName;
private String temp00;
private String temp01;
private String temp02;
private String temp03;
private String temp04;
private String temp05;
private String temp06;
private String temp07;
private String temp08;
private String temp09;
private String temp10;
private String temp11;
private String temp12;
private String temp13;
private String temp14;
private String temp15;
private String temp16;
private String temp17;
private String temp18;
private String temp19;
private String temp20;
private String temp21;
private String temp22;
private String temp23;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("curDate", curDate)
.append("buildingId", buildingId)
.append("buildingName", buildingName)
.append("deviceNum", deviceNum)
.append("deviceName", deviceName)
.append("temp00", temp00)
.append("temp01", temp01)
.append("temp02", temp02)
.append("temp03", temp03)
.append("temp04", temp04)
.append("temp05", temp05)
.append("temp06", temp06)
.append("temp07", temp07)
.append("temp08", temp08)
.append("temp09", temp09)
.append("temp10", temp10)
.append("temp11", temp11)
.append("temp12", temp12)
.append("temp13", temp13)
.append("temp14", temp14)
.append("temp15", temp15)
.append("temp16", temp16)
.append("temp17", temp17)
.append("temp18", temp18)
.append("temp19", temp19)
.append("temp20", temp20)
.append("temp21", temp21)
.append("temp22", temp22)
.append("temp23", temp23)
.toString();
}
}

117
mh-common/src/main/java/com/mh/common/core/domain/entity/WaterTemp.java

@ -0,0 +1,117 @@
package com.mh.common.core.domain.entity;
import com.baomidou.mybatisplus.annotation.TableName;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Date;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水温度
* @date 2025-06-19 16:18:12
*/
@Data
@TableName("water_temp")
public class WaterTemp {
private String id;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date curDate;
private String buildingId;
private String buildingName;
private String deviceNum;
private String deviceName;
private String temp00;
private String temp01;
private String temp02;
private String temp03;
private String temp04;
private String temp05;
private String temp06;
private String temp07;
private String temp08;
private String temp09;
private String temp10;
private String temp11;
private String temp12;
private String temp13;
private String temp14;
private String temp15;
private String temp16;
private String temp17;
private String temp18;
private String temp19;
private String temp20;
private String temp21;
private String temp22;
private String temp23;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("curDate", curDate)
.append("buildingId", buildingId)
.append("buildingName", buildingName)
.append("deviceNum", deviceNum)
.append("deviceName", deviceName)
.append("temp00", temp00)
.append("temp01", temp01)
.append("temp02", temp02)
.append("temp03", temp03)
.append("temp04", temp04)
.append("temp05", temp05)
.append("temp06", temp06)
.append("temp07", temp07)
.append("temp08", temp08)
.append("temp09", temp09)
.append("temp10", temp10)
.append("temp11", temp11)
.append("temp12", temp12)
.append("temp13", temp13)
.append("temp14", temp14)
.append("temp15", temp15)
.append("temp16", temp16)
.append("temp17", temp17)
.append("temp18", temp18)
.append("temp19", temp19)
.append("temp20", temp20)
.append("temp21", temp21)
.append("temp22", temp22)
.append("temp23", temp23)
.toString();
}
}

20
mh-common/src/main/java/com/mh/common/core/domain/entity/WeatherData.java

@ -77,6 +77,26 @@ public class WeatherData {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date createdTime;
/**
* 含湿量 g/kg
*/
private Double humidityContent;
/**
* 焓值kJ/kg
*/
private Double enthalpy;
/**
* 露点温度摄氏度
*/
private Double dewPointTemp;
/**
* 湿球温度
*/
private Double wetBulbTemp;
@Override
public String toString() {
return new ToStringBuilder(this)

3
mh-common/src/main/java/com/mh/common/core/domain/vo/DeviceMonitorVO.java

@ -62,6 +62,8 @@ public class DeviceMonitorVO {
private int orderNum;
private String gatewayId;
@Override
public String toString() {
return new ToStringBuilder(this)
@ -74,6 +76,7 @@ public class DeviceMonitorVO {
.append("collectValue", collectValue)
.append("paramType", paramType)
.append("orderNum", orderNum)
.append("gatewayId", gatewayId)
.toString();
}
}

69
mh-common/src/main/java/com/mh/common/core/domain/vo/HotWaterControlVO.java

@ -62,6 +62,21 @@ public class HotWaterControlVO {
private BigDecimal waterLevelSet;
private String waterLevelSetId;
// 水位设置 10
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0.0")
private BigDecimal waterLevelSet1;
private String waterLevelSetId1;
// 水位误差设置 46
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0.0")
private BigDecimal waterLevelErrorSet;
private String waterLevelErrorSetId;
// 水位误差设置 46
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0.0")
private BigDecimal waterLevelErrorSet1;
private String waterLevelErrorSetId1;
// 水位 11
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0.0")
private BigDecimal waterLevel;
@ -115,12 +130,66 @@ public class HotWaterControlVO {
private int emergencyStopStatus;
private String emergencyStopStatusId;
// 最低设置值 44
private BigDecimal minSet;
private String minSetId;
// 设定值上限
private BigDecimal maxValueSet;
private String maxValueSetId;
// 设定值下限
private BigDecimal minValueSet;
private String minValueSetId;
// 校准值
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal calibrationValue;
private String calibrationValueId;
// 工程量最低值
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal engineeringMinValue;
private String engineeringMinValueId;
// 工程量最高值
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal engineeringMaxValue;
private String engineeringMaxValueId;
// 数字量最低值
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal digitalMinValue;
private String digitalMinValueId;
// 数字量最高值
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal digitalMaxValue;
private String digitalMaxValueId;
// 中间值
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal middleValue;
private String middleValueId;
// 累积运行时长:小时单位
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "0")
private BigDecimal runningTime;
private String runningTimeId;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date curTime;
// 异常复位:45
private int exceptionReset;
private String exceptionResetId;
private int orderNum;
// 本地远程状态 22: 0-本地 1-远程
private int localRemoteStatus;
private String localRemoteStatusId;
public void setCounterSet(BigDecimal counterSet) {
if (counterSet != null) {
counterSet = counterSet.setScale(0, BigDecimal.ROUND_HALF_UP);

35
mh-common/src/main/java/com/mh/common/core/domain/wechat/First.java

@ -0,0 +1,35 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 10:59
* @Description
*/
public class First {
public String value;
public String color;
public First() {
}
public First(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

35
mh-common/src/main/java/com/mh/common/core/domain/wechat/Key1.java

@ -0,0 +1,35 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 10:59
* @Description
*/
public class Key1 {
public String value;
public String color;
public Key1() {
}
public Key1(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

36
mh-common/src/main/java/com/mh/common/core/domain/wechat/Key2.java

@ -0,0 +1,36 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 10:59
* @Description
*/
public class Key2 {
public String value;
public String color;
public Key2() {
}
public Key2(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

36
mh-common/src/main/java/com/mh/common/core/domain/wechat/Key3.java

@ -0,0 +1,36 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 11:00
* @Description
*/
public class Key3 {
public String value;
public String color;
public Key3() {
}
public Key3(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

36
mh-common/src/main/java/com/mh/common/core/domain/wechat/Key4.java

@ -0,0 +1,36 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 11:00
* @Description
*/
public class Key4 {
public String value;
public String color;
public Key4() {
}
public Key4(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

36
mh-common/src/main/java/com/mh/common/core/domain/wechat/Key5.java

@ -0,0 +1,36 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 11:00
* @Description
*/
public class Key5 {
public String value;
public String color;
public Key5() {
}
public Key5(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

115
mh-common/src/main/java/com/mh/common/core/domain/wechat/PushMsgEntity.java

@ -0,0 +1,115 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 10:58
* @Description 推送消息实体类
*/
public class PushMsgEntity {
public String touser; //接收人
public String templateId; //微信提供模板id
public String url; //消息推送消息url
public First first; //消息头消息
public Key1 key1;
public Key2 key2;
public Key3 key3;
public Key4 key4;
public Key5 key5;
public Remark remark;
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public String getTemplateId() {
return templateId;
}
public void setTemplateId(String templateId) {
this.templateId = templateId;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public First getFirst() {
return first;
}
public void setFirst(First first) {
this.first = first;
}
public Key1 getKey1() {
return key1;
}
public void setKey1(Key1 key1) {
this.key1 = key1;
}
public Key2 getKey2() {
return key2;
}
public void setKey2(Key2 key2) {
this.key2 = key2;
}
public Key3 getKey3() {
return key3;
}
public void setKey3(Key3 key3) {
this.key3 = key3;
}
public Key4 getKey4() {
return key4;
}
public void setKey4(Key4 key4) {
this.key4 = key4;
}
public Key5 getKey5() {
return key5;
}
public void setKey5(Key5 key5) {
this.key5 = key5;
}
public Remark getRemark() {
return remark;
}
public void setRemark(Remark remark) {
this.remark = remark;
}
@Override
public String toString() {
return "PushMsgEntity{" +
"touser='" + touser + '\'' +
", templateId='" + templateId + '\'' +
", url='" + url + '\'' +
", first=" + first +
", key1=" + key1 +
", key2=" + key2 +
", key3=" + key3 +
", key4=" + key4 +
", key5=" + key5 +
", remark=" + remark +
'}';
}
}

36
mh-common/src/main/java/com/mh/common/core/domain/wechat/Remark.java

@ -0,0 +1,36 @@
package com.mh.common.core.domain.wechat;
/**
* @author chison
* @date 2020-09-14 15:47
* @Description
*/
public class Remark {
public String value;
public String color;
public Remark() {
}
public Remark(String value, String color) {
this.value = value;
this.color = color;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}

70
mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatTemplate.java

@ -0,0 +1,70 @@
package com.mh.common.core.domain.wechat;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Date;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 微信模板
* @date 2025-06-27 11:43:54
*/
@Data
@TableName("wechat_template")
public class WechatTemplate {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String templateId;
private String templateName;
private String title;
private String content1;
private String content2;
private String content3;
private String content4;
private String content5;
private String remark;
private Date createTime;
private Date updateTime;
/**
* 0正常 1不使用
*/
private int grade;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("templateId", templateId)
.append("templateName", templateName)
.append("title", title)
.append("content1", content1)
.append("content2", content2)
.append("content3", content3)
.append("content4", content4)
.append("content5", content5)
.append("remark", remark)
.append("createTime", createTime)
.append("updateTime", updateTime)
.append("grade", grade)
.toString();
}
}

52
mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatTemplateProject.java

@ -0,0 +1,52 @@
package com.mh.common.core.domain.wechat;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import org.apache.commons.lang3.builder.ToStringBuilder;
import java.util.Date;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 微信模板
* @date 2025-06-27 11:43:54
*/
@Data
@TableName("wechat_template_project")
public class WechatTemplateProject {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private Long templateId;
private Long projectId;
private Long wechatUserId;
private Date createTime;
private Date updateTime;
/**
* 0正常 1不使用
*/
private int grade;
@Override
public String toString() {
return new ToStringBuilder(this)
.append("id", id)
.append("templateId", templateId)
.append("projectId", projectId)
.append("wechatUserId", wechatUserId)
.append("createTime", createTime)
.append("updateTime", updateTime)
.append("grade", grade)
.toString();
}
}

172
mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatUserInfo.java

@ -0,0 +1,172 @@
package com.mh.common.core.domain.wechat;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.util.Date;
/**
* @author LJF
* @version 1.0
* @project mh_esi
* @description 微信用户实体类
* @date 2024-11-27 16:58:55
*/
@TableName("wechat_user_info")
public class WechatUserInfo {
@TableId(value = "id", type = IdType.AUTO)
private Long id;
private String userName;
private String telNum;
private String openId;
private String nickName;
private int sex;
private String province;
private String city;
private String country;
private String headimgurl;
private int isStatus;
private Date createTime;
private Date updateTime;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getTelNum() {
return telNum;
}
public void setTelNum(String telNum) {
this.telNum = telNum;
}
public String getOpenId() {
return openId;
}
public void setOpenId(String openId) {
this.openId = openId;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickName) {
this.nickName = nickName;
}
public int getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public void setSex(int sex) {
this.sex = sex;
}
public String getHeadimgurl() {
return headimgurl;
}
public void setHeadimgurl(String headimgurl) {
this.headimgurl = headimgurl;
}
public int getIsStatus() {
return isStatus;
}
public void setIsStatus(int isStatus) {
this.isStatus = isStatus;
}
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
@Override
public String toString() {
return "WechatUserInfoEntity{" +
"id=" + id +
", userName='" + userName + '\'' +
", telNum='" + telNum + '\'' +
", openId='" + openId + '\'' +
", nickName='" + nickName + '\'' +
", sex=" + sex +
", province='" + province + '\'' +
", city='" + city + '\'' +
", country='" + country + '\'' +
", headimgurl='" + headimgurl + '\'' +
", isStatus=" + isStatus +
", createTime=" + createTime +
", updateTime=" + updateTime +
'}';
}
}

63
mh-common/src/main/java/com/mh/common/core/redis/RedisLock.java

@ -0,0 +1,63 @@
package com.mh.common.core.redis;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Component;
import java.util.Collections;
import java.util.concurrent.TimeUnit;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description
* @date 2025-06-06 16:08:13
*/
@Slf4j
@Component
public class RedisLock {
private final StringRedisTemplate redisTemplate;
public RedisLock(StringRedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
/**
* 获取锁
*/
public boolean lock(String key, String requestId, long expireTimeInSeconds) {
Boolean success = redisTemplate.opsForValue().setIfAbsent(key, requestId, expireTimeInSeconds, TimeUnit.SECONDS);
return Boolean.TRUE.equals(success);
}
/**
* 尝试获取锁带超时
*/
public boolean tryLock(String key, String requestId, long expireTime, long timeoutMs) throws InterruptedException {
long startTime = System.currentTimeMillis();
while (System.currentTimeMillis() - startTime < timeoutMs) {
if (lock(key, requestId, expireTime)) {
return true;
}
Thread.sleep(50);
}
return false;
}
/**
* 释放锁使用 Lua 脚本保证原子性
*/
public void unlock(String key, String requestId) {
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
RedisScript<Long> redisScript = RedisScript.of(script, Long.class);
Long result = redisTemplate.execute(redisScript, Collections.singletonList(key), requestId);
if (result == null || result == 0) {
log.warn("释放锁失败,可能已被其他线程释放 key={}", key);
}
}
}

55
mh-common/src/main/java/com/mh/common/enums/ComputeEnum.java

@ -11,6 +11,34 @@ import java.util.*;
*/
public enum ComputeEnum implements ComputeService {
/**
* 水表
*/
WATER("水表设备数据处理", 23) {
@Override
public ArrayList<Map<LocalDateTime, DeviceReport>> getDataList(
Map.Entry<String, Map<LocalDateTime, List<DeviceReport>>> entry) {
ArrayList<Map<LocalDateTime, DeviceReport>> result = new ArrayList<>();
//获取到电表的数据,按照表号分组分组,紧接着再按照小时分组。需要计算分组后的数据取出最大值
Map<LocalDateTime, List<DeviceReport>> deviceMap = entry.getValue();
String deviceNum = entry.getKey();
Set<Map.Entry<LocalDateTime, List<DeviceReport>>> groupEntryList = deviceMap.entrySet();
for (Map.Entry<LocalDateTime, List<DeviceReport>> listEntry : groupEntryList) {
LocalDateTime key = listEntry.getKey();
List<DeviceReport> value = listEntry.getValue();
DeviceReport maxEntity = value.stream()
.max(Comparator.comparing(obj -> Double.valueOf(obj.getCurValue())))
.orElse(null);
HashMap<LocalDateTime, DeviceReport> map = new HashMap<>();
map.put(key, maxEntity);
result.add(map);
}
return result;
}
},
/**
* 电表
*/
@ -75,6 +103,33 @@ public enum ComputeEnum implements ComputeService {
Map.Entry<String, Map<LocalDateTime, List<DeviceReport>>> entry) {
return null;
}
},
/**
* 蒸汽流量计数据处理
*/
STEAM_FLOW("蒸汽流量计数据处理", 12) {
@Override
public ArrayList<Map<LocalDateTime, DeviceReport>> getDataList(
Map.Entry<String, Map<LocalDateTime, List<DeviceReport>>> entry) {
ArrayList<Map<LocalDateTime, DeviceReport>> result = new ArrayList<>();
//获取到电表的数据,按照表号分组分组,紧接着再按照小时分组。需要计算分组后的数据取出最大值
Map<LocalDateTime, List<DeviceReport>> deviceMap = entry.getValue();
String deviceNum = entry.getKey();
Set<Map.Entry<LocalDateTime, List<DeviceReport>>> groupEntryList = deviceMap.entrySet();
for (Map.Entry<LocalDateTime, List<DeviceReport>> listEntry : groupEntryList) {
LocalDateTime key = listEntry.getKey();
List<DeviceReport> value = listEntry.getValue();
DeviceReport maxEntity = value.stream()
.max(Comparator.comparing(obj -> Double.valueOf(obj.getCurValue())))
.orElse(null);
HashMap<LocalDateTime, DeviceReport> map = new HashMap<>();
map.put(key, maxEntity);
result.add(map);
}
return result;
}
};
private String des;

5
mh-common/src/main/java/com/mh/common/model/request/AdvantechDatas.java

@ -22,4 +22,9 @@ public class AdvantechDatas<T extends Number> {
*/
private T value;
/**
* 质量值
*/
private T quality;
}

39
mh-common/src/main/java/com/mh/common/model/response/ParseResult.java

@ -0,0 +1,39 @@
package com.mh.common.model.response;
import lombok.Data;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 定义统一的数据解析结果对象
* @date 2026-04-28 11:41:34
*/
@Data
public class ParseResult {
private boolean success;
private BigDecimal value;
private String tagName;
private int quality;
private String errorMessage;
public static ParseResult success(BigDecimal value, String tagName) {
ParseResult result = new ParseResult();
result.setSuccess(true);
result.setValue(value);
result.setTagName(tagName);
result.setQuality(0);
return result;
}
public static ParseResult fail(String errorMessage) {
ParseResult result = new ParseResult();
result.setSuccess(false);
result.setErrorMessage(errorMessage);
return result;
}
}

446
mh-common/src/main/java/com/mh/common/utils/AnalysisReceiveOrder485.java

@ -0,0 +1,446 @@
package com.mh.common.utils;
import com.mh.common.core.domain.entity.CollectionParamsManage;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* @author ljf
* @title
* @description 解析485接收的数据
* @updateTime 2020-04-23
* @throws
*/
@Slf4j
public class AnalysisReceiveOrder485 {
// 调用service
// private final SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// private final DecimalFormat df = new DecimalFormat("#.##");
//解析冷量表
public void analysisCloudOrder485(final String dataStr1, final CollectionParamsManage deviceCodeParam) {
// 去掉空格
String dataStr = dataStr1.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
// Date date = new Date();
// String dateStr = sdf1.format(date);
//保留两位小数处理
DecimalFormat decimalFormat = new DecimalFormat("0.00");
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数
String data = "";
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6)
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4)
+ dataStr.substring(dataStr.length() - 12, dataStr.length() - 10)
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8);
String registerAddr = deviceCodeParam.getRegisterAddr();
// if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) {
// dateStr = dateStr.substring(0, 17) + "00";
// } else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) {
// dateStr = dateStr.substring(0, 17) + "30";
// }
try {
if (registerAddr.equals("32") || registerAddr.equals("33") || registerAddr.equals("35") || registerAddr.equals("36")) {
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
// log.info("冷量计==>{},寄存器地址==>{},读数==>{}", cloudId, registerAddr, data);
} else if (registerAddr.equals("31") || registerAddr.equals("34")) {
long lData = Long.parseLong(ExchangeStringUtil.hexToDec(data));
// log.info("冷量计==>{},寄存器地址==>{},累计读数==>{}", cloudId, registerAddr, lData);
}
} catch (Exception e) {
log.error("保存冷量计数据失败!", e);
}
} else {
// log.info("冷量计校验失败===>{}", dataStr);
}
}
/**
* 解析水表返回的数据
*
* @param dataStr1
*/
public String analysisWaterOrder485(final String dataStr1, final CollectionParamsManage deviceCodeParam) {
// 去掉空格
String dataStr = dataStr1.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
// Date date = new Date();
// String dateStr = sdf1.format(date);
//保留两位小数处理
DecimalFormat decimalFormat = new DecimalFormat("0.00");
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数
String data = "";
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6)
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4)
+ dataStr.substring(dataStr.length() - 12, dataStr.length() - 10)
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8);
int dataType = deviceCodeParam.getDataType();
// if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) {
// dateStr = dateStr.substring(0, 17) + "00";
// // System.out.println("插入时间00" + dateStr);
// } else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) {
// dateStr = dateStr.substring(0, 17) + "30";
// // System.out.println("插入时间30" + dateStr);
// }
try {
if (dataType == 3) {
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
// log.info("水表==>{},寄存器地址==>{},读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
} else if (dataType == 2) {
data = dataStr.substring(dataStr.length() - 12, dataStr.length() - 10)
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8)
+ dataStr.substring(dataStr.length() - 8, dataStr.length() - 6)
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4);
data = ExchangeStringUtil.hexToDec(data);
BigDecimal bigDecimal = new BigDecimal(data);
bigDecimal = bigDecimal.divide(new BigDecimal((int) Math.pow(10, deviceCodeParam.getDigits()))).setScale(2, RoundingMode.HALF_UP); // 除以1000并保留整数
data = bigDecimal.toString();
// log.info("水表==>{},寄存器地址==>{},累计读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
}
// 判断data大于99999999,就返回空
if (new BigDecimal(data).intValue() > 99999999) {
return "";
}
return data;
} catch (Exception e) {
log.error("保存水表数据失败!", e);
}
} else {
// log.info("水表===>{}", dataStr);
return "";
}
return "";
}
/**
* 解析电表返回的数据
*
* @param dataStr1
*/
public String analysisMeterOrder485(final String dataStr1, final CollectionParamsManage deviceCodeParam) {
// 去掉空格
String dataStr = dataStr1.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
// Date date = new Date();
// String dateStr = sdf1.format(date);
;
//保留两位小数处理
DecimalFormat decimalFormat = new DecimalFormat("0.00");
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数 02 04 04 00 04 4D 1F FD DD
String data = "";
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6)
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4)
+ dataStr.substring(dataStr.length() - 12, dataStr.length() - 10)
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8);
int dataType = deviceCodeParam.getDataType();
// if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) {
// dateStr = dateStr.substring(0, 17) + "00";
// // System.out.println("插入时间00" + dateStr);
// } else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) {
// dateStr = dateStr.substring(0, 17) + "30";
// // System.out.println("插入时间30" + dateStr);
// }
try {
if (dataType == 3) {
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
// log.info("电表==>{},寄存器地址==>{},读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
} else if (dataType == 2) {
data = ExchangeStringUtil.hexToDec(data);
// log.info("电表==>{},寄存器地址==>{},累计读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
} else if (dataType == 4) {
data = dataStr.substring(dataStr.length() - 12, dataStr.length() - 10)
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8)
+ dataStr.substring(dataStr.length() - 8, dataStr.length() - 6)
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4);
data = ExchangeStringUtil.hexToDec(data);
BigDecimal bigDecimal = new BigDecimal(data);
bigDecimal = bigDecimal.divide(new BigDecimal((int) Math.pow(10, deviceCodeParam.getDigits()))).setScale(2, RoundingMode.HALF_UP); // 除以1000并保留整数
data = bigDecimal.toString();
// log.info("电表==>{},寄存器地址==>{},累计读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
}
// 判断data大于99999999,就返回空
if (new BigDecimal(data).intValue() > 99999999) {
return "";
}
return data;
} catch (Exception e) {
log.error("保存电表数据失败!", e);
}
} else {
// log.info("电表===>{}", dataStr);
return "";
}
return "";
}
public static int dValue(String lastDate) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date lastTime = format.parse(lastDate);
long min = lastTime.getTime();
Calendar calendar = Calendar.getInstance();
long min1 = calendar.getTimeInMillis();
long subtract = min1 - min;
// // System.out.println("相减值: " + subtract/(1000*60));
return (int) subtract / (1000 * 60);
}
// 判断是否存在寄存器地址
public Boolean queryRegisterAddr(List<String> stringList, String registerAddr) {
boolean flag = false;
for (int i = 0; i < stringList.size(); i++) {
if (stringList.get(i).equalsIgnoreCase(registerAddr)) {
flag = true;
break;
}
}
return flag;
}
public String analysisHeatPumpOrder485(String receiveStr, CollectionParamsManage deviceCodeParam) {
// 去掉空格
String dataStr = receiveStr.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
// Date date = new Date();
// String dateStr = sdf1.format(date);
//保留两位小数处理
DecimalFormat decimalFormat = new DecimalFormat("0.00");
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数
String data = "";
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6)
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4);
int dataType = deviceCodeParam.getDataType();
// if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) {
// dateStr = dateStr.substring(0, 17) + "00";
// // System.out.println("插入时间00" + dateStr);
// } else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) {
// dateStr = dateStr.substring(0, 17) + "30";
// // System.out.println("插入时间30" + dateStr);
// }
try {
if (dataType == 3) {
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
} else if (dataType == 2 && (deviceCodeParam.getParamType().equals("5")
|| deviceCodeParam.getParamType().equals("2")
|| deviceCodeParam.getParamType().equals("12")
|| deviceCodeParam.getParamType().equals("14")
|| deviceCodeParam.getParamType().equals("48")
)) {
data = ExchangeStringUtil.hexToDec(data);
}
// log.info("热泵==>{},寄存器地址==>{},读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
return data;
} catch (Exception e) {
log.error("保存热泵数据失败!", e);
}
} else {
// log.info("热泵===>{}", dataStr);
return "";
}
return "";
}
public String analysisLiquidOrder485(String receiveStr, CollectionParamsManage deviceCodeParam) {
// 去掉空格
String dataStr = receiveStr.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
// Date date = new Date();
// String dateStr = sdf1.format(date);
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数
String data = "";
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 4);
int dataType = deviceCodeParam.getDataType();
// if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) {
// dateStr = dateStr.substring(0, 17) + "00";
// //// System.out.println("插入时间00" + dateStr);
// } else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) {
// dateStr = dateStr.substring(0, 17) + "30";
// //.out.println("插入时间30" + dateStr);
// }
try {
if (dataType == 2 && (deviceCodeParam.getParamType().equals("11"))) {
data = ExchangeStringUtil.hexToDec(data);
BigDecimal bigDecimal = new BigDecimal(data);
bigDecimal = bigDecimal.divide(new BigDecimal((int) Math.pow(10, deviceCodeParam.getDigits()))).setScale(3, RoundingMode.HALF_UP); // 除以1000并保留整数
data = bigDecimal.toString();
// log.info("液位==>{},寄存器地址==>{},实时读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
}
// 判断data大于99999999,就返回空
if (new BigDecimal(data).intValue() > 100) {
return "";
}
return data;
} catch (Exception e) {
log.error("保存液位数据失败!", e);
}
} else {
// log.info("液位===>{}", dataStr);
return "";
}
return "";
}
public String analysisTempHumiditySensorOrder485(String receiveStr, CollectionParamsManage deviceCodeParam) {
// 去掉空格
String dataStr = receiveStr.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数
String data = "";
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 4);
int dataType = deviceCodeParam.getDataType();
try {
if (dataType == 2) {
data = ExchangeStringUtil.hexToDec(data);
BigDecimal bigDecimal = new BigDecimal(data);
if (deviceCodeParam.getParamType().equals("12")){
// 温度
bigDecimal = bigDecimal.multiply(new BigDecimal(165)).divide(new BigDecimal(1650)).subtract(new BigDecimal(40));
} else if (deviceCodeParam.getParamType().equals("35")) {
// 湿度
bigDecimal = bigDecimal.multiply(new BigDecimal(100));
}
bigDecimal = bigDecimal.divide(new BigDecimal((int) Math.pow(10, deviceCodeParam.getDigits()))).setScale(3, RoundingMode.HALF_UP); // 除以1000并保留整数
data = bigDecimal.toString();
// log.info("液位==>{},寄存器地址==>{},实时读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data);
}
// // 判断data大于99999999,就返回空
// if (new BigDecimal(data).intValue() > 130) {
// return "";
// }
return data;
} catch (Exception e) {
log.error("保存液位数据失败!", e);
}
} else {
// log.info("液位===>{}", dataStr);
return "";
}
return "";
}
public String analysisLiquidControlOrder485(String receiveStr, CollectionParamsManage deviceCodeParam) {
// log.error("接收数据:{},{}", receiveStr,deviceCodeParam.toString());
String dataStr = receiveStr.replace(" ", "").toUpperCase();
// 检验报文
String checkStr = dataStr.substring(0, dataStr.length() - 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) {
// 表号
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2));
// 读数
String data = "";
data = dataStr.substring(dataStr.length() - 12, dataStr.length() - 8);
// 保留小数位数
String dot = "";
dot = dataStr.substring(dataStr.length() - 8, dataStr.length() - 4);
int dataType = deviceCodeParam.getDataType();
try {
if (dataType == 2) {
data = ExchangeStringUtil.hexToDec(data);
dot = ExchangeStringUtil.hexToDec(dot);
BigDecimal bigDecimal = new BigDecimal(data);
bigDecimal = bigDecimal.divide(BigDecimal.valueOf(Math.pow(10, Integer.parseInt(dot)))).setScale(3, RoundingMode.HALF_UP); // 除以1000并保留整数
data = bigDecimal.toString();
// log.error("贵宾楼液位报文==>{},地址==>{},寄存器地址==>{},实时读数==>{}", receiveStr, cloudId, deviceCodeParam.getRegisterAddr(), data);
}
// 判断data大于99999999,就返回空
if (new BigDecimal(data).intValue() > 10) {
return "";
}
return data;
} catch (Exception e) {
log.error("保存液位数据失败!", e);
}
} else {
// log.info("液位===>{}", dataStr);
return "";
}
return "";
}
public static void main(String[] args) {
CollectionParamsManage collectionParamsManage = new CollectionParamsManage();
collectionParamsManage.setDataType(2);
collectionParamsManage.setDigits(2);
System.out.println(new AnalysisReceiveOrder485().analysisWaterOrder485("2103040012D68765F6", collectionParamsManage));
}
}

1
mh-common/src/main/java/com/mh/common/utils/BigDecimalUtils.java

@ -23,6 +23,7 @@ public class BigDecimalUtils {
OPERATORS.put("<", (a, b) -> a.compareTo(b) < 0);
OPERATORS.put("<=", (a, b) -> a.compareTo(b) <= 0);
OPERATORS.put("==", (a, b) -> a.compareTo(b) == 0);
OPERATORS.put("=", (a, b) -> a.compareTo(b) == 0); // 添加对 = 运算符的支持
OPERATORS.put("!=", (a, b) -> a.compareTo(b) != 0);
}

253
mh-common/src/main/java/com/mh/common/utils/CRC16.java

@ -0,0 +1,253 @@
package com.mh.common.utils;
/**
* CRC16_CCITT多项式x16+x12+x5+10x1021初始值0x0000低位在前高位在后结果与0x0000异或
* CRC16_CCITT_FALSE多项式x16+x12+x5+10x1021初始值0xFFFF低位在后高位在前结果与0x0000异或
* CRC16_XMODEM多项式x16+x12+x5+10x1021初始值0x0000低位在后高位在前结果与0x0000异或
* CRC16_X25多项式x16+x12+x5+10x1021初始值0xffff低位在前高位在后结果与0xFFFF异或
* CRC16_MODBUS多项式x16+x15+x2+10x8005初始值0xFFFF低位在前高位在后结果与0x0000异或
* CRC16_IBM多项式x16+x15+x2+10x8005初始值0x0000低位在前高位在后结果与0x0000异或
* CRC16_MAXIM多项式x16+x15+x2+10x8005初始值0x0000低位在前高位在后结果与0xFFFF异或
* CRC16_USB多项式x16+x15+x2+10x8005初始值0xFFFF低位在前高位在后结果与0xFFFF异或
* CRC16_DNP多项式x16+x13+x12+x11+x10+x8+x6+x5+x2+10x3D65初始值0x0000低位在前高位在后结果与0xFFFF异或
* <p>
* 1预置1个16位的寄存器为十六进制FFFF即全为1称此寄存器为CRC寄存器
* 2把第一个8位二进制数据既通讯信息帧的第一个字节与16位的CRC寄存器的低8位相异或把结果放于CRC寄存器高八位数据不变
* 3把CRC寄存器的内容右移一位朝低位用0填补最高位并检查右移后的移出位
* 4如果移出位为0重复第3步再次右移一位如果移出位为1CRC寄存器与多项式A0011010 0000 0000 0001进行异或
* 5重复步骤3和4直到右移8次这样整个8位数据全部进行了处理
* 6重复步骤2到步骤5进行通讯信息帧下一个字节的处理
* 7将该通讯信息帧所有字节按上述步骤计算完成后得到的16位CRC寄存器的高低字节进行交换
* 8最后得到的CRC寄存器内容即为CRC码
* <p>
* 以上计算步骤中的多项式0xA001是0x8005按位颠倒后的结果
* 0x8408是0x1021按位颠倒后的结果
* 在线校验工具
* http://www.ip33.com/crc.html
* https://blog.csdn.net/htmlxx/article/details/17369105
* <p>
* Author:Water
* Time:2018/11/19 0019 15:03
*/
public class CRC16 {
/**
* CRC16_CCITT多项式x16+x12+x5+10x1021初始值0x0000低位在前高位在后结果与0x0000异或
* 0x8408是0x1021按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_CCITT(byte[] buffer) {
int wCRCin = 0x0000;
int wCPoly = 0x8408;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
} else {
wCRCin >>= 1;
}
}
}
// wCRCin=(wCRCin<<8)|(wCRCin>>8);
// wCRCin &= 0xffff;
return wCRCin ^= 0x0000;
}
/**
* CRC-CCITT (0xFFFF)
* CRC16_CCITT_FALSE多项式x16+x12+x5+10x1021初始值0xFFFF低位在后高位在前结果与0x0000异或
*
* @param buffer
* @return
*/
public static int CRC16_CCITT_FALSE(byte[] buffer) {
int wCRCin = 0xffff;
int wCPoly = 0x1021;
for (byte b : buffer) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((wCRCin >> 15 & 1) == 1);
wCRCin <<= 1;
if (c15 ^ bit)
wCRCin ^= wCPoly;
}
}
wCRCin &= 0xffff;
return wCRCin ^= 0x0000;
}
/**
* CRC-CCITT (XModem)
* CRC16_XMODEM多项式x16+x12+x5+10x1021初始值0x0000低位在后高位在前结果与0x0000异或
*
* @param buffer
* @return
*/
public static int CRC16_XMODEM(byte[] buffer) {
int wCRCin = 0x0000; // initial value 65535
int wCPoly = 0x1021; // 0001 0000 0010 0001 (0, 5, 12)
for (byte b : buffer) {
for (int i = 0; i < 8; i++) {
boolean bit = ((b >> (7 - i) & 1) == 1);
boolean c15 = ((wCRCin >> 15 & 1) == 1);
wCRCin <<= 1;
if (c15 ^ bit)
wCRCin ^= wCPoly;
}
}
wCRCin &= 0xffff;
return wCRCin ^= 0x0000;
}
/**
* CRC16_X25多项式x16+x12+x5+10x1021初始值0xffff低位在前高位在后结果与0xFFFF异或
* 0x8408是0x1021按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_X25(byte[] buffer) {
int wCRCin = 0xffff;
int wCPoly = 0x8408;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
} else {
wCRCin >>= 1;
}
}
}
return wCRCin ^= 0xffff;
}
/**
* CRC-16 (Modbus)
* CRC16_MODBUS多项式x16+x15+x2+10x8005初始值0xFFFF低位在前高位在后结果与0x0000异或
* 0xA001是0x8005按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_MODBUS(byte[] buffer) {
int wCRCin = 0xffff;
int POLYNOMIAL = 0xa001;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= POLYNOMIAL;
} else {
wCRCin >>= 1;
}
}
}
return wCRCin ^= 0x0000;
}
/**
* CRC-16
* CRC16_IBM多项式x16+x15+x2+10x8005初始值0x0000低位在前高位在后结果与0x0000异或
* 0xA001是0x8005按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_IBM(byte[] buffer) {
int wCRCin = 0x0000;
int wCPoly = 0xa001;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
} else {
wCRCin >>= 1;
}
}
}
return wCRCin ^= 0x0000;
}
/**
* CRC16_MAXIM多项式x16+x15+x2+10x8005初始值0x0000低位在前高位在后结果与0xFFFF异或
* 0xA001是0x8005按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_MAXIM(byte[] buffer) {
int wCRCin = 0x0000;
int wCPoly = 0xa001;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
} else {
wCRCin >>= 1;
}
}
}
return wCRCin ^= 0xffff;
}
/**
* CRC16_USB多项式x16+x15+x2+10x8005初始值0xFFFF低位在前高位在后结果与0xFFFF异或
* 0xA001是0x8005按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_USB(byte[] buffer) {
int wCRCin = 0xFFFF;
int wCPoly = 0xa001;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
} else {
wCRCin >>= 1;
}
}
}
return wCRCin ^= 0xffff;
}
/**
* CRC16_DNP多项式x16+x13+x12+x11+x10+x8+x6+x5+x2+10x3D65初始值0x0000低位在前高位在后结果与0xFFFF异或
* 0xA6BC是0x3D65按位颠倒后的结果
*
* @param buffer
* @return
*/
public static int CRC16_DNP(byte[] buffer) {
int wCRCin = 0x0000;
int wCPoly = 0xA6BC;
for (byte b : buffer) {
wCRCin ^= ((int) b & 0x00ff);
for (int j = 0; j < 8; j++) {
if ((wCRCin & 0x0001) != 0) {
wCRCin >>= 1;
wCRCin ^= wCPoly;
} else {
wCRCin >>= 1;
}
}
}
return wCRCin ^= 0xffff;
}
}

108
mh-common/src/main/java/com/mh/common/utils/DateUtils.java

@ -37,6 +37,40 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
"yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
"yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
public static String localDateToStr(LocalDateTime timeType) {
return timeType.format(DATE_TIME_FORMATTER);
}
public static String dayOfWeekValue() {
int dayOfWeek = Calendar.getInstance().get(Calendar.DAY_OF_WEEK);
String result = "";
switch (dayOfWeek) {
case Calendar.MONDAY:
result = "星期一";
break;
case Calendar.TUESDAY:
result = "星期二";
break;
case Calendar.WEDNESDAY:
result = "星期三";
break;
case Calendar.THURSDAY:
result = "星期四";
break;
case Calendar.FRIDAY:
result = "星期五";
break;
case Calendar.SATURDAY:
result = "星期六";
break;
case Calendar.SUNDAY:
result = "星期日";
break;
}
return result;
}
/**
* Date 类型的 curTime 转换为 LocalTime
*
@ -437,4 +471,78 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
// 格式化日期
return zonedDateTime.format(formatter);
}
public static boolean isBetween(LocalTime nowTime, LocalTime startTime, LocalTime endTime) {
if (startTime.isBefore(endTime)) {
return !nowTime.isBefore(startTime) && !nowTime.isAfter(endTime);
} else {
// 跨天情况,比如 22:00 - 6:00
return !nowTime.isBefore(startTime) || !nowTime.isAfter(endTime);
}
}
public static Date getStartOfDay(Date curTime) {
if (curTime != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(curTime);
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
return calendar.getTime();
}
return null;
}
public static Date getEndOfDay(Date curTime) {
if (curTime != null) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(curTime);
calendar.set(Calendar.HOUR_OF_DAY, 23);
calendar.set(Calendar.MINUTE, 59);
calendar.set(Calendar.SECOND, 59);
calendar.set(Calendar.MILLISECOND, 999);
return calendar.getTime();
}
return null;
}
public static int dayDiff(String startDate, String endDate) {
try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date start = sdf.parse(startDate);
Date end = sdf.parse(endDate);
long diff = (end.getTime() - start.getTime()) / (24 * 60 * 60 * 1000);
return Math.abs((int) diff) + 1;
} catch (ParseException e) {
return 0;
}
}
public static int monthDiff(String startDate, String endDate) {
try {
if (startDate == null || endDate == null || startDate.isEmpty() || endDate.isEmpty()) {
return 0;
}
LocalDate start = LocalDate.parse(startDate + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDate end = LocalDate.parse(endDate + "-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"));
Period period = Period.between(start, end);
int months = period.getYears() * 12 + period.getMonths();
return Math.abs(months)+1;
} catch (Exception e) {
return 0;
}
}
public static int yearDiff(String startDate, String endDate) {
try {
// startDate和endDate传入的值是“yyyy”
return Math.abs(Integer.parseInt(endDate) - Integer.parseInt(startDate))+1;
} catch (Exception e) {
return 0;
}
}
}

1350
mh-common/src/main/java/com/mh/common/utils/ExchangeStringUtil.java

File diff suppressed because it is too large Load Diff

99
mh-common/src/main/java/com/mh/common/utils/ModbusUtils.java

@ -0,0 +1,99 @@
package com.mh.common.utils;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description Modbus协议工具类
* @date 2025-06-06 14:40:24
*/
@Slf4j
public class ModbusUtils {
public static String createReadOrder(String mtCode, String funCode, String registerAddr, String registerNum) {
// 开始创建指令
// 拼接指令
String sendOrderStr = ExchangeStringUtil.addZeroForNum(mtCode, 2)
+ ExchangeStringUtil.addZeroForNum(funCode, 2)
+ ExchangeStringUtil.addZeroForNum(registerAddr, 4)
+ ExchangeStringUtil.addZeroForNum(registerNum, 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(sendOrderStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
sendOrderStr = sendOrderStr + checkWord;
return sendOrderStr;
}
public static String createControlCode(String mtCode, Integer type, String registerAddr, String param) {
String orderStr;
mtCode = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(mtCode), 2);
registerAddr = ExchangeStringUtil.addZeroForNum(registerAddr, 4);
param = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(param), 4);
orderStr = mtCode + "06" + registerAddr + param;
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(orderStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
// 发送的指令
// log.info("发送指令:{}", orderStr+checkWord);
return orderStr + checkWord;
}
public static ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) {
// byte类型的数据
// String sendStr = "5803004900021914"; // 冷量计
// 申请一个数据结构存储信息
ByteBuf buffer = ctx.alloc().buffer();
// 将信息放入数据结构中
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
return buffer;
}
public static ByteBuf createByteBuf(String sendStr) {
// byte类型的数据
// String sendStr = "5803004900021914"; // 冷量计
// 申请一个数据结构存储信息
ByteBuf buffer = Unpooled.buffer();
// 将信息放入数据结构中
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
return buffer;
}
public static String createTenControlCode(String mtCode, Integer type, String registerAddr, Integer digits, String param) {
// 14 10 01 08 00 02 04 07 08 00 03 7A 22
// 14:地址:mtCode
// 10:功能码
// 01 08:寄存器地址 registerAddr
// 寄存器大小: 00 02
// 04:数据长度
// 07 08:数据值
// 00 03:小数位数 digits
// 7A 22:校验码
String orderStr;
mtCode = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(mtCode), 2);
registerAddr = ExchangeStringUtil.addZeroForNum(registerAddr, 4);
param = String.valueOf(new BigDecimal(param).multiply(BigDecimal.valueOf(Math.pow(10, digits))).intValue());
param = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(param), 4);
String dot = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(String.valueOf(digits)), 4);
orderStr = mtCode + "10" + registerAddr + "0002" + "04" + param + dot;
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(orderStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
// 发送的指令
return orderStr+checkWord;
}
public static void main(String[] args) {
System.out.println(createTenControlCode("20", 1, "0108", 3, "2.1"));
}
}

77
mh-common/src/main/java/com/mh/common/utils/NettyTools.java

@ -0,0 +1,77 @@
package com.mh.common.utils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.Objects;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* @author LJF
* @version 1.0
* @project TAD_Server
* @description 缓存等待数据
* @date 2023/7/4 08:45:16
*/
@Slf4j
public class NettyTools {
/**
* 响应消息缓存
*/
private static final Cache<String, BlockingQueue<String>> responseMsgCache = CacheBuilder.newBuilder()
.maximumSize(500)
.expireAfterWrite(1000, TimeUnit.SECONDS)
.build();
/**
* 等待响应消息
* @param key 消息唯一标识
* @return ReceiveDdcMsgVo
*/
public static boolean waitReceiveMsg(String key) {
try {
//设置超时时间
String vo = Objects.requireNonNull(responseMsgCache.getIfPresent(key))
.poll(1000 * 10, TimeUnit.MILLISECONDS);
//删除key
responseMsgCache.invalidate(key);
return StringUtils.isNotBlank(vo);
} catch (Exception e) {
log.error("获取数据异常,sn={},msg=null",key);
return false;
}
}
/**
* 初始化响应消息的队列
* @param key 消息唯一标识
*/
public static void initReceiveMsg(String key) {
responseMsgCache.put(key,new LinkedBlockingQueue<String>(1));
}
/**
* 设置响应消息
* @param key 消息唯一标识
*/
public static void setReceiveMsg(String key, String msg) {
if(responseMsgCache.getIfPresent(key) != null){
Objects.requireNonNull(responseMsgCache.getIfPresent(key)).add(msg);
return;
}
log.warn("sn {}不存在",key);
}
}

64
mh-common/src/main/java/com/mh/common/utils/SendOrderUtils.java

@ -0,0 +1,64 @@
package com.mh.common.utils;
import com.mh.common.core.domain.entity.CollectionParamsManage;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import lombok.extern.slf4j.Slf4j;
/**
* @author ljf
* @title
* @description 发送指令工具类
* @updateTime 2021-01-26
* @throws
*/
@Slf4j
public class SendOrderUtils {
// 发送所有类型采集报文
public static void sendAllOrder(CollectionParamsManage paramsManage, ChannelHandlerContext ctx, int num, int size) {
// 开始创建指令
String mtCode = paramsManage.getMtCode(); // 采集编号
String funCode = paramsManage.getFuncCode(); // 功能码
String registerAddr = paramsManage.getRegisterAddr(); // 寄存器地址
String registerNum = String.valueOf(paramsManage.getRegisterSize()); // 寄存器数量
// 拼接指令
String sendOrderStr = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(mtCode), 2)
+ ExchangeStringUtil.addZeroForNum(funCode, 2)
+ ExchangeStringUtil.addZeroForNum(registerAddr, 4)
+ ExchangeStringUtil.addZeroForNum(registerNum, 4);
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(sendOrderStr);
int checkNum = CRC16.CRC16_MODBUS(strOrder);
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum));
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2);
sendOrderStr = sendOrderStr + checkWord;
ByteBuf buffer = getByteBuf(ctx, sendOrderStr);
// 发送数据
ctx.channel().writeAndFlush(buffer);
// log.info("sends :" + sendOrderStr + ",num:" + num + ",records:" + size);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
log.error("线程休眠异常", e);
}
}
private static ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) {
// 申请一个数据结构存储信息
ByteBuf buffer = ctx.alloc().buffer();
// 将信息放入数据结构中
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
return buffer;
}
public static void sendOrderToDTU(ChannelHandlerContext ctx, String sendStr) {
ByteBuf buffer = getByteBuf(ctx, sendStr);
// 发送数据
ctx.channel().writeAndFlush(buffer);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
log.error("线程休眠异常", e);
}
}
}

81
mh-common/src/main/java/com/mh/common/utils/file/handle/ExcelFillCellMergeHandler.java

@ -0,0 +1,81 @@
package com.mh.common.utils.file.handle;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddress;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 列合并
* @date 2024-06-03 10:01:07
*/
public class ExcelFillCellMergeHandler implements CellWriteHandler {
private static final String KEY ="%s-%s";
//所有的合并信息都存在了这个map里面
Map<String, Integer> mergeInfo = new HashMap<>();
public ExcelFillCellMergeHandler() {
}
public ExcelFillCellMergeHandler(Map<String, Integer> mergeInfo) {
this.mergeInfo = mergeInfo;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {
}
@Override
public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, WriteCellData<?> cellData, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
//当前行
int curRowIndex = cell.getRowIndex();
//当前列
int curColIndex = cell.getColumnIndex();
Integer num = mergeInfo.get(String.format(KEY, curRowIndex, curColIndex));
if(null != num){
// 合并最后一行 ,列
mergeWithPrevCol(writeSheetHolder, cell, curRowIndex, curColIndex,num);
}
}
public void mergeWithPrevCol(WriteSheetHolder writeSheetHolder, Cell cell, int curRowIndex, int curColIndex, int num) {
Sheet sheet = writeSheetHolder.getSheet();
CellRangeAddress cellRangeAddress = new CellRangeAddress(curRowIndex, curRowIndex, curColIndex, curColIndex + num);
sheet.addMergedRegion(cellRangeAddress);
}
//num从第几列开始增加多少列
// curRowIndex 在第几行进行行合并
// curColIndex 在第几列进行合并
// num 合并多少格
// 比如我上图中中心需要在第三行 从0列开始合并三列 所以我可以传入 (3,0,2)
public void add (int curRowIndex, int curColIndex , int num){
mergeInfo.put(String.format(KEY, curRowIndex, curColIndex),num);
}
}

46
mh-common/src/main/java/com/mh/common/utils/file/handle/ReportSysParamHandler.java

@ -0,0 +1,46 @@
package com.mh.common.utils.file.handle;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Row;
import org.springframework.util.PropertyPlaceholderHelper;
import java.util.List;
import java.util.Properties;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 报表handle
* @date 2024-05-31 17:36:38
*/
public class ReportSysParamHandler implements CellWriteHandler {
private final String title;
PropertyPlaceholderHelper placeholderHelper = new PropertyPlaceholderHelper("${", "}");
public ReportSysParamHandler(String title) {
this.title = title;
}
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
if (head != null) {
List<String> headNameList = head.getHeadNameList();
if (CollectionUtils.isNotEmpty(headNameList)) {
Properties properties = new Properties();
properties.setProperty("deviceType", title);
for (int i = 0; i < headNameList.size(); i++) {
headNameList.set(i, placeholderHelper.replacePlaceholders(headNameList.get(i), properties));
}
}
}
}
}

25
mh-common/src/main/java/com/mh/common/utils/file/handle/RowHeightStyleHandler.java

@ -0,0 +1,25 @@
package com.mh.common.utils.file.handle;
import com.alibaba.excel.write.style.row.AbstractRowHeightStyleStrategy;
import org.apache.poi.ss.usermodel.Row;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 处理行高
* @date 2024-08-09 15:03:37
*/
public class RowHeightStyleHandler extends AbstractRowHeightStyleStrategy {
@Override
protected void setHeadColumnHeight(Row row, int i) {
if (i == 2) {
row.setHeightInPoints(70);
}
}
@Override
protected void setContentColumnHeight(Row row, int i) {
}
}

12
mh-common/src/main/java/com/mh/common/utils/http/HttpUtils.java

@ -69,7 +69,7 @@ public class HttpUtils
try
{
String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
log.info("sendGet - {}", urlNameString);
// log.info("sendGet - {}", urlNameString);
URL realUrl = new URL(urlNameString);
URLConnection connection = realUrl.openConnection();
connection.setRequestProperty("accept", "*/*");
@ -82,7 +82,7 @@ public class HttpUtils
{
result.append(line);
}
log.info("recv - {}", result);
// log.info("recv - {}", result);
}
catch (ConnectException e)
{
@ -131,7 +131,7 @@ public class HttpUtils
StringBuilder result = new StringBuilder();
try
{
log.info("sendPost - {}", url);
// log.info("sendPost - {}", url);
URL realUrl = new URL(url);
URLConnection conn = realUrl.openConnection();
conn.setRequestProperty("accept", "*/*");
@ -150,7 +150,7 @@ public class HttpUtils
{
result.append(line);
}
log.info("recv - {}", result);
// log.info("recv - {}", result);
}
catch (ConnectException e)
{
@ -195,7 +195,7 @@ public class HttpUtils
String urlNameString = url + "?" + param;
try
{
log.info("sendSSLPost - {}", urlNameString);
// log.info("sendSSLPost - {}", urlNameString);
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
URL console = new URL(urlNameString);
@ -221,7 +221,7 @@ public class HttpUtils
result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8));
}
}
log.info("recv - {}", result);
// log.info("recv - {}", result);
conn.disconnect();
br.close();
}

14
mh-framework/src/main/java/com/mh/framework/aspectj/ControlDeviceAspect.java

@ -48,10 +48,10 @@ public class ControlDeviceAspect {
@Before("executionMethod()")
public void controlBefore(JoinPoint joinPoint) {
log.info("前置通知");
// log.info("前置通知");
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
log.info("获取到对应的参数==>{}",arg);
// log.info("获取到对应的参数==>{}",arg);
}
}
@ -68,10 +68,10 @@ public class ControlDeviceAspect {
// Object proceed;
// 获取参数
Object[] args = joinPoint.getArgs();
log.info("注解方法标注值=={}", annotation.value());
log.info("注解方法标注=={}", annotation.isAop());
// log.info("注解方法标注值=={}", annotation.value());
// log.info("注解方法标注=={}", annotation.isAop());
for (Object arg : args) {
log.info("方法内的参数==>{}", arg);
// log.info("方法内的参数==>{}", arg);
if (Objects.isNull(arg)) {
continue;
}
@ -104,10 +104,10 @@ public class ControlDeviceAspect {
}
}
// if (!annotation.isAop()) {
// log.info("你无需处理当前注解内容");
// // log.info("你无需处理当前注解内容");
// proceed = joinPoint.proceed();
// } else {
// log.info("进入aop判断");
// // log.info("进入aop判断");
// proceed = joinPoint.proceed();
//
// }

2
mh-framework/src/main/java/com/mh/framework/aspectj/RateLimiterAspect.java

@ -61,7 +61,7 @@ public class RateLimiterAspect
{
throw new ServiceException("访问过于频繁,请稍候再试");
}
log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
// log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
}
catch (ServiceException e)
{

2
mh-framework/src/main/java/com/mh/framework/datasource/DynamicDataSourceContextHolder.java

@ -23,7 +23,7 @@ public class DynamicDataSourceContextHolder
*/
public static void setDataSourceType(String dsType)
{
log.info("切换到{}数据源", dsType);
// log.info("切换到{}数据源", dsType);
CONTEXT_HOLDER.set(dsType);
}

137
mh-framework/src/main/java/com/mh/framework/dealdata/impl/DataProcessServiceImpl.java

@ -59,7 +59,7 @@ public class DataProcessServiceImpl implements DataProcessService {
}
private void insertTempDataToDb(OneTwoThreeTempData data, String registerKey, String cacheKey) {
log.info("{}数据解析入库:{}", registerKey.equals("SENSOR_REGISTER") ? "温湿度传感器" : "其他设备", data);
// // log.info("{}数据解析入库:{}", registerKey.equals("SENSOR_REGISTER") ? "温湿度传感器" : "其他设备", data);
if (registerKey.equals("SENSOR_REGISTER")) {
databaseMapper.createChillerTable();
} else {
@ -132,7 +132,7 @@ public class DataProcessServiceImpl implements DataProcessService {
}
private void insertData(AdvantechReceiver data, String registerKey, String cacheKey) {
log.info("{}数据解析入库:{}", registerKey.equals("CHILLERS_REGISTER") ? "冷水机组" : "计量设备", data);
// // log.info("{}数据解析入库:{}", registerKey.equals("CHILLERS_REGISTER") ? "冷水机组" : "计量设备", data);
if (registerKey.equals("CHILLERS_REGISTER")) {
databaseMapper.createChillerTable();
} else {
@ -151,31 +151,38 @@ public class DataProcessServiceImpl implements DataProcessService {
}
String timeString = data.getTs();
OffsetDateTime utcDateTime;
try {
// 尝试多种常见的时间格式
String formattedTime = "";
// 判断是否存在TimeZone
if (!timeString.contains("T")) {
formattedTime = timeString;
} else {
OffsetDateTime utcDateTime;
try {
utcDateTime = OffsetDateTime.parse(timeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
} catch (DateTimeParseException e1) {
// 尝试多种常见的时间格式
try {
utcDateTime = OffsetDateTime.parse(timeString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[XXX][XX][X]"));
} catch (DateTimeParseException e2) {
utcDateTime = OffsetDateTime.parse(timeString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[XXX][XX][X]"));
utcDateTime = OffsetDateTime.parse(timeString, DateTimeFormatter.ISO_OFFSET_DATE_TIME);
} catch (DateTimeParseException e1) {
try {
utcDateTime = OffsetDateTime.parse(timeString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[XXX][XX][X]"));
} catch (DateTimeParseException e2) {
utcDateTime = OffsetDateTime.parse(timeString, DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS[XXX][XX][X]"));
}
}
} catch (DateTimeParseException e) {
log.error("时间格式解析异常,时间字符串: {}", timeString, e);
return;
}
} catch (DateTimeParseException e) {
log.error("时间格式解析异常,时间字符串: {}", timeString, e);
return;
// 2. 转换为中国时区(UTC+8)
OffsetDateTime chinaDateTime = utcDateTime.withOffsetSameInstant(
ZoneOffset.ofHours(8)
);
// 3. 格式化为目标字符串
formattedTime = chinaDateTime.format(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
);
}
// 2. 转换为中国时区(UTC+8)
OffsetDateTime chinaDateTime = utcDateTime.withOffsetSameInstant(
ZoneOffset.ofHours(8)
);
// 3. 格式化为目标字符串
String formattedTime = chinaDateTime.format(
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
);
String dString = data.getD().toString();
// 替换掉inf
if (dString.contains("inf")) {
@ -186,7 +193,8 @@ public class DataProcessServiceImpl implements DataProcessService {
for (AdvantechDatas advantechDatas : list) {
String tag = advantechDatas.getTag();
String value = String.valueOf(advantechDatas.getValue());
log.info("时间: {},tag标签: {},value值: {}", formattedTime, tag, value);
String quality = String.valueOf(advantechDatas.getQuality());
// log.info("时间: {},tag标签: {},value值: {}, 质量:{}", formattedTime, tag, value, quality);
try {
if (StringUtils.isBlank(tag)) {
continue;
@ -197,6 +205,7 @@ public class DataProcessServiceImpl implements DataProcessService {
collectionParamsManage = entity;
try {
collectionParamsManage.setCurValue(new BigDecimal(value));
collectionParamsManage.setQuality(quality);
} catch (NumberFormatException e) {
log.error("数值格式解析异常", e);
continue;
@ -223,7 +232,7 @@ public class DataProcessServiceImpl implements DataProcessService {
@Override
public void insertOtherData(AdvantechReceiver data) {
log.info("其他设备数据解析入库:{}", data);
// log.info("其他设备数据解析入库:{}", data);
}
@Override
@ -261,7 +270,7 @@ public class DataProcessServiceImpl implements DataProcessService {
@Override
public void insertDatabase(List<DeviceReport> dataMinList) {
log.info("插入data_min数据,数据大小==>{}", dataMinList.size());
// // log.info("插入data_min数据,数据大小==>{}", dataMinList.size());
Calendar calendar = Calendar.getInstance();
//时间格式化0和5结尾的时间
int batchSize = 10;
@ -435,7 +444,7 @@ public class DataProcessServiceImpl implements DataProcessService {
tableName = tableName + DateUtils.dateToString(data.getCurTime(), "yyyy");
num = dataProcessMapper.selectDataByHH(tableName, data.getCurTime(), data.getDeviceNum());
if (num == 0) {
log.info("插入小时数据:{}", data.toString());
// log.info("插入小时数据:{}", data.toString());
}
break;
}
@ -486,39 +495,7 @@ public class DataProcessServiceImpl implements DataProcessService {
List<CollectionParamsManage> dataList1 = entry1.getValue();
// 进行数据处理入库操作等
try {
List<CollectionParamsManage> dealList = new ArrayList<>();
Map<Date, Optional<CollectionParamsManage>> dateOptionalMap = dealAndInsertChillers(dataList1, mtType);
for (Map.Entry<Date, Optional<CollectionParamsManage>> value : dateOptionalMap.entrySet()) {
boolean present = value.getValue().isPresent();
if (!present) {
continue;
}
dealList.add(value.getValue().get());
}
// 根据时间排序
dealList.sort(Comparator.comparing(CollectionParamsManage::getCurTime));
// 批量插入到chillers_data_min表
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int year = calendar.get(Calendar.YEAR);
String tableName = "chillers_data_min" + year;
for (CollectionParamsManage collectionParamsManage : dealList) {
// 判断是否存在,存在的话就不插入
DeviceReport deviceReport = new DeviceReport();
deviceReport.setDeviceNum(collectionParamsManage.getMtNum());
deviceReport.setCurTime(collectionParamsManage.getCurTime());
if (null != dataProcessMapper.isHaveData(deviceReport, tableName)) {
continue;
}
dataProcessMapper.batchInsertChiller(List.of(collectionParamsManage), tableName);
}
// int batchSize = 10;
// // 分页查询并插入数据
// for (int i = 0; i < cacheList.size(); i += batchSize) {
// List<CollectionParamsManage> batchList = cacheList.subList(i, Math.min(i + batchSize, cacheList.size()));
// // 执行插入语句
// dataProcessMapper.batchInsertChiller(batchList, tableName);
// }
dealAndInsertChillersData(dataList1, mtType);
} catch (Exception e) {
log.error("处理主机参数异常:{}", e);
}
@ -526,6 +503,48 @@ public class DataProcessServiceImpl implements DataProcessService {
}
}
/**
* 处理冷水机组数据并插入数据库每5分钟存储一条数据
* @param dataList 同一设备的数据列表
* @param deviceType 设备类型
*/
private void dealAndInsertChillersData(List<CollectionParamsManage> dataList, String deviceType) {
// 格式化时间点为5分钟间隔,然后取同样时间点的最大值
Map<Date, Optional<CollectionParamsManage>> collect = dataList.stream()
.peek(val -> val.setCurTime(DateUtils.stringToDate(DateUtils.getTimeMin(val.getCurTime(), 5), "yyyy-MM-dd HH:mm:ss")))
.collect(
Collectors.groupingBy(
CollectionParamsManage::getCurTime,
Collectors.maxBy(Comparator.comparing(CollectionParamsManage::getCurValue)))
);
collect = sortMapByDate(collect);
if (collect.isEmpty()) {
return;
}
// 批量插入到chillers_data_min表
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int year = calendar.get(Calendar.YEAR);
String tableName = "chillers_data_min" + year;
// 遍历处理后的数据,插入数据库
for (Map.Entry<Date, Optional<CollectionParamsManage>> entry : collect.entrySet()) {
if (entry.getValue().isPresent()) {
CollectionParamsManage collectionParamsManage = entry.getValue().get();
// 判断是否存在,存在的话就不插入
DeviceReport deviceReport = new DeviceReport();
deviceReport.setDeviceNum(collectionParamsManage.getMtNum());
deviceReport.setCurTime(collectionParamsManage.getCurTime());
if (null != dataProcessMapper.isHaveData(deviceReport, tableName)) {
continue;
}
dataProcessMapper.batchInsertChiller(List.of(collectionParamsManage), tableName);
}
}
}
/**
* 排序
* @param map

2
mh-framework/src/main/java/com/mh/framework/manager/factory/AsyncFactory.java

@ -116,7 +116,7 @@ public class AsyncFactory
public void run()
{
// 远程查询操作地点
log.info("mqtt开启日志记录");
// log.info("mqtt开启日志记录");
}
};
}

4
mh-framework/src/main/java/com/mh/framework/mqtt/handler/InboundMessageRouter.java

@ -44,10 +44,10 @@ public class InboundMessageRouter extends AbstractMessageRouter {
MessageHeaders headers = message.getHeaders();
String topic = Objects.requireNonNull(headers.get(MqttHeaders.RECEIVED_TOPIC)).toString();
// byte[] payload = (byte[]) message.getPayload();
// log.info("从当前主题 topic: {}, 接收到的消息:{}", topic, new String(payload));
// // log.info("从当前主题 topic: {}, 接收到的消息:{}", topic, new String(payload));
// 判断当前主题是否是当前项目的,温湿度目前写死的
if (!topic.startsWith(mHConfig.getName()) && !topic.contains("/temp")) {
log.info("当前主题 topic: {} 不是当前项目的,直接丢弃", topic);
// // log.info("当前主题 topic: {} 不是当前项目的,直接丢弃", topic);
return Collections.singleton(SpringUtils.getBean(ChannelName.DEFAULT_BOUND));
}
// 找到对应的主题消息通道

8
mh-framework/src/main/java/com/mh/framework/mqtt/service/impl/EventsServiceImpl.java

@ -64,7 +64,7 @@ public class EventsServiceImpl implements IEventsService {
@Override
public void handleInboundSend(byte[] receiver, MessageHeaders headers) throws IOException {
String sendStr = new String(receiver, CharsetUtil.UTF_8);
log.info("接收到控制指令下发=>{}", sendStr);
// log.info("接收到控制指令下发=>{}", sendStr);
}
private void handleInboundData(byte[] receiver,String topic, String logMessage) {
@ -72,7 +72,7 @@ public class EventsServiceImpl implements IEventsService {
AdvantechReceiver commonTopicReceiver = new AdvantechReceiver();
if (!topic.contains(Constants.TEMP)) {
commonTopicReceiver = mapper.readValue(receiver, AdvantechReceiver.class);
log.info("主题:{},类型:{}: ,数据:{}", topic, logMessage, commonTopicReceiver.toString());
// // log.info("主题:{},类型:{}: ,数据:{}", topic, logMessage, commonTopicReceiver.toString());
}
// 接入消息队列,利用消息对接进行数据处理
// 判断当前主题属于哪种主动上报数据
@ -88,11 +88,11 @@ public class EventsServiceImpl implements IEventsService {
} else if (topic.contains(Constants.TEMP)) {
// 温湿度数据
OneTwoThreeTempData oneTwoThreeTempData = mapper.readValue(receiver, OneTwoThreeTempData.class);
log.info("主题:{},类型:{}: ,数据:{}", topic, logMessage, oneTwoThreeTempData.toString());
// // log.info("主题:{},类型:{}: ,数据:{}", topic, logMessage, oneTwoThreeTempData.toString());
sendMsgByTopic.sendToTempMQ(JSONObject.toJSONString(oneTwoThreeTempData));
} else {
// 非本地主题处理
log.info("非本地主题处理: {}", topic);
// log.info("非本地主题处理: {}", topic);
}
} catch (IOException e) {
log.error("处理数据时发生错误: ", e);

4
mh-framework/src/main/java/com/mh/framework/mqtt/service/impl/MqttMsgSenderServiceImpl.java

@ -46,7 +46,7 @@ public class MqttMsgSenderServiceImpl implements IMqttMsgSenderService {
synchronized (this) {//注意:这里一定要同步,否则,在多线程publish的情况下,线程会发生死锁,分析见文章最后补充
try {
mqttGatewayService.publish(topic, pushMessage, 0);
log.info("发送主题:{},消息:{}", topic, pushMessage);
// log.info("发送主题:{},消息:{}", topic, pushMessage);
} catch (Exception e) {
log.error("发送主题异常:{},消息:{}", topic, pushMessage, e);
throw new RuntimeException(e);
@ -62,7 +62,7 @@ public class MqttMsgSenderServiceImpl implements IMqttMsgSenderService {
@Override
public void publish(String topic, int qos, CommonTopicResponse response) {
try {
log.info("发送主题:{},消息:{}", topic, response.toString());
// log.info("发送主题:{},消息:{}", topic, response.toString());
mqttGatewayService.publish(topic, mapper.writeValueAsBytes(response), qos);
} catch (JsonProcessingException e) {
log.error("发送主题:{},消息:{}", topic, response.toString(), e);

57
mh-framework/src/main/java/com/mh/framework/netty/EchoServer.java

@ -0,0 +1,57 @@
package com.mh.framework.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class EchoServer {
private final int port;
public EchoServer(int port) {
this.port = port;
}
public void start() {
// 创建EventLoopGroup
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.localAddress(port)
.option(ChannelOption.SO_BACKLOG, 1204)
.childHandler(new ServerChannelInitializer());
// 异步绑定端口
ChannelFuture channelFuture = serverBootstrap.bind();
// 添加监听器处理绑定结果
channelFuture.addListener(future -> {
if (future.isSuccess()) {
// log.info("服务器启动成功,开始监听端口: {}", port);
} else {
log.error("服务器启动失败,端口: {}", port, future.cause());
bossGroup.shutdownGracefully(); // 绑定失败立即关闭资源
workerGroup.shutdownGracefully();
}
});
// ❌ 移除 sync() 阻塞调用
// channelFuture.channel().closeFuture().sync(); --> 删除这行
// 可选:添加 JVM 关闭钩子优雅关闭资源
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
// log.info("JVM 正在关闭,准备释放 Netty 资源...");
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
// log.info("Netty 资源已释放");
}));
}
}

498
mh-framework/src/main/java/com/mh/framework/netty/EchoServerHandler.java

@ -0,0 +1,498 @@
package com.mh.framework.netty;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.mh.common.constant.Constants;
import com.mh.common.core.domain.entity.CollectionParamsManage;
import com.mh.common.core.domain.entity.SysDictData;
import com.mh.common.core.redis.RedisCache;
import com.mh.common.model.request.AdvantechDatas;
import com.mh.common.model.request.AdvantechReceiver;
import com.mh.common.utils.*;
import com.mh.common.utils.spring.SpringUtils;
import com.mh.framework.netty.session.ServerSession;
import com.mh.framework.netty.session.SessionMap;
import com.mh.framework.netty.task.CallbackTask;
//import com.mh.framework.netty.task.CallbackTaskScheduler;
import com.mh.framework.netty.task.CallbackTaskScheduler;
import com.mh.framework.rabbitmq.producer.SendMsgByTopic;
import com.mh.system.service.device.ICollectionParamsManageService;
import com.mh.system.service.device.IGatewayManageService;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
@Slf4j
public class EchoServerHandler extends ChannelInboundHandlerAdapter {
// 调用service层的接口信息
IGatewayManageService gatewayManageService = SpringUtils.getBean(IGatewayManageService.class);
ICollectionParamsManageService collectionParamsManageService = SpringUtils.getBean(ICollectionParamsManageService.class);
SendMsgByTopic sendMsgByTopic = SpringUtils.getBean(SendMsgByTopic.class);
RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
/**
* 空闲次数
*/
private int idleCount = 1;
private int count = 0;
private List<String> orderList;
private int num = 0;
private int size = 0;
private String IP;
private String port;
private String receiveStr = "";
private List<CollectionParamsManage> deviceCodeParamList;
/**
* 客户端连接会触发
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
// log.info("Channel active......");
}
/**
* 超时处理
* 如果120秒没有接受客户端的心跳就触发;
* 如果超过3次则直接关闭;
*/
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
if (obj instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) obj;
if (IdleState.READER_IDLE.equals(event.state())) { //如果读通道处于空闲状态,说明没有接收到心跳命令
// log.info("第{}已经40秒没有接收到客户端的信息了", idleCount);
receiveStr = "";
num = num + 1;
if (num > size - 1) {
num = 0;
// // 关闭连接
// ctx.close();
// 继续发送下一个采集指令
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num),ctx,num,size);
} else {
// 继续发送下一个采集指令
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size);
}
}
} else {
super.userEventTriggered(ctx, obj);
}
}
// 对于每一个传入的消息都要被调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
//接收到服务端发来的数据进行业务处理
ByteBuf buf = (ByteBuf) msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);//复制内容到字节数组bytes
buf.clear();
// 截取IP地址
IP = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", "/", ":");
// 截取端口号
port = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", ":", "");
if (bytes.length <= 1024) {
//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
receiveStr = receiveStr.replace("null", ""); //去null
receiveStr = receiveStr.replace(" ", ""); //去空格
//// log.info("channelRead接收到的数据:" + receiveStr + ",length:" + receiveStr.length());
}
} catch (Exception e) {
log.error("channelRead异常", e);
} finally {
ReferenceCountUtil.release(msg);
}
}
// 当前批量读取中的最后一条消息
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
//心跳包报文: 24 00 60 95
receiveStr = receiveStr.toUpperCase();//返回值全部变成大写
//心跳包处理
if ((receiveStr.length() == 8) && receiveStr.startsWith("24")) {
// 开始进行会话保存
dealSession(ctx);
idleCount = 1;
port = receiveStr.substring(4, 8);//心跳包包含网关端口(自己定义返回心跳包)
// 更新对应的网关在线情况
gatewayManageService.updateGatewayStatus(receiveStr);
//根据端口或者IP或者心跳包查询网关对应的项目名称
// 生成采集指令
if (!SpringUtils.getBean(RedisCache.class).hasKey(receiveStr)) {
collectionParamsManageService.createDtuCollectionParams();
}
JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(receiveStr);
if (StringUtils.isNotNull(arrayCache)) {
deviceCodeParamList = arrayCache.toList(CollectionParamsManage.class);
}
size = deviceCodeParamList.size();
// 清空receiveStr
receiveStr = "";
num = 0;
// 发送采集报文
if (size > 0) {
if (idleCount < 2) {
Thread.sleep(200);
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size);
idleCount++;
} else {
ctx.channel().close();
}
}
} else if (receiveStr.length() == 18) {
// 水电表返回数据解析或者液位传感器数据返回
idleCount = 1;
if (redisCache.hasKey("order_send_read")) {
log.error("order_send_read存在,接收到指令是{}", receiveStr);
if (redisCache.hasKey("order_send_register")) {
Object orderSendRegister = redisCache.getCacheObject("order_send_register");
String orderSendRegisterStr = String.valueOf(orderSendRegister);
// 根据_进行数据转换成数组
// redisCache.setCacheObject("order_send_register",
// collectionParamsManage.getMtCode() + "_"
// + collectionParamsManage.getRegisterAddr() + "_"
// + collectionParamsManage.getRegisterSize() + "_"
// + collectionParamsManage.getParamType() + "_"
// + collectionParamsManage.getDataType() + "_"
// + collectionParamsManage.getOtherName()
// );
String[] split = orderSendRegisterStr.split("_");
CollectionParamsManage collectionParamsManage = new CollectionParamsManage();
collectionParamsManage.setDataType(Integer.valueOf(split[4]));
collectionParamsManage.setParamType(split[3]);
collectionParamsManage.setOtherName(split[5]);
collectionParamsManage.setQuality("0");
analysisReceiveData(receiveStr, collectionParamsManage);
redisCache.deleteObject("order_send_read");
}
} else {
nextSendOrder(ctx);
}
} else if (receiveStr.length() == 12 || receiveStr.length() == 14) {
// 热泵返回数据解析
idleCount = 1;
// log.info("热泵读取接收===>{},长度:{},是否存在order_send_read: {}", receiveStr, receiveStr.length(), redisCache.hasKey("order_send_read"));
if (redisCache.hasKey("order_send_read")) {
log.error("order_send_read存在,接收到指令是{}", receiveStr);
if (redisCache.hasKey("order_send_register")) {
Object orderSendRegister = redisCache.getCacheObject("order_send_register");
String orderSendRegisterStr = String.valueOf(orderSendRegister);
// 根据_进行数据转换成数组
// redisCache.setCacheObject("order_send_register",
// collectionParamsManage.getMtCode() + "_"
// + collectionParamsManage.getRegisterAddr() + "_"
// + collectionParamsManage.getRegisterSize() + "_"
// + collectionParamsManage.getParamType() + "_"
// + collectionParamsManage.getDataType() + "_"
// + collectionParamsManage.getOtherName()
// );
String[] split = orderSendRegisterStr.split("_");
CollectionParamsManage collectionParamsManage = new CollectionParamsManage();
collectionParamsManage.setDataType(Integer.valueOf(split[4]));
collectionParamsManage.setParamType(split[3]);
collectionParamsManage.setOtherName(split[5]);
collectionParamsManage.setQuality("0");
analysisReceiveData(receiveStr, collectionParamsManage);
redisCache.deleteObject("order_send_read");
}
} else {
// 液位控制之类响应返回
if (receiveStr.length() == 12 && "10".equals(receiveStr.substring(2,4))) {
// 液位控制返回数据解析
idleCount = 1;
nextSendOrder(ctx);
controlOrder(ctx);
} else {
nextSendOrder(ctx);
}
}
} else if (receiveStr.length() == 16) {
idleCount = 1;
nextSendOrder(ctx);
// 热泵设置指令返回
controlOrder(ctx);
} else if (receiveStr.length() > 20 && receiveStr.length() < 100) {
idleCount = 1;
// 清空receiveStr
nextSendOrder(ctx);
controlOrder(ctx);
}
ctx.flush();
}
private void controlOrder(ChannelHandlerContext ctx) {
// 热泵设置指令返回
if (redisCache.hasKey("order_send")) {
// 判断是否有指令发送
Object orderSend = redisCache.getCacheObject("order_send");
String orderSendStr = String.valueOf(orderSend);
String orderSendRegisterStr = "";
if (redisCache.hasKey("order_send_register")) {
Object orderSendRegister = redisCache.getCacheObject("order_send_register");
orderSendRegisterStr = String.valueOf(orderSendRegister);
// 根据_进行数据转换成数组
// redisCache.setCacheObject("order_send_register",
// collectionParamsManage.getMtCode() + "_"
// + collectionParamsManage.getRegisterAddr() + "_"
// + collectionParamsManage.getRegisterSize() + "_"
// + collectionParamsManage.getRegisterSize() + "_"
// + collectionParamsManage.getDataType()
// );
String[] split = orderSendRegisterStr.split("_");
orderSendRegisterStr = split[1];
} else {
orderSendRegisterStr = orderSendStr.substring(4, 8);
}
String readOrder = "";
if (receiveStr.contains(orderSendStr)) {
// 发送读取热泵设置温度
readOrder = ModbusUtils.createReadOrder(orderSendStr.substring(0, 2),
"03",
orderSendRegisterStr,
"1");
} else if (receiveStr.substring(0, 8).equals(orderSendStr.substring(0, 8))){
// 发送读取液位设置值
readOrder = ModbusUtils.createReadOrder(orderSendStr.substring(0, 2),
"03",
orderSendRegisterStr,
"2");
}
// 发送读取指令
redisCache.setCacheObject("order_send_read", readOrder, 10, TimeUnit.SECONDS);
ctx.writeAndFlush(ModbusUtils.createByteBuf(readOrder));
// 发送读取指令
log.error("热泵设置读取指令发送:{},order_send_read键值:{}", readOrder, redisCache.hasKey("order_send_read"));
log.error("热泵设置指令返回:{}", receiveStr);
NettyTools.setReceiveMsg("order_wait", receiveStr);
redisCache.deleteObject("order_send");
receiveStr = "";
try {
Thread.sleep(500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
private void dealSession(ChannelHandlerContext ctx) {
// 获取表号
String deviceCode =receiveStr;
String meterNum = deviceCode;
deviceCode = deviceCode + ctx.channel().remoteAddress();
//新的session的创建
ServerSession session = new ServerSession(ctx.channel(), deviceCode);
//进行登录逻辑处理,异步进行处理。并且需要知道 处理的结果。 callbacktask就要
//派上用场了
String finalDeviceCode = deviceCode;
CallbackTaskScheduler.add(new CallbackTask<Boolean>() {
@Override
public Boolean execute() throws Exception {
//进行 login 逻辑的处理
return action(session, finalDeviceCode, ctx);
}
//没有异常的话,我们进行处理
@Override
public void onBack(Boolean result) {
if(result) {
// log.info("设备保存会话: 设备号 = " + session.getSessionId());
//ctx.pipeline().remove(LoginRequestHandler.class); //压测需要放开
} else {
// log.info("设备刷新会话: 设备号 = " + session.getSessionId());
SessionMap.inst().updateSession(finalDeviceCode ,session, meterNum);
//// log.info("设备登录失败: 设备号 = " + session.getSessionId());
//ServerSession.closeSession(ctx);
// 假如说已经在会话中了,直接断开连接
//ctx.close();
}
}
//有异常的话,我们进行处理
@Override
public void onException(Throwable t) {
// log.info("设备登录异常: 设备号 = " + session.getSessionId());
ServerSession.closeSession(ctx);
}
});
}
private void nextSendOrder(ChannelHandlerContext ctx) throws InterruptedException {
// 发送指令响应不用解析
if (receiveStr.length() != 16 && receiveStr.length() < 20) {
// 解析采集的报文,并保存到数据库
analysisReceiveData(receiveStr, deviceCodeParamList.get(num));
}
// 判断是否有远程指令发送,如果有先不采集
if (redisCache.hasKey("order_send")) {
log.error("有远程设置指令发送,不进行采集");
return;
}
// 清空receiveStr
receiveStr = "";
// 判断发送的下标,如果不等于指令数组大小
num = num + 1;
if (num > size - 1) {
num = 0;
Thread.sleep(1000);
// 继续发送下一个采集指令
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size);
// log.info("------一轮采集完成,继续下一轮--------");
} else {
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
if (Constants.WEB_FLAG) {
num = 0;
// 关闭连接
receiveStr = null;
ctx.close();
} else {
Thread.sleep(1000);
// 继续发送下一个采集指令
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size);
}
}
}
private void analysisReceiveData(final String receiveStr, final CollectionParamsManage deviceCodeParamEntity) {
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485();
String analysisData = "";
switch (deviceCodeParamEntity.getParamType()) {
case "16" ->
// 电表
analysisData = analysisReceiveOrder485.analysisMeterOrder485(receiveStr, deviceCodeParamEntity);
case "18" ->
// 水表
analysisData = analysisReceiveOrder485.analysisWaterOrder485(receiveStr, deviceCodeParamEntity);
case "5" ->
// 热泵故障报警
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "2" ->
// 热泵启停控制
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "12" -> {
if (deviceCodeParamEntity.getMtType().equals("8")) {
// 温湿度传感器
analysisData = analysisReceiveOrder485.analysisTempHumiditySensorOrder485(receiveStr, deviceCodeParamEntity);
} else {
// 热泵实际温度
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
}
}
case "14" ->
// 热泵读取温度设置
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "48" ->
// 热泵读取电流
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "11" -> {
// 液位设定值
if (deviceCodeParamEntity.getMtType().equals("11")) {
analysisData = analysisReceiveOrder485.analysisLiquidControlOrder485(receiveStr, deviceCodeParamEntity);
} else {
// 液位计
analysisData = analysisReceiveOrder485.analysisLiquidOrder485(receiveStr, deviceCodeParamEntity);
}
}
case "13" ->
// 压力
analysisData = analysisReceiveOrder485.analysisTempHumiditySensorOrder485(receiveStr, deviceCodeParamEntity);
case "35" ->
// 湿度
analysisData = analysisReceiveOrder485.analysisTempHumiditySensorOrder485(receiveStr, deviceCodeParamEntity);
case "10" -> {
// 液位设定值
if (deviceCodeParamEntity.getMtType().equals("11")) {
// 液位设定值
analysisData = analysisReceiveOrder485.analysisLiquidControlOrder485(receiveStr, deviceCodeParamEntity);
}
}
case "46" -> {
// 液位误差值设置
if (deviceCodeParamEntity.getMtType().equals("11")) {
// 液位误差设定值
analysisData = analysisReceiveOrder485.analysisLiquidControlOrder485(receiveStr, deviceCodeParamEntity);
}
}
default -> {
// log.info("设备类型错误");
return;
}
}
if (analysisData.isEmpty()) {
// log.info("解析数据为空");
return;
}
// 格式化数据,配置成研华网关 AdvantechReceiver
AdvantechReceiver advantechReceiver = new AdvantechReceiver();
advantechReceiver.setTs(DateUtils.dateToString(new Date(), Constants.DATE_FORMAT));
List<AdvantechDatas> advantechDatas = new ArrayList<>();
AdvantechDatas datas = new AdvantechDatas();
datas.setValue(new BigDecimal(analysisData));
datas.setTag(deviceCodeParamEntity.getOtherName());
datas.setQuality(0);
advantechDatas.add(datas);
advantechReceiver.setD(advantechDatas);
// log.error("接收到的指令==》{},发送数据到MQTT==》{}", receiveStr, JSONObject.toJSONString(advantechReceiver));
sendMsgByTopic.sendToDeviceMQ(JSONObject.toJSONString(advantechReceiver));
// 判断otherName的值
if ("2".equals(deviceCodeParamEntity.getGatewayId()) && deviceCodeParamEntity.getOtherName().contains("实际温度")) {
datas = new AdvantechDatas();
advantechDatas.clear();
datas.setValue(new BigDecimal(analysisData));
datas.setTag("贵宾楼水箱-温度");
datas.setQuality(0);
advantechDatas.add(datas);
advantechReceiver.setD(advantechDatas);
sendMsgByTopic.sendToDeviceMQ(JSONObject.toJSONString(advantechReceiver));
}
}
// 异常捕捉
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.getCause().printStackTrace();
// log.info("异常捕捉,执行ctx.close" + cause.getCause());
ctx.close(); // 关闭该Channel
}
// 客户端断开
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
ctx.close();// 关闭流
// log.info("客户端断开,执行ctx.close()......");
}
private boolean action(ServerSession session, String deviceCode, ChannelHandlerContext ctx) {
//user验证
boolean isValidUser = checkUser(deviceCode,session);
session.bind();
return true;
}
private boolean checkUser(String deviceCode,ServerSession session) {
//当前用户已经登录
if(SessionMap.inst().hasLogin(deviceCode)) {
// log.info("设备已经登录: 设备号 = " + deviceCode);
return false;
}
//一般情况下,我们会将 user存储到 DB中,然后对user的用户名和密码进行校验
//但是,我们这边没有进行db的集成,所以我们想一个别的办法进行user的校验。在我们的sessionMap进行以下校验
//为什么选sessionmap,因为我们user的会话,都是存储到sessionmap中的,sessionmap中只要有这个user的会话,说明就是ok的
return true;
}
}

18
mh-framework/src/main/java/com/mh/framework/netty/INettyService.java

@ -0,0 +1,18 @@
package com.mh.framework.netty;
import com.mh.common.core.domain.entity.OrderEntity;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description netty
* @date 2025-06-06 15:13:06
*/
public interface INettyService {
boolean sendOrder(List<OrderEntity> changeValues);
}

147
mh-framework/src/main/java/com/mh/framework/netty/NettyServiceImpl.java

@ -0,0 +1,147 @@
package com.mh.framework.netty;
import com.mh.common.core.domain.AjaxResult;
import com.mh.common.core.domain.entity.CollectionParamsManage;
import com.mh.common.core.domain.entity.GatewayManage;
import com.mh.common.core.domain.entity.OrderEntity;
import com.mh.common.core.redis.RedisCache;
import com.mh.common.core.redis.RedisLock;
import com.mh.common.utils.ModbusUtils;
import com.mh.common.utils.NettyTools;
import com.mh.common.utils.StringUtils;
import com.mh.framework.netty.session.ServerSession;
import com.mh.framework.netty.session.SessionMap;
import com.mh.system.mapper.device.CollectionParamsManageMapper;
import com.mh.system.mapper.device.GatewayManageMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description netty实现类
* @date 2025-06-06 15:13:23
*/
@Slf4j
@Service
public class NettyServiceImpl implements INettyService {
@Resource
private CollectionParamsManageMapper collectionParamsManageMapper;
@Resource
private GatewayManageMapper gatewayManageMapper;
@Resource
private RedisCache redisCache;
@Resource
private RedisLock redisLock;
@Override
public boolean sendOrder(List<OrderEntity> changeValues) {
for (OrderEntity changeValue : changeValues) {
String cpmId = changeValue.getId();
CollectionParamsManage collectionParamsManage = collectionParamsManageMapper.selectById(cpmId);
if (null == collectionParamsManage) {
return false;
}
GatewayManage gatewayManage = gatewayManageMapper.selectById(collectionParamsManage.getGatewayId());
if (null == gatewayManage || StringUtils.isEmpty(gatewayManage.getHeartBeat())) {
return false;
}
ConcurrentHashMap<String, ServerSession> map = SessionMap.inst().getMap();
Set<Map.Entry<String, ServerSession>> entries = map.entrySet();
boolean flag = false;
String keyVal = null;
for (Map.Entry<String, ServerSession> entry : entries) {
String key = entry.getKey();
if (key.contains(gatewayManage.getHeartBeat())){
flag = true;
keyVal = key;
break;
}
}
if (flag) {
ServerSession serverSession = map.get(keyVal);
String controlCode = "";
// 增加了液位控制仪
if ("11".equals(collectionParamsManage.getMtType())) {
controlCode = ModbusUtils.createTenControlCode(collectionParamsManage.getMtCode(),
changeValue.getType(),
collectionParamsManage.getRegisterAddr(),
collectionParamsManage.getDigits(),
changeValue.getParam());
} else {
// 目前只有DTU,modbus方式,只创建modbus先
controlCode = ModbusUtils.createControlCode(collectionParamsManage.getMtCode(),
changeValue.getType(),
collectionParamsManage.getRegisterAddr(),
changeValue.getParam());
}
if (StringUtils.isEmpty(controlCode)) {
log.error("创建控制码失败");
return false;
}
String requestId = UUID.randomUUID().toString(); // 唯一标识当前请求
String lockKey = "lock:order_send:" + gatewayManage.getHeartBeat(); // 按网关分锁
try {
if (!redisLock.tryLock(lockKey, requestId, 10, 10)) {
log.warn("获取锁失败,当前操作繁忙");
return false;
}
// 初始化发送指令
NettyTools.initReceiveMsg("order_wait");
// 设置缓存,方便在netty中判断发送的指令
redisCache.setCacheObject("order_send", controlCode, 10, TimeUnit.SECONDS);
redisCache.setCacheObject("order_send_register",
collectionParamsManage.getMtCode() + "_"
+ collectionParamsManage.getRegisterAddr() + "_"
+ collectionParamsManage.getRegisterSize() + "_"
+ collectionParamsManage.getParamType() + "_"
+ collectionParamsManage.getDataType() + "_"
+ collectionParamsManage.getOtherName()
);
Thread.sleep(500);
// 发送控制指令
// 会话通道
log.error("会话:{},通道:{},id:{}", serverSession, serverSession.getChannel(), serverSession.getSessionId());
serverSession.getChannel().writeAndFlush(ModbusUtils.createByteBuf(controlCode));
// 等待指令
if (NettyTools.waitReceiveMsg("order_wait")) {
// 初始化发送指令
Thread.sleep(3000);
return true;
// if (NettyTools.waitReceiveMsg("order_wait_read")) {
// return true;
// } else {
// log.error("读取指令异常,心跳包:{}", gatewayManage.getHeartBeat());
// return false;
// }
} else {
log.error("发送指令异常,心跳包:{}", gatewayManage.getHeartBeat());
return false;
}
} catch (InterruptedException e) {
log.error("发送指令异常", e);
} finally {
redisLock.unlock(lockKey, requestId);
}
}
log.error("当前设备不在线,心跳包:{}",gatewayManage.getHeartBeat());
return false;
}
return false;
}
}

495
mh-framework/src/main/java/com/mh/framework/netty/NewEchoServerHandler.java

@ -0,0 +1,495 @@
package com.mh.framework.netty;
import com.alibaba.fastjson2.JSONObject;
import com.mh.common.constant.Constants;
import com.mh.common.core.domain.entity.CollectionParamsManage;
import com.mh.common.core.redis.RedisCache;
import com.mh.common.model.request.AdvantechDatas;
import com.mh.common.model.request.AdvantechReceiver;
import com.mh.common.model.response.ParseResult;
import com.mh.common.utils.DateUtils;
import com.mh.common.utils.NettyTools;
import com.mh.common.utils.SendOrderUtils;
import com.mh.common.utils.spring.SpringUtils;
import com.mh.framework.netty.session.ServerSession;
import com.mh.framework.netty.session.SessionMap;
import com.mh.framework.netty.task.CallbackTask;
import com.mh.framework.netty.task.CallbackTaskScheduler;
import com.mh.framework.rabbitmq.producer.SendMsgByTopic;
import com.mh.system.service.device.ICollectionParamsManageService;
import com.mh.system.service.device.IGatewayManageService;
import com.mh.system.service.strategy.DeviceParserFactory;
import com.mh.system.service.strategy.IDeviceParser;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
@Slf4j
public class NewEchoServerHandler extends ChannelInboundHandlerAdapter {
private final IGatewayManageService gatewayManageService = SpringUtils.getBean(IGatewayManageService.class);
private final ICollectionParamsManageService collectionParamsManageService = SpringUtils.getBean(ICollectionParamsManageService.class);
private final SendMsgByTopic sendMsgByTopic = SpringUtils.getBean(SendMsgByTopic.class);
private final RedisCache redisCache = SpringUtils.getBean(RedisCache.class);
private final DeviceParserFactory parserFactory = SpringUtils.getBean(DeviceParserFactory.class);
private int idleCount = 1;
// ✅ 优化1:使用AtomicInteger保证线程安全
private final AtomicInteger num = new AtomicInteger(0);
private volatile int size = 0;
private String receiveStr = "";
private volatile List<CollectionParamsManage> deviceCodeParamList;
// ✅ 优化2:采集状态追踪(用于监控和调试)
private volatile long lastCollectTime = 0;
private volatile int totalCollectCount = 0;
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
log.info("客户端连接: {}", ctx.channel().remoteAddress());
}
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception {
if (obj instanceof IdleStateEvent) {
IdleStateEvent event = (IdleStateEvent) obj;
if (IdleState.READER_IDLE.equals(event.state())) {
log.warn("读取超时,第{}次未收到设备响应", idleCount);
receiveStr = "";
// ✅ 优化3:使用原子操作递增num,避免卡在同一个设备上
incrementNum();
// 检查是否有控制指令正在执行
if (redisCache.hasKey("order_send")) {
log.warn("读取超时且有控制指令在执行,跳过发送采集指令, num={}", num.get());
return;
}
// 继续发送下一个采集指令
sendCollectOrder(ctx);
}
} else {
super.userEventTriggered(ctx, obj);
}
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
ByteBuf buf = (ByteBuf) msg;
byte[] bytes = new byte[buf.readableBytes()];
buf.readBytes(bytes);
buf.clear();
if (bytes.length <= 1024) {
receiveStr = receiveStr + bytesToHexString(bytes);
receiveStr = receiveStr.replace("null", "").replace(" ", "");
}
} catch (Exception e) {
log.error("channelRead异常", e);
} finally {
ReferenceCountUtil.release(msg);
}
}
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
receiveStr = receiveStr.toUpperCase();
try {
if (isHeartbeat(receiveStr)) {
// 处理心跳
handleHeartbeat(ctx);
} else if (shouldParseData(receiveStr)) {
// 处理数据解析
handleDataParsing(ctx);
} else if (isControlResponse(receiveStr)) {
// 处理控制返回
handleControlResponse(ctx);
}
} catch (Exception e) {
log.error("数据处理异常: {}", receiveStr, e);
} finally {
ctx.flush();
}
}
private boolean isHeartbeat(String data) {
return data.length() == 8 && data.startsWith("2400");
}
private boolean shouldParseData(String data) {
return (data.length() == 18 || data.length() == 12 || data.length() == 14)
&& !redisCache.hasKey("order_send_read");
}
private boolean isControlResponse(String data) {
return data.length() == 16 || (data.length() > 20 && data.length() < 100);
}
private void handleHeartbeat(ChannelHandlerContext ctx) throws InterruptedException {
dealSession(ctx);
idleCount = 1;
// String port = receiveStr.substring(4, 8);
gatewayManageService.updateGatewayStatus(receiveStr);
if (!redisCache.hasKey(receiveStr)) {
collectionParamsManageService.createDtuCollectionParams();
}
List<CollectionParamsManage> cachedList = redisCache.getCacheObject(receiveStr);
if (cachedList != null) {
deviceCodeParamList = cachedList;
size = deviceCodeParamList.size();
receiveStr = "";
// ✅ 优化4:心跳包重置num为0
num.set(0);
if (size > 0 && idleCount < 2) {
Thread.sleep(200);
sendCollectOrder(ctx);
idleCount++;
} else {
ctx.channel().close();
}
}
}
private void handleDataParsing(ChannelHandlerContext ctx) throws InterruptedException {
idleCount = 1;
if (redisCache.hasKey("order_send_read") && redisCache.hasKey("order_send_register")) {
handleSpecialReadResponse();
} else {
nextSendOrder(ctx);
}
}
private void handleSpecialReadResponse() {
Object orderSendRegister = redisCache.getCacheObject("order_send_register");
String[] split = String.valueOf(orderSendRegister).split("_");
CollectionParamsManage params = new CollectionParamsManage();
params.setDataType(Integer.valueOf(split[4]));
params.setParamType(split[3]);
params.setOtherName(split[5]);
params.setQuality("0");
parseAndSendData(receiveStr, params);
redisCache.deleteObject("order_send_read");
}
private void handleControlResponse(ChannelHandlerContext ctx) throws InterruptedException {
idleCount = 1;
nextSendOrder(ctx);
controlOrder(ctx);
}
private void nextSendOrder(ChannelHandlerContext ctx) throws InterruptedException {
// 先解析当前接收到的数据(如果不是控制响应)
if (receiveStr.length() != 16 && receiveStr.length() < 20) {
parseAndSendData(receiveStr, deviceCodeParamList.get(num.get()));
}
// 清空接收字符串
receiveStr = "";
// 判断是否有远程指令发送
if (redisCache.hasKey("order_send")) {
log.warn("有远程设置指令发送,暂停采集,但保持num递增以维持轮询顺序, currentNum={}", num.get());
// ✅ 优化5:即使有控制指令,也要递增num,避免数据采集断层
incrementNum();
// 不发送下一个采集指令,等待控制指令完成
return;
}
// 正常情况:递增num并发送下一个采集指令
incrementNum();
sendCollectOrder(ctx);
}
/**
* 核心方法使用策略模式解析数据
*/
private void parseAndSendData(String rawData, CollectionParamsManage params) {
try {
if (!parserFactory.hasParser(params.getParamType(), params.getMtType())) {
log.warn("未找到对应的解析器, paramType: {}", params.getParamType());
return;
}
IDeviceParser parser = parserFactory.getParser(params.getParamType(), params.getMtType());
ParseResult result = parser.parse(rawData, params);
if (!result.isSuccess()) {
log.warn("数据解析失败: {}, 原因: {}", rawData, result.getErrorMessage());
return;
}
sendDataToMQ(result, params);
} catch (Exception e) {
log.error("数据解析异常: {}", rawData, e);
}
}
private void sendDataToMQ(ParseResult result, CollectionParamsManage params) {
AdvantechReceiver receiver = new AdvantechReceiver();
receiver.setTs(DateUtils.dateToString(new Date(), Constants.DATE_FORMAT));
List<AdvantechDatas> dataList = new ArrayList<>();
AdvantechDatas data = new AdvantechDatas();
data.setValue(result.getValue());
data.setTag(result.getTagName());
data.setQuality(result.getQuality());
dataList.add(data);
receiver.setD(dataList);
sendMsgByTopic.sendToDeviceMQ(JSONObject.toJSONString(receiver));
// 特殊业务逻辑:贵宾楼水箱温度
if ("2".equals(params.getGatewayId()) && params.getOtherName().contains("实际温度")) {
sendExtraTemperatureData(result.getValue());
}
}
private void sendExtraTemperatureData(BigDecimal temperature) {
AdvantechReceiver receiver = new AdvantechReceiver();
receiver.setTs(DateUtils.dateToString(new Date(), Constants.DATE_FORMAT));
List<AdvantechDatas> dataList = new ArrayList<>();
AdvantechDatas data = new AdvantechDatas();
data.setValue(temperature);
data.setTag("贵宾楼水箱-温度");
data.setQuality(0);
dataList.add(data);
receiver.setD(dataList);
sendMsgByTopic.sendToDeviceMQ(JSONObject.toJSONString(receiver));
}
private void controlOrder(ChannelHandlerContext ctx) {
if (!redisCache.hasKey("order_send")) {
return;
}
Object orderSend = redisCache.getCacheObject("order_send");
String orderSendStr = String.valueOf(orderSend);
String orderSendRegisterStr = "";
if (redisCache.hasKey("order_send_register")) {
Object orderSendRegister = redisCache.getCacheObject("order_send_register");
String[] split = String.valueOf(orderSendRegister).split("_");
orderSendRegisterStr = split[1];
} else {
orderSendRegisterStr = orderSendStr.substring(4, 8);
}
String readOrder = buildReadOrder(orderSendStr, orderSendRegisterStr);
if (readOrder != null && !readOrder.isEmpty()) {
redisCache.setCacheObject("order_send_read", readOrder, 10, TimeUnit.SECONDS);
ctx.writeAndFlush(com.mh.common.utils.ModbusUtils.createByteBuf(readOrder));
log.info("发送读取指令: {}", readOrder);
NettyTools.setReceiveMsg("order_wait", receiveStr);
redisCache.deleteObject("order_send");
// ⚠ 关键修复:不要在这里清空receiveStr,让后续流程处理
// receiveStr = ""; // 删除这行
try {
Thread.sleep(500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// ✅ 新增:控制指令发送后,立即恢复采集轮询
resumeCollectionAfterControl(ctx);
}
}
/**
* 控制指令完成后恢复数据采集
* 确保num不会因控制指令而停滞
*/
private void resumeCollectionAfterControl(ChannelHandlerContext ctx) {
// ✅ 优化6:递增num到下一个设备
incrementNum();
log.info("控制指令完成,继续采集下一个设备,num={}, totalCollectCount={}", num.get(), totalCollectCount);
// 延迟后发送下一个采集指令
try {
Thread.sleep(500); // 等待控制指令响应稳定
sendCollectOrder(ctx);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("恢复采集中断", e);
}
}
private String buildReadOrder(String orderSendStr, String registerAddr) {
if (receiveStr.contains(orderSendStr)) {
return com.mh.common.utils.ModbusUtils.createReadOrder(
orderSendStr.substring(0, 2), "03", registerAddr, "1"
);
} else if (receiveStr.substring(0, 8).equals(orderSendStr.substring(0, 8))) {
return com.mh.common.utils.ModbusUtils.createReadOrder(
orderSendStr.substring(0, 2), "03", registerAddr, "2"
);
}
return null;
}
private void dealSession(ChannelHandlerContext ctx) {
String deviceCode = receiveStr + ctx.channel().remoteAddress();
String meterNum = receiveStr;
ServerSession session = new ServerSession(ctx.channel(), deviceCode);
CallbackTaskScheduler.add(new CallbackTask<Boolean>() {
@Override
public Boolean execute() throws Exception {
return action(session, deviceCode, ctx);
}
@Override
public void onBack(Boolean result) {
if (result) {
log.info("设备保存会话: {}", session.getSessionId());
} else {
SessionMap.inst().updateSession(deviceCode, session, meterNum);
}
}
@Override
public void onException(Throwable t) {
log.error("设备登录异常: {}", session.getSessionId(), t);
ServerSession.closeSession(ctx);
}
});
}
private boolean action(ServerSession session, String deviceCode, ChannelHandlerContext ctx) {
checkUser(deviceCode, session);
session.bind();
return true;
}
private boolean checkUser(String deviceCode, ServerSession session) {
if (SessionMap.inst().hasLogin(deviceCode)) {
log.warn("设备已经登录: {}", deviceCode);
return false;
}
return true;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
log.error("通道异常", cause);
ctx.close();
}
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.info("客户端断开: {}", ctx.channel().remoteAddress());
ctx.close();
}
private String bytesToHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X", b));
}
return sb.toString();
}
/**
* 优化7原子性地递增num处理循环边界
* 使用CAS操作保证线程安全
*/
private void incrementNum() {
int currentNum;
int nextNum;
do {
currentNum = num.get();
nextNum = currentNum + 1;
if (nextNum >= size) {
nextNum = 0; // 循环回到第一个设备
log.debug("num循环重置: {} -> 0, size={}", currentNum, size);
}
} while (!num.compareAndSet(currentNum, nextNum));
// 更新采集统计
lastCollectTime = System.currentTimeMillis();
totalCollectCount++;
log.debug("num递增: {} -> {}, totalCollectCount={}", currentNum, nextNum, totalCollectCount);
}
/**
* 优化8统一的采集指令发送方法
* 包含边界检查和状态验证
*/
private void sendCollectOrder(ChannelHandlerContext ctx) {
if (deviceCodeParamList == null || deviceCodeParamList.isEmpty()) {
log.warn("设备参数列表为空,无法发送采集指令");
return;
}
int currentIndex = num.get();
if (currentIndex < 0 || currentIndex >= size) {
log.error("num索引越界: {}, size={}, 重置为0", currentIndex, size);
num.set(0);
currentIndex = 0;
}
try {
Thread.sleep(1000); // 控制采集频率
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(currentIndex), ctx, currentIndex, size);
log.debug("发送采集指令: num={}, deviceName={}", currentIndex,
deviceCodeParamList.get(currentIndex).getOtherName());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("发送采集指令中断", e);
} catch (Exception e) {
log.error("发送采集指令异常, num={}", currentIndex, e);
}
}
/**
* 优化9获取当前采集状态用于监控
*/
public CollectionStats getCollectionStats() {
CollectionStats stats = new CollectionStats();
stats.setCurrentNum(num.get());
stats.setSize(size);
stats.setTotalCollectCount(totalCollectCount);
stats.setLastCollectTime(lastCollectTime);
stats.setDeviceCodeParamListSize(deviceCodeParamList != null ? deviceCodeParamList.size() : 0);
return stats;
}
/**
* 采集状态DTO内部类
*/
@lombok.Data
public static class CollectionStats {
private int currentNum;
private int size;
private int totalCollectCount;
private long lastCollectTime;
private int deviceCodeParamListSize;
}
}

33
mh-framework/src/main/java/com/mh/framework/netty/ServerChannelInitializer.java

@ -0,0 +1,33 @@
package com.mh.framework.netty;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.timeout.IdleStateHandler;
import java.util.concurrent.TimeUnit;
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel>{
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline pipeline = socketChannel.pipeline();
/* LineBasedFrameDecoder的工作原理是依次遍历ByteBuf中的可读字节
判断看其是否有\n \r\n 如果有就以此位置为结束位置
从可读索引到结束位置的区间的字节就组成了一行 它是以换行符为结束标志的解码器
支持携带结束符和不带结束符两种解码方式同时支持配置单行的最大长度
如果读到了最大长度之后仍然没有发现换行符则抛出异常同时忽略掉之前读到的异常码流*/
// pipeline.addLast(new LineBasedFrameDecoder(10010));
//字符串解码和编码
//LineBasedFrameDecoder + StringDecoder 就是一个按行切换的文本解码器。
// pipeline.addLast( new StringDecoder());
// pipeline.addLast( new StringEncoder());
// 设置读写超时操作
// 入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式
pipeline.addLast(new IdleStateHandler(40, 40, 40, TimeUnit.SECONDS));
//服务器的逻辑
pipeline.addLast("handler", new EchoServerHandler());
}
}

66
mh-framework/src/main/java/com/mh/framework/netty/session/ServerSession.java

@ -0,0 +1,66 @@
package com.mh.framework.netty.session;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
@Data
@Slf4j
public class ServerSession {
public static final AttributeKey<ServerSession> SESSION_KEY =
AttributeKey.valueOf("SESSION_KEY");
//通道
private Channel channel;
private final String sessionId;
private boolean isLogin = false;
public ServerSession(Channel channel, String deviceCode){
this.channel = channel;
this.sessionId = deviceCode;
}
//session需要和通道进行一定的关联,他是在构造函数中关联上的;
//session还需要通过sessionkey和channel进行再次的关联;channel.attr方法.set当前的
// serverSession
//session需要被添加到我们的SessionMap中
public void bind(){
// log.info("server Session 会话进行绑定 :" + channel.remoteAddress());
channel.attr(SESSION_KEY).set(this);
SessionMap.inst().addSession(sessionId, this);
this.isLogin = true;
}
//通过channel获取session
public static ServerSession getSession(ChannelHandlerContext ctx){
Channel channel = ctx.channel();
return channel.attr(SESSION_KEY).get();
}
//关闭session,新增返回一个meterNum用于纪录设备下线时间2024-05-08
public static String closeSession(ChannelHandlerContext ctx){
String meterNum = null;
ServerSession serverSession = ctx.channel().attr(SESSION_KEY).get();
if(serverSession != null && serverSession.getSessionId() != null) {
ChannelFuture future = serverSession.channel.close();
future.addListener((ChannelFutureListener) future1 -> {
if(!future1.isSuccess()) {
// log.info("Channel close error!");
}
});
ctx.close();
meterNum = serverSession.sessionId;
SessionMap.inst().removeSession(serverSession.sessionId);
// log.info(ctx.channel().remoteAddress()+" "+serverSession.sessionId + "==>移除会话");
}
return meterNum;
}
//写消息
public void writeAndFlush(Object msg) {
channel.writeAndFlush(msg);
}
}

96
mh-framework/src/main/java/com/mh/framework/netty/session/SessionMap.java

@ -0,0 +1,96 @@
package com.mh.framework.netty.session;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
@Data
@Slf4j
public class SessionMap {
private ThreadLocal<Boolean> sceneThreadLocal = new ThreadLocal<>();
//用单例模式进行sessionMap的创建
private SessionMap(){}
private static SessionMap singleInstance = new SessionMap();
public static SessionMap inst() {
return singleInstance;
}
//进行会话的保存
//key 我们使用 sessionId;value 需要是 serverSession
private ConcurrentHashMap<String, ServerSession> map = new ConcurrentHashMap<>(256);
//添加session
public void addSession(String sessionId, ServerSession s) {
map.put(sessionId, s);
// log.info("IP地址:"+s.getChannel().remoteAddress()+" "+ sessionId + " 表具上线,总共表具:" + map.size());
}
//删除session
public void removeSession(String sessionId) {
if(map.containsKey(sessionId)) {
ServerSession s = map.get(sessionId);
map.remove(sessionId);
// log.info("设备id下线:{},在线设备:{}", s.getSessionId(), map.size() );
}
return;
}
public boolean hasLogin(String sessionId) {
Iterator<Map.Entry<String, ServerSession>> iterator = map.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry<String, ServerSession> next = iterator.next();
if(sessionId != null && sessionId.equalsIgnoreCase(next.getValue().getSessionId())) {
return true ;
}
}
return false;
}
//如果在线,肯定有sessionMap里保存的 serverSession
//如果不在线,serverSession也没有。用这个来判断是否在线
public List<ServerSession> getSessionBy(String sessionId) {
return map.values().stream().
filter(s -> s.getSessionId().equals(sessionId)).
collect(Collectors.toList());
}
public boolean getScene() {
return sceneThreadLocal.get();
}
public void initScene(Boolean status) {
if (sceneThreadLocal == null) {
// log.info("======创建ThreadLocal======");
sceneThreadLocal = new ThreadLocal<>();
}
// log.info("设置状态==>" + status);
sceneThreadLocal.set(status);
}
public void clearScene() {
initScene(null);
sceneThreadLocal.remove();
}
public void updateSession(String sessionId, ServerSession session, String meterNum) {
Iterator<Map.Entry<String, ServerSession>> iterator = map.entrySet().iterator();
while(iterator.hasNext()) {
Map.Entry<String, ServerSession> next = iterator.next();
if (next.getKey().contains(meterNum)){
iterator.remove();
}
if(sessionId != null && sessionId.equalsIgnoreCase(next.getValue().getSessionId())) {
next.setValue(session);
}
}
}
}

20
mh-framework/src/main/java/com/mh/framework/netty/task/CallbackTask.java

@ -0,0 +1,20 @@
package com.mh.framework.netty.task;
/**
* @author LJF
* @version 1.0
* @project TAD_Server
* @description 回调任务
* @date 2023/7/3 15:34:11
*/
public interface CallbackTask<T> {
T execute() throws Exception;
/**
* // 执行没有 异常的情况下的 返回值
* @param t
*/
void onBack(T t);
void onException(Throwable t);
}

78
mh-framework/src/main/java/com/mh/framework/netty/task/CallbackTaskScheduler.java

@ -0,0 +1,78 @@
package com.mh.framework.netty.task;
import com.google.common.util.concurrent.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* @author LJF
* @version 1.0
* @project TAD_Server
* @description 回调任务
* @date 2023/7/3 15:34:11
*/
public class CallbackTaskScheduler extends Thread {
private final BlockingQueue<CallbackTask> executeTaskQueue =
new LinkedBlockingQueue<>();
private final ExecutorService pool = Executors.newCachedThreadPool();
private final ListeningExecutorService lpool = MoreExecutors.listeningDecorator(pool);
private static CallbackTaskScheduler inst = new CallbackTaskScheduler();
private final AtomicBoolean running = new AtomicBoolean(true);
private CallbackTaskScheduler() {
this.start();
}
//add task
public static <T> void add(CallbackTask<T> executeTask) {
inst.executeTaskQueue.offer(executeTask);
}
@Override
public void run() {
while (running.get()) {
handleTask();
}
}
/**
* 停止调度器
*/
public static void shutdown() {
inst.running.set(false);
inst.pool.shutdown();
}
//任务执行
private void handleTask() {
try {
// 使用 take() 阻塞等待,直到有任务
CallbackTask executeTask = executeTaskQueue.take();
handleTask(executeTask);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private <T> void handleTask(CallbackTask<T> executeTask) {
ListenableFuture<T> future = lpool.submit(new Callable<T>() {
public T call() throws Exception {
return executeTask.execute();
}
});
Futures.addCallback(future, new FutureCallback<T>() {
@Override
public void onSuccess(T t) {
executeTask.onBack(t);
}
@Override
public void onFailure(Throwable throwable) {
executeTask.onException(throwable);
}
}, lpool);
}
}

6
mh-framework/src/main/java/com/mh/framework/netty/task/ExecuteTask.java

@ -0,0 +1,6 @@
package com.mh.framework.netty.task;
//不需要知道异步线程的 返回值
public interface ExecuteTask {
void execute();
}

67
mh-framework/src/main/java/com/mh/framework/netty/task/FutureTaskScheduler.java

@ -0,0 +1,67 @@
package com.mh.framework.netty.task;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* @author LJF
* @version 1.0
* @project TAD_Server
* @description 任务定时
* @date 2023/7/3 15:34:11
*/
public class FutureTaskScheduler extends Thread{
private ConcurrentLinkedQueue<ExecuteTask> executeTaskQueue =
new ConcurrentLinkedQueue<>();
private long sleepTime = 200;
private ExecutorService pool = Executors.newFixedThreadPool(10);
private static FutureTaskScheduler inst = new FutureTaskScheduler();
public FutureTaskScheduler() {
this.start();
}
//任务添加
public static void add(ExecuteTask executeTask) {
inst.executeTaskQueue.add(executeTask);
}
@Override
public void run() {
while (true) {
handleTask();
//threadSleep(sleepTime);
}
}
private void threadSleep(long sleepTime) {
try {
Thread.sleep(sleepTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//执行任务
private void handleTask() {
ExecuteTask executeTask;
while (executeTaskQueue.peek() != null) {
executeTask = executeTaskQueue.poll();
handleTask(executeTask);
}
//刷新心跳时间
}
private void handleTask(ExecuteTask executeTask) {
pool.execute(new ExecuteRunnable(executeTask));
}
class ExecuteRunnable implements Runnable {
ExecuteTask executeTask;
public ExecuteRunnable(ExecuteTask executeTask) {
this.executeTask = executeTask;
}
@Override
public void run() {
executeTask.execute();
}
}
}

8
mh-framework/src/main/java/com/mh/framework/rabbitmq/consumer/ReceiveHandler.java

@ -56,7 +56,7 @@ public class ReceiveHandler {
try {
//TODO 开启多线程处理主机数据,如果不通过线程池开启线程来处理,
// 设置SimpleRabbitListenerContainerFactory中的setConcurrentConsumers(10)数量也可以实现多线程处理
log.info("MQ消费者:主机数据采集:{}", msg);
// // log.info("MQ消费者:主机数据采集:{}", msg);
//TODO 数据解析入库操作 msg转成实体类,入库
AdvantechReceiver chillerData = JSONObject.parseObject(msg, AdvantechReceiver.class);
dataProcessService.insertChillerData(chillerData);
@ -89,7 +89,7 @@ public class ReceiveHandler {
public void receiveDeviceData(@Payload String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws InterruptedException, IOException {
try {
//TODO 处理电表等数据
log.info("MQ消费者:计量设备数据采集:{}", msg);
// // log.info("MQ消费者:计量设备数据采集:{}", msg);
//TODO 数据解析入库操作 msg转成实体类,入库
AdvantechReceiver deviceData = JSONObject.parseObject(msg, AdvantechReceiver.class);
dataProcessService.insertDeviceData(deviceData);
@ -121,7 +121,7 @@ public class ReceiveHandler {
))
public void receiveOtherData(@Payload String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws InterruptedException, IOException {
try {
log.info("MQ消费者:其他设备采集:{}", msg);
// // log.info("MQ消费者:其他设备采集:{}", msg);
//TODO 数据解析入库操作 msg转成实体类,入库
AdvantechReceiver OtherData = JSONObject.parseObject(msg, AdvantechReceiver.class);
dataProcessService.insertOtherData(OtherData);
@ -152,7 +152,7 @@ public class ReceiveHandler {
))
public void receiveTempData(@Payload String msg, Channel channel, @Header(AmqpHeaders.DELIVERY_TAG) long tag) throws InterruptedException, IOException {
try {
log.info("MQ消费者:温湿度设备采集:{}", msg);
// // log.info("MQ消费者:温湿度设备采集:{}", msg);
//TODO 数据解析入库操作 msg转成实体类,入库
OneTwoThreeTempData oneTwoThreeTempData = JSONObject.parseObject(msg, OneTwoThreeTempData.class);
dataProcessService.insertTempData(oneTwoThreeTempData);

6
mh-framework/src/main/java/com/mh/framework/web/service/UserDetailsServiceImpl.java

@ -37,13 +37,13 @@ public class UserDetailsServiceImpl implements UserDetailsService {
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser user = userService.selectUserByUserName(username);
if (StringUtils.isNull(user)) {
log.info("登录用户:{} 不存在.", username);
// log.info("登录用户:{} 不存在.", username);
throw new ServiceException(MessageUtils.message("user.not.exists"));
} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
log.info("登录用户:{} 已被删除.", username);
// log.info("登录用户:{} 已被删除.", username);
throw new ServiceException(MessageUtils.message("user.password.delete"));
} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
log.info("登录用户:{} 已被停用.", username);
// log.info("登录用户:{} 已被停用.", username);
throw new ServiceException(MessageUtils.message("user.blocked"));
}

2
mh-quartz/src/main/java/com/mh/quartz/task/CreateAlarmTask.java

@ -48,7 +48,7 @@ public class CreateAlarmTask {
}
public void createAlarmTask() {
log.info("创建报警记录");
// log.info("创建报警记录");
// 查询仪表报警规则记录,查看哪些规则启用了
List<AlarmRules> alarmRules = alarmRulesService.selectAlarmRulesListByStatus(0);
// 循环查询报警规则,判断是否满足报警条件

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save