UserHandler.java 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899
  1. package com.js.kbt.socket;
  2. import java.math.BigDecimal;
  3. import java.text.ParseException;
  4. import java.text.SimpleDateFormat;
  5. import java.time.LocalDateTime;
  6. import java.util.ArrayList;
  7. import java.util.Date;
  8. import java.util.List;
  9. import javax.annotation.Resource;
  10. import org.apache.log4j.Logger;
  11. import org.springframework.stereotype.Service;
  12. import org.springframework.util.CollectionUtils;
  13. import com.alibaba.fastjson.JSONObject;
  14. import com.js.kbt.mapper.ChangeIpCommandMapper;
  15. import com.js.kbt.mapper.EquipmentSendCommandMapper;
  16. import com.js.kbt.mapper.LonLatRecordMapper;
  17. import com.js.kbt.mapper.MouldCycleRuntimeMapper;
  18. import com.js.kbt.mapper.MouldDownPacketMapper;
  19. import com.js.kbt.mapper.MouldHistoryMapper;
  20. import com.js.kbt.mapper.MouldHistoryTimeMapper;
  21. import com.js.kbt.mapper.MouldHodingMapper;
  22. import com.js.kbt.mapper.RecDataLogMapper;
  23. import com.js.kbt.mapper.SensorThresholdMapper;
  24. import com.js.kbt.mapper.TbFactoryMapper;
  25. import com.js.kbt.mapper.TbMouldEquipmentMapper;
  26. import com.js.kbt.mapper.TbMouldMapper;
  27. import com.js.kbt.mapper.TimeCalibrationRecordMapper;
  28. import com.js.kbt.model.ChangeIpCommand;
  29. import com.js.kbt.model.ChangeIpCommandExample;
  30. import com.js.kbt.model.EquipmentSendCommand;
  31. import com.js.kbt.model.EquipmentSendCommandExample;
  32. import com.js.kbt.model.LonLatRecord;
  33. import com.js.kbt.model.LonLatRecordExample;
  34. import com.js.kbt.model.MouldDownPacket;
  35. import com.js.kbt.model.MouldDownPacketExample;
  36. import com.js.kbt.model.MouldHistory;
  37. import com.js.kbt.model.MouldHistoryExample;
  38. import com.js.kbt.model.MouldHistoryTime;
  39. import com.js.kbt.model.MouldHistoryTimeExample;
  40. import com.js.kbt.model.RecDataLog;
  41. import com.js.kbt.model.RecDataLogExample;
  42. import com.js.kbt.model.TbMould;
  43. import com.js.kbt.model.TbMouldEquipment;
  44. import com.js.kbt.model.TbMouldEquipmentExample;
  45. import com.js.kbt.model.TbMouldExample;
  46. import com.js.kbt.model.TimeCalibrationRecord;
  47. import io.netty.buffer.ByteBuf;
  48. import io.netty.buffer.Unpooled;
  49. import io.netty.channel.ChannelHandlerContext;
  50. import io.netty.channel.SimpleChannelInboundHandler;
  51. import io.netty.handler.timeout.IdleState;
  52. import io.netty.handler.timeout.IdleStateEvent;
  53. @Service("userHandler")
  54. public class UserHandler extends SimpleChannelInboundHandler<String> {
  55. public static final String CMD_STATUS = "01";//工作状态控制字;
  56. public static final String CMD_BUSY_PERIOD = "02";//工作忙状态周期
  57. public static final String CMD_IDLE_PERIOD = "03";//空闲状态周期
  58. public static final String CMD_TIME_FIX = "08";//网络时间校准
  59. public static final String CMD_NO_2G = "09";//NB切换2G阈值
  60. public static final String CMD_CLOSE_WTIME = "0C";//合模等待时间
  61. public static final String CMD_OPEN_WTIME = "0D";//开模等待时间1,单位1ms
  62. public static final String CMD_EEPROM = "0E";//重新上传EEPROM值
  63. public static final String CMD_WAITING_UPLOAD_TIME = "10";//待机上报时间
  64. public static final String CMD_COUNT = "12";//开合模总次数
  65. public static final String CMD_PURE_HEX = "100";//纯16进制指令,用户界面输入
  66. private static final Logger logger = Logger.getLogger(UserHandler.class);
  67. private ChannelHandlerContext ctx;
  68. @Resource
  69. private MouldHistoryMapper mouldHistoryMapper;
  70. @Resource
  71. private MouldHistoryTimeMapper mouldHistoryTimeMapper;
  72. @Resource
  73. private TbMouldMapper tbMouldMapper;
  74. @Resource
  75. private TbMouldEquipmentMapper tbMouldEquipmentMapper;
  76. @Resource
  77. private TbFactoryMapper tbFactoryMapper;
  78. @Resource
  79. private MouldHodingMapper mouldHodingMapper;
  80. @Resource
  81. private MouldDownPacketMapper mouldDownPacketMapper;
  82. @Resource
  83. private TimeCalibrationRecordMapper timeCalibrationRecordMapper;
  84. @Resource
  85. private MouldCycleRuntimeMapper mouldCycleRuntimeMapper;
  86. @Resource
  87. private SensorThresholdMapper sensorThresholdMapper;
  88. @Resource
  89. private RecDataLogMapper recDataLogMapper;
  90. @Resource
  91. private LonLatRecordMapper lonLatRecordMapper;
  92. @Resource
  93. private ChangeIpCommandMapper changeIpCommandMapper;
  94. @Resource
  95. private EquipmentSendCommandMapper equipmentSendCommandMapper;
  96. @Override
  97. protected void channelRead0(ChannelHandlerContext arg0, String arg1) throws ParseException {
  98. String pack = "FAAF0007001e781e50003C37D5";
  99. // 验证是否需要切换ip
  100. // sendChangeIp();
  101. logger.info("开始接受数据...");
  102. System.out.println("收到===" + arg1 + "\n");
  103. String equipmentNo = processMsg(arg1);
  104. // 校准时间
  105. timeCalibration(equipmentNo);
  106. // 以下是配置下行数据
  107. sendPackage(equipmentNo);
  108. }
  109. private String processMsg(String input) throws ParseException {
  110. // ScheduledExecutorService pool = Executors.newSingleThreadScheduledExecutor();
  111. String ret = "FA AF 00 07 02 1e 78 1e 50 00 3C";
  112. ret.replaceAll(" ", "");
  113. logger.info("=====接收到======" + input);
  114. if (!input.startsWith("FAAF")) {
  115. logger.info("非云模盒消息,不处理");
  116. return ret;
  117. }
  118. // 设备编号
  119. String deviceNum = "";
  120. // 创建一个字符串集合用于存储由于粘包需要拆分后的报文
  121. ret = input;
  122. //排重
  123. RecDataLogExample logExp = new RecDataLogExample();
  124. logExp.createCriteria().andRecDataEqualTo(input);
  125. if (recDataLogMapper.countByExample(logExp) > 0) {
  126. logger.info("重复消息,不作处理!");
  127. return ret;
  128. }
  129. RecDataLog logItem = new RecDataLog();
  130. logItem.setRecData(input);
  131. recDataLogMapper.insertSelective(logItem);
  132. List<String> strList = new ArrayList<>();
  133. while (ret.length() > 0) {
  134. String subStr = ret.substring(0,
  135. Integer.parseInt(highInFrontLowInBack(ret.substring((2) * 2, (4) * 2)), 16) * 2);
  136. strList.add(subStr);
  137. ret = ret.substring(subStr.length());
  138. logger.info("数据一包:"+subStr);
  139. }
  140. logger.info("粘包集合的長度==>" + strList.size());
  141. for (String string : strList) {
  142. MouldHistory item = new MouldHistory();
  143. // 抽取手机号码4-5(预留)丢包情况硬件会上报状态01,服务器判断02时候下发printall
  144. String mobilePart = string.substring(4 * 2, 5 * 2);
  145. System.out.println("原始mobile=" + mobilePart);
  146. String mobile = getStringFromHexStr(mobilePart);
  147. System.out.println("手机号码为" + mobile);
  148. item.setSim(mobile);
  149. // 获取设备编码15-24
  150. String deviceNumPart = string.substring(5 * 2, 25 * 2);
  151. deviceNum = getStringFromHexStr(deviceNumPart);
  152. logger.info("设备No=" + deviceNum);
  153. item.setEquipmentNo(deviceNum);
  154. // 发送数据包
  155. MouldDownPacketExample pExp = new MouldDownPacketExample();
  156. pExp.createCriteria().andEquipmentNoEqualTo(deviceNum).andPacketStrNotEqualTo("CLEAR_PROTOCOL");
  157. List<MouldDownPacket> packetList = mouldDownPacketMapper.selectByExample(pExp);
  158. if (packetList.size() > 0) {
  159. MouldDownPacket packet = packetList.get(0);
  160. logger.info("开始下发数据包==>" + packet.getPacketStr());
  161. sendMsg(packet.getPacketStr());
  162. // 下发完就将数据删除(防止后续数据过大造成性能的影响)
  163. mouldDownPacketMapper.deleteByPrimaryKey(packet.getId());
  164. }
  165. // 软件版本号25
  166. String version = string.substring(25 * 2, 26 * 2);
  167. System.out.println("软件版本号=" + version);
  168. item.setVersion(version);
  169. String status = string.substring(26 * 2, 27 * 2);
  170. System.out.println("工作状态=" + status);
  171. item.setStatus(Integer.decode("0x" + status).toString());
  172. // 经度27-37
  173. String longitude = getStringFromHexStr(string.substring(27 * 2, 38 * 2));
  174. System.out.println("经度=" + longitude);
  175. item.setLng(longitude);
  176. // 38-47纬度以 N 开头
  177. String latitude = getStringFromHexStr(string.substring(38 * 2, 48 * 2));
  178. System.out.println("纬度=" + latitude);
  179. item.setLat(latitude);
  180. System.out.println("==lac" + reverseParseHex(string.substring(48 * 2, 50 * 2)));
  181. System.out.println("==ci" + reverseParseHex(string.substring(50 * 2, 52 * 2)));
  182. // 临时变更高低位不做转换(由于硬件转递数据高低位传反导致,具体以上面为准)
  183. item.setGprsLac("" + reverseParseHex(string.substring(48 * 2, 50 * 2)));
  184. item.setGprsCi("" + reverseParseHex(string.substring(50 * 2, 52 * 2)));
  185. item.setWifiBbsid(string.substring(52 * 2, 58 * 2));
  186. String temp = "0x" + string.substring(58 * 2, 59 * 2);
  187. System.out.println(temp);
  188. int i = Integer.decode(temp) - 40;
  189. System.out.println(i);
  190. logger.info("温度-----------》: " + i);
  191. item.setTemperature(i);
  192. item.setBattery(Integer.decode("0x" + string.substring(59 * 2, 60 * 2)));
  193. item.setSig2g(Integer.decode("0x" + string.substring(60 * 2, 61 * 2)));
  194. item.setSigNb(Integer.decode("0x" + string.substring(61 * 2, 62 * 2)));
  195. item.setSigWifi(Integer.decode("0x" + string.substring(62 * 2, 63 * 2)));
  196. item.setExt0("" + Integer.decode("0x" + string.substring(63 * 2, 64 * 2)));
  197. item.setAlarm(Integer.decode("0x" + string.substring(64 * 2, 65 * 2)));
  198. String str = string.substring(65 * 2, 69 * 2);
  199. item.setRunCnt(reverseParseHex(str));
  200. LonLatRecordExample rExp = new LonLatRecordExample();
  201. rExp.createCriteria().andMccEqualTo("460").andMncEqualTo("0").andGprsCiEqualTo(item.getGprsCi())
  202. .andGprsLacEqualTo(item.getGprsLac());
  203. List<LonLatRecord> lRList = lonLatRecordMapper.selectByExample(rExp);
  204. if (lRList.size() > 0) {
  205. LonLatRecord lonLatRecord = lRList.get(0);
  206. item.setLng(lonLatRecord.getLng());
  207. item.setLat(lonLatRecord.getLat());
  208. } else {
  209. // 根据基站lac和ci获取经纬度
  210. String api = "http://api.cellocation.com:81/cell/?mcc=460&mnc=0&lac=" + item.getGprsLac() + "&ci="
  211. + item.getGprsCi() + "&output=json";
  212. String resp = com.js.kbt.util.HttpRequest.sendGet(api, null);
  213. JSONObject json = JSONObject.parseObject(resp);
  214. if (json != null && json.getInteger("errcode") == 0) {
  215. item.setLng(json.getDouble("lon") + "");
  216. item.setLat(json.getDouble("lat") + "");
  217. } else {
  218. logger.error("调用基站解析平台出错: " + resp);
  219. }
  220. LonLatRecord latRecord = new LonLatRecord();
  221. latRecord.setGprsCi(item.getGprsCi());
  222. latRecord.setMcc("460");
  223. latRecord.setMnc("0");
  224. latRecord.setGprsLac(item.getGprsLac());
  225. latRecord.setLat(item.getLat());
  226. latRecord.setLng(item.getLng());
  227. lonLatRecordMapper.insertSelective(latRecord);
  228. }
  229. String crcStr = string.substring(string.length() - 4);
  230. item.setCrcCode("" + reverseParseHex(crcStr));
  231. // 找寻上一条最新记录
  232. MouldHistoryExample mExp = new MouldHistoryExample();
  233. mExp.setOrderByClause("id desc limit 1");
  234. mExp.createCriteria().andEquipmentNoEqualTo(item.getEquipmentNo());
  235. List<MouldHistory> newList = mouldHistoryMapper.selectByExample(mExp);
  236. // 存入数据库
  237. mouldHistoryMapper.insertSelective(item);
  238. // 模具开合记录
  239. int cnt = item.getRunCnt();
  240. int start = 69;
  241. logger.info("累计开合模次数=" + cnt);
  242. int end = string.length() - 4; // 最后2位 0xXX,0xXX ,是CRC校验位
  243. logger.info("时间信息==" + string.substring(start * 2, end));
  244. Integer thisOpenCounts = 0;
  245. //用于接受上次最新的那一条开合数据
  246. List<MouldHistoryTime> historyList = new ArrayList<>();
  247. //用于接受第一包的开合时间与上次最新一包的开合时间差值
  248. long openTimeDiff = 0L;
  249. Date lastOpenTime = null;
  250. //用于接受第一包数据
  251. if (end - start * 2 >= 24) {// 时间最少6位,1位显示0x00,开合算两个时间,所以是6*2*2=24
  252. // 本次运行周期内的开合模次数
  253. int periodCnt = (end - start * 2) / 24;
  254. thisOpenCounts = periodCnt;
  255. logger.info("本次开合模次数==" + periodCnt);
  256. long aHeadOpenTimeLongVal = 0L;
  257. //用于接收判断是不是有包在当前包之后但已经发上来了,如16:11的开和数据先于16:10的数据先发上来
  258. for (int pos = 0; pos < periodCnt; pos++) {
  259. // 合模时间
  260. MouldHistoryTime time = new MouldHistoryTime();
  261. time.setHistoryId(item.getId());
  262. time.setEquipmentNo(item.getEquipmentNo());
  263. time.setSeq(pos + 1);
  264. Date closeTime = parseDate(string, start, pos, 0);
  265. time.setCloseTime(closeTime);
  266. // 开模时间
  267. Date openTime = parseDate(string, start, pos, 6);
  268. time.setOpenTime(openTime);
  269. lastOpenTime = openTime;
  270. logger.info("第" + (pos + 1) + "包");
  271. logger.info("本包开合时间戳--" + openTime.getTime());
  272. if (pos == 0) {
  273. MouldHistoryTimeExample mhtExp = new MouldHistoryTimeExample();
  274. //查询当前包是否是之前丢的包,判断依据,看看有没有比当前开合日期更后的开合数据
  275. mhtExp.setOrderByClause("open_time desc limit 1");
  276. mhtExp.createCriteria().andEquipmentNoEqualTo(item.getEquipmentNo()).andOpenTimeLessThanOrEqualTo(openTime);
  277. //小于当前开合时间的最新的一包开合数据
  278. historyList = mouldHistoryTimeMapper.selectByExample(mhtExp);
  279. if (historyList.size() > 0) {
  280. openTimeDiff = openTime.getTime() - historyList.get(0).getOpenTime().getTime();
  281. time.setTimeCost((int)openTimeDiff);
  282. } else {
  283. time.setTimeCost(0);
  284. }
  285. } else {
  286. logger.info("本次开合周期--" + (openTime.getTime() - aHeadOpenTimeLongVal));
  287. time.setTimeCost((int) (openTime.getTime() - aHeadOpenTimeLongVal));
  288. }
  289. mouldHistoryTimeMapper.insertSelective(time);
  290. // // 处理最后一包周期逻辑
  291. aHeadOpenTimeLongVal = openTime.getTime();
  292. }
  293. } else {
  294. logger.info("本次开合模次数==0");
  295. }
  296. // 统计该模盒的平均开合周期
  297. MouldHistoryTimeExample mtExp = new MouldHistoryTimeExample();
  298. mtExp.setOrderByClause("seq");
  299. mtExp.createCriteria().andHistoryIdEqualTo(item.getId()).andTimeCostGreaterThan(0);
  300. historyList = mouldHistoryTimeMapper.selectByExample(mtExp);
  301. int avgTime = 0;
  302. int totalTime = 0;
  303. if (historyList.size() > 1) {
  304. for (MouldHistoryTime mouldHistoryTime : historyList) {
  305. logger.info("totalTime" + totalTime);
  306. totalTime += mouldHistoryTime.getTimeCost();
  307. }
  308. logger.info("totalTime" + totalTime);
  309. avgTime = (int) (totalTime / historyList.size());
  310. }
  311. // }
  312. logger.info("avgTime-->" + avgTime);
  313. handleModLogic(item, avgTime, thisOpenCounts, lastOpenTime);
  314. // 判断预留字节的, 01-丢12包,02-丢50包
  315. // if ("02".equals(mobilePart)) {
  316. if ("01".equals(mobilePart) || "02".equals(mobilePart)) {
  317. // 丢包数据已占满缓存,调用读取命令
  318. // String strHexStr16 = strHexStr16("#PRINTFALL;");
  319. String strHexStr16 = getDownPackage(CMD_EEPROM, "00 00 00 00 00 01");
  320. logger.info("丢包数据已占满缓存下发调用读取命令#PRINTFALL;==>" + strHexStr16);
  321. sendMsg(strHexStr16);
  322. return deviceNum;
  323. }
  324. }
  325. return deviceNum;
  326. }
  327. // 下发切换服务器ip命令
  328. public void sendChangeIp() {
  329. ChangeIpCommandExample example = new ChangeIpCommandExample();
  330. example.createCriteria().andIsSendEqualTo(0);
  331. List<ChangeIpCommand> list = changeIpCommandMapper.selectByExample(example);
  332. if (!CollectionUtils.isEmpty(list)) {
  333. ChangeIpCommand changeIpCommand = list.get(0);
  334. // #IPADDS=58.213.104.114:9090;
  335. // 下发切换服务器命令
  336. StringBuffer sb = new StringBuffer();
  337. sb.append("#IPADDS=").append(changeIpCommand.getIp()).append(":").append(changeIpCommand.getPort())
  338. .append(";");
  339. logger.info("开始下发切换服务器命令字符串为;==>" + sb.toString());
  340. String strHexStr16 = strHexStr16(sb.toString());
  341. logger.info("下发切换服务器ip转换后的16进制为;==>" + strHexStr16);
  342. sendMsg(strHexStr16);
  343. // 下发完修改状态为已下发
  344. changeIpCommand.setIsSend(1);
  345. changeIpCommandMapper.updateByPrimaryKeySelective(changeIpCommand);
  346. }
  347. }
  348. //下发云模盒命令
  349. private void sendPackage(String equipmentNo) {
  350. if (equipmentNo.indexOf("FAAF") != -1) {
  351. logger.info("非法云模盒编号,不作下发处理");
  352. return;
  353. }
  354. //下发停用启用云模盒命令
  355. MouldDownPacketExample exp = new MouldDownPacketExample();
  356. exp.createCriteria().andEquipmentNoEqualTo(equipmentNo);
  357. List<MouldDownPacket> list = mouldDownPacketMapper.selectByExample(exp);
  358. if (list.size() > 0) {
  359. MouldDownPacket packet = list.get(0);
  360. TbMouldEquipmentExample meqExp = new TbMouldEquipmentExample();
  361. meqExp.createCriteria().andEquipmentNoEqualTo(equipmentNo);
  362. long count = tbMouldEquipmentMapper.countByExample(meqExp);
  363. // 下发数据包,下发完后修改状态
  364. logger.info("开始下发数据包==>" + packet.getPacketStr());
  365. sendMsg(packet.getPacketStr());
  366. if (null != packet.getThreshold()) {
  367. // 下发阈值命令
  368. sendMsg(strHexStr16("#LIMIT VALUE=" + packet.getThreshold()));
  369. }
  370. if (count > 0) {
  371. TbMouldEquipment me = tbMouldEquipmentMapper.selectByExample(meqExp).get(0);
  372. TbMouldEquipment tme = new TbMouldEquipment();
  373. tme.setId(me.getId());
  374. tme.setIsUse(packet.getIsUse());
  375. tbMouldEquipmentMapper.updateByPrimaryKeySelective(tme);
  376. logger.info("将启用中的云模盒改为启用成功==>" + me.getEquipmentNo());
  377. }
  378. // 下发完删除数据
  379. mouldDownPacketMapper.deleteByPrimaryKey(packet.getId());
  380. }
  381. //发送清空次数和其他指定
  382. EquipmentSendCommandExample escExample = new EquipmentSendCommandExample();
  383. escExample.createCriteria().andEquipmentNoEqualTo(equipmentNo).andIsSendEqualTo(0);
  384. List<EquipmentSendCommand> sendCommandLists = equipmentSendCommandMapper.selectByExample(escExample);
  385. if(sendCommandLists.size()>0){
  386. for (EquipmentSendCommand equipmentSendCommand : sendCommandLists) {
  387. switch (equipmentSendCommand.getCmd()) {
  388. case CMD_STATUS:
  389. break;
  390. case CMD_BUSY_PERIOD:
  391. break;
  392. case CMD_IDLE_PERIOD:
  393. break;
  394. case CMD_TIME_FIX:
  395. break;
  396. case CMD_NO_2G:
  397. break;
  398. case CMD_CLOSE_WTIME:
  399. break;
  400. case CMD_OPEN_WTIME:
  401. break;
  402. case CMD_EEPROM:
  403. break;
  404. case CMD_WAITING_UPLOAD_TIME:
  405. break;
  406. case CMD_COUNT:
  407. sendMsg(getDownPackage(CMD_COUNT, "00 00 00 00 00 00"));
  408. equipmentSendCommand.setIsSend(1);
  409. equipmentSendCommand.setSendTime(new Date());
  410. equipmentSendCommandMapper.updateByPrimaryKeySelective(equipmentSendCommand);
  411. break;
  412. case CMD_PURE_HEX:
  413. String pack = equipmentSendCommand.getParam();
  414. System.out.println("下发16进制手动指令=="+pack);
  415. if (pack.contains(" ")) {
  416. pack = pack.replaceAll(" ", "");
  417. }
  418. sendMsg(pack);
  419. equipmentSendCommand.setIsSend(1);
  420. equipmentSendCommand.setSendTime(new Date());
  421. equipmentSendCommandMapper.updateByPrimaryKeySelective(equipmentSendCommand);
  422. break;
  423. }
  424. }
  425. }
  426. }
  427. public void timeCalibration(String equipmentNo) {
  428. // logger.info("下发校准时间的云模盒equipmentNo"+equipmentNo);
  429. if (equipmentNo.indexOf("FAAF") != -1) {
  430. logger.info("非法云模盒编号,不作下发处理");
  431. return;
  432. }
  433. List<TimeCalibrationRecord> count = timeCalibrationRecordMapper.selectCountByToday(equipmentNo);
  434. // 今天未校准时间,下发时间校准,已经校准过了,则不再校准
  435. if (count.size() == 0) {
  436. // Date date = new Date();
  437. // SimpleDateFormat sdf = new SimpleDateFormat("yy-MM-dd,HH:mm:ss");
  438. // String dateStr = sdf.format(date);
  439. // dateStr = "#TIME=" + dateStr + ";";
  440. // // #TIME=18-03-06,15:31:48;
  441. // logger.info("校准系统模块时间==>" + dateStr);
  442. // // 将字符串转成16进制字符串
  443. // String strHexStr16 = strHexStr16(dateStr);
  444. // logger.info("校准系统模块时间转成16进制的字符串==>" + strHexStr16);
  445. //新协议
  446. String hexDate = getNowDateHex();
  447. logger.info("校准系统模块时间转成16进制的字符串==>" + hexDate);
  448. sendMsg(getDownPackage(CMD_TIME_FIX, hexDate));
  449. TimeCalibrationRecord timeCalibrationRecord = new TimeCalibrationRecord();
  450. timeCalibrationRecord.setIndate(new Date());
  451. timeCalibrationRecord.setEquipmentNo(equipmentNo);
  452. timeCalibrationRecordMapper.insertSelective(timeCalibrationRecord);
  453. }
  454. }
  455. //构建下行的命令
  456. public static String getDownPackage(String hexCmd, String hexData) {
  457. if (hexData.contains(" ")) {
  458. hexData = hexData.replaceAll(" ", "");
  459. }
  460. hexData = hexData.toUpperCase();
  461. byte[] b = getCRCByCmd(hexCmd, hexData);
  462. String crc = getCRC(b).toUpperCase();
  463. if (crc.length() < 4) {
  464. crc = "0" + crc;
  465. }
  466. //低位在前转化
  467. crc = crc.substring(2,4) +crc.substring(0,2);
  468. StringBuilder sb = new StringBuilder();
  469. sb.append("FAAF0D00")
  470. .append(hexCmd)
  471. .append(hexData)
  472. .append(crc);
  473. String str = sb.toString();
  474. //中间加空格
  475. StringBuilder mm = new StringBuilder();
  476. for (int i=0;i<str.length(); i+=2) {
  477. mm.append(str.substring(i, i+2));
  478. if (i < str.length() -2) {
  479. mm.append(" ");
  480. }
  481. }
  482. System.out.println(mm.toString());
  483. return mm.toString();
  484. }
  485. public static byte[] getCRCByCmd(String cmd, String hexData) {
  486. byte[] crcByte = new byte[11];
  487. crcByte[0]= (byte)Integer.parseInt("FA", 16);
  488. crcByte[1]= (byte)Integer.parseInt("AF", 16);
  489. crcByte[2]= (byte)Integer.parseInt("0D", 16);
  490. crcByte[3]= (byte)Integer.parseInt("00", 16);
  491. crcByte[4]= (byte)Integer.parseInt(cmd, 16);
  492. crcByte[5] = (byte)Integer.parseInt(hexData.substring(0, 2), 16);;
  493. crcByte[6] = (byte)Integer.parseInt(hexData.substring(2, 4), 16);;
  494. crcByte[7] = (byte)Integer.parseInt(hexData.substring(4, 6), 16);;
  495. crcByte[8] = (byte)Integer.parseInt(hexData.substring(6, 8), 16);;
  496. crcByte[9] = (byte)Integer.parseInt(hexData.substring(8, 10), 16);;
  497. crcByte[10] = (byte)Integer.parseInt(hexData.substring(10, 12), 16);;
  498. return crcByte;
  499. }
  500. /**
  501. * 计算CRC16校验码
  502. *
  503. * @param bytes
  504. * @return
  505. */
  506. public static String getCRC(byte[] bytes) {
  507. int CRC = 0x0000ffff;
  508. int POLYNOMIAL = 0x0000a001;
  509. int i, j;
  510. for (i = 0; i < bytes.length; i++) {
  511. CRC ^= ((int) bytes[i] & 0x000000ff);
  512. for (j = 0; j < 8; j++) {
  513. if ((CRC & 0x00000001) != 0) {
  514. CRC >>= 1;
  515. CRC ^= POLYNOMIAL;
  516. } else {
  517. CRC >>= 1;
  518. }
  519. }
  520. }
  521. return Integer.toHexString(CRC);
  522. }
  523. private void handleModLogic(MouldHistory item, int avgTime, Integer thisOpenCount, Date lastOpenTime) {
  524. logger.info("进了handleModLogic逻辑--");
  525. logger.info("item==>" + item);
  526. TbMouldEquipmentExample meqExp = new TbMouldEquipmentExample();
  527. meqExp.createCriteria().andEquipmentNoEqualTo(item.getEquipmentNo());
  528. if (tbMouldEquipmentMapper.countByExample(meqExp) > 0) {
  529. TbMouldEquipment me = tbMouldEquipmentMapper.selectByExample(meqExp).get(0);
  530. me.setCurhillNumber(item.getBattery() + "");
  531. if (item.getLng() != null) {
  532. logger.info("更新经纬度:");
  533. me.setLng(Double.parseDouble(item.getLng()));
  534. me.setLat(Double.parseDouble(item.getLat()));
  535. }
  536. me.setCurtemperature(item.getTemperature());
  537. if (item.getAlarm() == 8) {
  538. me.setStage(3);// 安装被拆
  539. } else if (item.getAlarm() == 1) {
  540. me.setStage(2);// 低电量
  541. } else if (item.getAlarm() == 2) {
  542. me.setStage(1);// 高温
  543. } else {
  544. me.setStage(item.getAlarm());
  545. }
  546. // 处理报警
  547. if (item.getAlarm() > 0) {
  548. /**
  549. * 无报警 0; 低电量报警 1; 温度过热 2; 安装被拆 8。
  550. */
  551. logger.info("设备报警啦:" + item.getAlarm());
  552. }
  553. //处理最后一次开模时间
  554. if (me.getLastopentime() == null) {
  555. me.setLastopentime(lastOpenTime);
  556. } else if (lastOpenTime != null && me.getLastopentime().before(lastOpenTime)) {
  557. me.setLastopentime(lastOpenTime);
  558. logger.info("设置最后开模时间:" + new SimpleDateFormat("yyyy-M-dd HH:mm:ss").format(lastOpenTime));
  559. }
  560. tbMouldEquipmentMapper.updateByPrimaryKeySelective(me);
  561. logger.info("更新完了tbMouldEquipment的状态和温度以及经纬度");
  562. TbMouldExample tExp = new TbMouldExample();
  563. tExp.setOrderByClause("id desc limit 1");
  564. tExp.createCriteria().andEquipmentIdEqualTo(me.getId());
  565. if (tbMouldMapper.countByExample(tExp) > 0) {
  566. logger.info("准备更新运行次数:");
  567. TbMould tm = tbMouldMapper.selectByExample(tExp).get(0);
  568. MouldHistoryTimeExample mhtExp = new MouldHistoryTimeExample();
  569. // 一次接受到数据,超过5次开合标记为运行状态
  570. if (thisOpenCount > 5) {
  571. tm.setState(item.getStatus());
  572. } else {
  573. tm.setState("0");
  574. }
  575. // 云模盒运行次数+模具的历史运行次数
  576. tm.setRunTimes(item.getRunCnt() + tm.getHistoryRunTimes());
  577. tm.setLastRecTime(new Date());
  578. // 处理每模平均周期(单位秒)
  579. if (0 != avgTime) {
  580. logger.info("开始修改平均每模周期值为:" + avgTime);
  581. BigDecimal bd = new BigDecimal(avgTime * 1.00 / 1000);
  582. tm.setOcCycle(bd);
  583. }
  584. tbMouldMapper.updateByPrimaryKeySelective(tm);
  585. }
  586. }
  587. }
  588. /**
  589. * 低位在前的16进制解析
  590. *
  591. * @param rHex
  592. * @return
  593. */
  594. public static int reverseParseHex(String rHex) {
  595. int size = rHex.length() / 2;
  596. StringBuilder sb = new StringBuilder();
  597. for (int i = 0; i < size; i++) {
  598. sb.append(rHex.substring((size - i - 1) * 2, (size - i) * 2));
  599. }
  600. String str = sb.toString();
  601. return Integer.parseInt(str, 16);
  602. }
  603. private static Date parseDate(String input, int start, int pos, int dateStartPos) {
  604. // pos为开合的一组的下标,一个开合时间占位是12*2
  605. String year = input.substring((start + pos * 12 + dateStartPos) * 2, (start + pos * 12 + 1 + dateStartPos) * 2);
  606. String month = input.substring((start + pos * 12 + 1 + dateStartPos) * 2,
  607. (start + pos * 12 + 2 + dateStartPos) * 2);
  608. String day = input.substring((start + pos * 12 + 2 + dateStartPos) * 2,
  609. (start + pos * 12 + 3 + dateStartPos) * 2);
  610. String hh = input.substring((start + pos * 12 + 3 + dateStartPos) * 2,
  611. (start + pos * 12 + 4 + dateStartPos) * 2);
  612. String mm = input.substring((start + pos * 12 + 4 + dateStartPos) * 2,
  613. (start + pos * 12 + 5 + dateStartPos) * 2);
  614. String ss = input.substring((start + pos * 12 + 5 + dateStartPos) * 2,
  615. (start + pos * 12 + 6 + dateStartPos) * 2);
  616. logger.info("时间="+year + month+day+hh+mm+ss);
  617. StringBuilder sb = new StringBuilder();
  618. int yearInt = Integer.parseInt(year, 16);
  619. if (yearInt == 0) {
  620. sb.append("2019-01-01");
  621. } else {
  622. sb.append(yearInt < 100 ? "20" : "2");
  623. sb.append(yearInt).append("-");
  624. int monthInt = Integer.parseInt(month, 16);
  625. sb.append(monthInt < 10 ? "0" : "").append(monthInt).append("-");
  626. int dayInt = Integer.parseInt(day, 16);
  627. sb.append(dayInt < 10 ? "0" : "").append(dayInt);
  628. }
  629. Date parseDate = null;
  630. try {
  631. parseDate = new SimpleDateFormat("yyyy-MM-dd").parse(sb.toString());
  632. parseDate.setHours(Integer.parseInt(hh, 16));
  633. parseDate.setMinutes(Integer.parseInt(mm, 16));
  634. parseDate.setSeconds(Integer.parseInt(ss, 16));
  635. } catch (ParseException e) {
  636. e.printStackTrace();
  637. }
  638. return parseDate;
  639. }
  640. private static String getStringFromHexStr(String hexStr) {
  641. StringBuilder sb = new StringBuilder();
  642. for (int i = 0; i < hexStr.length() / 2; i++) {
  643. String str = "0x" + hexStr.substring(i * 2, i * 2 + 2);
  644. int intVal = Integer.decode(str).intValue();
  645. char c = (char) intVal;
  646. sb.append(c);
  647. }
  648. return sb.toString();
  649. }
  650. public void close() {
  651. ctx.close();
  652. }
  653. public void sendMsg(String hexString) {
  654. System.out.println("发送消息==" + hexString);
  655. byte[] buffer = hexStrToBinaryStr(hexString);
  656. ByteBuf bf = Unpooled.buffer(hexString.length() / 2);
  657. bf.writeBytes(buffer);
  658. ctx.writeAndFlush(bf);
  659. // ctx.close();
  660. }
  661. /**
  662. * channel被激活时调用
  663. */
  664. @Override
  665. public void channelActive(ChannelHandlerContext ctx) {
  666. // TODO Auto-generated method stub
  667. this.ctx = ctx;
  668. System.out.println("==========Active=========" + ctx.channel().localAddress().toString() + ", connection num="
  669. + HelloServer.deviceMap.size());
  670. }
  671. @Override
  672. public void channelInactive(ChannelHandlerContext ctx) throws Exception {
  673. super.channelInactive(ctx);
  674. System.out.println("==========Inactive=========");
  675. }
  676. @Override
  677. public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
  678. // TODO Auto-generated method stub
  679. super.handlerRemoved(ctx);
  680. System.out.println("[YunSu]handlerRemoved=掉线了===");
  681. }
  682. @Override
  683. public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
  684. // TODO Auto-generated method stub
  685. super.exceptionCaught(ctx, cause);
  686. System.out.println("我捕捉到异常信息了");
  687. }
  688. @Override
  689. public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
  690. if (evt instanceof IdleStateEvent) {
  691. IdleStateEvent event = (IdleStateEvent) evt;
  692. if (event.state().equals(IdleState.READER_IDLE)) {
  693. } else if (event.state().equals(IdleState.WRITER_IDLE)) {
  694. // System.out.println("WRITER_IDLE=="+userInfo.getWxName());
  695. // logger.debug(ctx.channel().remoteAddress().toString()+
  696. // "WRITER_IDLE");
  697. // 超时关闭channel
  698. // ctx.close();
  699. } else if (event.state().equals(IdleState.ALL_IDLE)) {
  700. // 发送心跳
  701. ctx.channel().writeAndFlush("$&_".toString());
  702. }
  703. }
  704. // super.userEventTriggered(ctx, evt);
  705. }
  706. /**
  707. * 将十六进制的字符串转换成字节数组
  708. *
  709. * @param hexString
  710. * @return
  711. */
  712. public static byte[] hexStrToBinaryStr(String hexString) {
  713. if (hexString == null || "".contentEquals(hexString)) {
  714. return null;
  715. }
  716. hexString = hexString.replaceAll(" ", "");
  717. int len = hexString.length();
  718. int index = 0;
  719. byte[] bytes = new byte[len / 2];
  720. while (index < len) {
  721. String sub = hexString.substring(index, index + 2);
  722. bytes[index / 2] = (byte) Integer.parseInt(sub, 16);
  723. index += 2;
  724. }
  725. return bytes;
  726. }
  727. /**
  728. * 将字节数组转换成十六进制的字符串
  729. *
  730. * @return
  731. */
  732. public static String BinaryToHexString(byte[] bytes) {
  733. String hexStr = "0123456789ABCDEF";
  734. String result = "";
  735. String hex = "";
  736. for (byte b : bytes) {
  737. hex = String.valueOf(hexStr.charAt((b & 0xF0) >> 4));
  738. hex += String.valueOf(hexStr.charAt(b & 0x0F));
  739. result += hex + " ";
  740. }
  741. return result;
  742. }
  743. /**
  744. * 普通字符串转16进制字符串
  745. *
  746. * @param str
  747. * @return
  748. */
  749. public static String strHexStr16(String str) {
  750. char[] chars = "0123456789ABCDEF".toCharArray();
  751. StringBuilder sb = new StringBuilder("");
  752. byte[] bs = str.getBytes();
  753. int bit;
  754. for (int i = 0; i < bs.length; i++) {
  755. bit = (bs[i] & 0x0f0) >> 4;
  756. sb.append(chars[bit]);
  757. bit = bs[i] & 0x0f;
  758. sb.append(chars[bit]);
  759. // sb.append(' ');
  760. }
  761. return sb.toString().trim();
  762. }
  763. // 转换16进制字符串低位在前,高位在后 成 高位在前,低位在后
  764. public static String highInFrontLowInBack(String result) {
  765. return result.substring(2, 4) + result.substring(0, 2);// 高位在前,低位在后
  766. }
  767. public static void main(String[] args) throws ParseException {
  768. String ret = "FA AF 00 07 02 1e 78 1e 50 00 3C";
  769. String input = "FAAFE30000383938363034313631323138383035383439333733011200000000000000000000000000000000000000005F55D712000000000000485A4A3A000100301A000014040B0B2B2714040B0B2C0B14040B0B2C0D14040B0B2C2D14040B0B2C2F14040B0B2D1514040B0B2D1B14040B0B2D3514040B0B2D3814040B0B2E1C14040B0B2E1E14040B0B2F0214040B0B2F0414040B0B2F2414040B0B2F2614040B0B300A14040B0B300C14040B0B302C14040B0B302F14040B0B311214040B0B311514040B0B313514040B0B313714040B0B321B14040B0B321D14040B0B33011DD6FAAF270200383938363034313631323138383035383439333733011200000000000000000000000000000000000000005F55D712000000000000485A4A37000100671A000014040B0B330314040B0B332314040B0B332514040B0B340B14040B0B340E14040B0B342E14040B0B343314040B0B351214040B0B351414040B0B353414040B0B353614040B0B361A14040B0B361C14040B0B370014040B0B370214040B0B372514040B0B372714040B0B380814040B0B380B14040B0B382A14040B0B382D14040B0B391114040B0B391314040B0B393314040B0B393514040B0B3A1914040B0B3A1B14040B0B3A3B14040B0B3B0114040B0B3B2114040B0B3B2414040B0C000814040B0C000A14040B0C002A14040B0C002C14040B0C011014040B0C011214040B0C013214040B0C013414040B0C021814040B0C021A14040B0C023A14040B0C030114040B0C032014040B0C032314040B0C040714040B0C040914040B0C042914040B0C042B14040B0C050F14040B0C051114040B0C053314040B0C053514040B0C061714040B0C061914040B0C070014040B0C070214040B0C072214040B0C072714040B0C080614040B0C080814040B0C082814040B0C082A14040B0C090E14040B0C091014040B0C093114040B0C093314040B0C0A1614040B0C0A1914040B0C0A3914040B0C0A3B14040B0C0B1F14040B0C0B2114040B0C0C0514040B0C0C0714040B0C0C2814040B0C0C2914040B0C0D0D14040B0C0D1014040B0C0D320038";
  770. ret.replaceAll(" ", "");
  771. logger.info("=====接收到======" + input);
  772. if (!input.startsWith("FAAF")) {
  773. logger.info("非云模盒消息,不处理");
  774. }
  775. // 设备编号
  776. String deviceNum = "";
  777. // 创建一个字符串集合用于存储由于粘包需要拆分后的报文
  778. ret = input;
  779. List<String> strList = new ArrayList<>();
  780. while (ret.length() > 0) {
  781. String subStr = ret.substring(0,
  782. Integer.parseInt(highInFrontLowInBack(ret.substring((2) * 2, (4) * 2)), 16) * 2);
  783. strList.add(subStr);
  784. ret = ret.substring(subStr.length());
  785. }
  786. logger.info("粘包集合的長度==>" + strList.size());
  787. for (String string : strList) {
  788. String str = string.substring(65 * 2, 69 * 2);
  789. logger.info("cnt str=="+str);
  790. int cnt = reverseParseHex(str);
  791. int start = 69;
  792. logger.info("累计开合模次数=" + cnt);
  793. int end = string.length() - 4; // 最后2位 0xXX,0xXX ,是CRC校验位
  794. logger.info("时间信息==" + string.substring(start * 2, end));
  795. Integer thisOpenCounts = 0;
  796. //用于接受上次最新的那一条开合数据
  797. //用于接受第一包数据
  798. if (end - start * 2 >= 24) {// 时间最少6位,1位显示0x00,开合算两个时间,所以是6*2*2=24
  799. // 本次运行周期内的开合模次数
  800. int periodCnt = (end - start * 2) / 24;
  801. thisOpenCounts = periodCnt;
  802. logger.info("本次开合模次数==" + periodCnt);
  803. long aHeadOpenTimeLongVal = 0L;
  804. //用于接收判断是不是有包在当前包之后但已经发上来了,如16:11的开和数据先于16:10的数据先发上来
  805. for (int pos = 0; pos < periodCnt; pos++) {
  806. // 合模时间
  807. Date closeTime = parseDate(string, start, pos, 0);
  808. // 开模时间
  809. Date openTime = parseDate(string, start, pos, 6);
  810. logger.info("第" + (pos + 1) + "包");
  811. logger.info("本包开合时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(openTime));
  812. logger.info("本包开合时间戳: " + openTime.getTime());
  813. logger.info("本次开合周期:" + (openTime.getTime() - aHeadOpenTimeLongVal));
  814. aHeadOpenTimeLongVal = openTime.getTime();
  815. }
  816. } else {
  817. logger.info("本次开合模次数==0");
  818. }
  819. }
  820. // String str = getDownPackage("02", "00 00 00 00 00 1e");
  821. // System.out.println(str);
  822. }
  823. private String getNowDateHex() {
  824. LocalDateTime now = LocalDateTime.now();
  825. int yearBit = now.getYear()%100;
  826. String yearHex = fillZeroLeft(Integer.toHexString(yearBit));
  827. String monthHex = fillZeroLeft(Integer.toHexString(now.getMonthValue()));
  828. String dayHex = fillZeroLeft(Integer.toHexString(now.getDayOfMonth()));
  829. String hourHex = fillZeroLeft(Integer.toHexString(now.getHour()));
  830. String minHex = fillZeroLeft(Integer.toHexString(now.getMinute()));
  831. String secHex = fillZeroLeft(Integer.toHexString(now.getSecond()));
  832. return yearHex + monthHex + dayHex + hourHex + minHex + secHex;
  833. }
  834. private static String fillZeroLeft(String str) {
  835. if (str.length() == 1) {
  836. str = "0" + str;
  837. }
  838. return str;
  839. }
  840. }