Browse Source

1、增加正帝热泵控制参数显示

dev
3067418132@qq.com 2 weeks ago
parent
commit
629ba3ee77
  1. 2
      user-service/src/main/java/com/mh/user/constants/Constant.java
  2. 11
      user-service/src/main/java/com/mh/user/controller/HotWaterMonitorController.java
  3. 10
      user-service/src/main/java/com/mh/user/dto/HotWaterControlListVO.java
  4. 87
      user-service/src/main/java/com/mh/user/dto/HotWaterControlZDListVO.java
  5. 4
      user-service/src/main/java/com/mh/user/entity/CollectionParamsManageEntity.java
  6. 3
      user-service/src/main/java/com/mh/user/entity/DeviceInstallEntity.java
  7. 4
      user-service/src/main/java/com/mh/user/job/CollectionLoopRunner.java
  8. 6
      user-service/src/main/java/com/mh/user/job/DealDataJob.java
  9. 52
      user-service/src/main/java/com/mh/user/mapper/CollectionParamsManageMapper.java
  10. 7
      user-service/src/main/java/com/mh/user/mapper/DeviceInstallMapper.java
  11. 4
      user-service/src/main/java/com/mh/user/service/CollectionParamsManageService.java
  12. 7
      user-service/src/main/java/com/mh/user/service/DeviceInstallService.java
  13. 238
      user-service/src/main/java/com/mh/user/service/impl/CollectionParamsManageServiceImpl.java
  14. 78
      user-service/src/main/java/com/mh/user/service/impl/DeviceInstallServiceImpl.java
  15. 178
      user-service/src/main/java/com/mh/user/strategy/HeatPumpStrategy.java
  16. 71
      user-service/src/main/java/com/mh/user/utils/GetReadOrder485.java
  17. 362
      user-service/src/main/java/com/mh/user/utils/XK814ModbusParamReadUtil.java
  18. 172
      user-service/src/main/java/com/mh/user/utils/XK814ModbusParamWriteUtil.java
  19. 4
      user-service/src/main/resources/application-dev.yml
  20. 20
      user-service/src/main/resources/application-prod.yml
  21. 2
      user-service/src/main/resources/application.yml

2
user-service/src/main/java/com/mh/user/constants/Constant.java

@ -53,6 +53,8 @@ public class Constant {
public static final String BRAND_HAI_ER = "海尔";
public static final String BRAND_HAI_ER_TWO = "海尔2";
public static final String BRAND_ZHENG_DI = "正帝";
public static final String BRAND_YUAN_XIANG = "远向";
public static final String BRAND_DING_WEI = "顶威";

11
user-service/src/main/java/com/mh/user/controller/HotWaterMonitorController.java

@ -43,9 +43,14 @@ public class HotWaterMonitorController {
* @return
*/
@GetMapping("/operateList")
public HttpResult operateList(@RequestParam("buildingId") String buildingId) {
List<HotWaterControlDTO> list = collectionParamsManageService.operateList(buildingId);
return HttpResult.ok(list);
public HttpResult operateList(@RequestParam("buildingId") String buildingId, @RequestParam("deviceInstallId") Integer deviceInstallId) {
if (deviceInstallId == null) {
List<HotWaterControlDTO> list = collectionParamsManageService.operateList(buildingId);
return HttpResult.ok(list);
} else {
List<HotWaterControlDTO> list = collectionParamsManageService.operateList(buildingId, deviceInstallId);
return HttpResult.ok(list);
}
}

10
user-service/src/main/java/com/mh/user/dto/HotWaterControlListVO.java

@ -1,5 +1,6 @@
package com.mh.user.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
@ -20,6 +21,8 @@ public class HotWaterControlListVO {
private String cpmId;
private String registerAddr;
private String buildingId;
private String buildingName;
@ -32,13 +35,16 @@ public class HotWaterControlListVO {
private BigDecimal curValue;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date curTime;
private String paramTypeId;
private String paramTypeGroupId;
private String otherName;
private int dtOrderNum;
private int orderNum;
private int dlOrderNum;
@ -71,7 +77,7 @@ public class HotWaterControlListVO {
.add("curTime=" + curTime)
.add("paramTypeId='" + paramTypeId + "'")
.add("otherName='" + otherName + "'")
.add("dtOrderNum=" + dtOrderNum)
.add("orderNum=" + orderNum)
.add("dlOrderNum=" + dlOrderNum)
.add("ctOrderNum=" + ctOrderNum)
.toString();

87
user-service/src/main/java/com/mh/user/dto/HotWaterControlZDListVO.java

@ -0,0 +1,87 @@
package com.mh.user.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Getter;
import lombok.Setter;
import java.math.BigDecimal;
import java.util.Date;
import java.util.StringJoiner;
/**
* @author LJF
* @version 1.0
* @project EEMCS
* @description 生活热水监控需要的列表信息
* @date 2025-03-14 09:07:46
*/
@Setter
@Getter
public class HotWaterControlZDListVO {
private String cpmId;
private String registerAddr;
private String buildingId;
private String buildingName;
private String deviceType;
private String deviceId;
private String deviceName;
private String curValue;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date curTime;
private String paramTypeId;
private String paramTypeGroupId;
private String otherName;
private int orderNum;
private int dlOrderNum;
private int ctOrderNum;
private int digits;
public String getCurValue() {
return curValue;
}
public void setCurValue(String curValue) {
// 判断curValue是否是数字类型
boolean isNumeric = curValue!= null && curValue.matches("[0-9]+(\\.[0-9]+)?");
if (curValue!= null && isNumeric) {
// 保留两位小数
curValue = new BigDecimal(curValue).setScale(2, BigDecimal.ROUND_HALF_UP).toString();
}
this.curValue = curValue;
}
@Override
public String toString() {
return new StringJoiner(", ", HotWaterControlZDListVO.class.getSimpleName() + "[", "]")
.add("cpmId='" + cpmId + "'")
.add("buildingId='" + buildingId + "'")
.add("buildingName='" + buildingName + "'")
.add("deviceType='" + deviceType + "'")
.add("deviceId='" + deviceId + "'")
.add("deviceName='" + deviceName + "'")
.add("curValue=" + curValue)
.add("curTime=" + curTime)
.add("paramTypeId='" + paramTypeId + "'")
.add("otherName='" + otherName + "'")
.add("orderNum=" + orderNum)
.add("dlOrderNum=" + dlOrderNum)
.add("ctOrderNum=" + ctOrderNum)
.toString();
}
}

4
user-service/src/main/java/com/mh/user/entity/CollectionParamsManageEntity.java

@ -75,6 +75,10 @@ public class CollectionParamsManageEntity implements Serializable {
private Integer grade;
/** 参数id */
private Integer paramTypeId;
/**
* 参数组类型
*/
private Integer paramGroupTypeId;
/** 遥测、遥信数据类型 */
private Integer collectionType;
/** 上报质量 */

3
user-service/src/main/java/com/mh/user/entity/DeviceInstallEntity.java

@ -1,5 +1,6 @@
package com.mh.user.entity;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
@ -16,6 +17,7 @@ public class DeviceInstallEntity {
private double ratio;
private double initValue;
private double lastValue;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date lastDate;
private String supDeviceAddr;
private String isOnline;
@ -28,6 +30,7 @@ public class DeviceInstallEntity {
private String buildingId;
private String buildingName;
private String installer;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date installDate;
private String remarks;
private double dayValue;

4
user-service/src/main/java/com/mh/user/job/CollectionLoopRunner.java

@ -67,8 +67,8 @@ public class CollectionLoopRunner implements ApplicationRunner {
// 获取天气数据
getWeatherInfoJob.getWeatherInfo();
// 启动netty端口
// NettyEchoServer nettyEchoServer = new NettyEchoServer();
// nettyEchoServer.bind(8098);
NettyEchoServer nettyEchoServer = new NettyEchoServer();
nettyEchoServer.bind(8098);
// 初始化mqtt订阅记录
// initializeMqttSubscription();
}

6
user-service/src/main/java/com/mh/user/job/DealDataJob.java

@ -74,7 +74,7 @@ public class DealDataJob {
/**
* 采集
*/
// @Scheduled(cron = "35 0/2 * * * ?")
@Scheduled(cron = "35 0/2 * * * ?")
// @Scheduled(cron = "0 0/1 * * * ?")
// @Scheduled(cron = "0 0/5 * * * ?") //5分钟
public void collect() {
@ -184,7 +184,7 @@ public class DealDataJob {
/**
* 每天12小时预测一次
*/
@Scheduled(cron = "0 5 0/12 * * ?")
// @Scheduled(cron = "0 5 0/12 * * ?")
public void preUseData() {
// 每12时预测一次数据
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
@ -205,7 +205,7 @@ public class DealDataJob {
/**
* 每周一凌晨1点训练一次数据
*/
@Scheduled(cron = "0 0 1 ? * 1")
// @Scheduled(cron = "0 0 1 ? * 1")
public void preTrainData() {
// 每周训练一次数据
List<BuildingModel> buildingModels = buildingService.selectBuildingName();

52
user-service/src/main/java/com/mh/user/mapper/CollectionParamsManageMapper.java

@ -1,6 +1,7 @@
package com.mh.user.mapper;
import com.mh.user.dto.HotWaterControlListVO;
import com.mh.user.dto.HotWaterControlZDListVO;
import com.mh.user.entity.CollectionParamsManageEntity;
import com.mh.user.entity.DeviceInstallEntity;
import com.mh.user.model.SanShiFengDatas;
@ -326,4 +327,55 @@ public interface CollectionParamsManageMapper extends BaseMapper<CollectionParam
@Result(column = "building_id", property = "buildingId")
})
List<CollectionParamsManageEntity> selectAllCPMList();
@Update("update collection_params_manage set cur_value = #{curValue}, cur_time = #{dateStr} where device_install_id = #{deviceInstallId} " +
"and register_addr = #{regAddr} and building_id = #{buildingId} ")
void updateCollectionParamsManage(Integer deviceInstallId, String regAddr, String curValue, String dateStr, String buildingId);
@Select("SELECT " +
" cpm.id as cpm_id, " +
" cpm.register_addr, " +
" di.building_id, " +
" di.building_name, " +
" ct.des as device_type, " +
" di.id as device_id, " +
" di.device_name, " +
" cpm.other_name, " +
" COALESCE(cpm.cur_value, 0) as cur_value, " +
" cpm.cur_time, " +
" cpm.param_type_id, " +
" cpm.param_type_group_id, " +
" cpm.digits, " +
" ct.order_num AS ct_order_num, " +
" di.order_num AS dl_order_num, " +
" cpm.order_num AS order_num " +
"FROM " +
" device_install di " +
" JOIN collection_params_manage cpm ON di.id = cpm.device_install_id " +
" JOIN code_table ct ON ct.code = cpm.param_type_group_id " +
" AND di.building_id = #{buildingId} " +
" AND cpm.device_install_id = #{deviceInstallId} " +
" AND ct.name = 'paramGroupType' " +
"ORDER BY " +
" ct.order_num, " +
" di.order_num ")
@Results({
@Result(column = "cpm_id", property = "cpmId"),
@Result(column = "building_id", property = "buildingId"),
@Result(column = "register_addr", property = "registerAddr"),
@Result(column = "building_name", property = "buildingName"),
@Result(column = "device_type", property = "deviceType"),
@Result(column = "device_id", property = "deviceId"),
@Result(column = "device_name", property = "deviceName"),
@Result(column = "other_name", property = "otherName"),
@Result(column = "cur_value", property = "curValue"),
@Result(column = "cur_time", property = "curTime"),
@Result(column = "param_type_id", property = "paramTypeId"),
@Result(column = "param_type_group_id", property = "paramTypeGroupId"),
@Result(column = "digits", property = "digits"),
@Result(column = "ct_order_num", property = "ctOrderNum"),
@Result(column = "dl_order_num", property = "dlOrderNum"),
@Result(column = "order_num", property = "orderNum")
})
List<HotWaterControlZDListVO> selectHotWaterByDeviceInstallId(String buildingId, Integer deviceInstallId);
}

7
user-service/src/main/java/com/mh/user/mapper/DeviceInstallMapper.java

@ -360,4 +360,11 @@ public interface DeviceInstallMapper extends BaseMapper<DeviceInstallEntity> {
@Select("select count(1) from device_install where building_id = #{buildingId} and device_type = '热泵' ")
int queryPumpCount(String buildingId);
@Select("select top 1 id from device_install where building_id = #{buildingId} "+
" and data_com = #{dataCom} "+
" and device_type = #{deviceType} "+
" and brand = #{brand} " +
" and device_addr = #{deviceAddr} ")
Integer selectDeviceByParam(String buildingId, String dataCom, String deviceType, String brand, String deviceAddr);
}

4
user-service/src/main/java/com/mh/user/service/CollectionParamsManageService.java

@ -38,7 +38,11 @@ public interface CollectionParamsManageService {
List<HotWaterControlDTO> operateList(String floorId);
List<HotWaterControlDTO> operateList(String floorId, Integer deviceInstallId);
void getBatchUpdateCollectionParams(List<SanShiFengDatas> batch, String sn, String plcName, String projectName, String time, String buildingId);
List<CollectionParamsManageEntity> selectAllCPMList();
void updateCollectionParamsManage(Integer deviceInstallId, String regAddr, String string, String dateStr, String buildingId);
}

7
user-service/src/main/java/com/mh/user/service/DeviceInstallService.java

@ -1,9 +1,6 @@
package com.mh.user.service;
import com.mh.user.entity.BuildingEntity;
import com.mh.user.entity.DeviceInstallEntity;
import com.mh.user.entity.DeviceInstallTempEntity;
import com.mh.user.entity.UploadDeviceInstallEntity;
import com.mh.user.entity.*;
import com.mh.user.mapper.provider.DeviceInstallProvider;
import com.mh.user.model.DeviceModel;
import org.apache.ibatis.annotations.Param;
@ -194,4 +191,6 @@ public interface DeviceInstallService {
String selectSinglePumpId(String buildingId, String pumpId);
int queryPumpCount(String buildingId);
Integer selectDeviceByOtherParams(DeviceCodeParamEntity deviceCodeParamEntity);
}

238
user-service/src/main/java/com/mh/user/service/impl/CollectionParamsManageServiceImpl.java

@ -8,9 +8,13 @@ import com.mh.user.entity.DeviceInstallEntity;
import com.mh.user.mapper.CollectionParamsManageMapper;
import com.mh.user.model.SanShiFengDatas;
import com.mh.user.service.CollectionParamsManageService;
import com.mh.user.utils.XK814ModbusParamReadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
@ -33,12 +37,54 @@ public class CollectionParamsManageServiceImpl implements CollectionParamsManage
this.collectionParamsManageMapper = collectionParamsManageMapper;
}
@Override
public void updateCollectionParamsManage(Integer deviceInstallId, String regAddr, String string, String dateStr, String buildingId) {
// 更新采集参数管理表
collectionParamsManageMapper.updateCollectionParamsManage(deviceInstallId, regAddr, string, dateStr, buildingId);
}
@Override
public List<HotWaterNowDataDTO> monitorList(String buildingId) {
// 查询nowData表中数据
return Collections.emptyList();
}
@Override
public List<HotWaterControlDTO> operateList(String floorId, Integer deviceInstallId) {
List<HotWaterControlZDListVO> list = collectionParamsManageMapper.selectHotWaterByDeviceInstallId(floorId, deviceInstallId);
// 开始根据deviceType进行数据分组,组内的数据根据ctOrderNum进行升序排序
Map<String, List<HotWaterControlZDListVO>> groupedList = list.stream()
.collect(Collectors.groupingBy(HotWaterControlZDListVO::getDeviceType));
List<HotWaterControlDTO> dtos = groupedList.entrySet().stream()
.map(this::convertToHotWaterControlDTO2)
.sorted(Comparator.comparingInt(HotWaterControlDTO::getOrderNum))
.collect(Collectors.toList());
// 对每个DTO的children进行二次分组
List<HotWaterControlDTO> result = dtos.stream()
.map(dto -> {
HotWaterControlDTO newDto = new HotWaterControlDTO();
newDto.setId(dto.getId());
newDto.setName(dto.getName());
newDto.setOrderNum(dto.getOrderNum());
// 获取原始children列表
List<?> originalChildren = dto.getChildren();
if (originalChildren != null && !originalChildren.isEmpty()) {
// 根据设备类型和orderNum进行二次分组
List<HotWaterControlDTO> groupedChildren = groupChildrenByCategory(originalChildren, dto.getName());
newDto.setChildren(groupedChildren);
} else {
newDto.setChildren(Collections.emptyList());
}
return newDto;
})
.collect(Collectors.toList());
return result;
}
@Override
public List<HotWaterControlDTO> operateList(String floorId) {
List<HotWaterControlListVO> hotWaterControlListVOS = collectionParamsManageMapper.selectHotWaterByBuildingId(floorId);
@ -54,6 +100,15 @@ public class CollectionParamsManageServiceImpl implements CollectionParamsManage
.collect(Collectors.toList());
}
private HotWaterControlDTO convertToHotWaterControlDTO2(Map.Entry<String, List<HotWaterControlZDListVO>> houseEntry) {
HotWaterControlDTO dto = new HotWaterControlDTO();
dto.setId(houseEntry.getKey());
dto.setName(houseEntry.getValue().get(0).getDeviceType());
dto.setOrderNum(houseEntry.getValue().get(0).getCtOrderNum());
dto.setChildren(houseEntry.getValue());
return dto;
}
private HotWaterControlDTO convertToHotWaterControlDTO(Map.Entry<String, List<HotWaterControlListVO>> houseEntry) {
HotWaterControlDTO dto = new HotWaterControlDTO();
dto.setId(houseEntry.getKey());
@ -91,6 +146,189 @@ public class CollectionParamsManageServiceImpl implements CollectionParamsManage
return 0;
}
/**
* 根据设备类型和orderNum对children进行二次分组
* @param children 原始children列表
* @param deviceType 设备类型
* @return 分组后的HotWaterControlDTO列表
*/
private List<HotWaterControlDTO> groupChildrenByCategory(List<?> children, String deviceType) {
// 定义分组规则
Map<String, int[]> categoryRules = new HashMap<>();
if ("运行参数".equals(deviceType)) {
// 运行参数分组规则
categoryRules.put("探头监控数据", new int[]{1, 13});
categoryRules.put("电流运行数据", new int[]{14, 15});
categoryRules.put("电子膨胀阀开度", new int[]{16, 19});
categoryRules.put("机组模式", new int[]{20, Integer.MAX_VALUE});
} else if ("设置参数".equals(deviceType)) {
// 设置参数分组规则
categoryRules.put("开机界面", new int[]{1, 6});
categoryRules.put("水箱界面", new int[]{7, 8});
categoryRules.put("未分组", new int[]{9, Integer.MAX_VALUE});
}
// 如果没有定义分组规则,直接返回原children包装成的DTO列表
if (categoryRules.isEmpty()) {
return children.stream()
.map(child -> {
HotWaterControlDTO childDto = new HotWaterControlDTO();
childDto.setId(getIdFromObject(child));
childDto.setName(getNameFromObject(child));
childDto.setOrderNum(getOrderNumFromObject(child));
childDto.setChildren(Collections.singletonList(child));
return childDto;
})
.collect(Collectors.toList());
}
// 按类别分组
Map<String, List<Object>> categorizedMap = new LinkedHashMap<>();
for (String category : categoryRules.keySet()) {
categorizedMap.put(category, new ArrayList<>());
}
// 将children分配到对应的类别中
for (Object child : children) {
int orderNum = getOrderNumFromObject(child);
String assignedCategory = assignToCategory(orderNum, categoryRules);
if (assignedCategory != null) {
categorizedMap.get(assignedCategory).add(child);
}
}
// 转换为HotWaterControlDTO列表
List<HotWaterControlDTO> result = new ArrayList<>();
int index = 1;
for (Map.Entry<String, List<Object>> entry : categorizedMap.entrySet()) {
if (!entry.getValue().isEmpty()) {
HotWaterControlDTO categoryDto = new HotWaterControlDTO();
categoryDto.setId("category_" + index);
categoryDto.setName(entry.getKey());
categoryDto.setOrderNum(index);
// 将该类别下的children设置为子项
List<Object> categoryChildren = entry.getValue().stream()
.sorted((o1, o2) -> Integer.compare(getOrderNumFromObject(o1), getOrderNumFromObject(o2)))
.collect(Collectors.toList());
// 这里再根据entry.getKey() == '机组模式'进行更细化修改处理,比如otherName='版本号',需要进行XK814ModbusParamReadUtil.parseVersion解析,并封装为DTO对象。
if ("机组模式".equals(entry.getKey())) {
List<Object> newCategoryChildren = new ArrayList<>();
for (Object child : categoryChildren) {
// child对象转换成HotWaterControlListVO对象
HotWaterControlZDListVO childVO = new HotWaterControlZDListVO();
BeanUtils.copyProperties(child, childVO);
if ("版本号".equals(getNameFromObject(child))
|| "输入开关状态".equals(getNameFromObject(child))
|| "水位开关状态".equals(getNameFromObject(child))
|| "输出1状态".equals(getNameFromObject(child))
|| "输出2状态".equals(getNameFromObject(child))
|| "输出3状态".equals(getNameFromObject(child))
|| "机组信息".equals(getNameFromObject(child))
|| "主板类别".equals(getNameFromObject(child))
) {
int parseInt = (int) Double.parseDouble(childVO.getCurValue());
// 解析并封装为DTO对象,此处省略具体实现细节。
String parse = String.valueOf(XK814ModbusParamReadUtil.parse(childVO.getRegisterAddr(), parseInt));
if (parse != null && !parse.isEmpty()) {
String[] arr = parse.split(";");
Collections.reverse(Arrays.asList(arr));
// 开始遍历
for (String s : arr) {
String[] split = s.split(":");
HotWaterControlZDListVO newChildVO = new HotWaterControlZDListVO();
BeanUtils.copyProperties(childVO, newChildVO);
if (split.length > 1) {
newChildVO.setOtherName(split[0]);
newChildVO.setCurValue(split[1]);
}
newCategoryChildren.add(newChildVO);
}
}
} else {
newCategoryChildren.add(childVO);
}
}
categoryChildren = newCategoryChildren;
}
categoryDto.setChildren(categoryChildren);
result.add(categoryDto);
index++;
}
}
return result;
}
/**
* 根据orderNum分配到对应的类别
* @param orderNum 排序号
* @param categoryRules 分类规则
* @return 分配的类别名称
*/
private String assignToCategory(int orderNum, Map<String, int[]> categoryRules) {
for (Map.Entry<String, int[]> entry : categoryRules.entrySet()) {
int[] range = entry.getValue();
if (orderNum >= range[0] && orderNum <= range[1]) {
return entry.getKey();
}
}
return null;
}
/**
* 从对象中获取ID
* @param obj 对象
* @return ID字符串
*/
private String getIdFromObject(Object obj) {
try {
if (obj != null) {
java.lang.reflect.Method getIdMethod = obj.getClass().getMethod("getId");
Object id = getIdMethod.invoke(obj);
if (id == null) {
Method getCpmIdMethod = obj.getClass().getMethod("getCpmId");
id = getCpmIdMethod.invoke(obj);
}
return id != null ? id.toString() : "";
}
} catch (Exception e) {
// 忽略异常
}
return "";
}
/**
* 从对象中获取名称
* @param obj 对象
* @return 名称字符串
*/
private String getNameFromObject(Object obj) {
try {
if (obj != null) {
java.lang.reflect.Method getNameMethod = obj.getClass().getMethod("getName");
Object name = getNameMethod.invoke(obj);
if (name == null) {
Method getCpmNameMethod = obj.getClass().getMethod("getOtherName");
name = getCpmNameMethod.invoke(obj);
}
return name != null ? name.toString() : "";
}
} catch (Exception e) {
// 忽略异常
try {
Method getCpmNameMethod = obj.getClass().getMethod("getOtherName");
Object name = getCpmNameMethod.invoke(obj);
return name != null ? name.toString() : "";
} catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException ex) {
// 忽略异常
}
}
return "";
}
private Object createDeviceVO(Map.Entry<String, List<HotWaterControlListVO>> dlEntry, HotWaterControlDTO parentDto) {
List<HotWaterControlListVO> dlItems = dlEntry.getValue();

78
user-service/src/main/java/com/mh/user/service/impl/DeviceInstallServiceImpl.java

@ -14,16 +14,14 @@ import com.mh.user.service.BuildingService;
import com.mh.user.service.DeviceInstallService;
import com.mh.user.utils.CacheUtil;
import com.mh.user.utils.ExchangeStringUtil;
import com.mh.user.utils.XK814ModbusParamReadUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.*;
@Slf4j
@Service
@ -40,6 +38,15 @@ public class DeviceInstallServiceImpl implements DeviceInstallService {
@Autowired
private NowDataMapper nowDataMapper;
@Override
public Integer selectDeviceByOtherParams(DeviceCodeParamEntity deviceCodeParamEntity) {
return deviceInstallMapper.selectDeviceByParam(deviceCodeParamEntity.getBuildingId(),
deviceCodeParamEntity.getDataCom(),
deviceCodeParamEntity.getDeviceType(),
deviceCodeParamEntity.getBrand(),
deviceCodeParamEntity.getDeviceAddr());
}
@Override
public int saveDevice(DeviceInstallEntity deviceInstallEntity) {
if (StringUtil.isEmpty(deviceInstallEntity.getBuildingId()) && !StringUtil.isEmpty(deviceInstallEntity.getBuildingName())) {
@ -225,6 +232,69 @@ public class DeviceInstallServiceImpl implements DeviceInstallService {
deviceCodeParamEntity.setFunCode("04");
deviceCodeParamMapper.insertDeviceCodeParamList(Collections.singletonList(deviceCodeParamEntity));
break;
case "正帝":
// 需要把XK814ModbusParserUtil类钟的所有常量放入到deviceCodeParamEntityList中
// 使用功能码03读取,每次读取2个寄存器
String[] zhengDiAddrs = {
XK814ModbusParamReadUtil.ADDR_DISPLAY_WATER_TEMP, // 显示水温
XK814ModbusParamReadUtil.ADDR_TANK_TEMP, // 水箱温度
XK814ModbusParamReadUtil.ADDR_OUTLET_TEMP, // 出水温度
XK814ModbusParamReadUtil.ADDR_INLET_TEMP, // 回水温度
XK814ModbusParamReadUtil.ADDR_AMBIENT_TEMP, // 环境温度
XK814ModbusParamReadUtil.ADDR_COIL1_TEMP, // 盘管1温度
XK814ModbusParamReadUtil.ADDR_SUCTION1_TEMP, // 吸气1温度
XK814ModbusParamReadUtil.ADDR_EXHAUST1_TEMP, // 排气1温度
XK814ModbusParamReadUtil.ADDR_VALVE_AFTER1_OR_RETURN, // 阀后1温度
XK814ModbusParamReadUtil.ADDR_MAIN_EXP_VALVE1_OPEN, // 主膨胀阀1开度
XK814ModbusParamReadUtil.ADDR_AUX_EXP_VALVE1_OPEN, // 辅膨胀阀1开度
XK814ModbusParamReadUtil.ADDR_COMP1_CURRENT, // 压缩机1电流
XK814ModbusParamReadUtil.ADDR_COIL2_TEMP, // 盘管2温度
XK814ModbusParamReadUtil.ADDR_SUCTION2_TEMP, // 吸气2温度
XK814ModbusParamReadUtil.ADDR_EXHAUST2_TEMP, // 排气2温度
XK814ModbusParamReadUtil.ADDR_VALVE_AFTER2_TEMP, // 阀后2温度
XK814ModbusParamReadUtil.ADDR_MAIN_EXP_VALVE2_OPEN, // 主膨胀阀2开度
XK814ModbusParamReadUtil.ADDR_AUX_EXP_VALVE2_OPEN, // 辅膨胀阀2开度
XK814ModbusParamReadUtil.ADDR_COMP2_CURRENT, // 压缩机2电流
XK814ModbusParamReadUtil.ADDR_RECOVERABLE_FAULT, // 可恢复故障
XK814ModbusParamReadUtil.ADDR_UNRECOVERABLE_FAULT, // 不可恢复故障
XK814ModbusParamReadUtil.ADDR_VERSION_INFO, // 版本信息
XK814ModbusParamReadUtil.ADDR_INPUT_SWITCH_STATUS, // 输入开关状态
XK814ModbusParamReadUtil.ADDR_WATER_LEVEL_SWITCH, // 水位开关状态
XK814ModbusParamReadUtil.ADDR_OUTPUT1_STATUS, // 输出1状态
XK814ModbusParamReadUtil.ADDR_OUTPUT2_STATUS, // 输出2状态
XK814ModbusParamReadUtil.ADDR_OUTPUT3_STATUS, // 输出3状态
XK814ModbusParamReadUtil.ADDR_DIP_SWITCH, // 拨码开关
XK814ModbusParamReadUtil.ADDR_MAINBOARD_TYPE, // 主板类型
XK814ModbusParamReadUtil.ADDR_CONSTANT_TEMP_SET, // 恒温设置温度
XK814ModbusParamReadUtil.ADDR_ON_OFF, // 开关机
XK814ModbusParamReadUtil.ADDR_COOL_SET_TEMP, // 制冷设置温度
XK814ModbusParamReadUtil.ADDR_HEAT_SET_TEMP, // 制热设置温度
XK814ModbusParamReadUtil.ADDR_MODE, // 运行模式
XK814ModbusParamReadUtil.ADDR_HOT_WATER_SET_TEMP, // 热水设置温度
XK814ModbusParamReadUtil.ADDR_FORCE_ELECTRIC_HEAT, // 强制电加热
XK814ModbusParamReadUtil.ADDR_FORCE_DEFROST, // 强制除霜
XK814ModbusParamReadUtil.ADDR_RETURN_VALVE_TIMER, // 回水阀定时
XK814ModbusParamReadUtil.ADDR_SUPPLY_VALVE_TIMER // 供水阀定时
};
List<DeviceCodeParamEntity> deviceCodeParamEntityList = new ArrayList<>();
for (String addr : zhengDiAddrs) {
DeviceCodeParamEntity param = new DeviceCodeParamEntity();
param.setRegisterAddr(addr);
param.setFunCode("03"); // 使用功能码03读取
param.setDeviceAddr(deviceInstallEntity.getDeviceAddr());
param.setDeviceName(deviceInstallEntity.getDeviceName());
param.setDeviceType(deviceInstallEntity.getDeviceType());
param.setBaudrate(deviceInstallEntity.getBaudRate());
param.setBrand(deviceInstallEntity.getBrand());
param.setDataCom(deviceInstallEntity.getDataCom());
param.setBuildingId(deviceInstallEntity.getBuildingId());
param.setParity(deviceInstallEntity.getParity());
param.setThread(ExchangeStringUtil.getNumFromString(deviceInstallEntity.getDataCom()));
deviceCodeParamEntityList.add(param);
}
deviceCodeParamMapper.insertDeviceCodeParamList(deviceCodeParamEntityList);
break;
default:
break;
}

178
user-service/src/main/java/com/mh/user/strategy/HeatPumpStrategy.java

@ -9,6 +9,8 @@ import com.mh.user.entity.NowPublicDataEntity;
import com.mh.user.service.*;
import com.mh.user.utils.ExchangeStringUtil;
import com.mh.user.utils.SpringBeanUtil;
import com.mh.user.utils.XK814ModbusParamReadUtil;
import com.mh.user.utils.XK814ModbusParamWriteUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
@ -32,6 +34,7 @@ public class HeatPumpStrategy implements DeviceStrategy {
PumpSetService pumpSetService = context.getBean(PumpSetService.class);
DeviceInstallService deviceInstallService = context.getBean(DeviceInstallService.class);
DealDataService dealDataService = context.getBean(DealDataService.class);
CollectionParamsManageService collectionParamsManageService = context.getBean(CollectionParamsManageService.class);
private static class SingletonHolder {
private static final HeatPumpStrategy INSTANCE = new HeatPumpStrategy();
@ -215,7 +218,15 @@ public class HeatPumpStrategy implements DeviceStrategy {
String dataStr = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(String.valueOf(dataValue)), 4);
str = str + funCode + registerAddr + dataStr;
}
} else if (Constant.BRAND_ZHENG_DI.equals(brand)) {
if (StringUtils.isBlank(funCode) || funCode.equals("03")) {
str = str + funCode + registerAddr + "0002";
} else if ("06".equals(funCode)) {
str = XK814ModbusParamWriteUtil.buildWriteSingleRegisterMessage(Integer.parseInt(deviceAddr), registerAddr, dataValue);
str = str.substring(0, str.length() - 4);
}
}
String checkWord = ExchangeStringUtil.getStrCRC16(str); //CRC16校验
str = str + checkWord;
} catch (Exception e) {
@ -279,6 +290,8 @@ public class HeatPumpStrategy implements DeviceStrategy {
rtData = getHaiEr(dateStr, registerAddr, buildingId, buildingName, checkStr, sValue, addr, dataType);
} else if (Constant.BRAND_HAI_ER_TWO.equals(brand)) {
rtData = getHaiErTwo(dateStr, registerAddr, buildingId, buildingName, checkStr, sValue, addr, dataType);
} else if (Constant.BRAND_ZHENG_DI.equals(brand)) {
rtData = getZhengDi(dateStr, registerAddr, buildingId, buildingName, checkStr, sValue, addr, dataType, deviceCodeParamEntity);
}
if (!StringUtils.isBlank(rtData)) {
nowDataService.saveNowHistoryData(addr, "热泵", rtData, dataType.toString(), buildingId);
@ -289,6 +302,171 @@ public class HeatPumpStrategy implements DeviceStrategy {
return rtData;
}
private String getZhengDi(String dateStr, String registerAddr, String buildingId, String buildingName, String checkStr, String sValue, String addr, StringBuffer dataType, DeviceCodeParamEntity deviceCodeParamEntity) {
// 开始解析
// checkStr 格式: 地址(2) + 功能码(2) + 字节数(2) + 数据(n*4)
// 例如: 010304A0000064xxxx (读取2个寄存器,返回4字节数据)
try {
// 获取数据字节数
int byteCount = Integer.parseInt(checkStr.substring(4, 6), 16);
// 根据字节数计算寄存器数量(每个寄存器2字节)
int registerCount = byteCount / 2;
// 遍历所有寄存器数据
for (int i = 0; i < registerCount; i++) {
// 提取寄存器值(每4个字符代表一个寄存器)
String hexValue = checkStr.substring(6 + i * 4, 10 + i * 4);
int value = Integer.parseInt(hexValue, 16);
// 计算寄存器地址
String regAddr = ExchangeStringUtil.addZeroForNum(registerAddr, 4).toUpperCase();
// 使用 XK814ModbusParserUtil 解析
Object parsedValue = XK814ModbusParamReadUtil.parse(regAddr, value);
if (parsedValue != null) {
log.info("正帝热泵解析 - 地址: {}, 原始值: {}, 解析结果: {}", regAddr, value, parsedValue);
// 根据不同的寄存器地址处理不同的业务逻辑
processZhengDiData(regAddr, parsedValue, value, buildingId, buildingName, addr, dataType);
sValue = String.valueOf(parsedValue);
// 这里根据com口、deviceType、brand、deviceAddr、buildingId查询对应deviceInstall的ID值
Integer deviceInstallId = deviceInstallService.selectDeviceByOtherParams(deviceCodeParamEntity);
if (deviceInstallId != null) {
// 再根据deviceInstall的id和deviceAddr更新collectionParamManage对应的值
collectionParamsManageService.updateCollectionParamsManage(deviceInstallId, regAddr, parsedValue.toString(), dateStr, buildingId);
}
}
}
} catch (Exception e) {
log.error("正帝热泵数据解析异常: " + checkStr, e);
sValue = Constant.FAIL;
}
return sValue;
}
/**
* 处理正帝热泵解析后的数据
*/
private void processZhengDiData(String regAddr, Object parsedValue, int rawValue,
String buildingId, String buildingName, String addr,
StringBuffer dataType) {
try {
// 温度相关数据
if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_DISPLAY_WATER_TEMP) ||
regAddr.equals(XK814ModbusParamReadUtil.ADDR_TANK_TEMP)) {
// 显示水温或水箱温度
dataType.setLength(0);
dataType.append("waterTemp");
String tempStr = parsedValue.toString();
// 保存公共数据
NowPublicDataEntity publicData = new NowPublicDataEntity();
publicData.setBuildingId(buildingId);
publicData.setSingleTemp(tempStr);
nowPublicDataService.saveNowHistoryPublicData(publicData);
log.info("楼栋名称:{}, 热泵编号:{}, 水箱温度:{}", buildingName, addr, tempStr);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_OUTLET_TEMP)) {
// 出水温度
dataType.setLength(0);
dataType.append("outletTemp");
log.info("楼栋名称:{}, 热泵编号:{}, 出水温度:{}", buildingName, addr, parsedValue);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_INLET_TEMP)) {
// 回水温度
dataType.setLength(0);
dataType.append("inletTemp");
log.info("楼栋名称:{}, 热泵编号:{}, 回水温度:{}", buildingName, addr, parsedValue);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_AMBIENT_TEMP)) {
// 环境温度
dataType.setLength(0);
dataType.append("ambientTemp");
log.info("楼栋名称:{}, 热泵编号:{}, 环境温度:{}", buildingName, addr, parsedValue);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_COOL_SET_TEMP)) {
// 制冷设置温度
dataType.setLength(0);
dataType.append("coolSetTemp");
pumpSetService.updatePumpSetTemp(parsedValue.toString(), buildingId, addr);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_HEAT_SET_TEMP)) {
// 制热设置温度
dataType.setLength(0);
dataType.append("heatSetTemp");
pumpSetService.updatePumpSetTemp(parsedValue.toString(), buildingId, addr);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_HOT_WATER_SET_TEMP)) {
// 热水设置温度
dataType.setLength(0);
dataType.append("hotWaterSetTemp");
pumpSetService.updatePumpSetTemp(parsedValue.toString(), buildingId, addr);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_CONSTANT_TEMP_SET)) {
// 恒温设置温度
dataType.setLength(0);
dataType.append("constantTempSet");
pumpSetService.updatePumpSetTemp(parsedValue.toString(), buildingId, addr);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_MODE)) {
// 运行模式
dataType.setLength(0);
dataType.append("runMode");
log.info("楼栋名称:{}, 热泵编号:{}, 运行模式:{}", buildingName, addr, parsedValue);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_ON_OFF)) {
// 开关机状态
dataType.setLength(0);
dataType.append("runState");
log.info("楼栋名称:{}, 热泵编号:{}, 开关状态:{}", buildingName, addr, parsedValue);
// 计算热泵运行时间
nowDataService.proPumpMinutes(buildingId, addr, parsedValue.toString());
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_RECOVERABLE_FAULT) ||
regAddr.equals(XK814ModbusParamReadUtil.ADDR_UNRECOVERABLE_FAULT)) {
// 故障状态
dataType.setLength(0);
dataType.append("isFault");
String faultStatus = (rawValue == 0) ? "无故障" : "有故障";
deviceInstallService.updateDeviceFault((rawValue == 0) ? "0" : "1", addr, "热泵");
log.info("楼栋名称:{}, 热泵编号:{}, 故障状态:{}", buildingName, addr, faultStatus);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_INPUT_SWITCH_STATUS)) {
// 输入开关状态
dataType.setLength(0);
dataType.append("inputSwitchStatus");
log.info("楼栋名称:{}, 热泵编号:{}, 输入开关状态:{}", buildingName, addr, parsedValue);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_OUTPUT1_STATUS) ||
regAddr.equals(XK814ModbusParamReadUtil.ADDR_OUTPUT2_STATUS) ||
regAddr.equals(XK814ModbusParamReadUtil.ADDR_OUTPUT3_STATUS)) {
// 输出状态
dataType.setLength(0);
dataType.append("outputStatus");
log.info("楼栋名称:{}, 热泵编号:{}, 输出状态:{}", buildingName, addr, parsedValue);
} else if (regAddr.equals(XK814ModbusParamReadUtil.ADDR_VERSION_INFO)) {
// 版本信息
dataType.setLength(0);
dataType.append("versionInfo");
log.info("楼栋名称:{}, 热泵编号:{}, 版本信息:{}", buildingName, addr, parsedValue);
} else {
// 其他未处理的寄存器
log.debug("楼栋名称:{}, 热泵编号:{}, 寄存器:{}, 值:{}", buildingName, addr, regAddr, parsedValue);
}
} catch (Exception e) {
log.error("处理正帝热泵数据异常 - 地址: {}, 值: {}", regAddr, parsedValue, e);
}
}
private String getHaiEr(String dateStr, String registerAddr, String buildingId, String buildingName, String checkStr, String sValue, String addr, StringBuffer stringBuffer) {
String data;
stringBuffer.setLength(0);

71
user-service/src/main/java/com/mh/user/utils/GetReadOrder485.java

@ -5,8 +5,6 @@ import com.mh.user.constants.Constant;
import com.mh.user.entity.*;
import com.mh.user.service.DeviceCodeParamService;
import com.mh.user.service.DeviceInstallService;
import com.mh.user.service.GatewayManageService;
import com.mh.user.service.impl.DeviceDisplayServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
@ -666,9 +664,9 @@ public class GetReadOrder485 {
deviceCodeParamEntity3.setDataCom(devices.getDataCom());
deviceCodeParamEntity3.setBuildingId(devices.getBuildingId());
deviceCodeParamEntity3.setParity(devices.getParity());
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
// 只获取字符串数字
deviceCodeParamEntity3.setThread(ExchangeStringUtil.getNumFromString(devices.getDataCom()));
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
break;
case "瑞星":
deviceCodeParamEntity3.setRegisterAddr("0046");//实际水温
@ -681,9 +679,9 @@ public class GetReadOrder485 {
deviceCodeParamEntity3.setDataCom(devices.getDataCom());
deviceCodeParamEntity3.setBuildingId(devices.getBuildingId());
deviceCodeParamEntity3.setParity(devices.getParity());
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
// 只获取字符串数字
deviceCodeParamEntity3.setThread(ExchangeStringUtil.getNumFromString(devices.getDataCom()));
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
break;
case "海尔":
// 多联机模式
@ -698,9 +696,9 @@ public class GetReadOrder485 {
deviceCodeParamEntity3.setDataCom(devices.getDataCom());
deviceCodeParamEntity3.setBuildingId(devices.getBuildingId());
deviceCodeParamEntity3.setParity(devices.getParity());
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
// 只获取字符串数字
deviceCodeParamEntity3.setThread(ExchangeStringUtil.getNumFromString(devices.getDataCom()));
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
break;
case "海尔2":
// 线控模式
@ -715,11 +713,70 @@ public class GetReadOrder485 {
deviceCodeParamEntity3.setDataCom(devices.getDataCom());
deviceCodeParamEntity3.setBuildingId(devices.getBuildingId());
deviceCodeParamEntity3.setParity(devices.getParity());
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
// 只获取字符串数字
deviceCodeParamEntity3.setThread(ExchangeStringUtil.getNumFromString(devices.getDataCom()));
deviceCodeParamEntityList.add(deviceCodeParamEntity3);
break;
default:
case "正帝":
// 需要把XK814ModbusParserUtil类钟的所有常量放入到deviceCodeParamEntityList中
// 使用功能码03读取,每次读取2个寄存器
String[] zhengDiAddrs = {
XK814ModbusParamReadUtil.ADDR_DISPLAY_WATER_TEMP, // 显示水温
XK814ModbusParamReadUtil.ADDR_TANK_TEMP, // 水箱温度
XK814ModbusParamReadUtil.ADDR_OUTLET_TEMP, // 出水温度
XK814ModbusParamReadUtil.ADDR_INLET_TEMP, // 回水温度
XK814ModbusParamReadUtil.ADDR_AMBIENT_TEMP, // 环境温度
XK814ModbusParamReadUtil.ADDR_COIL1_TEMP, // 盘管1温度
XK814ModbusParamReadUtil.ADDR_SUCTION1_TEMP, // 吸气1温度
XK814ModbusParamReadUtil.ADDR_EXHAUST1_TEMP, // 排气1温度
XK814ModbusParamReadUtil.ADDR_VALVE_AFTER1_OR_RETURN, // 阀后1温度
XK814ModbusParamReadUtil.ADDR_MAIN_EXP_VALVE1_OPEN, // 主膨胀阀1开度
XK814ModbusParamReadUtil.ADDR_AUX_EXP_VALVE1_OPEN, // 辅膨胀阀1开度
XK814ModbusParamReadUtil.ADDR_COMP1_CURRENT, // 压缩机1电流
XK814ModbusParamReadUtil.ADDR_COIL2_TEMP, // 盘管2温度
XK814ModbusParamReadUtil.ADDR_SUCTION2_TEMP, // 吸气2温度
XK814ModbusParamReadUtil.ADDR_EXHAUST2_TEMP, // 排气2温度
XK814ModbusParamReadUtil.ADDR_VALVE_AFTER2_TEMP, // 阀后2温度
XK814ModbusParamReadUtil.ADDR_MAIN_EXP_VALVE2_OPEN, // 主膨胀阀2开度
XK814ModbusParamReadUtil.ADDR_AUX_EXP_VALVE2_OPEN, // 辅膨胀阀2开度
XK814ModbusParamReadUtil.ADDR_COMP2_CURRENT, // 压缩机2电流
XK814ModbusParamReadUtil.ADDR_RECOVERABLE_FAULT, // 可恢复故障
XK814ModbusParamReadUtil.ADDR_UNRECOVERABLE_FAULT, // 不可恢复故障
XK814ModbusParamReadUtil.ADDR_VERSION_INFO, // 版本信息
XK814ModbusParamReadUtil.ADDR_INPUT_SWITCH_STATUS, // 输入开关状态
XK814ModbusParamReadUtil.ADDR_WATER_LEVEL_SWITCH, // 水位开关状态
XK814ModbusParamReadUtil.ADDR_OUTPUT1_STATUS, // 输出1状态
XK814ModbusParamReadUtil.ADDR_OUTPUT2_STATUS, // 输出2状态
XK814ModbusParamReadUtil.ADDR_OUTPUT3_STATUS, // 输出3状态
XK814ModbusParamReadUtil.ADDR_DIP_SWITCH, // 拨码开关
XK814ModbusParamReadUtil.ADDR_MAINBOARD_TYPE, // 主板类型
XK814ModbusParamReadUtil.ADDR_CONSTANT_TEMP_SET, // 恒温设置温度
XK814ModbusParamReadUtil.ADDR_ON_OFF, // 开关机
XK814ModbusParamReadUtil.ADDR_COOL_SET_TEMP, // 制冷设置温度
XK814ModbusParamReadUtil.ADDR_HEAT_SET_TEMP, // 制热设置温度
XK814ModbusParamReadUtil.ADDR_MODE, // 运行模式
XK814ModbusParamReadUtil.ADDR_HOT_WATER_SET_TEMP, // 热水设置温度
XK814ModbusParamReadUtil.ADDR_FORCE_ELECTRIC_HEAT, // 强制电加热
XK814ModbusParamReadUtil.ADDR_FORCE_DEFROST, // 强制除霜
XK814ModbusParamReadUtil.ADDR_RETURN_VALVE_TIMER, // 回水阀定时
XK814ModbusParamReadUtil.ADDR_SUPPLY_VALVE_TIMER // 供水阀定时
};
for (String addr : zhengDiAddrs) {
DeviceCodeParamEntity param = new DeviceCodeParamEntity();
param.setRegisterAddr(addr);
param.setFunCode("03"); // 使用功能码03读取
param.setDeviceAddr(devices.getDeviceAddr());
param.setDeviceName(devices.getDeviceName());
param.setDeviceType(devices.getDeviceType());
param.setBaudrate(devices.getBaudRate());
param.setBrand(devices.getBrand());
param.setDataCom(devices.getDataCom());
param.setBuildingId(devices.getBuildingId());
param.setParity(devices.getParity());
param.setThread(ExchangeStringUtil.getNumFromString(devices.getDataCom()));
deviceCodeParamEntityList.add(param);
}
break;
}
}

362
user-service/src/main/java/com/mh/user/utils/XK814ModbusParamReadUtil.java

@ -0,0 +1,362 @@
package com.mh.user.utils;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* @author LJF
* @version 1.0
* @project CHWS
* @description 正帝热泵协议解析
* @date 2026-05-25 17:15:42
*/
public class XK814ModbusParamReadUtil {
/**
* XK814 冷热水机 Modbus 协议 V1.0 解析器第三张表
* 地址范围A000 ~ B009, AFFF
*/
// ==================== 地址常量(字符串格式)====================
public static final String ADDR_DISPLAY_WATER_TEMP = "A000"; // 40960
public static final String ADDR_TANK_TEMP = "A001"; // 40961
public static final String ADDR_OUTLET_TEMP = "A002"; // 40962
public static final String ADDR_INLET_TEMP = "A003"; // 40963
public static final String ADDR_AMBIENT_TEMP = "A004"; // 40964
public static final String ADDR_COIL1_TEMP = "A005"; // 40965
public static final String ADDR_SUCTION1_TEMP = "A006"; // 40966
public static final String ADDR_EXHAUST1_TEMP = "A007"; // 40967
public static final String ADDR_VALVE_AFTER1_OR_RETURN = "A008"; // 40968
public static final String ADDR_RESERVED_A009 = "A009";
public static final String ADDR_RESERVED_A00A = "A00A";
public static final String ADDR_MAIN_EXP_VALVE1_OPEN = "A00B"; // 40971
public static final String ADDR_AUX_EXP_VALVE1_OPEN = "A00C"; // 40972
public static final String ADDR_COMP1_CURRENT = "A00D"; // 40973
public static final String ADDR_COIL2_TEMP = "A00E"; // 40974
public static final String ADDR_SUCTION2_TEMP = "A00F"; // 40975
public static final String ADDR_EXHAUST2_TEMP = "A010"; // 40976
public static final String ADDR_VALVE_AFTER2_TEMP = "A011"; // 40977
public static final String ADDR_RESERVED_A012 = "A012";
public static final String ADDR_RESERVED_A013 = "A013";
public static final String ADDR_MAIN_EXP_VALVE2_OPEN = "A014"; // 40980
public static final String ADDR_AUX_EXP_VALVE2_OPEN = "A015"; // 40981
public static final String ADDR_COMP2_CURRENT = "A016"; // 40982
public static final String ADDR_RECOVERABLE_FAULT = "A017"; // 40983
public static final String ADDR_UNRECOVERABLE_FAULT = "A018"; // 40984
public static final String ADDR_VERSION_INFO = "A019"; // 40985
public static final String ADDR_INPUT_SWITCH_STATUS = "A01A"; // 40986
public static final String ADDR_WATER_LEVEL_SWITCH = "A01B"; // 40987
public static final String ADDR_OUTPUT1_STATUS = "A01C"; // 40988
public static final String ADDR_OUTPUT2_STATUS = "A01D"; // 40989
public static final String ADDR_OUTPUT3_STATUS = "A01E"; // 40990
public static final String ADDR_DIP_SWITCH = "A01F"; // 40991
public static final String ADDR_MAINBOARD_TYPE = "A020"; // 40992
public static final String ADDR_CONSTANT_TEMP_SET = "AFFF"; // 45055
public static final String ADDR_ON_OFF = "B000"; // 45056
public static final String ADDR_COOL_SET_TEMP = "B001"; // 45057
public static final String ADDR_HEAT_SET_TEMP = "B002"; // 45058
public static final String ADDR_MODE = "B003"; // 45059
public static final String ADDR_HOT_WATER_SET_TEMP = "B004"; // 45060
public static final String ADDR_FORCE_ELECTRIC_HEAT = "B005"; // 45061
public static final String ADDR_FORCE_DEFROST = "B006"; // 45062
public static final String ADDR_RESERVED_B007 = "B007";
public static final String ADDR_RETURN_VALVE_TIMER = "B008"; // 45064
public static final String ADDR_SUPPLY_VALVE_TIMER = "B009"; // 45065
// ==================== 解析器映射表 ====================
private static final Map<String, Function<Integer, Object>> PARSERS = new HashMap<>();
// ==================== 编码器映射表(写操作) ====================
private static final Map<String, Function<Object, Integer>> ENCODERS = new HashMap<>();
static {
// ---------- TEMP1 类型(无符号byte,低8位有效)----------
// 公式:温度 = (raw - 64) / 2,raw=1 表示传感器故障/未接
Function<Integer, Object> temp1Parser = v -> parseTemp1(v & 0xFF);
Function<Object, Integer> temp1Encoder = val -> encodeTemp1((Double) val);
// ---------- TEMP2 类型(无符号byte,低8位有效)----------
// 公式:温度 = raw - 32,raw=1 表示传感器故障/未接
Function<Integer, Object> temp2Parser = v -> parseTemp2(v & 0xFF);
Function<Object, Integer> temp2Encoder = val -> encodeTemp2((Integer) val);
// ---------- DIGI1 类型(无符号byte,低8位有效)----------
Function<Integer, Object> digi1Parser = v -> v & 0xFF;
Function<Object, Integer> digi1Encoder = val -> ((Number) val).intValue() & 0xFF ;
// ---------- DIG2 类型(16位无符号整型)----------
Function<Integer, Object> dig2Parser = v -> v & 0xFFFF;
Function<Object, Integer> dig2Encoder = val -> ((Number) val).intValue() & 0xFFFF;
// 地址配置(解析器 + 编码器)
// 温度读取地址(只读)
String[] temp1Addrs = {ADDR_DISPLAY_WATER_TEMP, ADDR_TANK_TEMP, ADDR_OUTLET_TEMP,
ADDR_INLET_TEMP, ADDR_AMBIENT_TEMP, ADDR_COIL1_TEMP, ADDR_SUCTION1_TEMP,
ADDR_VALVE_AFTER1_OR_RETURN, ADDR_COIL2_TEMP, ADDR_SUCTION2_TEMP,
ADDR_VALVE_AFTER2_TEMP};
for (String addr : temp1Addrs) {
PARSERS.put(addr, temp1Parser);
// 这些是只读地址,不设置编码器
}
// TEMP2 只读
String[] temp2Addrs = {ADDR_EXHAUST1_TEMP, ADDR_EXHAUST2_TEMP};
for (String addr : temp2Addrs) {
PARSERS.put(addr, temp2Parser);
}
// DIG2 只读
String[] dig2Addrs = {ADDR_MAIN_EXP_VALVE1_OPEN, ADDR_AUX_EXP_VALVE1_OPEN,
ADDR_MAIN_EXP_VALVE2_OPEN, ADDR_AUX_EXP_VALVE2_OPEN};
for (String addr : dig2Addrs) {
PARSERS.put(addr, dig2Parser);
}
// DIGI1 只读
String[] digi1Addrs = {ADDR_COMP1_CURRENT, ADDR_COMP2_CURRENT,
ADDR_RECOVERABLE_FAULT, ADDR_UNRECOVERABLE_FAULT};
for (String addr : digi1Addrs) {
PARSERS.put(addr, digi1Parser);
}
// 版本号(特殊解析)
PARSERS.put(ADDR_VERSION_INFO, XK814ModbusParamReadUtil::parseVersion);
// 位域状态
PARSERS.put(ADDR_INPUT_SWITCH_STATUS, XK814ModbusParamReadUtil::parseInputSwitchStatus);
PARSERS.put(ADDR_WATER_LEVEL_SWITCH, XK814ModbusParamReadUtil::parseWaterLevelSwitch);
PARSERS.put(ADDR_OUTPUT1_STATUS, XK814ModbusParamReadUtil::parseOutput1Status);
PARSERS.put(ADDR_OUTPUT2_STATUS, XK814ModbusParamReadUtil::parseOutput2Status);
PARSERS.put(ADDR_OUTPUT3_STATUS, XK814ModbusParamReadUtil::parseOutput3Status);
PARSERS.put(ADDR_DIP_SWITCH, XK814ModbusParamReadUtil::parseDipSwitch);
PARSERS.put(ADDR_MAINBOARD_TYPE, XK814ModbusParamReadUtil::parseMainboardType);
// ========== 可读写地址 ==========
// AFFFH 恒温设置温度 (TEMP2)
PARSERS.put(ADDR_CONSTANT_TEMP_SET, temp2Parser);
ENCODERS.put(ADDR_CONSTANT_TEMP_SET, temp2Encoder);
// B000H 开关机 (0关机,1开机)
PARSERS.put(ADDR_ON_OFF, v -> (v & 0xFF) == 0 ? "关机" : "开机");
ENCODERS.put(ADDR_ON_OFF, val -> (val.equals("开机") ? 1 : 0) & 0xFF);
// B001H 制冷设置温度 (TEMP2)
PARSERS.put(ADDR_COOL_SET_TEMP, temp2Parser);
ENCODERS.put(ADDR_COOL_SET_TEMP, temp2Encoder);
// B002H 制热设置温度 (TEMP2)
PARSERS.put(ADDR_HEAT_SET_TEMP, temp2Parser);
ENCODERS.put(ADDR_HEAT_SET_TEMP, temp2Encoder);
// B003H 运行模式 (0制热,1制冷,2恒温)
PARSERS.put(ADDR_MODE, v -> {
int mode = v & 0xFF;
switch (mode) {
case 0:
return "制热";
case 1:
return "制冷";
case 2:
return "恒温";
default:
return "未知";
}
});
ENCODERS.put(ADDR_MODE, val -> {
String mode = (String) val;
switch (mode) {
case "制热":
return 0;
case "制冷":
return 1;
case "恒温":
return 2;
default:
throw new IllegalArgumentException("无效模式: " + mode);
}
});
// B004H 热水设置温度 (TEMP2)
PARSERS.put(ADDR_HOT_WATER_SET_TEMP, temp2Parser);
ENCODERS.put(ADDR_HOT_WATER_SET_TEMP, temp2Encoder);
// B005H 强制电加热
PARSERS.put(ADDR_FORCE_ELECTRIC_HEAT, v -> (v & 0xFF) == 0 ? "取消强制" : "开启强制");
ENCODERS.put(ADDR_FORCE_ELECTRIC_HEAT, val -> val.equals("开启强制") ? 1 : 0);
// B006H 强制除霜
PARSERS.put(ADDR_FORCE_DEFROST, v -> (v & 0xFF) == 0 ? "取消强制" : "开启强制");
ENCODERS.put(ADDR_FORCE_DEFROST, val -> val.equals("开启强制") ? 1 : 0);
// B008H 回水阀定时开关 (bit0)
PARSERS.put(ADDR_RETURN_VALVE_TIMER, v -> ((v & 01) == 0) ? "关闭" : "开启");
ENCODERS.put(ADDR_RETURN_VALVE_TIMER, val -> (val.equals("开启") ? 1 : 0) & 01);
// B009H 供水阀定时开关 (bit0)
PARSERS.put(ADDR_SUPPLY_VALVE_TIMER, v -> ((v & 01) == 0) ? "关闭" : "开启");
ENCODERS.put(ADDR_SUPPLY_VALVE_TIMER, val -> (val.equals("开启") ? 1 : 0) & 01);
}
/**
* 解析寄存器值
*
* @param address 寄存器地址字符串格式 "A000"
* @param value 寄存器原始值0~65535
* @return 解析后的物理值若地址未定义则返回 null
*/
public static Object parse(String address, int value) {
Function<Integer, Object> parser = PARSERS.get(address);
if (parser == null) {
return null;
}
return parser.apply(value);
}
/**
* 将物理值编码为寄存器值用于写操作
*
* @param address 寄存器地址字符串格式 "A000"
* @param physicalValue 物理值类型需与协议匹配
* @return 要写入寄存器的整数值若地址不支持写或类型错误则抛出异常
*/
public static int encode(String address, Object physicalValue) {
Function<Object, Integer> encoder = ENCODERS.get(address);
if (encoder == null) {
throw new UnsupportedOperationException("地址 " + address + " 不支持写操作");
}
return encoder.apply(physicalValue);
}
// ==================== 私有解析/编码辅助方法 ====================
// TEMP1 解析:温度 = (raw - 64)/2,raw=1 表示故障
private static Double parseTemp1(int raw) {
if (raw == 1) return null; // 传感器故障或未接
return (raw - 64) / 2.0;
}
// TEMP1 编码:给定温度(Double),返回 raw 值
private static int encodeTemp1(Double temp) {
if (temp == null) return 1; // 故障时写入1?协议未明确写故障,一般写有效值
int raw = (int) Math.round(temp * 2 + 64);
// 限制范围 0~255,但协议中有效温度对应 raw 范围 4~? 不做严格限制
return Math.min(255, Math.max(0, raw));
}
// TEMP2 解析:温度 = raw - 32,raw=1 表示故障
private static Integer parseTemp2(int raw) {
if (raw == 1) return null;
return raw - 32;
}
// TEMP2 编码
private static int encodeTemp2(Integer temp) {
if (temp == null) return 1;
int raw = temp + 32;
return Math.min(255, Math.max(0, raw));
}
// 版本号解析:高8位类别版本,低8位主板版本
private static String parseVersion(int value) {
int high = (value >> 8) & 0xFF;
int low = value & 0xFF;
return String.format("版本_类别版本:%d;版本_主板版本:%d", high, low);
}
// A01AH 输入开关状态
private static String parseInputSwitchStatus(int value) {
StringBuilder sb = new StringBuilder();
sb.append("输入开关状态_系统2状态:").append(((value >> 13) & 1) == 0 ? "保温" : "运行").append(";");
sb.append("输入开关状态_系统1状态:").append(((value >> 12) & 1) == 0 ? "保温" : "运行").append(";");
sb.append("输入开关状态_除霜运行:").append(((value >> 11) & 1) == 0 ? "无" : "开启").append(";");
sb.append("输入开关状态_水箱防冻/二级防冻:").append(((value >> 10) & 1) == 0 ? "无" : "开启").append(";");
sb.append("输入开关状态_管路防冻:").append(((value >> 9) & 1) == 0 ? "无" : "开启").append(";");
sb.append("输入开关状态_末端开关状态:").append(((value >> 8) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_高压开关1:").append(((value >> 7) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_高压开关2:").append(((value >> 6) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_低压开关1:").append(((value >> 5) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_低压开关2:").append(((value >> 4) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_联锁开关:").append(((value >> 3) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_末端开关:").append(((value >> 2) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("输入开关状态_水流开关:").append(((value >> 1) & 1) == 0 ? "闭合" : "断开");
return sb.toString();
}
// A01BH 水位开关状态
private static String parseWaterLevelSwitch(int value) {
StringBuilder sb = new StringBuilder();
sb.append("水位开关状态_高水位开关:").append(((value >> 7) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("水位开关状态_中水位开关:").append(((value >> 6) & 1) == 0 ? "闭合" : "断开").append(";");
sb.append("水位开关状态_低水位开关:").append(((value >> 5) & 1) == 0 ? "闭合" : "断开");
return sb.toString();
}
// A01CH 输出1状态
private static String parseOutput1Status(int value) {
StringBuilder sb = new StringBuilder();
sb.append("输出1状态_四通阀2:").append(((value >> 5) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出1状态_四通阀1:").append(((value >> 4) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出1状态_压缩机2:").append(((value >> 1) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出1状态_压缩机1:").append((value & 1) == 0 ? "关闭" : "开启");
return sb.toString();
}
// A01DH 输出2状态
private static String parseOutput2Status(int value) {
StringBuilder sb = new StringBuilder();
sb.append("输出2状态_外风机2:").append(((value >> 5) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出2状态_外风机1:").append(((value >> 4) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出2状态_循环水泵:").append(((value >> 3) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出2状态_曲轴加热:").append(((value >> 2) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出2状态_补水阀:").append(((value >> 1) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出2状态_电加热:").append((value & 1) == 0 ? "关闭" : "开启");
return sb.toString();
}
// A01EH 输出3状态
private static String parseOutput3Status(int value) {
StringBuilder sb = new StringBuilder();
sb.append("输出3状态_底盘加热:").append(((value >> 7) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出3状态_回水阀:").append(((value >> 6) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出3状态_末端水泵:").append(((value >> 5) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出3状态_增焓阀:").append(((value >> 4) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出3状态_供水阀:").append(((value >> 3) & 1) == 0 ? "关闭" : "开启").append(";");
sb.append("输出3状态_三通阀:").append(((value >> 2) & 1) == 0 ? "关闭" : "开启");
return sb.toString();
}
// A01FH 机组信息
private static String parseDipSwitch(int value) {
StringBuilder sb = new StringBuilder();
sb.append("机组信息_系统:").append(((value >> 4) & 1) == 0 ? "单系统" : "双系统").append(";");
sb.append("机组信息_机型选择:").append(((value >> 3) & 1) == 0 ? "冷热水机" : "热水机").append(";");
sb.append("机组信息_主路膨胀阀控制选择:").append(((value >> 2) & 1) == 0 ? "无" : "有").append(";");
sb.append("机组信息_电压选择:").append((value & 1) == 0 ? "单相220V" : "三相380V");
return sb.toString();
}
// A020H 主板类别
private static String parseMainboardType(int value) {
boolean hasConstant = ((value >> 4) & 1) != 0;
int type = value & 0x0F;
String typeStr;
if (type == 1) typeStr = "主板类别_冷热水机";
else if (type == 2) typeStr = "主板类别_热水机";
else typeStr = "主板类别_未知";
return (hasConstant ? "主板类别_有恒温模式;" : "主板类别_无恒温模式;") + typeStr;
}
// ==================== 测试示例 ====================
public static void main(String[] args) {
// 示例:解析 A000H 显示水温,原始值 110 -> 温度 (110-64)/2 = 23℃
System.out.println("显示水温: " + parse(ADDR_DISPLAY_WATER_TEMP, 110) + "℃");
System.out.println(ADDR_DISPLAY_WATER_TEMP);
// 示例:解析 A007H 排气1温度,原始值 33 -> 33-32=1℃
System.out.println("排气1温度: " + parse(ADDR_EXHAUST1_TEMP, 33) + "℃");
// 示例:解析 B003H 运行模式,原始值 1 -> 制冷
System.out.println("运行模式: " + parse("A01D", 1));
// 编码示例:写恒温设置温度 25℃
int encoded = encode(ADDR_CONSTANT_TEMP_SET, 25); // 25+32=57
System.out.println("恒温设置温度 25℃ 编码为: " + encoded);
// 写开关机:开机
encoded = encode(ADDR_ON_OFF, "开机");
System.out.println("开机编码: " + encoded);
// 测试字符串地址传入
System.out.println("\n--- 测试字符串地址 ---");
System.out.println("显示水温: " + parse("A000", 110) + "℃");
System.out.println("运行模式: " + parse("B003", 1));
}
}

172
user-service/src/main/java/com/mh/user/utils/XK814ModbusParamWriteUtil.java

@ -0,0 +1,172 @@
package com.mh.user.utils;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* @author LJF
* @version 1.0
* @project CHWS
* @description XK814 V1.0 协议通用参数设置功能码 06
* @date 2026-05-25 19:51:30
*/
public class XK814ModbusParamWriteUtil {
// 地址常量(十六进制字符串)
public static final String ADDR_CONSTANT_TEMP_SET = "AFFF"; // 恒温设置温度
public static final String ADDR_ON_OFF = "B000"; // 开关机
public static final String ADDR_COOL_SET_TEMP = "B001"; // 制冷设置温度
public static final String ADDR_HEAT_SET_TEMP = "B002"; // 制热设置温度
public static final String ADDR_MODE = "B003"; // 运行模式
public static final String ADDR_HOT_WATER_SET_TEMP = "B004"; // 热水设置温度
public static final String ADDR_FORCE_ELECTRIC_HEAT = "B005"; // 强制电加热
public static final String ADDR_FORCE_DEFROST = "B006"; // 强制除霜
public static final String ADDR_RETURN_VALVE_TIMER = "B008"; // 回水阀定时开关
public static final String ADDR_SUPPLY_VALVE_TIMER = "B009"; // 供水阀定时开关
// 编码器映射:地址字符串 -> 物理值转寄存器值(0~65535)的函数
private static final Map<String, Function<Object, Integer>> ENCODERS = new HashMap<>();
static {
// TEMP2 编码:温度 → raw = temp + 32
Function<Object, Integer> temp2Encoder = val -> {
if (!(val instanceof Integer)) throw new IllegalArgumentException("温度值必须是 Integer 类型");
int temp = (Integer) val;
return temp + 32;
};
// 布尔值编码:true→1, false→0
Function<Object, Integer> boolEncoder = val -> {
if (!(val instanceof Boolean)) throw new IllegalArgumentException("开关值必须是 Boolean 类型");
return (Boolean) val ? 1 : 0;
};
// 模式编码:字符串映射到 0/1/2
Function<Object, Integer> modeEncoder = val -> {
if (!(val instanceof String)) throw new IllegalArgumentException("模式必须是 String 类型");
String mode = (String) val;
switch (mode) {
case "制热":
return 0;
case "制冷":
return 1;
case "恒温":
return 2;
default:
throw new IllegalArgumentException("无效模式,必须为 制热/制冷/恒温");
}
};
ENCODERS.put(ADDR_CONSTANT_TEMP_SET, temp2Encoder);
ENCODERS.put(ADDR_COOL_SET_TEMP, temp2Encoder);
ENCODERS.put(ADDR_HEAT_SET_TEMP, temp2Encoder);
ENCODERS.put(ADDR_HOT_WATER_SET_TEMP, temp2Encoder);
ENCODERS.put(ADDR_ON_OFF, boolEncoder);
ENCODERS.put(ADDR_MODE, modeEncoder);
ENCODERS.put(ADDR_FORCE_ELECTRIC_HEAT, boolEncoder);
ENCODERS.put(ADDR_FORCE_DEFROST, boolEncoder);
ENCODERS.put(ADDR_RETURN_VALVE_TIMER, boolEncoder);
ENCODERS.put(ADDR_SUPPLY_VALVE_TIMER, boolEncoder);
}
/**
* 生成 Modbus 06 写单个寄存器的 RTU 报文
*
* @param slaveId 从机地址1~247
* @param address 寄存器地址十六进制字符串 "B000"
* @param value 物理值类型需与地址匹配参考协议
* @return 完整的 RTU 报文字节数组包含 CRC
*/
public static String buildWriteSingleRegisterMessage(int slaveId, String address, Object value) {
// 获取编码器
String addrUpper = address.toUpperCase();
Function<Object, Integer> encoder = ENCODERS.get(addrUpper);
if (encoder == null) {
throw new UnsupportedOperationException("地址 " + address + " 不支持写操作");
}
// 编码为寄存器值
int regValue = encoder.apply(value);
// 地址字符串转整数
int regAddr = Integer.parseInt(addrUpper, 16);
// 构建报文(不含 CRC)
byte[] pdu = new byte[6];
pdu[0] = (byte) (regAddr >> 8); // 地址高字节
pdu[1] = (byte) (regAddr & 0xFF); // 地址低字节
pdu[2] = (byte) (regValue >> 8); // 值高字节
pdu[3] = (byte) (regValue & 0xFF);// 值低字节
// 添加从机地址和功能码
byte[] frameWithoutCRC = new byte[1 + 1 + 6];
frameWithoutCRC[0] = (byte) slaveId;
frameWithoutCRC[1] = 0x06; // 功能码
System.arraycopy(pdu, 0, frameWithoutCRC, 2, 6);
// 计算 CRC16
int crc = calculateCRC(frameWithoutCRC, 0, frameWithoutCRC.length);
// 完整报文
byte[] fullFrame = new byte[frameWithoutCRC.length + 2];
System.arraycopy(frameWithoutCRC, 0, fullFrame, 0, frameWithoutCRC.length);
fullFrame[fullFrame.length - 2] = (byte) (crc & 0xFF);
fullFrame[fullFrame.length - 1] = (byte) ((crc >> 8) & 0xFF);
return toHexString(fullFrame);
}
/**
* 重载地址使用整数形式
*
* @param slaveId 从机地址
* @param address 寄存器地址整数 0xB000
* @param value 物理值
* @return 报文
*/
public static String buildWriteSingleRegisterMessage(int slaveId, int address, Object value) {
String addrHex = Integer.toHexString(address).toUpperCase();
// 补齐为4位十六进制
while (addrHex.length() < 4) addrHex = "0" + addrHex;
return buildWriteSingleRegisterMessage(slaveId, addrHex, value);
}
// CRC16 (Modbus RTU) 计算
private static int calculateCRC(byte[] data, int offset, int len) {
int crc = 0xFFFF;
for (int i = offset; i < offset + len; i++) {
crc ^= (data[i] & 0xFF);
for (int j = 0; j < 8; j++) {
if ((crc & 0x0001) != 0) {
crc = (crc >> 1) ^ 0xA001;
} else {
crc = crc >> 1;
}
}
}
return crc;
}
// 辅助方法:打印十六进制字符串
public static String toHexString(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
sb.append(String.format("%02X ", b));
}
return sb.toString().trim();
}
// 示例
public static void main(String[] args) {
// 示例1:从机地址1,设置开机(B000H,true)
String msg = buildWriteSingleRegisterMessage(1, ADDR_ON_OFF, true);
System.out.println("开机报文: " + (msg));
// 示例2:设置制热温度45℃(B002H,45)
msg = buildWriteSingleRegisterMessage(1, ADDR_HEAT_SET_TEMP, 45);
System.out.println("设置制热温度45℃: " + (msg));
// 示例3:设置模式为制冷(B003H,"制冷")
msg = buildWriteSingleRegisterMessage(1, ADDR_MODE, "制冷");
System.out.println("设置制冷模式: " + (msg));
// 示例4:使用整数地址
msg = buildWriteSingleRegisterMessage(1, 0xB005, true); // 强制电加热开启
System.out.println("强制电加热开启: " + (msg));
}
}

4
user-service/src/main/resources/application-dev.yml

@ -1,7 +1,7 @@
# 项目相关配置
mh:
# 名称
name: nfxy_dev
name: dev
# 版本
version: 1.0.0
# 版权年份
@ -22,7 +22,7 @@ spring:
type: com.alibaba.druid.pool.DruidDataSource
druid:
#添加allowMultiQueries=true 在批量更新时才不会出错
url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=chws_nfxy;allowMultiQueries=true;encrypt=false
url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=chws_bsdz;allowMultiQueries=true;encrypt=false
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
username: sa
password: mh@803

20
user-service/src/main/resources/application-prod.yml

@ -30,10 +30,10 @@ spring:
# password: mh@803
## url: jdbc:sqlserver://120.25.220.177:32012;DatabaseName=M_CHWS;allowMultiQueries=true
#阿里云服务器-广州理工
url: jdbc:sqlserver://111.230.50.186:32012;DatabaseName=CHWS;allowMultiQueries=true;encrypt=false
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
username: test
password: minghan123456@
# url: jdbc:sqlserver://111.230.50.186:32012;DatabaseName=CHWS;allowMultiQueries=true;encrypt=false
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# username: test
# password: minghan123456@
# #华厦云服务器
# url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=CHWS;allowMultiQueries=true
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
@ -80,14 +80,14 @@ spring:
# username: chws_jm
# password: Mhtech@803
# # 珠海北师大
# url: jdbc:sqlserver://127.0.0.1:8033;DatabaseName=chws_bsdz;allowMultiQueries=true;encrypt=false
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# username: chws_bsdz
# password: Mhtech@803803
# 珠海北师大
url: jdbc:sqlserver://127.0.0.1:8033;DatabaseName=chws_bsdz;allowMultiQueries=true;encrypt=false
driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
username: chws_bsdz
password: Mhtech@803803
# #南方学院
# url: jdbc:sqlserver://175.178.153.91:8033;DatabaseName=chws_nfxy;allowMultiQueries=true;encrypt=false
# url: jdbc:sqlserver://127.0.0.1:8033;DatabaseName=chws_nfxy;allowMultiQueries=true;encrypt=false
# driver-class-name: com.microsoft.sqlserver.jdbc.SQLServerDriver
# username: chws_nfxy
# password: minghan@123456

2
user-service/src/main/resources/application.yml

@ -1,6 +1,6 @@
spring:
profiles:
active: prod
active: dev
mvc:
pathmatch:
matching-strategy: ant_path_matcher

Loading…
Cancel
Save