package com.ld.igds.protocol.bhzn.grainv2.msg; import com.ld.igds.common.CoreCommonService; import com.ld.igds.common.CoreSerService; import com.ld.igds.common.dto.THDto; import com.ld.igds.constant.BizType; import com.ld.igds.constant.Constant; import com.ld.igds.grain.GrainUtil; import com.ld.igds.grain.dto.GrainItemInfo; import com.ld.igds.io.notify.NotifyGrainInvoker; import com.ld.igds.models.DepotConf; import com.ld.igds.models.DeviceSer; import com.ld.igds.models.DicSysConf; import com.ld.igds.models.Grain; import com.ld.igds.order.ExeOrderService; import com.ld.igds.order.data.ExeRequest; import com.ld.igds.protocol.bhzn.grainv1.server.BhznGrainV1ServerUtils; import com.ld.igds.protocol.bhzn.grainv2.msg.builder.CommandBuild; import com.ld.igds.protocol.bhzn.grainv2.msg.builder.ReMessageBuilder; import com.ld.igds.protocol.bhzn.grainv2.msg.message.IoMessage; import com.ld.igds.protocol.bhzn.grainv2.server.BhznGrainV2ServerEngine; import com.ld.igds.util.BytesUtil; import com.ld.igds.util.ContextUtil; import com.ld.igds.warn.WarnUtils; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.*; /** * 协议解析 * * @author vince */ @Slf4j @Component(AnalysisService.BEAN_ID) public class AnalysisService { /** * 针对分包粮情报文进行封装 */ public static Map contextMapGrain = new HashMap<>(); /** * 用于存放返回的仓温仓湿信息 */ public static Map contextMapTH = new HashMap<>(); public static final String BEAN_ID = "bhznGrainv2.analysisService"; @Autowired private CoreSerService coreSerService; @Autowired private BhznGrainV2ServerEngine serverEngine; @Autowired private CoreCommonService commonService; @Autowired private NotifyGrainInvoker notifyGrainInvoker; @Autowired private GrainUtil grainUtil; @Autowired private WarnUtils warnUtils; @Autowired private ExeOrderService exeOrderService; /** * @param sessionKey ip:port */ public void analysis(String sessionKey, IoMessage message) throws Exception { //注册 if (BhznGrainV1ServerUtils.FUNCTION_ID_F1.equals(message.getFunctionId())) { //DO NOTHING log.info("主机------->>平台:注册信息报文={}", message); DeviceSer ser = coreSerService.getCacheSerBySn(ContextUtil.getDefaultCompanyId(),message.getAddr()); if(ser!= null ){ ser.setIp(message.getIp()); ser.setPort(message.getPort()); ser.setStatus(Constant.YN_Y); coreSerService.updateByData(ser); log.info("主机------->>平台:注册成功,分机信息={}", ser); } return; } //心跳 if (BhznGrainV1ServerUtils.FUNCTION_ID_F2.equals(message.getFunctionId())) { //String hexStr = CommandBuild.getMsgHeartReply(message.getAddr()); //log.info("平台--------->>>主机,返回心跳收到信息,报文={}", hexStr); // serverEngine.pushByMin(hexStr); return; } // 93 解析仓温仓湿,并返回收到报文 if (BhznGrainV1ServerUtils.FUNCTION_ID_93.equals(message.getFunctionId())) { log.info("主机------->>平台:温湿度信息报文={}", message); analysisTh(message); return; } // 92 解析粮温,并返回收到报文 if (BhznGrainV1ServerUtils.FUNCTION_ID_92.equals(message.getFunctionId())) { log.info("主机------->>平台:粮情信息报文={}", message); analysisGrain(message); } } private void analysisGrain(IoMessage message) { try { //根据分机地址获取分机信息 DeviceSer ser = coreSerService.getCacheSer(ContextUtil.getDefaultCompanyId(), message.getAddr()); if (ser == null) { replayGrain(message); log.error("主机-------->>平台,解析粮情失败,未获取到系统粮情主机配置:" + message.getAddr()); return; } // 首先获取到系统参数,判断是否需要批次自动优化 DicSysConf sysConf = commonService.getCacheSysConf(ser.getCompanyId()); List list = exeOrderService.getInProgressOrderBySerId(BizType.GRAIN.getCode(), ser.getId()); if (null == list || list.isEmpty()) { String info = "粮情解析失败:分机=" + ser.getName() + "没有获取到所属仓库信息。"; log.error("分机------>>>平台:" + info); return; } //获取针对当前仓库的命令 ExeRequest exeRequest = list.get(0); if (null == exeRequest) { String info = "粮情解析失败:分机=" + ser.getName() + "没有获取历史命令。"; log.error("分机------>>>平台:" + info); return; } DepotConf depotConf = commonService.getCacheDepotConf(exeRequest.getCompanyId(), exeRequest.getDepotId()); if (null == depotConf) { String info = "粮情解析失败:分机=" + ser.getName() + "没有获取到粮情参数配置信息。"; log.error("分机------>>>平台:" + info); return; } // 粮情的批次号重新根据频率调整 String batchId = ContextUtil.getBatchIdByFireq(depotConf.getGrainFreq()); // 判断数据有没有收取完整 String[] attCable = depotConf.getCableRule().split("-"); int cableZ = Integer.valueOf(attCable[0]); int cableY = Integer.valueOf(attCable[1]); int cableX = Integer.valueOf(attCable[2]); int sumPoint = cableZ * cableY * cableX; //获取当前粮情温度报文 String grainHex = message.getContent().substring(16); //当前报文温度点数 int curPoint = BytesUtil.hexToInt(BytesUtil.tran_LH(message.getContent().substring(4, 8))); //如果当前包的数据个数大于等于当前仓库的配置点位则表示单包返回 if (curPoint >= sumPoint) { log.info("分机------>>>平台:粮情数据单包=" + grainHex); //返回粮情接收信息 replayGrain(message); analysisGrain2(ser, message, exeRequest, depotConf, sysConf, batchId, grainHex); return; } //表示分包传递 String key = "GRAIN_" + message.getAddr(); String oldGrainHex = contextMapGrain.get(key) == null ? "" : contextMapGrain.get(key); //获取当前包起始点的层行列 int hang = BytesUtil.hexToInt(BytesUtil.tran_LH(message.getContent().substring(8, 10))); int lie = BytesUtil.hexToInt(BytesUtil.tran_LH(message.getContent().substring(10, 12))); int ceng = BytesUtil.hexToInt(BytesUtil.tran_LH(message.getContent().substring(12, 14))); if (hang > 0 || lie > 0 || ceng > 0) { //说明非第一包数据 grainHex = oldGrainHex + grainHex; } if (grainHex.length() >= sumPoint * 4) { //返回粮情接收信息 replayGrain(message); log.info("分机------>>>平台:粮情数据多包,完整数据=" + grainHex); analysisGrain2(ser, message, exeRequest, depotConf, sysConf, batchId, grainHex); return; } else { log.info("分机------>>>平台:将第一包数据存入内存=" + grainHex); contextMapGrain.put(key, grainHex); replayGrain(message); } } catch (Exception e) { log.error(e.getMessage(), e); } } /** * 返回粮情收到报文信息,需要注意:如果存在分包情况下,需要等所有包收到后返回 * * @param message */ private void replayGrain(IoMessage message) throws InterruptedException { Thread.sleep(50); String hexStr = CommandBuild.getMsgGrainReply(message.getAddr()); log.info("平台--------->>>主机,返回粮情报文收到信息,报文={}", hexStr); serverEngine.push(message.getIp(),message.getPort(),BytesUtil.hexStrToBytes(hexStr)); } private void analysisGrain2(DeviceSer ser, IoMessage message, ExeRequest exeRequest, DepotConf depotConf, DicSysConf sysConf, String batchId, String grainStr) { // 获取完整的粮情包信息 String[] attCable = depotConf.getCableRule().split("-"); int cableZ = Integer.valueOf(attCable[0]); int cableY = Integer.valueOf(attCable[1]); int cableX = Integer.valueOf(attCable[2]); // 根据层行列获取指定长度 int start = 4 * (depotConf.getCableStart() - ser.getCableStart()) * cableZ * cableY; int len = 4 * cableZ * cableY * cableX; log.info("分机------>>>平台:返回粮情完整信息,所属组织={},分机={}", ser.getCompanyId(), ser.getName()); String strPoints = grainStr.substring(start, start + len); // 将粮情解析成数组 List temps = new ArrayList<>(); double tempValue; String temp; for (int i = 0; i < strPoints.length() / 4; i++) { temp = strPoints.substring(i * 4, i * 4 + 4); if (temp == null) { temp = "0000"; } if (ReMessageBuilder.ERROR_TAG.equals(temp)) { tempValue = Constant.ERROR_TEMP; } else { tempValue = BytesUtil.hexToInt(BytesUtil.tran_LH(temp)) / 10.0; } // 故障值处理 if (tempValue >= ReMessageBuilder.FAULT_CHECK_TAG) { tempValue = Constant.FAULT_TEMP; } temps.add(tempValue); } log.debug("-------CheckGrainRequest--={}", exeRequest.toString()); THDto thDto = this.getTH(message); if (null != thDto) { log.debug("-------THDto--={}", thDto.toString()); } //清空 String key = "GRAIN_" + message.getAddr(); contextMapGrain.put(key, null); // 将集合解析成坐标数据 addPoint1(temps, depotConf, ser, exeRequest, thDto, sysConf, batchId); } /** * 平房仓,解析第二步,解析到坐标数据 * * @param temps * @throws Exception */ private void addPoint1(List temps, DepotConf depotConf, DeviceSer ser, ExeRequest exeRequest, THDto thDto, DicSysConf sysConf, String batchId) { //根据电缆起始方位和布线方向,对粮情数据进行调整 if (null != depotConf.getStartOrientation()) { temps = reversalGrainPoint(temps, depotConf); } //若起点点位为底部,则将粮情数据进行翻转 if (null != depotConf.getStartPoint() && Constant.GRAIN_START_POINT_BELOW.equals(depotConf.getStartPoint())) { temps = grainUtil.reversalUpAndDown(temps, depotConf.getCableRule()); } String[] attCable = depotConf.getCableRule().split("-"); int cableZ = Integer.valueOf(attCable[0]); int cableY = Integer.valueOf(attCable[1]); int cableX = Integer.valueOf(attCable[2]); Grain grain = new Grain(); grain.setDepotId(depotConf.getDepotId()); grain.setCompanyId(depotConf.getCompanyId()); grain.setCable(depotConf.getCableRule()); grain.setBatchId(batchId); grain.setTempIn(Constant.ERROR_TEMP); grain.setHumidityIn(Constant.ERROR_TEMP); if (null != thDto) { log.debug("粮情解析中获取到的温湿度信息={}", thDto.toString()); grain.setHumidityIn(thDto.getHumidityIn()); grain.setTempIn(thDto.getTempIn()); } grain.setReceiveDate(new Date()); grain.setRemark("粮温正常"); // 获取缓存中的命令信息 grain.setCheckUser(exeRequest.getExeUser()); double max = ReMessageBuilder.MAX_TEMP, min = ReMessageBuilder.MIN_TEMP, sumT = 0.0, sumNum = cableX * cableY * cableZ; // 校验和实现统计,生成采集点信息 List listGrainItems = new ArrayList<>(); int i = 1; for (Double temp : temps) { if (temp == Constant.ERROR_TEMP || temp == Constant.FAULT_TEMP || temp == Constant.ADD_TEMP) { sumNum--; } else { sumT += temp; if (temp > max) { max = temp; } if (temp < min) { min = temp; } } listGrainItems.add(new GrainItemInfo(i, temp)); i++; } if (sumNum == 0) { sumNum = 1; grain.setRemark("当前粮情采集异常"); } //过滤比较用的最大最小值 if (max == ReMessageBuilder.MAX_TEMP) { max = 0.0; } if (min == ReMessageBuilder.MIN_TEMP) { min = 0.0; } if (null != depotConf.getTempMax() && max > depotConf.getTempMax()) { grain.setRemark("仓库配置高温警告值:" + depotConf.getTempMax() + ",当前检测高温值:" + max); warnUtils.addGrainWarn(depotConf, grain); } grain.setTempAve(sumT / sumNum); grain.setTempMax(max); grain.setTempMin(min); grain.setPoints(org.apache.commons.lang3.StringUtils.join(temps, ",")); String depotIds = exeRequest.getDepotIds(); boolean notifyWeb = true; if (null != depotIds && depotIds.indexOf(depotConf.getDepotId()) == -1) { notifyWeb = false; } // 用户封装好数据即可 notifyGrainInvoker.analysisSuccess(grain, listGrainItems, depotConf, sysConf, notifyWeb, exeRequest); } private List reversalGrainPoint(List temps, DepotConf conf) { if (org.apache.commons.lang3.StringUtils.isEmpty(conf.getStartOrientation())) { //若起始方位为空,则默认起始方位和方向,直接返回 return temps; } //起始方位为右边时 if (Constant.GRAIN_START_ORIENTATION_RIGHT.equals(conf.getStartOrientation())) { if (org.apache.commons.lang3.StringUtils.isEmpty(conf.getStartDirection())) { //右边起始,默认纵向布线,直接返回 return temps; } if (Constant.GRAIN_START_DIRECTION_TRANSVERSE.equals(conf.getStartDirection())) { //右边起始,横向布线 return grainUtil.reversalRight1(temps, conf.getCableRule()); } //右边起始,默认纵向布线,直接返回 return temps; } //起始方位为右上时 if (Constant.GRAIN_START_ORIENTATION_RIGHT_UP.equals(conf.getStartOrientation())) { if (org.apache.commons.lang3.StringUtils.isEmpty(conf.getStartDirection())) { //右上起始,默认纵向布线 return grainUtil.reversalRightUp2(temps, conf.getCableRule()); } if (Constant.GRAIN_START_DIRECTION_TRANSVERSE.equals(conf.getStartDirection())) { //右上起始,横向布线 return grainUtil.reversalRightUp1(temps, conf.getCableRule()); } //右上起始,默认纵向布线 return grainUtil.reversalRightUp2(temps, conf.getCableRule()); } //起始方位为左边时 if (Constant.GRAIN_START_ORIENTATION_LEFT.equals(conf.getStartOrientation())) { if (org.apache.commons.lang3.StringUtils.isEmpty(conf.getStartDirection())) { //左边起始,默认纵向布线 return grainUtil.reversalLeft2(temps, conf.getCableRule()); } if (Constant.GRAIN_START_DIRECTION_TRANSVERSE.equals(conf.getStartDirection())) { //左边起始,横向布线 return grainUtil.reversalLeft1(temps, conf.getCableRule()); } //左边起始,默认纵向布线 return grainUtil.reversalLeft2(temps, conf.getCableRule()); } //起始方位为左上时 if (Constant.GRAIN_START_ORIENTATION_LEFT_UP.equals(conf.getStartOrientation())) { if (org.apache.commons.lang3.StringUtils.isEmpty(conf.getStartDirection())) { //左上起始,默认纵向布线 return grainUtil.reversalLeftUp2(temps, conf.getCableRule()); } if (Constant.GRAIN_START_DIRECTION_TRANSVERSE.equals(conf.getStartDirection())) { //左上起始,横向布线 return grainUtil.reversalLeftUp1(temps, conf.getCableRule()); } //左上起始,默认纵向布线 return grainUtil.reversalLeftUp2(temps, conf.getCableRule()); } return temps; } private void analysisTh(IoMessage message) { try { THDto th = new THDto(); th.setCompanyId(ContextUtil.getDefaultCompanyId()); String data = message.getContent(); String houseNo = data.substring(0, 2); String t = data.substring(4, 8); String h = data.substring(8, 12); double temp, humy; if (ReMessageBuilder.ERROR_TAG.equals(t)) { temp = 0.0; } else { temp = (double) BytesUtil.hexToBigInt(BytesUtil.tran_LH(t)) / 10; } if (ReMessageBuilder.ERROR_TAG.equals(h)) { humy = 0.0; } else { humy = (double) BytesUtil.hexToBigInt(BytesUtil.tran_LH(h)) / 10; } th.setTempIn(temp); th.setHumidityIn(humy); log.info("主机--------->>>平台,解析仓温仓湿信息,仓库={},结果={}", houseNo, th.toString()); String key = "TH_" + houseNo; contextMapTH.put(key, th); } catch (Exception e) { log.error(e.getMessage(), e); } finally { String hexStr = CommandBuild.getMsgTHReply(message.getAddr()); log.info("平台--------->>>主机,返回仓温仓湿收到信息,报文={}", hexStr); serverEngine.push(message.getIp(),message.getPort(),BytesUtil.hexStrToBytes(hexStr)); } } private THDto getTH(IoMessage message) { String data = message.getContent(); String houseNo = data.substring(0, 2); String key = "TH_" + houseNo; return contextMapTH.get(key); } }