80 changed files with 6844 additions and 170 deletions
@ -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); |
||||
} |
||||
|
||||
} |
||||
@ -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; |
||||
} |
||||
} |
||||
@ -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(); |
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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(); |
||||
} |
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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; |
||||
|
||||
} |
||||
@ -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(); |
||||
} |
||||
} |
||||
@ -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(); |
||||
} |
||||
} |
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,336 @@
|
||||
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)); |
||||
// 读数
|
||||
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); |
||||
} |
||||
// 判断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 ""; |
||||
} |
||||
} |
||||
@ -0,0 +1,253 @@
|
||||
package com.mh.common.utils; |
||||
|
||||
/** |
||||
* CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,结果与0x0000异或 |
||||
* CRC16_CCITT_FALSE:多项式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,高位在前,结果与0x0000异或 |
||||
* CRC16_XMODEM:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,高位在前,结果与0x0000异或 |
||||
* CRC16_X25:多项式x16+x12+x5+1(0x1021),初始值0xffff,低位在前,高位在后,结果与0xFFFF异或 |
||||
* CRC16_MODBUS:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0x0000异或 |
||||
* CRC16_IBM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,结果与0x0000异或 |
||||
* CRC16_MAXIM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或 |
||||
* CRC16_USB:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0xFFFF异或 |
||||
* CRC16_DNP:多项式x16+x13+x12+x11+x10+x8+x6+x5+x2+1(0x3D65),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或 |
||||
* <p> |
||||
* (1)、预置1个16位的寄存器为十六进制FFFF(即全为1),称此寄存器为CRC寄存器; |
||||
* (2)、把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器,高八位数据不变; |
||||
* (3)、把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位; |
||||
* (4)、如果移出位为0:重复第3步(再次右移一位);如果移出位为1,CRC寄存器与多项式A001(1010 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+1(0x1021),初始值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+1(0x1021),初始值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+1(0x1021),初始值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+1(0x1021),初始值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+1(0x8005),初始值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+1(0x8005),初始值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+1(0x8005),初始值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+1(0x8005),初始值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+1(0x3D65),初始值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; |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -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; |
||||
} |
||||
} |
||||
@ -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); |
||||
} |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
@ -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 资源已释放"); |
||||
})); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,427 @@
|
||||
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); |
||||
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; |
||||
} |
||||
|
||||
} |
||||
@ -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); |
||||
|
||||
} |
||||
@ -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; |
||||
} |
||||
} |
||||
@ -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()); |
||||
} |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
} |
||||
@ -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); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
} |
||||
|
||||
} |
||||
|
||||
@ -0,0 +1,6 @@
|
||||
package com.mh.framework.netty.task; |
||||
|
||||
//不需要知道异步线程的 返回值
|
||||
public interface ExecuteTask { |
||||
void execute(); |
||||
} |
||||
@ -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(); |
||||
} |
||||
} |
||||
} |
||||
@ -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; |
||||
} |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
@ -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); |
||||
|
||||
} |
||||
@ -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, " + |
||||
" SUBSTRING(fi.floor_name from '(-?\\d+楼)') 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) <= 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); |
||||
|
||||
} |
||||
@ -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); |
||||
} |
||||
@ -0,0 +1,103 @@
|
||||
package com.mh.system.mapper.energy; |
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||
import com.mh.common.core.domain.entity.WaterTemp; |
||||
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 WaterTempMapper extends BaseMapper<WaterTemp> { |
||||
|
||||
|
||||
@Select("select " + |
||||
" t1.*, " + |
||||
" csr.floor_id, " + |
||||
" csr.house_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 dl.device_type = '11' " + |
||||
" and cpm.param_type = '12' " + |
||||
" ) 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>> getNowWaterTemp(); |
||||
|
||||
@Select("select count(1) from water_temp 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_temp(cur_date,building_id, device_num, device_name, ${tempTime}) values(#{date}::timestamp,#{buildingId},#{pumpId},#{pumpName},#{curValue})") |
||||
void insertWaterTemp(String date, String buildingId, String pumpId, String pumpName, BigDecimal curValue, String tempTime); |
||||
|
||||
@Update("update water_temp set ${tempTime} = #{curValue} where date(cur_date) = date(#{date}::timestamp) and building_id = #{buildingId} and device_num = #{pumpId}") |
||||
void updateWaterTemp(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_temp 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<WaterTemp> queryAvgWaterTemp(String curDate); |
||||
|
||||
@Select("select wt.*, SUBSTRING(fi.floor_name FROM '(-?\\d+楼)') as building_name from water_temp 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<WaterTemp> queryWaterTemp(String buildingId, String curDate); |
||||
} |
||||
@ -0,0 +1,14 @@
|
||||
package com.mh.system.service.energy; |
||||
|
||||
/** |
||||
* @author LJF |
||||
* @version 1.0 |
||||
* @project EEMCS |
||||
* @description 热水温度服务类 |
||||
* @date 2025-06-19 16:26:10 |
||||
*/ |
||||
public interface IWaterLevelService { |
||||
|
||||
void calcWaterLevel(); |
||||
|
||||
} |
||||
@ -0,0 +1,14 @@
|
||||
package com.mh.system.service.energy; |
||||
|
||||
/** |
||||
* @author LJF |
||||
* @version 1.0 |
||||
* @project EEMCS |
||||
* @description 热水温度服务类 |
||||
* @date 2025-06-19 16:26:10 |
||||
*/ |
||||
public interface IWaterTempService { |
||||
|
||||
void calcWaterTemp(); |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
|
||||
package com.mh.system.service.energy.impl; |
||||
|
||||
import com.mh.system.mapper.energy.WaterLevelMapper; |
||||
import com.mh.system.mapper.energy.WaterTempMapper; |
||||
import com.mh.system.service.energy.IWaterLevelService; |
||||
import com.mh.system.service.energy.IWaterTempService; |
||||
import jakarta.annotation.Resource; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
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:26:36 |
||||
*/ |
||||
@Service |
||||
public class WaterLevelServiceImpl implements IWaterLevelService { |
||||
|
||||
@Resource |
||||
private WaterLevelMapper waterLevelMapper; |
||||
|
||||
@Override |
||||
public void calcWaterLevel() { |
||||
// todo 1、获取到多少个水箱,以及水位对应的实时水位
|
||||
// todo 2、根据对应的水箱id查询水箱对应的液位
|
||||
// todo 3、再根据绑定关系表查询到热泵对应的楼层id
|
||||
List<Map<String, Object>> list = waterLevelMapper.getNowWaterLevel(); |
||||
// 开始遍历数据
|
||||
for (Map<String, Object> map : list) { |
||||
// todo 5、拼接sql语句,插入到存储表中(id,楼栋id,水箱id,水箱名称,temp00至temp23)
|
||||
String cpmId = map.get("id").toString(); |
||||
BigDecimal curValue = new BigDecimal(map.get("cur_value").toString()).setScale(1, BigDecimal.ROUND_HALF_UP); |
||||
String buildingId = map.get("floor_id").toString(); |
||||
String pumpId = map.get("mt_num").toString(); |
||||
String pumpName = map.get("device_name").toString(); |
||||
String curDate = map.get("cur_time").toString(); |
||||
|
||||
String tempTime = "temp" + curDate.substring(11, 13); |
||||
|
||||
// 格式化时间
|
||||
String date = curDate.substring(0,10) + " 00:00:00"; |
||||
// 判断是否存在值
|
||||
int count = waterLevelMapper.isExits(date, buildingId, pumpId); |
||||
|
||||
if (count == 0) { |
||||
// todo 6、插入数据
|
||||
waterLevelMapper.insertWaterLevel(date, buildingId, pumpId, pumpName, curValue, tempTime); |
||||
} else { |
||||
// todo 7、更新数据
|
||||
waterLevelMapper.updateWaterLevel(date, buildingId, pumpId, pumpName, curValue, tempTime); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,60 @@
|
||||
package com.mh.system.service.energy.impl; |
||||
|
||||
import com.mh.common.utils.DateUtils; |
||||
import com.mh.system.mapper.energy.WaterTempMapper; |
||||
import com.mh.system.service.energy.IWaterTempService; |
||||
import jakarta.annotation.Resource; |
||||
import org.springframework.stereotype.Service; |
||||
|
||||
import java.math.BigDecimal; |
||||
import java.util.Date; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* @author LJF |
||||
* @version 1.0 |
||||
* @project EEMCS |
||||
* @description 热水温度服务类实现类 |
||||
* @date 2025-06-19 16:26:36 |
||||
*/ |
||||
@Service |
||||
public class WaterTempServiceImpl implements IWaterTempService { |
||||
|
||||
@Resource |
||||
private WaterTempMapper waterTempMapper; |
||||
|
||||
@Override |
||||
public void calcWaterTemp() { |
||||
// todo 1、获取到多少个热泵,以及热泵对应的实时温度
|
||||
// todo 2、根据热泵id查询热泵对应的实时温度
|
||||
// todo 3、再根据绑定关系表查询到热泵对应的楼层id
|
||||
List<Map<String, Object>> list = waterTempMapper.getNowWaterTemp(); |
||||
// 开始遍历数据
|
||||
for (Map<String, Object> map : list) { |
||||
// todo 5、拼接sql语句,插入到存储表中(id,楼栋id,热泵采集id,热泵名称,temp00至temp23)
|
||||
String cpmId = map.get("id").toString(); |
||||
BigDecimal curValue = new BigDecimal(map.get("cur_value").toString()).setScale(1, BigDecimal.ROUND_HALF_UP); |
||||
String buildingId = map.get("floor_id").toString(); |
||||
String pumpId = map.get("mt_num").toString(); |
||||
String pumpName = map.get("device_name").toString(); |
||||
String curDate = map.get("cur_time").toString(); |
||||
|
||||
String tempTime = "temp" + curDate.substring(11, 13); |
||||
|
||||
// 格式化时间
|
||||
String date = curDate.substring(0,10) + " 00:00:00"; |
||||
// 判断是否存在值
|
||||
int count = waterTempMapper.isExits(date, buildingId, pumpId); |
||||
|
||||
if (count == 0) { |
||||
// todo 6、插入数据
|
||||
waterTempMapper.insertWaterTemp(date, buildingId, pumpId, pumpName, curValue, tempTime); |
||||
} else { |
||||
// todo 7、更新数据
|
||||
waterTempMapper.updateWaterTemp(date, buildingId, pumpId, pumpName, curValue, tempTime); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue