package com.js.kbt.socket; import java.math.BigDecimal; import java.text.ParseException; import java.text.SimpleDateFormat; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.annotation.Resource; import org.apache.log4j.Logger; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import com.alibaba.fastjson.JSONObject; import com.js.kbt.mapper.ChangeIpCommandMapper; import com.js.kbt.mapper.EquipmentSendCommandMapper; import com.js.kbt.mapper.LonLatRecordMapper; import com.js.kbt.mapper.MouldCycleRuntimeMapper; import com.js.kbt.mapper.MouldDownPacketMapper; import com.js.kbt.mapper.MouldHistoryMapper; import com.js.kbt.mapper.MouldHistoryTimeMapper; import com.js.kbt.mapper.MouldHodingMapper; import com.js.kbt.mapper.RecDataLogMapper; import com.js.kbt.mapper.SensorThresholdMapper; import com.js.kbt.mapper.TbFactoryMapper; import com.js.kbt.mapper.TbMouldEquipmentMapper; import com.js.kbt.mapper.TbMouldMapper; import com.js.kbt.mapper.TimeCalibrationRecordMapper; import com.js.kbt.model.ChangeIpCommand; import com.js.kbt.model.ChangeIpCommandExample; import com.js.kbt.model.EquipmentSendCommand; import com.js.kbt.model.EquipmentSendCommandExample; import com.js.kbt.model.LonLatRecord; import com.js.kbt.model.LonLatRecordExample; import com.js.kbt.model.MouldDownPacket; import com.js.kbt.model.MouldDownPacketExample; import com.js.kbt.model.MouldHistory; import com.js.kbt.model.MouldHistoryExample; import com.js.kbt.model.MouldHistoryTime; import com.js.kbt.model.MouldHistoryTimeExample; import com.js.kbt.model.RecDataLog; import com.js.kbt.model.RecDataLogExample; import com.js.kbt.model.TbMould; import com.js.kbt.model.TbMouldEquipment; import com.js.kbt.model.TbMouldEquipmentExample; import com.js.kbt.model.TbMouldExample; import com.js.kbt.model.TimeCalibrationRecord; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.timeout.IdleState; import io.netty.handler.timeout.IdleStateEvent; @Service("userHandler") public class UserHandler extends SimpleChannelInboundHandler { public static final String CMD_STATUS = "01";//工作状态控制字; public static final String CMD_BUSY_PERIOD = "02";//工作忙状态周期 public static final String CMD_IDLE_PERIOD = "03";//空闲状态周期 public static final String CMD_TIME_FIX = "08";//网络时间校准 public static final String CMD_NO_2G = "09";//NB切换2G阈值 public static final String CMD_CLOSE_WTIME = "0C";//合模等待时间 public static final String CMD_OPEN_WTIME = "0D";//开模等待时间1,单位1ms public static final String CMD_EEPROM = "0E";//重新上传EEPROM值 public static final String CMD_WAITING_UPLOAD_TIME = "10";//待机上报时间 public static final String CMD_COUNT = "12";//开合模总次数 public static final String CMD_PURE_HEX = "100";//纯16进制指令,用户界面输入 private static final Logger logger = Logger.getLogger(UserHandler.class); private ChannelHandlerContext ctx; @Resource private MouldHistoryMapper mouldHistoryMapper; @Resource private MouldHistoryTimeMapper mouldHistoryTimeMapper; @Resource private TbMouldMapper tbMouldMapper; @Resource private TbMouldEquipmentMapper tbMouldEquipmentMapper; @Resource private TbFactoryMapper tbFactoryMapper; @Resource private MouldHodingMapper mouldHodingMapper; @Resource private MouldDownPacketMapper mouldDownPacketMapper; @Resource private TimeCalibrationRecordMapper timeCalibrationRecordMapper; @Resource private MouldCycleRuntimeMapper mouldCycleRuntimeMapper; @Resource private SensorThresholdMapper sensorThresholdMapper; @Resource private RecDataLogMapper recDataLogMapper; @Resource private LonLatRecordMapper lonLatRecordMapper; @Resource private ChangeIpCommandMapper changeIpCommandMapper; @Resource private EquipmentSendCommandMapper equipmentSendCommandMapper; @Override protected void channelRead0(ChannelHandlerContext arg0, String arg1) throws ParseException { String pack = "FAAF0007001e781e50003C37D5"; // 验证是否需要切换ip // sendChangeIp(); logger.info("开始接受数据..."); System.out.println("收到===" + arg1 + "\n"); String equipmentNo = processMsg(arg1); // 校准时间 timeCalibration(equipmentNo); // 以下是配置下行数据 sendPackage(equipmentNo); } private String processMsg(String input) throws ParseException { // ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor(); String ret = "FA AF 00 07 02 1e 78 1e 50 00 3C"; ret.replaceAll(" ", ""); logger.info("=====接收到======" + input); if (!input.startsWith("FAAF")) { logger.info("非云模盒消息,不处理"); return ret; } // 设备编号 String deviceNum = ""; // 创建一个字符串集合用于存储由于粘包需要拆分后的报文 ret = input; //排重 RecDataLogExample logExp = new RecDataLogExample(); logExp.createCriteria().andRecDataEqualTo(input); if (recDataLogMapper.countByExample(logExp) > 0) { logger.info("重复消息,不作处理!"); return ret; } RecDataLog logItem = new RecDataLog(); logItem.setRecData(input); recDataLogMapper.insertSelective(logItem); List strList = new ArrayList<>(); while (ret.length() > 0) { String subStr = ret.substring(0, Integer.parseInt(highInFrontLowInBack(ret.substring((2) * 2, (4) * 2)), 16) * 2); strList.add(subStr); ret = ret.substring(subStr.length()); logger.info("数据一包:"+subStr); } logger.info("粘包集合的長度==>" + strList.size()); for (String string : strList) { MouldHistory item = new MouldHistory(); // 抽取手机号码4-5(预留)丢包情况硬件会上报状态01,服务器判断02时候下发printall String mobilePart = string.substring(4 * 2, 5 * 2); System.out.println("原始mobile=" + mobilePart); String mobile = getStringFromHexStr(mobilePart); System.out.println("手机号码为" + mobile); item.setSim(mobile); // 获取设备编码15-24 String deviceNumPart = string.substring(5 * 2, 25 * 2); deviceNum = getStringFromHexStr(deviceNumPart); logger.info("设备No=" + deviceNum); item.setEquipmentNo(deviceNum); // 发送数据包 MouldDownPacketExample pExp = new MouldDownPacketExample(); pExp.createCriteria().andEquipmentNoEqualTo(deviceNum).andPacketStrNotEqualTo("CLEAR_PROTOCOL"); List packetList = mouldDownPacketMapper.selectByExample(pExp); if (packetList.size() > 0) { MouldDownPacket packet = packetList.get(0); logger.info("开始下发数据包==>" + packet.getPacketStr()); sendMsg(packet.getPacketStr()); // 下发完就将数据删除(防止后续数据过大造成性能的影响) mouldDownPacketMapper.deleteByPrimaryKey(packet.getId()); } // 软件版本号25 String version = string.substring(25 * 2, 26 * 2); System.out.println("软件版本号=" + version); item.setVersion(version); String status = string.substring(26 * 2, 27 * 2); System.out.println("工作状态=" + status); item.setStatus(Integer.decode("0x" + status).toString()); // 经度27-37 String longitude = getStringFromHexStr(string.substring(27 * 2, 38 * 2)); System.out.println("经度=" + longitude); item.setLng(longitude); // 38-47纬度以 N 开头 String latitude = getStringFromHexStr(string.substring(38 * 2, 48 * 2)); System.out.println("纬度=" + latitude); item.setLat(latitude); System.out.println("==lac" + reverseParseHex(string.substring(48 * 2, 50 * 2))); System.out.println("==ci" + reverseParseHex(string.substring(50 * 2, 52 * 2))); // 临时变更高低位不做转换(由于硬件转递数据高低位传反导致,具体以上面为准) item.setGprsLac("" + reverseParseHex(string.substring(48 * 2, 50 * 2))); item.setGprsCi("" + reverseParseHex(string.substring(50 * 2, 52 * 2))); item.setWifiBbsid(string.substring(52 * 2, 58 * 2)); String temp = "0x" + string.substring(58 * 2, 59 * 2); System.out.println(temp); int i = Integer.decode(temp) - 40; System.out.println(i); logger.info("温度-----------》: " + i); item.setTemperature(i); item.setBattery(Integer.decode("0x" + string.substring(59 * 2, 60 * 2))); item.setSig2g(Integer.decode("0x" + string.substring(60 * 2, 61 * 2))); item.setSigNb(Integer.decode("0x" + string.substring(61 * 2, 62 * 2))); item.setSigWifi(Integer.decode("0x" + string.substring(62 * 2, 63 * 2))); item.setExt0("" + Integer.decode("0x" + string.substring(63 * 2, 64 * 2))); item.setAlarm(Integer.decode("0x" + string.substring(64 * 2, 65 * 2))); String str = string.substring(65 * 2, 69 * 2); item.setRunCnt(reverseParseHex(str)); LonLatRecordExample rExp = new LonLatRecordExample(); rExp.createCriteria().andMccEqualTo("460").andMncEqualTo("0").andGprsCiEqualTo(item.getGprsCi()) .andGprsLacEqualTo(item.getGprsLac()); List lRList = lonLatRecordMapper.selectByExample(rExp); if (lRList.size() > 0) { LonLatRecord lonLatRecord = lRList.get(0); item.setLng(lonLatRecord.getLng()); item.setLat(lonLatRecord.getLat()); } else { // 根据基站lac和ci获取经纬度 String api = "http://api.cellocation.com:81/cell/?mcc=460&mnc=0&lac=" + item.getGprsLac() + "&ci=" + item.getGprsCi() + "&output=json"; String resp = com.js.kbt.util.HttpRequest.sendGet(api, null); JSONObject json = JSONObject.parseObject(resp); if (json != null && json.getInteger("errcode") == 0) { item.setLng(json.getDouble("lon") + ""); item.setLat(json.getDouble("lat") + ""); } else { logger.error("调用基站解析平台出错: " + resp); } LonLatRecord latRecord = new LonLatRecord(); latRecord.setGprsCi(item.getGprsCi()); latRecord.setMcc("460"); latRecord.setMnc("0"); latRecord.setGprsLac(item.getGprsLac()); latRecord.setLat(item.getLat()); latRecord.setLng(item.getLng()); lonLatRecordMapper.insertSelective(latRecord); } String crcStr = string.substring(string.length() - 4); item.setCrcCode("" + reverseParseHex(crcStr)); // 找寻上一条最新记录 MouldHistoryExample mExp = new MouldHistoryExample(); mExp.setOrderByClause("id desc limit 1"); mExp.createCriteria().andEquipmentNoEqualTo(item.getEquipmentNo()); List newList = mouldHistoryMapper.selectByExample(mExp); // 存入数据库 mouldHistoryMapper.insertSelective(item); // 模具开合记录 int cnt = item.getRunCnt(); int start = 69; logger.info("累计开合模次数=" + cnt); int end = string.length() - 4; // 最后2位 0xXX,0xXX ,是CRC校验位 logger.info("时间信息==" + string.substring(start * 2, end)); Integer thisOpenCounts = 0; //用于接受上次最新的那一条开合数据 List historyList = new ArrayList<>(); //用于接受第一包的开合时间与上次最新一包的开合时间差值 long openTimeDiff = 0L; Date lastOpenTime = null; //用于接受第一包数据 if (end - start * 2 >= 24) {// 时间最少6位,1位显示0x00,开合算两个时间,所以是6*2*2=24 // 本次运行周期内的开合模次数 int periodCnt = (end - start * 2) / 24; thisOpenCounts = periodCnt; logger.info("本次开合模次数==" + periodCnt); long aHeadOpenTimeLongVal = 0L; //用于接收判断是不是有包在当前包之后但已经发上来了,如16:11的开和数据先于16:10的数据先发上来 for (int pos = 0; pos < periodCnt; pos++) { // 合模时间 MouldHistoryTime time = new MouldHistoryTime(); time.setHistoryId(item.getId()); time.setEquipmentNo(item.getEquipmentNo()); time.setSeq(pos + 1); Date closeTime = parseDate(string, start, pos, 0); time.setCloseTime(closeTime); // 开模时间 Date openTime = parseDate(string, start, pos, 6); time.setOpenTime(openTime); lastOpenTime = openTime; logger.info("第" + (pos + 1) + "包"); logger.info("本包开合时间戳--" + openTime.getTime()); if (pos == 0) { MouldHistoryTimeExample mhtExp = new MouldHistoryTimeExample(); //查询当前包是否是之前丢的包,判断依据,看看有没有比当前开合日期更后的开合数据 mhtExp.setOrderByClause("open_time desc limit 1"); mhtExp.createCriteria().andEquipmentNoEqualTo(item.getEquipmentNo()).andOpenTimeLessThanOrEqualTo(openTime); //小于当前开合时间的最新的一包开合数据 historyList = mouldHistoryTimeMapper.selectByExample(mhtExp); if (historyList.size() > 0) { openTimeDiff = openTime.getTime() - historyList.get(0).getOpenTime().getTime(); time.setTimeCost((int)openTimeDiff); } else { time.setTimeCost(0); } } else { logger.info("本次开合周期--" + (openTime.getTime() - aHeadOpenTimeLongVal)); time.setTimeCost((int) (openTime.getTime() - aHeadOpenTimeLongVal)); } mouldHistoryTimeMapper.insertSelective(time); // // 处理最后一包周期逻辑 aHeadOpenTimeLongVal = openTime.getTime(); } } else { logger.info("本次开合模次数==0"); } // 统计该模盒的平均开合周期 MouldHistoryTimeExample mtExp = new MouldHistoryTimeExample(); mtExp.setOrderByClause("seq"); mtExp.createCriteria().andHistoryIdEqualTo(item.getId()).andTimeCostGreaterThan(0); historyList = mouldHistoryTimeMapper.selectByExample(mtExp); int avgTime = 0; int totalTime = 0; if (historyList.size() > 1) { for (MouldHistoryTime mouldHistoryTime : historyList) { logger.info("totalTime" + totalTime); totalTime += mouldHistoryTime.getTimeCost(); } logger.info("totalTime" + totalTime); avgTime = (int) (totalTime / historyList.size()); } // } logger.info("avgTime-->" + avgTime); handleModLogic(item, avgTime, thisOpenCounts, lastOpenTime); // 判断预留字节的, 01-丢12包,02-丢50包 // if ("02".equals(mobilePart)) { if ("01".equals(mobilePart) || "02".equals(mobilePart)) { // 丢包数据已占满缓存,调用读取命令 // String strHexStr16 = strHexStr16("#PRINTFALL;"); String strHexStr16 = getDownPackage(CMD_EEPROM, "00 00 00 00 00 01"); logger.info("丢包数据已占满缓存下发调用读取命令#PRINTFALL;==>" + strHexStr16); sendMsg(strHexStr16); return deviceNum; } } return deviceNum; } // 下发切换服务器ip命令 public void sendChangeIp() { ChangeIpCommandExample example = new ChangeIpCommandExample(); example.createCriteria().andIsSendEqualTo(0); List list = changeIpCommandMapper.selectByExample(example); if (!CollectionUtils.isEmpty(list)) { ChangeIpCommand changeIpCommand = list.get(0); // #IPADDS=58.213.104.114:9090; // 下发切换服务器命令 StringBuffer sb = new StringBuffer(); sb.append("#IPADDS=").append(changeIpCommand.getIp()).append(":").append(changeIpCommand.getPort()) .append(";"); logger.info("开始下发切换服务器命令字符串为;==>" + sb.toString()); String strHexStr16 = strHexStr16(sb.toString()); logger.info("下发切换服务器ip转换后的16进制为;==>" + strHexStr16); sendMsg(strHexStr16); // 下发完修改状态为已下发 changeIpCommand.setIsSend(1); changeIpCommandMapper.updateByPrimaryKeySelective(changeIpCommand); } } //下发云模盒命令 private void sendPackage(String equipmentNo) { if (equipmentNo.indexOf("FAAF") != -1) { logger.info("非法云模盒编号,不作下发处理"); return; } //下发停用启用云模盒命令 MouldDownPacketExample exp = new MouldDownPacketExample(); exp.createCriteria().andEquipmentNoEqualTo(equipmentNo); List list = mouldDownPacketMapper.selectByExample(exp); if (list.size() > 0) { MouldDownPacket packet = list.get(0); TbMouldEquipmentExample meqExp = new TbMouldEquipmentExample(); meqExp.createCriteria().andEquipmentNoEqualTo(equipmentNo); long count = tbMouldEquipmentMapper.countByExample(meqExp); // 下发数据包,下发完后修改状态 logger.info("开始下发数据包==>" + packet.getPacketStr()); sendMsg(packet.getPacketStr()); if (null != packet.getThreshold()) { // 下发阈值命令 sendMsg(strHexStr16("#LIMIT VALUE=" + packet.getThreshold())); } if (count > 0) { TbMouldEquipment me = tbMouldEquipmentMapper.selectByExample(meqExp).get(0); TbMouldEquipment tme = new TbMouldEquipment(); tme.setId(me.getId()); tme.setIsUse(packet.getIsUse()); tbMouldEquipmentMapper.updateByPrimaryKeySelective(tme); logger.info("将启用中的云模盒改为启用成功==>" + me.getEquipmentNo()); } // 下发完删除数据 mouldDownPacketMapper.deleteByPrimaryKey(packet.getId()); } //发送清空次数和其他指定 EquipmentSendCommandExample escExample = new EquipmentSendCommandExample(); escExample.createCriteria().andEquipmentNoEqualTo(equipmentNo).andIsSendEqualTo(0); List sendCommandLists = equipmentSendCommandMapper.selectByExample(escExample); if(sendCommandLists.size()>0){ for (EquipmentSendCommand equipmentSendCommand : sendCommandLists) { switch (equipmentSendCommand.getCmd()) { case CMD_STATUS: break; case CMD_BUSY_PERIOD: break; case CMD_IDLE_PERIOD: break; case CMD_TIME_FIX: break; case CMD_NO_2G: break; case CMD_CLOSE_WTIME: break; case CMD_OPEN_WTIME: break; case CMD_EEPROM: break; case CMD_WAITING_UPLOAD_TIME: break; case CMD_COUNT: sendMsg(getDownPackage(CMD_COUNT, "00 00 00 00 00 00")); equipmentSendCommand.setIsSend(1); equipmentSendCommand.setSendTime(new Date()); equipmentSendCommandMapper.updateByPrimaryKeySelective(equipmentSendCommand); break; case CMD_PURE_HEX: String pack = equipmentSendCommand.getParam(); System.out.println("下发16进制手动指令=="+pack); if (pack.contains(" ")) { pack = pack.replaceAll(" ", ""); } sendMsg(pack); equipmentSendCommand.setIsSend(1); equipmentSendCommand.setSendTime(new Date()); equipmentSendCommandMapper.updateByPrimaryKeySelective(equipmentSendCommand); break; } } } } public void timeCalibration(String equipmentNo) { // logger.info("下发校准时间的云模盒equipmentNo"+equipmentNo); if (equipmentNo.indexOf("FAAF") != -1) { logger.info("非法云模盒编号,不作下发处理"); return; } List count = timeCalibrationRecordMapper.selectCountByToday(equipmentNo); // 今天未校准时间,下发时间校准,已经校准过了,则不再校准 if (count.size() == 0) { // Date date = new Date(); // SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd,HH:mm:ss"); // String dateStr = sdf.format(date); // dateStr = "#TIME=" + dateStr + ";"; // // #TIME=18-03-06,15:31:48; // logger.info("校准系统模块时间==>" + dateStr); // // 将字符串转成16进制字符串 // String strHexStr16 = strHexStr16(dateStr); // logger.info("校准系统模块时间转成16进制的字符串==>" + strHexStr16); //新协议 String hexDate = getNowDateHex(); logger.info("校准系统模块时间转成16进制的字符串==>" + hexDate); sendMsg(getDownPackage(CMD_TIME_FIX, hexDate)); TimeCalibrationRecord timeCalibrationRecord = new TimeCalibrationRecord(); timeCalibrationRecord.setIndate(new Date()); timeCalibrationRecord.setEquipmentNo(equipmentNo); timeCalibrationRecordMapper.insertSelective(timeCalibrationRecord); } } //构建下行的命令 public static String getDownPackage(String hexCmd, String hexData) { if (hexData.contains(" ")) { hexData = hexData.replaceAll(" ", ""); } hexData = hexData.toUpperCase(); byte[] b = getCRCByCmd(hexCmd, hexData); String crc = getCRC(b).toUpperCase(); if (crc.length() < 4) { crc = "0" + crc; } //低位在前转化 crc = crc.substring(2,4) +crc.substring(0,2); StringBuilder sb = new StringBuilder(); sb.append("FAAF0D00") .append(hexCmd) .append(hexData) .append(crc); String str = sb.toString(); //中间加空格 StringBuilder mm = new StringBuilder(); for (int i=0;i>= 1; CRC ^= POLYNOMIAL; } else { CRC >>= 1; } } } return Integer.toHexString(CRC); } private void handleModLogic(MouldHistory item, int avgTime, Integer thisOpenCount, Date lastOpenTime) { logger.info("进了handleModLogic逻辑--"); logger.info("item==>" + item); TbMouldEquipmentExample meqExp = new TbMouldEquipmentExample(); meqExp.createCriteria().andEquipmentNoEqualTo(item.getEquipmentNo()); if (tbMouldEquipmentMapper.countByExample(meqExp) > 0) { TbMouldEquipment me = tbMouldEquipmentMapper.selectByExample(meqExp).get(0); me.setCurhillNumber(item.getBattery() + ""); if (item.getLng() != null) { logger.info("更新经纬度:"); me.setLng(Double.parseDouble(item.getLng())); me.setLat(Double.parseDouble(item.getLat())); } me.setCurtemperature(item.getTemperature()); if (item.getAlarm() == 8) { me.setStage(3);// 安装被拆 } else if (item.getAlarm() == 1) { me.setStage(2);// 低电量 } else if (item.getAlarm() == 2) { me.setStage(1);// 高温 } else { me.setStage(item.getAlarm()); } // 处理报警 if (item.getAlarm() > 0) { /** * 无报警 0; 低电量报警 1; 温度过热 2; 安装被拆 8。 */ logger.info("设备报警啦:" + item.getAlarm()); } //处理最后一次开模时间 if (me.getLastopentime() == null) { me.setLastopentime(lastOpenTime); } else if (lastOpenTime != null && me.getLastopentime().before(lastOpenTime)) { me.setLastopentime(lastOpenTime); logger.info("设置最后开模时间:" + new SimpleDateFormat("yyyy-M-dd HH:mm:ss").format(lastOpenTime)); } tbMouldEquipmentMapper.updateByPrimaryKeySelective(me); logger.info("更新完了tbMouldEquipment的状态和温度以及经纬度"); TbMouldExample tExp = new TbMouldExample(); tExp.setOrderByClause("id desc limit 1"); tExp.createCriteria().andEquipmentIdEqualTo(me.getId()); if (tbMouldMapper.countByExample(tExp) > 0) { logger.info("准备更新运行次数:"); TbMould tm = tbMouldMapper.selectByExample(tExp).get(0); MouldHistoryTimeExample mhtExp = new MouldHistoryTimeExample(); // 一次接受到数据,超过5次开合标记为运行状态 if (thisOpenCount > 5) { tm.setState(item.getStatus()); } else { tm.setState("0"); } // 云模盒运行次数+模具的历史运行次数 tm.setRunTimes(item.getRunCnt() + tm.getHistoryRunTimes()); tm.setLastRecTime(new Date()); // 处理每模平均周期(单位秒) if (0 != avgTime) { logger.info("开始修改平均每模周期值为:" + avgTime); BigDecimal bd = new BigDecimal(avgTime * 1.00 / 1000); tm.setOcCycle(bd); } tbMouldMapper.updateByPrimaryKeySelective(tm); } } } /** * 低位在前的16进制解析 * * @param rHex * @return */ public static int reverseParseHex(String rHex) { int size = rHex.length() / 2; StringBuilder sb = new StringBuilder(); for (int i = 0; i < size; i++) { sb.append(rHex.substring((size - i - 1) * 2, (size - i) * 2)); } String str = sb.toString(); return Integer.parseInt(str, 16); } private static Date parseDate(String input, int start, int pos, int dateStartPos) { // pos为开合的一组的下标,一个开合时间占位是12*2 String year = input.substring((start + pos * 12 + dateStartPos) * 2, (start + pos * 12 + 1 + dateStartPos) * 2); String month = input.substring((start + pos * 12 + 1 + dateStartPos) * 2, (start + pos * 12 + 2 + dateStartPos) * 2); String day = input.substring((start + pos * 12 + 2 + dateStartPos) * 2, (start + pos * 12 + 3 + dateStartPos) * 2); String hh = input.substring((start + pos * 12 + 3 + dateStartPos) * 2, (start + pos * 12 + 4 + dateStartPos) * 2); String mm = input.substring((start + pos * 12 + 4 + dateStartPos) * 2, (start + pos * 12 + 5 + dateStartPos) * 2); String ss = input.substring((start + pos * 12 + 5 + dateStartPos) * 2, (start + pos * 12 + 6 + dateStartPos) * 2); logger.info("时间="+year + month+day+hh+mm+ss); StringBuilder sb = new StringBuilder(); int yearInt = Integer.parseInt(year, 16); if (yearInt == 0) { sb.append("2019-01-01"); } else { sb.append(yearInt < 100 ? "20" : "2"); sb.append(yearInt).append("-"); int monthInt = Integer.parseInt(month, 16); sb.append(monthInt < 10 ? "0" : "").append(monthInt).append("-"); int dayInt = Integer.parseInt(day, 16); sb.append(dayInt < 10 ? "0" : "").append(dayInt); } Date parseDate = null; try { parseDate = new SimpleDateFormat("yyyy-MM-dd").parse(sb.toString()); parseDate.setHours(Integer.parseInt(hh, 16)); parseDate.setMinutes(Integer.parseInt(mm, 16)); parseDate.setSeconds(Integer.parseInt(ss, 16)); } catch (ParseException e) { e.printStackTrace(); } return parseDate; } private static String getStringFromHexStr(String hexStr) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < hexStr.length() / 2; i++) { String str = "0x" + hexStr.substring(i * 2, i * 2 + 2); int intVal = Integer.decode(str).intValue(); char c = (char) intVal; sb.append(c); } return sb.toString(); } public void close() { ctx.close(); } public void sendMsg(String hexString) { System.out.println("发送消息==" + hexString); byte[] buffer = hexStrToBinaryStr(hexString); ByteBuf bf = Unpooled.buffer(hexString.length() / 2); bf.writeBytes(buffer); ctx.writeAndFlush(bf); // ctx.close(); } /** * channel被激活时调用 */ @Override public void channelActive(ChannelHandlerContext ctx) { // TODO Auto-generated method stub this.ctx = ctx; System.out.println("==========Active=========" + ctx.channel().localAddress().toString() + ", connection num=" + HelloServer.deviceMap.size()); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { super.channelInactive(ctx); System.out.println("==========Inactive========="); } @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // TODO Auto-generated method stub super.handlerRemoved(ctx); System.out.println("[YunSu]handlerRemoved=掉线了==="); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // TODO Auto-generated method stub super.exceptionCaught(ctx, cause); System.out.println("我捕捉到异常信息了"); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { if (evt instanceof IdleStateEvent) { IdleStateEvent event = (IdleStateEvent) evt; if (event.state().equals(IdleState.READER_IDLE)) { } else if (event.state().equals(IdleState.WRITER_IDLE)) { // System.out.println("WRITER_IDLE=="+userInfo.getWxName()); // logger.debug(ctx.channel().remoteAddress().toString()+ // "WRITER_IDLE"); // 超时关闭channel // ctx.close(); } else if (event.state().equals(IdleState.ALL_IDLE)) { // 发送心跳 ctx.channel().writeAndFlush("$&_".toString()); } } // super.userEventTriggered(ctx, evt); } /** * 将十六进制的字符串转换成字节数组 * * @param hexString * @return */ public static byte[] hexStrToBinaryStr(String hexString) { if (hexString == null || "".contentEquals(hexString)) { return null; } hexString = hexString.replaceAll(" ", ""); int len = hexString.length(); int index = 0; byte[] bytes = new byte[len / 2]; while (index < len) { String sub = hexString.substring(index, index + 2); bytes[index / 2] = (byte) Integer.parseInt(sub, 16); index += 2; } return bytes; } /** * 将字节数组转换成十六进制的字符串 * * @return */ public static String BinaryToHexString(byte[] bytes) { String hexStr = "0123456789ABCDEF"; String result = ""; String hex = ""; for (byte b : bytes) { hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4)); hex += String.valueOf(hexStr.charAt(b & 0x0F)); result += hex + " "; } return result; } /** * 普通字符串转16进制字符串 * * @param str * @return */ public static String strHexStr16(String str) { char[] chars = "0123456789ABCDEF".toCharArray(); StringBuilder sb = new StringBuilder(""); byte[] bs = str.getBytes(); int bit; for (int i = 0; i < bs.length; i++) { bit = (bs[i] & 0x0f0) >> 4; sb.append(chars[bit]); bit = bs[i] & 0x0f; sb.append(chars[bit]); // sb.append(' '); } return sb.toString().trim(); } // 转换16进制字符串低位在前,高位在后 成 高位在前,低位在后 public static String highInFrontLowInBack(String result) { return result.substring(2, 4) + result.substring(0, 2);// 高位在前,低位在后 } public static void main(String[] args) throws ParseException { String ret = "FA AF 00 07 02 1e 78 1e 50 00 3C"; String input = "FAAFE30000383938363034313631323138383035383439333733011200000000000000000000000000000000000000005F55D712000000000000485A4A3A000100301A000014040B0B2B2714040B0B2C0B14040B0B2C0D14040B0B2C2D14040B0B2C2F14040B0B2D1514040B0B2D1B14040B0B2D3514040B0B2D3814040B0B2E1C14040B0B2E1E14040B0B2F0214040B0B2F0414040B0B2F2414040B0B2F2614040B0B300A14040B0B300C14040B0B302C14040B0B302F14040B0B311214040B0B311514040B0B313514040B0B313714040B0B321B14040B0B321D14040B0B33011DD6FAAF270200383938363034313631323138383035383439333733011200000000000000000000000000000000000000005F55D712000000000000485A4A37000100671A000014040B0B330314040B0B332314040B0B332514040B0B340B14040B0B340E14040B0B342E14040B0B343314040B0B351214040B0B351414040B0B353414040B0B353614040B0B361A14040B0B361C14040B0B370014040B0B370214040B0B372514040B0B372714040B0B380814040B0B380B14040B0B382A14040B0B382D14040B0B391114040B0B391314040B0B393314040B0B393514040B0B3A1914040B0B3A1B14040B0B3A3B14040B0B3B0114040B0B3B2114040B0B3B2414040B0C000814040B0C000A14040B0C002A14040B0C002C14040B0C011014040B0C011214040B0C013214040B0C013414040B0C021814040B0C021A14040B0C023A14040B0C030114040B0C032014040B0C032314040B0C040714040B0C040914040B0C042914040B0C042B14040B0C050F14040B0C051114040B0C053314040B0C053514040B0C061714040B0C061914040B0C070014040B0C070214040B0C072214040B0C072714040B0C080614040B0C080814040B0C082814040B0C082A14040B0C090E14040B0C091014040B0C093114040B0C093314040B0C0A1614040B0C0A1914040B0C0A3914040B0C0A3B14040B0C0B1F14040B0C0B2114040B0C0C0514040B0C0C0714040B0C0C2814040B0C0C2914040B0C0D0D14040B0C0D1014040B0C0D320038"; ret.replaceAll(" ", ""); logger.info("=====接收到======" + input); if (!input.startsWith("FAAF")) { logger.info("非云模盒消息,不处理"); } // 设备编号 String deviceNum = ""; // 创建一个字符串集合用于存储由于粘包需要拆分后的报文 ret = input; List strList = new ArrayList<>(); while (ret.length() > 0) { String subStr = ret.substring(0, Integer.parseInt(highInFrontLowInBack(ret.substring((2) * 2, (4) * 2)), 16) * 2); strList.add(subStr); ret = ret.substring(subStr.length()); } logger.info("粘包集合的長度==>" + strList.size()); for (String string : strList) { String str = string.substring(65 * 2, 69 * 2); logger.info("cnt str=="+str); int cnt = reverseParseHex(str); int start = 69; logger.info("累计开合模次数=" + cnt); int end = string.length() - 4; // 最后2位 0xXX,0xXX ,是CRC校验位 logger.info("时间信息==" + string.substring(start * 2, end)); Integer thisOpenCounts = 0; //用于接受上次最新的那一条开合数据 //用于接受第一包数据 if (end - start * 2 >= 24) {// 时间最少6位,1位显示0x00,开合算两个时间,所以是6*2*2=24 // 本次运行周期内的开合模次数 int periodCnt = (end - start * 2) / 24; thisOpenCounts = periodCnt; logger.info("本次开合模次数==" + periodCnt); long aHeadOpenTimeLongVal = 0L; //用于接收判断是不是有包在当前包之后但已经发上来了,如16:11的开和数据先于16:10的数据先发上来 for (int pos = 0; pos < periodCnt; pos++) { // 合模时间 Date closeTime = parseDate(string, start, pos, 0); // 开模时间 Date openTime = parseDate(string, start, pos, 6); logger.info("第" + (pos + 1) + "包"); logger.info("本包开合时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(openTime)); logger.info("本包开合时间戳: " + openTime.getTime()); logger.info("本次开合周期:" + (openTime.getTime() - aHeadOpenTimeLongVal)); aHeadOpenTimeLongVal = openTime.getTime(); } } else { logger.info("本次开合模次数==0"); } } // String str = getDownPackage("02", "00 00 00 00 00 1e"); // System.out.println(str); } private String getNowDateHex() { LocalDateTime now = LocalDateTime.now(); int yearBit = now.getYear()%100; String yearHex = fillZeroLeft(Integer.toHexString(yearBit)); String monthHex = fillZeroLeft(Integer.toHexString(now.getMonthValue())); String dayHex = fillZeroLeft(Integer.toHexString(now.getDayOfMonth())); String hourHex = fillZeroLeft(Integer.toHexString(now.getHour())); String minHex = fillZeroLeft(Integer.toHexString(now.getMinute())); String secHex = fillZeroLeft(Integer.toHexString(now.getSecond())); return yearHex + monthHex + dayHex + hourHex + minHex + secHex; } private static String fillZeroLeft(String str) { if (str.length() == 1) { str = "0" + str; } return str; } }