Compare commits

...

10 Commits

  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. 20
      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. 20
      mh-admin/src/main/java/com/mh/web/controller/monitor/HotWaterMonitorController.java
  7. 18
      mh-admin/src/main/java/com/mh/web/controller/space/BuildingInfoController.java
  8. 5
      mh-admin/src/main/java/com/mh/web/controller/space/SpaceController.java
  9. 30
      mh-admin/src/main/resources/application-dev.yml
  10. 30
      mh-admin/src/main/resources/application-prod.yml
  11. 14
      mh-admin/src/main/resources/application-test.yml
  12. 2
      mh-admin/src/main/resources/logback.xml
  13. 7
      mh-common/pom.xml
  14. 28
      mh-common/src/main/java/com/mh/common/config/wechat/RestTemplateConfig.java
  15. 94
      mh-common/src/main/java/com/mh/common/config/wechat/WechatMpConfig.java
  16. 62
      mh-common/src/main/java/com/mh/common/config/wechat/WechatSignUtil.java
  17. 25
      mh-common/src/main/java/com/mh/common/constant/EnergyType.java
  18. 68
      mh-common/src/main/java/com/mh/common/core/domain/dto/DataResultDTO.java
  19. 10
      mh-common/src/main/java/com/mh/common/core/domain/dto/HotWaterNowDataDTO.java
  20. 13
      mh-common/src/main/java/com/mh/common/core/domain/entity/AlarmRecords.java
  21. 46
      mh-common/src/main/java/com/mh/common/core/domain/entity/AnalysisMonth.java
  22. 27
      mh-common/src/main/java/com/mh/common/core/domain/entity/AnalysisYear.java
  23. 81
      mh-common/src/main/java/com/mh/common/core/domain/entity/CollectionParamsManage.java
  24. 8
      mh-common/src/main/java/com/mh/common/core/domain/entity/CpmSpaceRelation.java
  25. 84
      mh-common/src/main/java/com/mh/common/core/domain/entity/DeviceState.java
  26. 89
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyDay.java
  27. 74
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyDaySum.java
  28. 220
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyHour.java
  29. 89
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyMonth.java
  30. 74
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyMonthSum.java
  31. 89
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyYear.java
  32. 74
      mh-common/src/main/java/com/mh/common/core/domain/entity/EnergyYearSum.java
  33. 9
      mh-common/src/main/java/com/mh/common/core/domain/entity/GatewayManage.java
  34. 15
      mh-common/src/main/java/com/mh/common/core/domain/entity/HouseInfo.java
  35. 117
      mh-common/src/main/java/com/mh/common/core/domain/entity/WaterLevel.java
  36. 117
      mh-common/src/main/java/com/mh/common/core/domain/entity/WaterTemp.java
  37. 35
      mh-common/src/main/java/com/mh/common/core/domain/wechat/First.java
  38. 35
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key1.java
  39. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key2.java
  40. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key3.java
  41. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key4.java
  42. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Key5.java
  43. 115
      mh-common/src/main/java/com/mh/common/core/domain/wechat/PushMsgEntity.java
  44. 36
      mh-common/src/main/java/com/mh/common/core/domain/wechat/Remark.java
  45. 70
      mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatTemplate.java
  46. 52
      mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatTemplateProject.java
  47. 172
      mh-common/src/main/java/com/mh/common/core/domain/wechat/WechatUserInfo.java
  48. 63
      mh-common/src/main/java/com/mh/common/core/redis/RedisLock.java
  49. 5
      mh-common/src/main/java/com/mh/common/model/request/AdvantechDatas.java
  50. 346
      mh-common/src/main/java/com/mh/common/utils/AnalysisReceiveOrder485.java
  51. 1
      mh-common/src/main/java/com/mh/common/utils/BigDecimalUtils.java
  52. 253
      mh-common/src/main/java/com/mh/common/utils/CRC16.java
  53. 69
      mh-common/src/main/java/com/mh/common/utils/DateUtils.java
  54. 1350
      mh-common/src/main/java/com/mh/common/utils/ExchangeStringUtil.java
  55. 67
      mh-common/src/main/java/com/mh/common/utils/ModbusUtils.java
  56. 77
      mh-common/src/main/java/com/mh/common/utils/NettyTools.java
  57. 64
      mh-common/src/main/java/com/mh/common/utils/SendOrderUtils.java
  58. 12
      mh-common/src/main/java/com/mh/common/utils/http/HttpUtils.java
  59. 14
      mh-framework/src/main/java/com/mh/framework/aspectj/ControlDeviceAspect.java
  60. 2
      mh-framework/src/main/java/com/mh/framework/aspectj/RateLimiterAspect.java
  61. 2
      mh-framework/src/main/java/com/mh/framework/datasource/DynamicDataSourceContextHolder.java
  62. 23
      mh-framework/src/main/java/com/mh/framework/dealdata/impl/DataProcessServiceImpl.java
  63. 2
      mh-framework/src/main/java/com/mh/framework/manager/factory/AsyncFactory.java
  64. 4
      mh-framework/src/main/java/com/mh/framework/mqtt/handler/InboundMessageRouter.java
  65. 8
      mh-framework/src/main/java/com/mh/framework/mqtt/service/impl/EventsServiceImpl.java
  66. 4
      mh-framework/src/main/java/com/mh/framework/mqtt/service/impl/MqttMsgSenderServiceImpl.java
  67. 57
      mh-framework/src/main/java/com/mh/framework/netty/EchoServer.java
  68. 428
      mh-framework/src/main/java/com/mh/framework/netty/EchoServerHandler.java
  69. 18
      mh-framework/src/main/java/com/mh/framework/netty/INettyService.java
  70. 135
      mh-framework/src/main/java/com/mh/framework/netty/NettyServiceImpl.java
  71. 33
      mh-framework/src/main/java/com/mh/framework/netty/ServerChannelInitializer.java
  72. 66
      mh-framework/src/main/java/com/mh/framework/netty/session/ServerSession.java
  73. 96
      mh-framework/src/main/java/com/mh/framework/netty/session/SessionMap.java
  74. 20
      mh-framework/src/main/java/com/mh/framework/netty/task/CallbackTask.java
  75. 78
      mh-framework/src/main/java/com/mh/framework/netty/task/CallbackTaskScheduler.java
  76. 6
      mh-framework/src/main/java/com/mh/framework/netty/task/ExecuteTask.java
  77. 67
      mh-framework/src/main/java/com/mh/framework/netty/task/FutureTaskScheduler.java
  78. 8
      mh-framework/src/main/java/com/mh/framework/rabbitmq/consumer/ReceiveHandler.java
  79. 6
      mh-framework/src/main/java/com/mh/framework/web/service/UserDetailsServiceImpl.java
  80. 2
      mh-quartz/src/main/java/com/mh/quartz/task/CreateAlarmTask.java
  81. 2
      mh-quartz/src/main/java/com/mh/quartz/task/DealDataTask.java
  82. 2
      mh-quartz/src/main/java/com/mh/quartz/task/DealOnOrOffData.java
  83. 291
      mh-quartz/src/main/java/com/mh/quartz/task/HotWaterTask.java
  84. 168
      mh-quartz/src/main/java/com/mh/quartz/task/PushDataToWechatTask.java
  85. 26
      mh-system/src/main/java/com/mh/system/mapper/WechatMapper.java
  86. 40
      mh-system/src/main/java/com/mh/system/mapper/device/CollectionParamsManageMapper.java
  87. 2
      mh-system/src/main/java/com/mh/system/mapper/device/DataProcessMapper.java
  88. 13
      mh-system/src/main/java/com/mh/system/mapper/device/DeviceLedgerMapper.java
  89. 22
      mh-system/src/main/java/com/mh/system/mapper/device/DeviceStateMapper.java
  90. 2
      mh-system/src/main/java/com/mh/system/mapper/device/GatewayManageMapper.java
  91. 56
      mh-system/src/main/java/com/mh/system/mapper/energy/AnalysisMapper.java
  92. 28
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyDayMapper.java
  93. 22
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyDaySumMapper.java
  94. 27
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyHourMapper.java
  95. 28
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyMonthMapper.java
  96. 23
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyMonthSumMapper.java
  97. 27
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyYearMapper.java
  98. 24
      mh-system/src/main/java/com/mh/system/mapper/energy/EnergyYearSumMapper.java
  99. 125
      mh-system/src/main/java/com/mh/system/mapper/energy/HotEnergyQueryMapper.java
  100. 102
      mh-system/src/main/java/com/mh/system/mapper/energy/WaterLevelMapper.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));
}
}

20
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 {
// 判断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);
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);
}
}

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);
}
}

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/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" />

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;
}
}

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();
}
}

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

@ -22,10 +22,16 @@ public class HotWaterNowDataDTO {
private String waterTemp; //水箱水温
private String runState; //运行状态
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泵状态

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;
}

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;
}

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

@ -0,0 +1,74 @@
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_sum")
public class EnergyDaySum {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
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;
}

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;
}

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

@ -0,0 +1,74 @@
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_sum")
public class EnergyMonthSum {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
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/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;
}

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

@ -0,0 +1,74 @@
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_sum")
public class EnergyYearSum {
@TableId(value = "id", type = IdType.ASSIGN_UUID)
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;
}

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)

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();
}
}

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);
}
}
}

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;
}

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

@ -0,0 +1,346 @@
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 "";
}
}

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;
}
}

69
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,39 @@ 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;
}
}

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

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,67 @@
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;
/**
* @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(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;
}
}

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);
}
}
}

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);
}

23
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,6 +151,11 @@ public class DataProcessServiceImpl implements DataProcessService {
}
String timeString = data.getTs();
String formattedTime = "";
// 判断是否存在TimeZone
if (!timeString.contains("T")) {
formattedTime = timeString;
} else {
OffsetDateTime utcDateTime;
try {
// 尝试多种常见的时间格式
@ -173,9 +178,11 @@ public class DataProcessServiceImpl implements DataProcessService {
);
// 3. 格式化为目标字符串
String formattedTime = chinaDateTime.format(
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;
}

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 资源已释放");
}));
}
}

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

@ -0,0 +1,428 @@
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();//返回值全部变成大写
// log.info("channelReadComplete接收到的数据{}, 长度: ===> {}", receiveStr, receiveStr.length());
//心跳包处理
if ((receiveStr.length() == 8) && receiveStr.startsWith("24")) {
// if ((receiveStr.length() == 8) && receiveStr.startsWith("C0A801FE")) {
// log.info("接收到心跳包 ===> {}", receiveStr);
// 开始进行会话保存
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();
// // log.info("deviceCodeParam size ===> {}", 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 {
// log.info("gateway not find deviceCodeParam!");
}
} else if (receiveStr.length() == 18) {
// 水电表返回数据解析
idleCount = 1;
// log.info("水电表、热泵设置接收==>{},长度:{}", receiveStr, receiveStr.length());
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 {
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 controlCode = ModbusUtils.createReadOrder(orderSendStr.substring(0, 2),
// "03",
// "0003",
// "1");
// SendOrderUtils.sendOrderToDTU(ctx, controlCode);
if (receiveStr.contains(orderSendStr)) {
String readOrder = ModbusUtils.createReadOrder(orderSendStr.substring(0, 2),
"03",
orderSendRegisterStr,
"1");
// 初始化发送指令
// NettyTools.initReceiveMsg("order_wait_read");
// 发送读取指令
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" ->
// 热泵实际温度
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "14" ->
// 热泵读取温度设置
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "48" ->
// 热泵读取电流
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity);
case "11" ->
// 液位计
analysisData = analysisReceiveOrder485.analysisLiquidOrder485(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));
}
// 异常捕捉
@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);
}

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

@ -0,0 +1,135 @@
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);
// 目前只有DTU,modbus方式,只创建modbus先
String 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);
// 发送控制指令
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;
}
}

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);
// 循环查询报警规则,判断是否满足报警条件

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

@ -272,7 +272,7 @@ public class DealDataTask {
.sorted(Comparator.comparing(temMap -> temMap.keySet().iterator().next()))
.collect(Collectors.toList());
//计算上次值,当前值
log.info("计算小时表数据:{}", sortedList);
// // log.info("计算小时表数据:{}", sortedList);
hourList = calcListData(hourList, key, "hour", sortedList);
}
//批量插入小时报表

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

@ -22,7 +22,7 @@ public class DealOnOrOffData {
}
public void dealDeviceLedger() {
log.info("处理设备在线状态数据");
// log.info("处理设备在线状态数据");
deviceLedgerService.updateDeviceLedgerStatus();
}

291
mh-quartz/src/main/java/com/mh/quartz/task/HotWaterTask.java

@ -0,0 +1,291 @@
package com.mh.quartz.task;
import com.mh.common.constant.EnergyType;
import com.mh.common.core.domain.entity.DataMonth;
import com.mh.common.utils.StringUtils;
import com.mh.system.service.device.IDeviceLedgerService;
import com.mh.system.service.energy.IEnergyQueryService;
import com.mh.system.service.energy.IWaterLevelService;
import com.mh.system.service.energy.IWaterTempService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 生活热水供水系统定时器
* @date 2025-06-17 16:12:04
*/
@Slf4j
@Component("hotWaterTask")
public class HotWaterTask {
@Resource
private IDeviceLedgerService deviceLedgerService;
@Resource
private IEnergyQueryService energyQueryService;
@Resource
private IWaterTempService waterTempService;
@Resource
private IWaterLevelService waterLevelService;
private boolean createOrUpdateDeviceState = false;
// 计算能耗表
private boolean calcEnergyState = false;
// 计算楼层能耗数据
private boolean calcFloorEnergyState = false;
// 计算热水温度状态
private boolean calcWaterTempState = false;
// 计算水箱水位
private boolean calcWaterLevelState = false;
// 计算数据分析
private boolean calcAnalysisState = false;
/**
* 定时数据分析
* @param lastHourTime
*/
public void calcAnalysisData(String lastHourTime) {
try {
if (!calcAnalysisState) {
calcAnalysisState = true;
if (StringUtils.isEmpty(lastHourTime)) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime lastHour = now.minusHours(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
lastHourTime = lastHour.format(formatter);
}
energyQueryService.calcAnalysisData(lastHourTime);
}
} catch (Exception e) {
log.error("计算数据分析", e);
calcAnalysisState = false;
} finally {
calcAnalysisState = false;
}
}
/**
* 定时计算水箱水位插入到存储表中
*/
public void calcWaterLevel() {
try {
if (!calcWaterLevelState) {
calcWaterLevelState = true;
waterLevelService.calcWaterLevel();
}
} catch (Exception e) {
log.error("计算水箱水位失败", e);
calcWaterLevelState = false;
} finally {
calcWaterLevelState = false;
}
}
/**
* 新增或者更新设备状态表
*/
public void createOrUpdateDeviceState() {
try {
if (!createOrUpdateDeviceState) {
createOrUpdateDeviceState = true;
deviceLedgerService.createOrUpdateDeviceState();
}
} catch (Exception e) {
log.error("新增或者更新设备状态表失败", e);
createOrUpdateDeviceState = false;
} finally {
createOrUpdateDeviceState = false;
}
}
/**
* 定时计算水温度插入到存储表中
*/
public void calcWaterTemp() {
try {
if (!calcWaterTempState) {
calcWaterTempState = true;
waterTempService.calcWaterTemp();
}
} catch (Exception e) {
log.error("计算水温度失败", e);
calcWaterTempState = false;
} finally {
calcWaterTempState = false;
}
}
/**
* 定时计算楼层能耗数据
* @param lastHourTime
*/
public void calcFloorEnergyData(String lastHourTime) {
try {
if (!calcFloorEnergyState) {
calcFloorEnergyState = true;
if (StringUtils.isEmpty(lastHourTime)) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime lastHour = now.minusHours(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
lastHourTime = lastHour.format(formatter);
}
energyQueryService.calcFloorEnergyDataDetail(lastHourTime);
}
} catch (Exception e) {
log.error("计算楼层能耗数据失败", e);
calcFloorEnergyState = false;
} finally {
calcFloorEnergyState = false;
}
}
/**
* 定时计算能耗数据任务
* @param lastHourTime
*/
public void calcEnergyData(String lastHourTime) {
try {
if (!calcEnergyState) {
calcEnergyState = true;
calcEnergyDataDetail(lastHourTime);
}
} catch (Exception e) {
log.error("计算能耗表失败", e);
calcEnergyState = false;
} finally {
calcEnergyState = false;
}
}
/**
* 计算能耗表
*/
public void calcEnergyDataDetail(String lastHourTime) {
//TODO 1、查询sql获取对应计算的楼层id、楼层名称用来当作楼栋id和楼栋名称
List<Map<String, Object>> floorInfos = energyQueryService.queryFloorInfo();
// 开始遍历
if (StringUtils.isEmpty(lastHourTime)) {
LocalDateTime now = LocalDateTime.now();
LocalDateTime lastHour = now.minusHours(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:00:00");
lastHourTime = lastHour.format(formatter);
}
String tableName = "data_hour" + lastHourTime.substring(0, 4);
List<Map<String, Double>> hourList = new ArrayList<>();
List<Map<String, Double>> dayList = new ArrayList<>();
List<Map<String, Double>> monthList = new ArrayList<>();
List<Map<String, Double>> yearList = new ArrayList<>();
for (Map<String, Object> floorInfo : floorInfos) {
String buildingId = floorInfo.get("id").toString();
String buildingName = floorInfo.get("building_name").toString();
// 根据楼栋id查询对应楼层下的所有设备
//TODO 2、计算每小时用电量、用水量、单耗(用电量/用水量)
Map<String, Double> hourMap = processEnergy(buildingId, buildingName, lastHourTime, tableName, "hour", EnergyType.HOUR);
if (null != hourMap) {
hourList.add(hourMap);
}
//TODO 3、计算每日用用电量、用水量、单耗(用电量/用水量)
Map<String, Double> dayMap = processEnergy(buildingId, buildingName, lastHourTime, tableName, "day", EnergyType.DAY);
if (null != dayMap) {
dayList.add(dayMap);
}
//TODO 4、计算月用电量、用水量、单耗(用电量/用水量)
Map<String, Double> monthMap = processEnergy(buildingId, buildingName, lastHourTime, tableName, "month", EnergyType.MONTH);
if (null != monthMap) {
monthList.add(monthMap);
}
//TODO 5、计算年用电量、用水量、单耗(用电量/用水量)
Map<String, Double> yearMap = processEnergy(buildingId, buildingName, lastHourTime, tableName, "year", EnergyType.YEAR);
if (null != yearMap) {
yearList.add(yearMap);
}
}
// 更新插入所有楼栋的数据表
processAndInsertEnergyData("hour", hourList, lastHourTime);
processAndInsertEnergyData("day", dayList, lastHourTime);
processAndInsertEnergyData("month", monthList, lastHourTime);
processAndInsertEnergyData("year", yearList, lastHourTime);
}
private void processAndInsertEnergyData(String timeUnit, List<Map<String, Double>> dataList, String lastHourTime) {
if (dataList.isEmpty()) return;
double electricity = 0.0;
double water = 0.0;
for (Map<String, Double> map : dataList) {
electricity += map.getOrDefault("electricity", 0.0);
water += map.getOrDefault("water", 0.0);
}
double specificConsumption = water > 0 ? electricity / water : 0.0;
energyQueryService.insertOrUpdateEnergyData(timeUnit, "所有", "所有", lastHourTime, electricity, water, specificConsumption);
}
private Map<String, Double> processEnergy(String buildingId, String buildingName, String curDate, String tableName, String dateType, EnergyType energyType) {
List<DataMonth> datas = energyQueryService.queryEnergyDatas(tableName, buildingId, curDate, dateType);
Map<String, Double> result = new HashMap<>();
double electricity = 0.0;
double water = 0.0;
double specificConsumption = 0.0;
if (datas == null || datas.isEmpty()) {
log.warn("未找到 {} 类型的能耗数据,buildingId={}, curDate={}", energyType, buildingId, curDate);
result.put("electricity", electricity);
result.put("water", water);
} else {
Map<String, List<DataMonth>> grouped = datas.stream()
.collect(Collectors.groupingBy(DataMonth::getDeviceType));
electricity = grouped.getOrDefault("5", Collections.emptyList()).stream()
.mapToDouble(data -> Optional.ofNullable(data.getCalcValue()).map(BigDecimal::doubleValue).orElse(0.0))
.sum();
result.put("electricity", electricity);
water = grouped.getOrDefault("23", Collections.emptyList()).stream()
.mapToDouble(data -> Optional.ofNullable(data.getCalcValue()).map(BigDecimal::doubleValue).orElse(0.0))
.sum();
result.put("water", water);
specificConsumption = water > 0 ? electricity / water : 0.0;
// log.info("楼栋: {}, {}电表总量: {}, 水表总量: {}, 单耗: {}", buildingName, energyType, electricity, water, specificConsumption);
}
energyQueryService.insertOrUpdateEnergyData(
energyType.getCode(), buildingId, buildingName, curDate,
electricity,
water,
specificConsumption
);
return result;
}
}

168
mh-quartz/src/main/java/com/mh/quartz/task/PushDataToWechatTask.java

@ -0,0 +1,168 @@
package com.mh.quartz.task;
import com.mh.common.constant.Constants;
import com.mh.common.core.domain.entity.AlarmRecords;
import com.mh.common.core.domain.wechat.*;
import com.mh.common.utils.DateUtils;
import com.mh.common.utils.DictUtils;
import com.mh.system.service.ISysParamsService;
import com.mh.system.service.IWechatService;
import com.mh.system.service.impl.SysParamsServiceImpl;
import com.mh.system.service.operation.IAlarmRecordsService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 微信推送数据
* @date 2025-06-27 10:54:23
*/
@Slf4j
@Component("pushDataToWechatTask")
public class PushDataToWechatTask {
@Resource
private IAlarmRecordsService alarmRecordsService;
@Resource
private IWechatService wechatService;
@Resource
private ISysParamsService sysParamsService;
public void pushDataToWechat() {
// 查询报警内容
AlarmRecords alarmRecords = new AlarmRecords();
alarmRecords.setStatus(0);
alarmRecords.setIsSend(0);
Map<String, Object> param = new HashMap<>();
param.put("beginTime", DateUtils.dateToString(new Date(), "yyyy-MM-dd 00:00:00"));
param.put("endTime", DateUtils.dateToString(new Date(), "yyyy-MM-dd 23:59:59"));
alarmRecords.setParams(param);
List<AlarmRecords> alarmRecords1 = alarmRecordsService.selectAlarmRecordsList(alarmRecords);
if (null == alarmRecords1 || alarmRecords1.isEmpty()) {
return;
}
alarmRecords1.forEach(alarmRecords2 -> {
// 查询需要推送的微信用户
List<Map<String, Object>> wechatUserList = wechatService.queryWechatUser(0);
if (null == wechatUserList || wechatUserList.isEmpty()) {
// log.info("没有查询到微信用户");
}
// 开始推送数据
for (Map<String, Object> map : wechatUserList) {
PushMsgEntity pushMsgEntity = new PushMsgEntity();
try {
// 判断模板id种类
switch (map.get("template_id").toString()) {
case "fqAXCFXSBCqHLJjBLIjD-Wr_dN8RLsTcsatUQa3Ktx4":
// 设备异常告警提醒
pushDeviceExceptionParams(map, pushMsgEntity, alarmRecords2);
break;
case "SiyBtZeZuF0Qo8V3NlvGwhc95-vX-a6wsvIxpAq3d_Y":
// 设备告警通知
pushDeviceArmParams(map, pushMsgEntity, alarmRecords2);
break;
default:
break;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
if (!pushMsgEntity.getTouser().isEmpty()) {
String result = wechatService.pushMsg(pushMsgEntity);
if (Constants.SUCCESS.equals(result)) {
// 更新数据:已发送通知
alarmRecordsService.updateAlarmRecordById(alarmRecords2.getId(), 1);
}
}
}
});
}
private void pushDeviceArmParams(Map<String, Object> map, PushMsgEntity pushMsgEntity, AlarmRecords alarmRecords2) {
pushMsgEntity.setTouser(map.get("open_id").toString());
pushMsgEntity.setTemplateId(map.get("template_id").toString());
pushMsgEntity.setUrl("http://bajnd.mhwsh.net:9090/");
First first = new First();
first.setValue("设备告警通知");
pushMsgEntity.setFirst(first);
// 项目名称
Key1 key1 = new Key1();
key1.setValue(sysParamsService.queryList().get(0).getProName());
pushMsgEntity.setKey1(key1);
// 设备名称
Key2 key2 = new Key2();
key2.setValue(alarmRecords2.getDeviceName());
pushMsgEntity.setKey2(key2);
// 告警等级
Key3 key3 = new Key3();
// 通过告警等级id得到value值
String alarmLevel = alarmRecords2.getAlarmLevel();
String alarmLevel1 = DictUtils.getDictLabel("alarm_level", alarmLevel);
key3.setValue(alarmLevel1);
pushMsgEntity.setKey3(key3);
// 异常原因
Key4 key4 = new Key4();
key4.setValue(alarmRecords2.getContent().substring(0, 20));
pushMsgEntity.setKey4(key4);
// 发生时间
Key5 key5 = new Key5();
key5.setValue(DateUtils.dateToString(alarmRecords2.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
pushMsgEntity.setKey5(key5);
}
/**
* 推送设备异常告警提醒
* @param map
* @param pushMsgEntity
* @param alarmRecords2
*/
private void pushDeviceExceptionParams(Map<String, Object> map, PushMsgEntity pushMsgEntity, AlarmRecords alarmRecords2) {
pushMsgEntity.setTouser(map.get("open_id").toString());
pushMsgEntity.setTemplateId(map.get("template_id").toString());
pushMsgEntity.setUrl("http://bajnd.mhwsh.net:9090/");
First first = new First();
first.setValue("设备异常告警提醒");
pushMsgEntity.setFirst(first);
Key1 key1 = new Key1();
key1.setValue(alarmRecords2.getDeviceName());
pushMsgEntity.setKey1(key1);
Key2 key2 = new Key2();
// 通过告警等级id得到value值
String alarmLevel = alarmRecords2.getAlarmLevel();
String alarmLevel1 = DictUtils.getDictLabel("alarm_level", alarmLevel);
key2.setValue(alarmLevel1);
pushMsgEntity.setKey2(key2);
Key3 key3 = new Key3();
// 通过告警类型id得到value值
String alarmType = alarmRecords2.getAlarmType();
String alarmType1 = DictUtils.getDictLabel( "alarm_type", alarmType);
key3.setValue(alarmType1);
pushMsgEntity.setKey3(key3);
Key4 key4 = new Key4();
key4.setValue(alarmRecords2.getContent().substring(0, 20));
pushMsgEntity.setKey4(key4);
Key5 key5 = new Key5();
key5.setValue(DateUtils.dateToString(alarmRecords2.getCreateTime(), "yyyy-MM-dd HH:mm:ss"));
pushMsgEntity.setKey5(key5);
}
}

26
mh-system/src/main/java/com/mh/system/mapper/WechatMapper.java

@ -0,0 +1,26 @@
package com.mh.system.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 微信相关mapper
* @date 2025-06-27 14:02:37
*/
@Mapper
public interface WechatMapper {
@Select("select wt.template_id, wui.open_id from wechat_template_project wtp " +
" join wechat_template wt on wtp.template_id = wt.id " +
" join wechat_user_info wui on wtp.wechat_user_id = wui.id" +
" where wtp.grade = #{grade} and wui.is_status = 1 ")
List<Map<String, Object>> queryWechatUser(@Param("grade") int grade);
}

40
mh-system/src/main/java/com/mh/system/mapper/device/CollectionParamsManageMapper.java

@ -3,6 +3,7 @@ package com.mh.system.mapper.device;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.dto.TempHumidityDTO;
import com.mh.common.core.domain.entity.CollectionParamsManage;
import com.mh.common.core.domain.entity.FloorInfo;
import com.mh.common.core.domain.vo.CollectionParamsManageVO;
import com.mh.common.core.domain.vo.DeviceMonitorVO;
import com.mh.common.core.domain.vo.HotWaterControlListVO;
@ -218,9 +219,9 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
" order by dl.device_type ,dl.order_num ,cpm.order_num ")
List<CollectionParamsManageVO> selectBySystemType(@Param("systemType") String systemType);
@Select("select " +
" hi.house_name || right(cpm.other_name, " +
" 4) as name, " +
@Select("<script>" +
"select " +
" hi.house_name || right(cpm.other_name, 3) as name, " +
" cpm.cur_value as value, " +
" cpm.cur_time as \"curTime\" " +
"from " +
@ -234,16 +235,22 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
"where " +
" (cpm.param_type = '12' " +
" or cpm.param_type = '13') " +
" and csr.floor_id = #{floorId} " +
" and cpm.system_type = #{systemType}" +
" order by hi.house_name, cpm.param_type ")
" and hi.house_name is not null " +
" and csr.floor_id IN " +
" <foreach collection='floorIds' item='floorId' open='(' separator=',' close=')'>" +
" #{floorId}" +
" </foreach>" +
" order by hi.house_name, cpm.param_type " +
"</script>")
List<Map<String, Object>> selectBySystemTypeAndBuildingId(@Param("systemType") String systemType,
@Param("floorId") String floor_id);
@Param("floorIds") List<String> floorIds);
@Select("select " +
" dl.id, " +
" dl.device_name, " +
" cpm.cur_value as collectValue, " +
" ROUND(cpm.cur_value, 1) as collectValue, " +
" cpm.cur_time as collectTime, " +
" cpm.param_type as paramType, " +
" cpm.other_name as collectName, " +
@ -297,6 +304,7 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
" csr.floor_id = #{floorId} " +
" and cpm.system_type = #{systemType} " +
" and cpm.is_use = 0 " +
" and hi.house_name is not null " +
" order by dl.order_num ")
List<HotWaterControlListVO> selectHotWaterBySystemTypeAndBuildingId(@Param("systemType") String systemType,
@Param("floorId") String floorId);
@ -309,7 +317,8 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
" cpm.other_name, " +
" cpm.cur_value, " +
" cpm.cur_time, " +
" cpm.param_type " +
" cpm.param_type," +
" cpm.quality " +
"from " +
" collection_params_manage cpm " +
"left join device_ledger dl on " +
@ -320,7 +329,8 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
" csr.house_id = hi.id " +
"where " +
" csr.house_id = #{houseId} " +
" and cpm.system_type = #{systemType} " +
" and cpm.system_type = #{systemType}" +
" and cpm.is_use = 0 " +
" order by dl.order_num ")
List<CollectionParamsManageVO> selectBySystemTypeAndHouseId(@Param("systemType") String systemType,
@Param("houseId") String houseId);
@ -338,4 +348,16 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
" and device_ledger_id is not null " +
" group by device_ledger_id;")
List<String> OffLine();
@Select("select * from collection_params_manage cpm " +
" where (cpm.system_type = '1' or cpm.system_type = '6') and is_use = 0 " +
" and (param_type= '16' " +
" or param_type='18' " +
" or param_type = '5' " +
" or param_type = '2' " +
" or param_type = '12' " +
" or param_type = '14' " +
" or param_type = '11' " +
" or param_type = '48')")
List<CollectionParamsManage> createOrderList();
}

2
mh-system/src/main/java/com/mh/system/mapper/device/DataProcessMapper.java

@ -170,7 +170,7 @@ public interface DataProcessMapper {
* @param deviceNum
* @return
*/
@Select("select mt_init_value from collection_params_manage where mt_num = #{deviceNum} and is_use = '0'")
@Select("select mt_init_value from collection_params_manage where mt_num = #{deviceNum} and is_use = '0' limit 1 ")
String queryInitValue(@Param("deviceNum") String deviceNum);
@Select("select * from ${tableName} where register_id = #{registerId} and cur_time >= CURRENT_TIMESTAMP - INTERVAL '24 hours' ")

13
mh-system/src/main/java/com/mh/system/mapper/device/DeviceLedgerMapper.java

@ -2,9 +2,11 @@ package com.mh.system.mapper.device;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.DeviceLedger;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Update;
import com.mh.common.core.domain.entity.DeviceState;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.StatementType;
import java.util.List;
/**
* @author LJF
@ -21,4 +23,9 @@ public interface DeviceLedgerMapper extends BaseMapper<DeviceLedger> {
@Update("update device_ledger set status = #{status}, update_time = current_timestamp where id = #{id}")
void updateOnlineOrOfflineStatus(@Param("id") String deviceLedgerId, @Param("status") int integer);
@Update("select pro_device_state(#{curDate})")
@Options(statementType = StatementType.CALLABLE)
void createOrUpdateDeviceState(@Param("curDate") String curDate);
}

22
mh-system/src/main/java/com/mh/system/mapper/device/DeviceStateMapper.java

@ -0,0 +1,22 @@
package com.mh.system.mapper.device;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.DeviceState;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 设备状态mapper类
* @date 2025-06-17 17:40:14
*/
@Mapper
public interface DeviceStateMapper extends BaseMapper<DeviceState> {
@Select("select * from device_state where system_type = #{systemType} and date(cur_date) = date(now()) limit 1")
List<DeviceState> deviceState(String systemType);
}

2
mh-system/src/main/java/com/mh/system/mapper/device/GatewayManageMapper.java

@ -19,4 +19,6 @@ public interface GatewayManageMapper extends BaseMapper<GatewayManage> {
@Update("update gateway_manage set status = 0, connect_time = CURRENT_TIMESTAMP where id = #{gatewayId}")
void updateOnlineStatus(@Param("gatewayId") String gatewayId);
@Update("update gateway_manage set status = 0, connect_time = CURRENT_TIMESTAMP where heart_beat = #{heartBeat}")
void updateOnlineStatusByHeartBeat(@Param("heartBeat") String heartBeat);
}

56
mh-system/src/main/java/com/mh/system/mapper/energy/AnalysisMapper.java

@ -0,0 +1,56 @@
package com.mh.system.mapper.energy;
import com.mh.common.core.domain.entity.AnalysisMonth;
import com.mh.common.core.domain.entity.AnalysisYear;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 用能分析
* @date 2025-06-24 15:10:04
*/
@Mapper
public interface AnalysisMapper {
/**
* 分析查询
* 根据日期楼栋查询
* @param curDate
* @param buildingId
* @return
*/
@Select("select * from analysis_elect_year where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisYear> queryAnalysisElectYear(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_Water_year where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisYear> queryAnalysisWaterYear(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_Energy_year where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisYear> queryAnalysisEnergyYear(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_Maintain_year where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisYear> queryAnalysisMaintainYear(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_runtime_year where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisYear> queryAnalysisRuntimeYear(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_elect_month where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisMonth> queryAnalysisElectMonth(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_Water_month where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisMonth> queryAnalysisWaterMonth(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_Energy_month where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisMonth> queryAnalysisEnergyMonth(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_maintain_month where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisMonth> queryAnalysisMaintainMonth(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
@Select("select * from analysis_runtime_month where cur_date=#{curDate} and building_id=#{buildingId} order by id ")
List<AnalysisMonth> queryAnalysisRuntimeMonth(@Param("curDate") String curDate, @Param("buildingId") String buildingId);
}

28
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyDayMapper.java

@ -0,0 +1,28 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyDay;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.poi.ss.formula.functions.T;
import java.math.BigDecimal;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyDayMapper extends BaseMapper<EnergyDay> {
@Update("update energy_day set elect_value = #{electricity}, use_hot_water = #{water}, elect_water = #{consumption} where building_id = #{buildingId} and cur_date = #{curDate}")
void updateByOther(String buildingId, String curDate, BigDecimal electricity, BigDecimal water, BigDecimal consumption);
@Select("select * from energy_day where building_id = #{buildingId} and cur_date >= #{startDate} and cur_date <= #{endDate} order by cur_date desc ")
List<EnergyDay> queryEnergyDay(String buildingId, String startDate, String endDate);
}

22
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyDaySumMapper.java

@ -0,0 +1,22 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyDaySum;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyDaySumMapper extends BaseMapper<EnergyDaySum> {
@Select("select * from energy_day_sum where building_id = #{buildingId} and cur_date = #{startDate} ")
List<EnergyDaySum> queryEnergyDaySum(String buildingId, String startDate);
}

27
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyHourMapper.java

@ -0,0 +1,27 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyHour;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.math.BigDecimal;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyHourMapper extends BaseMapper<EnergyHour> {
@Update("update energy_hour set elect_value = #{electricity}, use_hot_water = #{water}, elect_water = #{consumption} where building_id = #{buildingId} and cur_date = #{curDate}")
void updateByOther(String buildingId, String curDate, BigDecimal electricity, BigDecimal water, BigDecimal consumption);
@Select("select * from energy_hour where building_id = #{buildingId} and cur_date >= #{startDate} and cur_date <= #{endDate} order by cur_date desc ")
List<EnergyHour> queryEnergyHour(String buildingId, String startDate, String endDate);
}

28
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyMonthMapper.java

@ -0,0 +1,28 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyMonth;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import org.apache.poi.ss.formula.functions.T;
import java.math.BigDecimal;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyMonthMapper extends BaseMapper<EnergyMonth> {
@Update("update energy_month set elect_value = #{electricity}, use_hot_water = #{water}, elect_water = #{consumption} where building_id = #{buildingId} and cur_date = #{curDate}")
void updateByOther(String buildingId, String curDate, BigDecimal electricity, BigDecimal water, BigDecimal consumption);
@Select("select * from energy_month where building_id = #{buildingId} and cur_date >= #{startDate} and cur_date <= #{endDate} order by cur_date desc ")
List<EnergyMonth> queryEnergyMonth(String buildingId, String startDate, String endDate);
}

23
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyMonthSumMapper.java

@ -0,0 +1,23 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyMonthSum;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyMonthSumMapper extends BaseMapper<EnergyMonthSum> {
@Select("select * from energy_month_sum where building_id = #{buildingId} and cur_date = #{startDate} ")
List<EnergyMonthSum> queryEnergyMonthSum(String buildingId, String startDate);
}

27
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyYearMapper.java

@ -0,0 +1,27 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyYear;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;
import java.math.BigDecimal;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyYearMapper extends BaseMapper<EnergyYear> {
@Update("update energy_year set elect_value = #{electricity}, use_hot_water = #{water}, elect_water = #{consumption} where building_id = #{buildingId} and cur_date = #{curDate}")
void updateByOther(String buildingId, String curDate, BigDecimal electricity, BigDecimal water, BigDecimal consumption);
@Select("select * from energy_year where building_id = #{buildingId} and cur_date >= #{startDate} and cur_date <= #{endDate} order by cur_date desc ")
List<EnergyYear> queryEnergyYear(String buildingId, String startDate, String endDate);
}

24
mh-system/src/main/java/com/mh/system/mapper/energy/EnergyYearSumMapper.java

@ -0,0 +1,24 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.EnergyMonthSum;
import com.mh.common.core.domain.entity.EnergyYearSum;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水小时
* @date 2025-06-18 15:37:04
*/
@Mapper
public interface EnergyYearSumMapper extends BaseMapper<EnergyYearSum> {
@Select("select * from energy_year_sum where building_id = #{buildingId} and cur_date = #{startDate} ")
List<EnergyYearSum> queryEnergyYearSum(String buildingId, String startDate);
}

125
mh-system/src/main/java/com/mh/system/mapper/energy/HotEnergyQueryMapper.java

@ -0,0 +1,125 @@
package com.mh.system.mapper.energy;
import com.mh.common.core.domain.dto.DataResultDTO;
import com.mh.common.core.domain.entity.DataMonth;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
import java.util.Map;
/**
* @author LJF
* @version 1.0
* @project NewZhujiang_Server
* @description 热水能耗查询
* @date 2023-12-13 16:00:01
*/
@Mapper
public interface HotEnergyQueryMapper {
@Select("select " +
" t1.id, t1.floor_name as building_name " +
"from " +
" ( " +
" select " +
" distinct fi.id,fi.floor_name " +
" from " +
" floor_info fi " +
" join " +
"building_info bi " +
"on " +
" fi.building_id = bi.id " +
" join area_info ai on " +
" bi.area_id = ai.id " +
" where " +
" ai.system_type = '1' " +
" ) t1 " +
"join cpm_space_relation csr on " +
" csr.floor_id = t1.id " +
"where " +
" csr.house_id = '' " +
"group by " +
" t1.id,t1.floor_name order by building_name")
List<Map<String, Object>> queryFloorInfo();
@Select("<script>" +
"select " +
" dh.* " +
"from " +
" ${tableName} dh " +
"join ( " +
" select " +
" mt_num " +
" from " +
" collection_params_manage cpm " +
" where " +
" id in( " +
" select " +
" cpm_id " +
" from " +
" cpm_space_relation csr " +
" where " +
" floor_id = #{buildingId} " +
" and house_id = '' " +
")) t1 on " +
" dh.device_num = t1.mt_num " +
"where " +
" date_trunc(#{dateType}, dh.cur_time) = date_trunc(#{dateType},#{lastHour}::timestamp) " +
"order by " +
" cur_time; " +
"</script>")
List<DataMonth> queryEnergyDatas(@Param("tableName") String tableName,
@Param("buildingId") String buildingId,
@Param("lastHour") String lastHourTime,
@Param("dateType") String dateType);
@Select("select count(1) from ${tableName} where building_id = #{buildingId} and cur_date = #{curDate}")
int haveRecord(String tableName, String buildingId, String curDate);
@Select("SELECT pro_energy_sum(#{lastHourTime}); ")
Map<String, Object> calcFloorEnergyDataDetail(@Param("lastHourTime") String lastHourTime);
@Select("<script>" +
"select " +
" fi.id as building_id, " +
" fi.floor_name as building_name, " +
" cpm.other_name as device_name, " +
" dm.* " +
"from " +
" ${tableName} dm " +
"join " +
"collection_params_manage cpm " +
"on " +
" dm.device_num = cpm.mt_num " +
" and dm.device_code = cpm.mt_code " +
"join cpm_space_relation csr on " +
" cpm.id = csr.cpm_id " +
"join floor_info fi on " +
" fi.id = csr.floor_id " +
"where " +
" date(dm.cur_time) >= date(#{startDate}) " +
" and date(dm.cur_time) &lt;= date(#{endDate}) " +
" and cpm.param_type = #{deviceType} " +
" and cpm.grade = 40 " +
" and csr.house_id = '' " +
"<if test='buildingId != null and buildingId != \"所有\" and buildingId != \"\" '>" +
" and csr.floor_id = #{buildingId} " +
"</if>" +
"order by " +
" dm.cur_time desc " +
"</script>")
List<DataResultDTO> queryDeviceDatas(@Param("buildingId") String buildingId,
@Param("startDate") String startDate,
@Param("endDate") String endDate,
@Param("deviceType") String deviceType,
@Param("tableName") String tableName);
@Select("SELECT pro_analysis_month(#{lastHourTime}); ")
Map<String, Object> calcAnalysisDataMonth(String lastHourTime);
@Select("SELECT pro_analysis_year(#{lastHourTime}); ")
Map<String, Object> calcAnalysisDataYear(String lastHourTime);
}

102
mh-system/src/main/java/com/mh/system/mapper/energy/WaterLevelMapper.java

@ -0,0 +1,102 @@
package com.mh.system.mapper.energy;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.mh.common.core.domain.entity.WaterLevel;
import org.apache.ibatis.annotations.*;
import java.math.BigDecimal;
import java.util.List;
import java.util.Map;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 热水温度记录
* @date 2025-06-19 16:24:31
*/
@Mapper
public interface WaterLevelMapper extends BaseMapper<WaterLevel> {
@Select("select " +
" t1.*, " +
" csr.floor_id " +
"from " +
" ( " +
" select " +
" cpm.id, " +
" cpm.cur_value, " +
" cpm.cur_time, " +
" cpm.mt_num, " +
" dl.device_name " +
" from " +
" collection_params_manage cpm " +
" join device_ledger dl on " +
" cpm.device_ledger_id = dl.id " +
" where " +
" dl.system_type = '1' " +
" and device_type = '16' " +
" and cpm.param_type = '11' " +
" ) t1 " +
"join cpm_space_relation csr on " +
" t1.id = csr.cpm_id " +
"where " +
" csr.house_id = '' " +
"order by " +
" t1.device_name ")
List<Map<String, Object>> getNowWaterLevel();
@Select("select count(1) from water_level where date(cur_date) = date(#{date}::timestamp) and building_id = #{buildingId} and device_num = #{pumpId}")
int isExits(@Param("date") String date,
@Param("buildingId") String buildingId,
@Param("pumpId") String pumpId);
@Insert("insert into water_level(cur_date,building_id,device_num,device_name, ${tempTime}) values(#{date}::timestamp,#{buildingId},#{pumpId},#{pumpName},#{curValue})")
void insertWaterLevel(String date, String buildingId, String pumpId, String pumpName, BigDecimal curValue, String tempTime);
@Update("update water_level set ${tempTime} = #{curValue} where date(cur_date) = date(#{date}::timestamp) and building_id = #{buildingId} and device_num = #{pumpId}")
void updateWaterLevel(String date, String buildingId, String pumpId, String pumpName, BigDecimal curValue, String tempTime);
@Select("select " +
" wt.building_id, " +
" SUBSTRING(fi.floor_name FROM '(-?\\d+楼)') as building_name, " +
" ROUND(avg(temp00::numeric(24, 1)),1) as temp00, " +
" ROUND(avg(temp01::numeric(24, 1)),1) as temp01, " +
" ROUND(avg(temp02::numeric(24, 1)),1) as temp02, " +
" ROUND(avg(temp03::numeric(24, 1)),1) as temp03, " +
" ROUND(avg(temp04::numeric(24, 1)),1) as temp04, " +
" ROUND(avg(temp05::numeric(24, 1)),1) as temp05, " +
" ROUND(avg(temp06::numeric(24, 1)),1) as temp06, " +
" ROUND(avg(temp07::numeric(24, 1)),1) as temp07, " +
" ROUND(avg(temp08::numeric(24, 1)),1) as temp08, " +
" ROUND(avg(temp09::numeric(24, 1)),1) as temp09, " +
" ROUND(avg(temp10::numeric(24, 1)),1) as temp10, " +
" ROUND(avg(temp11::numeric(24, 1)),1) as temp11, " +
" ROUND(avg(temp12::numeric(24, 1)),1) as temp12, " +
" ROUND(avg(temp13::numeric(24, 1)),1) as temp13, " +
" ROUND(avg(temp14::numeric(24, 1)),1) as temp14, " +
" ROUND(avg(temp15::numeric(24, 1)),1) as temp15, " +
" ROUND(avg(temp16::numeric(24, 1)),1) as temp16, " +
" ROUND(avg(temp17::numeric(24, 1)),1) as temp17, " +
" ROUND(avg(temp18::numeric(24, 1)),1) as temp18, " +
" ROUND(avg(temp19::numeric(24, 1)),1) as temp19, " +
" ROUND(avg(temp20::numeric(24, 1)),1) as temp20, " +
" ROUND(avg(temp21::numeric(24, 1)),1) as temp21, " +
" ROUND(avg(temp22::numeric(24, 1)),1) as temp22, " +
" ROUND(avg(temp23::numeric(24, 1)),1) as temp23 " +
"from " +
" water_level wt " +
"join floor_info fi on wt.building_id = fi.id " +
"where " +
" date(wt.cur_date) = date(#{curDate}) " +
"group by " +
" wt.building_id, fi.floor_name " +
"order by SUBSTRING(fi.floor_name FROM '(-?\\d)') ")
List<WaterLevel> queryAvgWaterTemp(String curDate);
@Select("select wt.*, SUBSTRING(fi.floor_name FROM '(-?\\d+楼)') as building_name from water_level wt " +
" join floor_info fi on wt.building_id = fi.id " +
" where wt.building_id = #{buildingId} and date(wt.cur_date) = date(#{curDate}) order by wt.device_name ")
List<WaterLevel> queryWaterTemp(String buildingId, String curDate);
}

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

Loading…
Cancel
Save