22 changed files with 2469 additions and 38 deletions
@ -0,0 +1,277 @@ |
|||||||
|
package com.mh.common.utils; |
||||||
|
|
||||||
|
import com.mh.common.core.domain.entity.CollectionParamsManage; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.math.RoundingMode; |
||||||
|
import java.text.DecimalFormat; |
||||||
|
import java.text.ParseException; |
||||||
|
import java.text.SimpleDateFormat; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ljf |
||||||
|
* @title : |
||||||
|
* @description : 解析485接收的数据 |
||||||
|
* @updateTime 2020-04-23 |
||||||
|
* @throws : |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class AnalysisReceiveOrder485 { |
||||||
|
|
||||||
|
// 调用service
|
||||||
|
private final SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||||
|
private final DecimalFormat df = new DecimalFormat("#.##"); |
||||||
|
|
||||||
|
//解析冷量表
|
||||||
|
public void analysisCloudOrder485(final String dataStr1, final CollectionParamsManage deviceCodeParam) { |
||||||
|
// 去掉空格
|
||||||
|
String dataStr = dataStr1.replace(" ", "").toUpperCase(); |
||||||
|
// 检验报文
|
||||||
|
String checkStr = dataStr.substring(0, dataStr.length() - 4); |
||||||
|
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); |
||||||
|
int checkNum = CRC16.CRC16_MODBUS(strOrder); |
||||||
|
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum)); |
||||||
|
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2); |
||||||
|
|
||||||
|
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) { |
||||||
|
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
|
||||||
|
Date date = new Date(); |
||||||
|
String dateStr = sdf1.format(date); |
||||||
|
; |
||||||
|
//保留两位小数处理
|
||||||
|
DecimalFormat decimalFormat = new DecimalFormat("0.00"); |
||||||
|
// 表号
|
||||||
|
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2)); |
||||||
|
// 读数
|
||||||
|
String data = ""; |
||||||
|
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6) |
||||||
|
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4) |
||||||
|
+ dataStr.substring(dataStr.length() - 12, dataStr.length() - 10) |
||||||
|
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8); |
||||||
|
|
||||||
|
String registerAddr = deviceCodeParam.getRegisterAddr(); |
||||||
|
if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "00"; |
||||||
|
} else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "30"; |
||||||
|
} |
||||||
|
try { |
||||||
|
if (registerAddr.equals("32") || registerAddr.equals("33") || registerAddr.equals("35") || registerAddr.equals("36")) { |
||||||
|
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
|
||||||
|
log.info("冷量计==>{},寄存器地址==>{},读数==>{}", cloudId, registerAddr, data); |
||||||
|
} else if (registerAddr.equals("31") || registerAddr.equals("34")) { |
||||||
|
long lData = Long.parseLong(ExchangeStringUtil.hexToDec(data)); |
||||||
|
log.info("冷量计==>{},寄存器地址==>{},累计读数==>{}", cloudId, registerAddr, lData); |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("保存冷量计数据失败!", e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
log.info("冷量计校验失败===>{}", dataStr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 解析水表返回的数据 |
||||||
|
* |
||||||
|
* @param dataStr1 |
||||||
|
*/ |
||||||
|
public String analysisWaterOrder485(final String dataStr1, final CollectionParamsManage deviceCodeParam) { |
||||||
|
// 去掉空格
|
||||||
|
String dataStr = dataStr1.replace(" ", "").toUpperCase(); |
||||||
|
// 检验报文
|
||||||
|
String checkStr = dataStr.substring(0, dataStr.length() - 4); |
||||||
|
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); |
||||||
|
int checkNum = CRC16.CRC16_MODBUS(strOrder); |
||||||
|
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum)); |
||||||
|
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2); |
||||||
|
|
||||||
|
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) { |
||||||
|
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
|
||||||
|
Date date = new Date(); |
||||||
|
String dateStr = sdf1.format(date); |
||||||
|
; |
||||||
|
//保留两位小数处理
|
||||||
|
DecimalFormat decimalFormat = new DecimalFormat("0.00"); |
||||||
|
// 表号
|
||||||
|
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2)); |
||||||
|
// 读数
|
||||||
|
String data = ""; |
||||||
|
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6) |
||||||
|
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4) |
||||||
|
+ dataStr.substring(dataStr.length() - 12, dataStr.length() - 10) |
||||||
|
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8); |
||||||
|
|
||||||
|
int dataType = deviceCodeParam.getDataType(); |
||||||
|
if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "00"; |
||||||
|
System.out.println("插入时间00" + dateStr); |
||||||
|
} else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "30"; |
||||||
|
System.out.println("插入时间30" + dateStr); |
||||||
|
} |
||||||
|
try { |
||||||
|
if (dataType == 3) { |
||||||
|
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
|
||||||
|
log.info("水表==>{},寄存器地址==>{},读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data); |
||||||
|
} else if (dataType == 2) { |
||||||
|
data = dataStr.substring(dataStr.length() - 12, dataStr.length() - 10) |
||||||
|
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8) |
||||||
|
+ dataStr.substring(dataStr.length() - 8, dataStr.length() - 6) |
||||||
|
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4); |
||||||
|
data = ExchangeStringUtil.hexToDec(data); |
||||||
|
BigDecimal bigDecimal = new BigDecimal(data); |
||||||
|
bigDecimal = bigDecimal.divide(new BigDecimal((int) Math.pow(10, deviceCodeParam.getDigits()))).setScale(2, RoundingMode.HALF_UP); // 除以1000并保留整数
|
||||||
|
data = bigDecimal.toString(); |
||||||
|
log.info("水表==>{},寄存器地址==>{},累计读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data); |
||||||
|
} |
||||||
|
return data; |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("保存水表数据失败!", e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
log.info("水表===>{}", dataStr); |
||||||
|
return ""; |
||||||
|
} |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* 解析电表返回的数据 |
||||||
|
* |
||||||
|
* @param dataStr1 |
||||||
|
*/ |
||||||
|
public String analysisMeterOrder485(final String dataStr1, final CollectionParamsManage deviceCodeParam) { |
||||||
|
// 去掉空格
|
||||||
|
String dataStr = dataStr1.replace(" ", "").toUpperCase(); |
||||||
|
// 检验报文
|
||||||
|
String checkStr = dataStr.substring(0, dataStr.length() - 4); |
||||||
|
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); |
||||||
|
int checkNum = CRC16.CRC16_MODBUS(strOrder); |
||||||
|
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum)); |
||||||
|
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2); |
||||||
|
|
||||||
|
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) { |
||||||
|
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
|
||||||
|
Date date = new Date(); |
||||||
|
String dateStr = sdf1.format(date); |
||||||
|
; |
||||||
|
//保留两位小数处理
|
||||||
|
DecimalFormat decimalFormat = new DecimalFormat("0.00"); |
||||||
|
// 表号
|
||||||
|
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2)); |
||||||
|
// 读数
|
||||||
|
String data = ""; |
||||||
|
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6) |
||||||
|
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4) |
||||||
|
+ dataStr.substring(dataStr.length() - 12, dataStr.length() - 10) |
||||||
|
+ dataStr.substring(dataStr.length() - 10, dataStr.length() - 8); |
||||||
|
|
||||||
|
int dataType = deviceCodeParam.getDataType(); |
||||||
|
if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "00"; |
||||||
|
System.out.println("插入时间00" + dateStr); |
||||||
|
} else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "30"; |
||||||
|
System.out.println("插入时间30" + dateStr); |
||||||
|
} |
||||||
|
try { |
||||||
|
if (dataType == 3) { |
||||||
|
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
|
||||||
|
log.info("电表==>{},寄存器地址==>{},读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data); |
||||||
|
} else if (dataType == 2) { |
||||||
|
data = ExchangeStringUtil.hexToDec(data); |
||||||
|
log.info("电表==>{},寄存器地址==>{},累计读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data); |
||||||
|
} |
||||||
|
return data; |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("保存电表数据失败!", e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
log.info("电表===>{}", dataStr); |
||||||
|
return ""; |
||||||
|
} |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
public static int dValue(String lastDate) throws ParseException { |
||||||
|
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); |
||||||
|
Date lastTime = format.parse(lastDate); |
||||||
|
long min = lastTime.getTime(); |
||||||
|
Calendar calendar = Calendar.getInstance(); |
||||||
|
long min1 = calendar.getTimeInMillis(); |
||||||
|
long subtract = min1 - min; |
||||||
|
// System.out.println("相减值: " + subtract/(1000*60));
|
||||||
|
return (int) subtract / (1000 * 60); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// 判断是否存在寄存器地址
|
||||||
|
public Boolean queryRegisterAddr(List<String> stringList, String registerAddr) { |
||||||
|
boolean flag = false; |
||||||
|
for (int i = 0; i < stringList.size(); i++) { |
||||||
|
if (stringList.get(i).equalsIgnoreCase(registerAddr)) { |
||||||
|
flag = true; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
return flag; |
||||||
|
} |
||||||
|
|
||||||
|
public String analysisHeatPumpOrder485(String receiveStr, CollectionParamsManage deviceCodeParam) { |
||||||
|
// 去掉空格
|
||||||
|
String dataStr = receiveStr.replace(" ", "").toUpperCase(); |
||||||
|
// 检验报文
|
||||||
|
String checkStr = dataStr.substring(0, dataStr.length() - 4); |
||||||
|
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(checkStr); |
||||||
|
int checkNum = CRC16.CRC16_MODBUS(strOrder); |
||||||
|
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum)); |
||||||
|
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2); |
||||||
|
|
||||||
|
if (checkWord.equalsIgnoreCase(dataStr.substring(dataStr.length() - 4))) { |
||||||
|
//创建SimpleDateFormat对象,指定样式 2019-05-13 22:39:30
|
||||||
|
Date date = new Date(); |
||||||
|
String dateStr = sdf1.format(date); |
||||||
|
|
||||||
|
//保留两位小数处理
|
||||||
|
DecimalFormat decimalFormat = new DecimalFormat("0.00"); |
||||||
|
// 表号
|
||||||
|
String cloudId = ExchangeStringUtil.hexToDec(dataStr.substring(0, 2)); |
||||||
|
// 读数
|
||||||
|
String data = ""; |
||||||
|
data = dataStr.substring(dataStr.length() - 8, dataStr.length() - 6) |
||||||
|
+ dataStr.substring(dataStr.length() - 6, dataStr.length() - 4); |
||||||
|
|
||||||
|
int dataType = deviceCodeParam.getDataType(); |
||||||
|
if (ExchangeStringUtil.isInDate(date, "00:00:00", "00:00:30")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "00"; |
||||||
|
System.out.println("插入时间00" + dateStr); |
||||||
|
} else if (ExchangeStringUtil.isInDate(date, "00:00:30", "00:00:59")) { |
||||||
|
dateStr = dateStr.substring(0, 17) + "30"; |
||||||
|
System.out.println("插入时间30" + dateStr); |
||||||
|
} |
||||||
|
try { |
||||||
|
if (dataType == 3) { |
||||||
|
data = decimalFormat.format(Math.abs(ExchangeStringUtil.hexToSingle(data)));//十六进制字符串转IEEE754浮点型
|
||||||
|
} else if (dataType == 2 && (deviceCodeParam.getParamType().equals("5") |
||||||
|
|| deviceCodeParam.getParamType().equals("2") |
||||||
|
|| deviceCodeParam.getParamType().equals("12") |
||||||
|
|| deviceCodeParam.getParamType().equals("14") |
||||||
|
)) { |
||||||
|
data = ExchangeStringUtil.hexToDec(data); |
||||||
|
} |
||||||
|
log.info("热泵==>{},寄存器地址==>{},读数==>{}", cloudId, deviceCodeParam.getRegisterAddr(), data); |
||||||
|
return data; |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("保存热泵数据失败!", e); |
||||||
|
} |
||||||
|
} else { |
||||||
|
log.info("热泵===>{}", dataStr); |
||||||
|
return ""; |
||||||
|
} |
||||||
|
return ""; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,253 @@ |
|||||||
|
package com.mh.common.utils; |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,结果与0x0000异或 |
||||||
|
* CRC16_CCITT_FALSE:多项式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,高位在前,结果与0x0000异或 |
||||||
|
* CRC16_XMODEM:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,高位在前,结果与0x0000异或 |
||||||
|
* CRC16_X25:多项式x16+x12+x5+1(0x1021),初始值0xffff,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* CRC16_MODBUS:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0x0000异或 |
||||||
|
* CRC16_IBM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,结果与0x0000异或 |
||||||
|
* CRC16_MAXIM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* CRC16_USB:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* CRC16_DNP:多项式x16+x13+x12+x11+x10+x8+x6+x5+x2+1(0x3D65),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* <p> |
||||||
|
* (1)、预置1个16位的寄存器为十六进制FFFF(即全为1),称此寄存器为CRC寄存器; |
||||||
|
* (2)、把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器,高八位数据不变; |
||||||
|
* (3)、把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位; |
||||||
|
* (4)、如果移出位为0:重复第3步(再次右移一位);如果移出位为1,CRC寄存器与多项式A001(1010 0000 0000 0001)进行异或; |
||||||
|
* (5)、重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理; |
||||||
|
* (6)、重复步骤2到步骤5,进行通讯信息帧下一个字节的处理; |
||||||
|
* (7)、将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换; |
||||||
|
* (8)、最后得到的CRC寄存器内容即为:CRC码。 |
||||||
|
* <p> |
||||||
|
* 以上计算步骤中的多项式0xA001是0x8005按位颠倒后的结果。 |
||||||
|
* 0x8408是0x1021按位颠倒后的结果。 |
||||||
|
* 在线校验工具 |
||||||
|
* http://www.ip33.com/crc.html
|
||||||
|
* https://blog.csdn.net/htmlxx/article/details/17369105
|
||||||
|
* <p> |
||||||
|
* Author:Water |
||||||
|
* Time:2018/11/19 0019 15:03 |
||||||
|
*/ |
||||||
|
public class CRC16 { |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC16_CCITT:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在前,高位在后,结果与0x0000异或 |
||||||
|
* 0x8408是0x1021按位颠倒后的结果。 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_CCITT(byte[] buffer) { |
||||||
|
int wCRCin = 0x0000; |
||||||
|
int wCPoly = 0x8408; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// wCRCin=(wCRCin<<8)|(wCRCin>>8);
|
||||||
|
// wCRCin &= 0xffff;
|
||||||
|
return wCRCin ^= 0x0000; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC-CCITT (0xFFFF) |
||||||
|
* CRC16_CCITT_FALSE:多项式x16+x12+x5+1(0x1021),初始值0xFFFF,低位在后,高位在前,结果与0x0000异或 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_CCITT_FALSE(byte[] buffer) { |
||||||
|
int wCRCin = 0xffff; |
||||||
|
int wCPoly = 0x1021; |
||||||
|
for (byte b : buffer) { |
||||||
|
for (int i = 0; i < 8; i++) { |
||||||
|
boolean bit = ((b >> (7 - i) & 1) == 1); |
||||||
|
boolean c15 = ((wCRCin >> 15 & 1) == 1); |
||||||
|
wCRCin <<= 1; |
||||||
|
if (c15 ^ bit) |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} |
||||||
|
} |
||||||
|
wCRCin &= 0xffff; |
||||||
|
return wCRCin ^= 0x0000; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC-CCITT (XModem) |
||||||
|
* CRC16_XMODEM:多项式x16+x12+x5+1(0x1021),初始值0x0000,低位在后,高位在前,结果与0x0000异或 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_XMODEM(byte[] buffer) { |
||||||
|
int wCRCin = 0x0000; // initial value 65535
|
||||||
|
int wCPoly = 0x1021; // 0001 0000 0010 0001 (0, 5, 12)
|
||||||
|
for (byte b : buffer) { |
||||||
|
for (int i = 0; i < 8; i++) { |
||||||
|
boolean bit = ((b >> (7 - i) & 1) == 1); |
||||||
|
boolean c15 = ((wCRCin >> 15 & 1) == 1); |
||||||
|
wCRCin <<= 1; |
||||||
|
if (c15 ^ bit) |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} |
||||||
|
} |
||||||
|
wCRCin &= 0xffff; |
||||||
|
return wCRCin ^= 0x0000; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* CRC16_X25:多项式x16+x12+x5+1(0x1021),初始值0xffff,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* 0x8408是0x1021按位颠倒后的结果。 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_X25(byte[] buffer) { |
||||||
|
int wCRCin = 0xffff; |
||||||
|
int wCPoly = 0x8408; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return wCRCin ^= 0xffff; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC-16 (Modbus) |
||||||
|
* CRC16_MODBUS:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0x0000异或 |
||||||
|
* 0xA001是0x8005按位颠倒后的结果 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_MODBUS(byte[] buffer) { |
||||||
|
int wCRCin = 0xffff; |
||||||
|
int POLYNOMIAL = 0xa001; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= POLYNOMIAL; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return wCRCin ^= 0x0000; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC-16 |
||||||
|
* CRC16_IBM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,结果与0x0000异或 |
||||||
|
* 0xA001是0x8005按位颠倒后的结果 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_IBM(byte[] buffer) { |
||||||
|
int wCRCin = 0x0000; |
||||||
|
int wCPoly = 0xa001; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return wCRCin ^= 0x0000; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC16_MAXIM:多项式x16+x15+x2+1(0x8005),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* 0xA001是0x8005按位颠倒后的结果 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_MAXIM(byte[] buffer) { |
||||||
|
int wCRCin = 0x0000; |
||||||
|
int wCPoly = 0xa001; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return wCRCin ^= 0xffff; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC16_USB:多项式x16+x15+x2+1(0x8005),初始值0xFFFF,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* 0xA001是0x8005按位颠倒后的结果 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_USB(byte[] buffer) { |
||||||
|
int wCRCin = 0xFFFF; |
||||||
|
int wCPoly = 0xa001; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return wCRCin ^= 0xffff; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* CRC16_DNP:多项式x16+x13+x12+x11+x10+x8+x6+x5+x2+1(0x3D65),初始值0x0000,低位在前,高位在后,结果与0xFFFF异或 |
||||||
|
* 0xA6BC是0x3D65按位颠倒后的结果 |
||||||
|
* |
||||||
|
* @param buffer |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
public static int CRC16_DNP(byte[] buffer) { |
||||||
|
int wCRCin = 0x0000; |
||||||
|
int wCPoly = 0xA6BC; |
||||||
|
for (byte b : buffer) { |
||||||
|
wCRCin ^= ((int) b & 0x00ff); |
||||||
|
for (int j = 0; j < 8; j++) { |
||||||
|
if ((wCRCin & 0x0001) != 0) { |
||||||
|
wCRCin >>= 1; |
||||||
|
wCRCin ^= wCPoly; |
||||||
|
} else { |
||||||
|
wCRCin >>= 1; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return wCRCin ^= 0xffff; |
||||||
|
} |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,53 @@ |
|||||||
|
package com.mh.common.utils; |
||||||
|
|
||||||
|
import com.mh.common.core.domain.entity.CollectionParamsManage; |
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.netty.channel.ChannelHandlerContext; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author ljf |
||||||
|
* @title : |
||||||
|
* @description : 发送指令工具类 |
||||||
|
* @updateTime 2021-01-26 |
||||||
|
* @throws : |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class SendOrderUtils { |
||||||
|
|
||||||
|
// 发送所有类型采集报文
|
||||||
|
public static void sendAllOrder(CollectionParamsManage paramsManage, ChannelHandlerContext ctx, int num, int size) { |
||||||
|
// 开始创建指令
|
||||||
|
String mtCode = paramsManage.getMtCode(); // 采集编号
|
||||||
|
String funCode = paramsManage.getFuncCode(); // 功能码
|
||||||
|
String registerAddr = paramsManage.getRegisterAddr(); // 寄存器地址
|
||||||
|
String registerNum = String.valueOf(paramsManage.getRegisterSize()); // 寄存器数量
|
||||||
|
// 拼接指令
|
||||||
|
String sendOrderStr = ExchangeStringUtil.addZeroForNum(ExchangeStringUtil.decToHex(mtCode), 2) |
||||||
|
+ ExchangeStringUtil.addZeroForNum(funCode, 2) |
||||||
|
+ ExchangeStringUtil.addZeroForNum(registerAddr, 4) |
||||||
|
+ ExchangeStringUtil.addZeroForNum(registerNum, 4); |
||||||
|
byte[] strOrder = ExchangeStringUtil.hexStrToBinaryStr(sendOrderStr); |
||||||
|
int checkNum = CRC16.CRC16_MODBUS(strOrder); |
||||||
|
String checkWord = ExchangeStringUtil.decToHex(String.valueOf(checkNum)); |
||||||
|
checkWord = checkWord.substring(2, 4) + checkWord.substring(0, 2); |
||||||
|
sendOrderStr = sendOrderStr + checkWord; |
||||||
|
ByteBuf buffer = getByteBuf(ctx, sendOrderStr); |
||||||
|
// 发送数据
|
||||||
|
ctx.channel().writeAndFlush(buffer); |
||||||
|
log.info("sends :" + sendOrderStr + ",num:" + num + ",records:" + size); |
||||||
|
try { |
||||||
|
Thread.sleep(1000); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
log.error("线程休眠异常", e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static ByteBuf getByteBuf(ChannelHandlerContext ctx, String sendStr) { |
||||||
|
// 申请一个数据结构存储信息
|
||||||
|
ByteBuf buffer = ctx.alloc().buffer(); |
||||||
|
// 将信息放入数据结构中
|
||||||
|
buffer.writeBytes(ExchangeStringUtil.hexStrToBinaryStr(sendStr));//对接需要16进制
|
||||||
|
return buffer; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,57 @@ |
|||||||
|
package com.mh.framework.netty; |
||||||
|
|
||||||
|
import io.netty.bootstrap.ServerBootstrap; |
||||||
|
import io.netty.channel.ChannelFuture; |
||||||
|
import io.netty.channel.ChannelOption; |
||||||
|
import io.netty.channel.nio.NioEventLoopGroup; |
||||||
|
import io.netty.channel.socket.nio.NioServerSocketChannel; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class EchoServer { |
||||||
|
|
||||||
|
private final int port; |
||||||
|
|
||||||
|
public EchoServer(int port) { |
||||||
|
this.port = port; |
||||||
|
} |
||||||
|
|
||||||
|
public void start() { |
||||||
|
// 创建EventLoopGroup
|
||||||
|
NioEventLoopGroup bossGroup = new NioEventLoopGroup(); |
||||||
|
NioEventLoopGroup workerGroup = new NioEventLoopGroup(); |
||||||
|
|
||||||
|
ServerBootstrap serverBootstrap = new ServerBootstrap(); |
||||||
|
serverBootstrap.group(bossGroup, workerGroup) |
||||||
|
.channel(NioServerSocketChannel.class) |
||||||
|
.localAddress(port) |
||||||
|
.option(ChannelOption.SO_BACKLOG, 1204) |
||||||
|
.childHandler(new ServerChannelInitializer()); |
||||||
|
|
||||||
|
// 异步绑定端口
|
||||||
|
ChannelFuture channelFuture = serverBootstrap.bind(); |
||||||
|
|
||||||
|
// 添加监听器处理绑定结果
|
||||||
|
channelFuture.addListener(future -> { |
||||||
|
if (future.isSuccess()) { |
||||||
|
log.info("服务器启动成功,开始监听端口: {}", port); |
||||||
|
} else { |
||||||
|
log.error("服务器启动失败,端口: {}", port, future.cause()); |
||||||
|
bossGroup.shutdownGracefully(); // 绑定失败立即关闭资源
|
||||||
|
workerGroup.shutdownGracefully(); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
// ❌ 移除 sync() 阻塞调用
|
||||||
|
// channelFuture.channel().closeFuture().sync(); --> 删除这行
|
||||||
|
|
||||||
|
// 可选:添加 JVM 关闭钩子优雅关闭资源
|
||||||
|
Runtime.getRuntime().addShutdownHook(new Thread(() -> { |
||||||
|
log.info("JVM 正在关闭,准备释放 Netty 资源..."); |
||||||
|
bossGroup.shutdownGracefully(); |
||||||
|
workerGroup.shutdownGracefully(); |
||||||
|
log.info("Netty 资源已释放"); |
||||||
|
})); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,264 @@ |
|||||||
|
package com.mh.framework.netty; |
||||||
|
|
||||||
|
import com.alibaba.fastjson2.JSONArray; |
||||||
|
import com.alibaba.fastjson2.JSONObject; |
||||||
|
import com.mh.common.constant.Constants; |
||||||
|
import com.mh.common.core.domain.entity.CollectionParamsManage; |
||||||
|
import com.mh.common.core.domain.entity.SysDictData; |
||||||
|
import com.mh.common.core.redis.RedisCache; |
||||||
|
import com.mh.common.model.request.AdvantechDatas; |
||||||
|
import com.mh.common.model.request.AdvantechReceiver; |
||||||
|
import com.mh.common.utils.*; |
||||||
|
import com.mh.common.utils.spring.SpringUtils; |
||||||
|
import com.mh.framework.rabbitmq.producer.SendMsgByTopic; |
||||||
|
import com.mh.system.service.device.ICollectionParamsManageService; |
||||||
|
import com.mh.system.service.device.IGatewayManageService; |
||||||
|
import io.netty.buffer.ByteBuf; |
||||||
|
import io.netty.channel.ChannelHandlerContext; |
||||||
|
import io.netty.channel.ChannelInboundHandlerAdapter; |
||||||
|
import io.netty.handler.timeout.IdleState; |
||||||
|
import io.netty.handler.timeout.IdleStateEvent; |
||||||
|
import io.netty.util.ReferenceCountUtil; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Date; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
public class EchoServerHandler extends ChannelInboundHandlerAdapter { |
||||||
|
|
||||||
|
// 调用service层的接口信息
|
||||||
|
IGatewayManageService gatewayManageService = SpringUtils.getBean(IGatewayManageService.class); |
||||||
|
ICollectionParamsManageService collectionParamsManageService = SpringUtils.getBean(ICollectionParamsManageService.class); |
||||||
|
SendMsgByTopic sendMsgByTopic = SpringUtils.getBean(SendMsgByTopic.class); |
||||||
|
|
||||||
|
/** |
||||||
|
* 空闲次数 |
||||||
|
*/ |
||||||
|
private int idleCount = 1; |
||||||
|
private int count = 0; |
||||||
|
private List<String> orderList; |
||||||
|
private int num = 0; |
||||||
|
private int size = 0; |
||||||
|
private String IP; |
||||||
|
private String port; |
||||||
|
private String receiveStr = ""; |
||||||
|
private List<CollectionParamsManage> deviceCodeParamList; |
||||||
|
|
||||||
|
/** |
||||||
|
* 客户端连接会触发 |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void channelActive(ChannelHandlerContext ctx) throws Exception { |
||||||
|
log.info("Channel active......"); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 超时处理 |
||||||
|
* 如果120秒没有接受客户端的心跳,就触发; |
||||||
|
* 如果超过3次,则直接关闭; |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void userEventTriggered(ChannelHandlerContext ctx, Object obj) throws Exception { |
||||||
|
if (obj instanceof IdleStateEvent) { |
||||||
|
IdleStateEvent event = (IdleStateEvent) obj; |
||||||
|
if (IdleState.READER_IDLE.equals(event.state())) { //如果读通道处于空闲状态,说明没有接收到心跳命令
|
||||||
|
log.info("第{}已经40秒没有接收到客户端的信息了", idleCount); |
||||||
|
receiveStr = ""; |
||||||
|
num = num + 1; |
||||||
|
if (num > size - 1) { |
||||||
|
num = 0; |
||||||
|
// // 关闭连接
|
||||||
|
// ctx.close();
|
||||||
|
// 继续发送下一个采集指令
|
||||||
|
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num),ctx,num,size); |
||||||
|
} else { |
||||||
|
// 继续发送下一个采集指令
|
||||||
|
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
super.userEventTriggered(ctx, obj); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 对于每一个传入的消息都要被调用
|
||||||
|
@Override |
||||||
|
public void channelRead(ChannelHandlerContext ctx, Object msg) { |
||||||
|
try { |
||||||
|
//接收到服务端发来的数据进行业务处理
|
||||||
|
ByteBuf buf = (ByteBuf) msg; |
||||||
|
byte[] bytes = new byte[buf.readableBytes()]; |
||||||
|
buf.readBytes(bytes);//复制内容到字节数组bytes
|
||||||
|
buf.clear(); |
||||||
|
// 截取IP地址
|
||||||
|
IP = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", "/", ":"); |
||||||
|
// 截取端口号
|
||||||
|
port = ExchangeStringUtil.getMidString(ctx.channel().remoteAddress() + "", ":", ""); |
||||||
|
if (bytes.length <= 1024) { |
||||||
|
//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
||||||
|
receiveStr = receiveStr + ExchangeStringUtil.bytesToHexString(bytes);//将接收到的数据转为字符串,此字符串就是客户端发送的字符串
|
||||||
|
receiveStr = receiveStr.replace("null", ""); //去null
|
||||||
|
receiveStr = receiveStr.replace(" ", ""); //去空格
|
||||||
|
//log.info("channelRead接收到的数据:" + receiveStr + ",length:" + receiveStr.length());
|
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
log.error("channelRead异常", e); |
||||||
|
} finally { |
||||||
|
ReferenceCountUtil.release(msg); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 当前批量读取中的最后一条消息
|
||||||
|
@Override |
||||||
|
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { |
||||||
|
//心跳包报文: 24 00 60 95
|
||||||
|
receiveStr = receiveStr.toUpperCase();//返回值全部变成大写
|
||||||
|
log.info("channelReadComplete接收到的数据{}, 长度: ===> {}", receiveStr, receiveStr.length()); |
||||||
|
//心跳包处理
|
||||||
|
if ((receiveStr.length() == 8) && receiveStr.startsWith("24")) { |
||||||
|
// if ((receiveStr.length() == 8) && receiveStr.startsWith("C0A801FE")) {
|
||||||
|
log.info("接收到心跳包 ===> {}", receiveStr); |
||||||
|
idleCount = 1; |
||||||
|
port = receiveStr.substring(4, 8);//心跳包包含网关端口(自己定义返回心跳包)
|
||||||
|
// 更新对应的网关在线情况
|
||||||
|
gatewayManageService.updateGatewayStatus(receiveStr); |
||||||
|
//根据端口或者IP或者心跳包查询网关对应的项目名称
|
||||||
|
// 生成采集指令
|
||||||
|
if (!SpringUtils.getBean(RedisCache.class).hasKey(receiveStr)) { |
||||||
|
collectionParamsManageService.createDtuCollectionParams(); |
||||||
|
} |
||||||
|
JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(receiveStr); |
||||||
|
if (StringUtils.isNotNull(arrayCache)) { |
||||||
|
deviceCodeParamList = arrayCache.toList(CollectionParamsManage.class); |
||||||
|
} |
||||||
|
size = deviceCodeParamList.size(); |
||||||
|
log.info("deviceCodeParam size ===> {}", size); |
||||||
|
// 清空receiveStr
|
||||||
|
receiveStr = ""; |
||||||
|
num = 0; |
||||||
|
// 发送采集报文
|
||||||
|
if (size > 0) { |
||||||
|
if (idleCount < 2) { |
||||||
|
Thread.sleep(200); |
||||||
|
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size); |
||||||
|
idleCount++; |
||||||
|
} else { |
||||||
|
ctx.channel().close(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
log.info("gateway not find deviceCodeParam!"); |
||||||
|
} |
||||||
|
} else if (receiveStr.length() == 34 || receiveStr.length() == 36 || receiveStr.length() == 40 || receiveStr.length() == 44 || receiveStr.length() == 50) { |
||||||
|
//电表返回数据解析
|
||||||
|
idleCount = 1; |
||||||
|
log.info("电表接收===> {},长度:{}", receiveStr, receiveStr.length()); |
||||||
|
//解析采集的报文,并保存到数据库
|
||||||
|
nextSendOrder(ctx); |
||||||
|
} else if (receiveStr.length() == 18) { |
||||||
|
//冷量计返回数据解析
|
||||||
|
idleCount = 1; |
||||||
|
log.info("水电表、热泵设置接收==>{},长度:{}", receiveStr, receiveStr.length()); |
||||||
|
nextSendOrder(ctx); |
||||||
|
} else if (receiveStr.length() == 12 || receiveStr.length() == 14) { |
||||||
|
//冷水机返回数据解析
|
||||||
|
idleCount = 1; |
||||||
|
log.info("热泵读取接收===>{},长度:{}", receiveStr, receiveStr.length()); |
||||||
|
nextSendOrder(ctx); |
||||||
|
} else if (receiveStr.length() > 50 && receiveStr.length() < 100) { |
||||||
|
idleCount = 1; |
||||||
|
// 清空receiveStr
|
||||||
|
nextSendOrder(ctx); |
||||||
|
} |
||||||
|
ctx.flush(); |
||||||
|
} |
||||||
|
|
||||||
|
private void nextSendOrder(ChannelHandlerContext ctx) throws InterruptedException { |
||||||
|
// 解析采集的报文,并保存到数据库
|
||||||
|
analysisReceiveData(receiveStr, deviceCodeParamList.get(num)); |
||||||
|
// 清空receiveStr
|
||||||
|
receiveStr = ""; |
||||||
|
// 判断发送的下标,如果不等于指令数组大小
|
||||||
|
num = num + 1; |
||||||
|
if (num > size - 1) { |
||||||
|
num = 0; |
||||||
|
Thread.sleep(1000); |
||||||
|
// 继续发送下一个采集指令
|
||||||
|
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size); |
||||||
|
log.info("------一轮采集完成,继续下一轮--------"); |
||||||
|
} else { |
||||||
|
// 添加一个状态值,判断是否继续发送指令 update by ljf on 2020-08-07
|
||||||
|
if (Constants.WEB_FLAG) { |
||||||
|
num = 0; |
||||||
|
// 关闭连接
|
||||||
|
receiveStr = null; |
||||||
|
ctx.close(); |
||||||
|
} else { |
||||||
|
Thread.sleep(1000); |
||||||
|
// 继续发送下一个采集指令
|
||||||
|
SendOrderUtils.sendAllOrder(deviceCodeParamList.get(num), ctx, num, size); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void analysisReceiveData(final String receiveStr, final CollectionParamsManage deviceCodeParamEntity) { |
||||||
|
AnalysisReceiveOrder485 analysisReceiveOrder485 = new AnalysisReceiveOrder485(); |
||||||
|
String analysisData = ""; |
||||||
|
switch (deviceCodeParamEntity.getParamType()) { |
||||||
|
case "16" -> |
||||||
|
// 电表
|
||||||
|
analysisData = analysisReceiveOrder485.analysisMeterOrder485(receiveStr, deviceCodeParamEntity); |
||||||
|
case "18" -> |
||||||
|
// 水表
|
||||||
|
analysisData = analysisReceiveOrder485.analysisWaterOrder485(receiveStr, deviceCodeParamEntity); |
||||||
|
case "5" -> |
||||||
|
// 热泵故障报警
|
||||||
|
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity); |
||||||
|
case "2" -> |
||||||
|
// 热泵启停控制
|
||||||
|
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity); |
||||||
|
case "12" -> |
||||||
|
// 热泵实际温度
|
||||||
|
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity); |
||||||
|
case "14" -> |
||||||
|
// 热泵读取温度设置
|
||||||
|
analysisData = analysisReceiveOrder485.analysisHeatPumpOrder485(receiveStr, deviceCodeParamEntity); |
||||||
|
default -> { |
||||||
|
log.info("设备类型错误"); |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
if (analysisData.isEmpty()) { |
||||||
|
log.info("解析数据为空"); |
||||||
|
return; |
||||||
|
} |
||||||
|
// 格式化数据,配置成研华网关 AdvantechReceiver
|
||||||
|
AdvantechReceiver advantechReceiver = new AdvantechReceiver(); |
||||||
|
advantechReceiver.setTs(DateUtils.dateToString(new Date(), Constants.DATE_FORMAT)); |
||||||
|
List<AdvantechDatas> advantechDatas = new ArrayList<>(); |
||||||
|
AdvantechDatas datas = new AdvantechDatas(); |
||||||
|
datas.setValue(new BigDecimal(analysisData)); |
||||||
|
datas.setTag(deviceCodeParamEntity.getOtherName()); |
||||||
|
advantechDatas.add(datas); |
||||||
|
advantechReceiver.setD(advantechDatas); |
||||||
|
sendMsgByTopic.sendToDeviceMQ(JSONObject.toJSONString(advantechReceiver)); |
||||||
|
} |
||||||
|
|
||||||
|
// 异常捕捉
|
||||||
|
@Override |
||||||
|
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { |
||||||
|
cause.getCause().printStackTrace(); |
||||||
|
log.info("异常捕捉,执行ctx.close" + cause.getCause()); |
||||||
|
ctx.close(); // 关闭该Channel
|
||||||
|
} |
||||||
|
|
||||||
|
// 客户端断开
|
||||||
|
@Override |
||||||
|
public void channelInactive(ChannelHandlerContext ctx) throws Exception { |
||||||
|
ctx.close();// 关闭流
|
||||||
|
log.info("客户端断开,执行ctx.close()......"); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.mh.framework.netty; |
||||||
|
|
||||||
|
import io.netty.channel.ChannelInitializer; |
||||||
|
import io.netty.channel.ChannelPipeline; |
||||||
|
import io.netty.channel.socket.SocketChannel; |
||||||
|
import io.netty.handler.timeout.IdleStateHandler; |
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
public class ServerChannelInitializer extends ChannelInitializer<SocketChannel>{ |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void initChannel(SocketChannel socketChannel) throws Exception { |
||||||
|
ChannelPipeline pipeline = socketChannel.pipeline(); |
||||||
|
|
||||||
|
/* LineBasedFrameDecoder的工作原理是:依次遍历ByteBuf中的可读字节, |
||||||
|
判断看其是否有”\n” 或 “\r\n”, 如果有就以此位置为结束位置。 |
||||||
|
从可读索引到结束位置的区间的字节就组成了一行。 它是以换行符为结束标志的解码器, |
||||||
|
支持携带结束符和不带结束符两种解码方式,同时支持配置单行的最大长度, |
||||||
|
如果读到了最大长度之后仍然没有发现换行符,则抛出异常,同时忽略掉之前读到的异常码流。*/ |
||||||
|
// pipeline.addLast(new LineBasedFrameDecoder(10010));
|
||||||
|
//字符串解码和编码
|
||||||
|
//LineBasedFrameDecoder + StringDecoder 就是一个按行切换的文本解码器。
|
||||||
|
// pipeline.addLast( new StringDecoder());
|
||||||
|
// pipeline.addLast( new StringEncoder());
|
||||||
|
// 设置读写超时操作
|
||||||
|
// 入参说明: 读超时时间、写超时时间、所有类型的超时时间、时间格式
|
||||||
|
pipeline.addLast(new IdleStateHandler(40, 40, 40, TimeUnit.SECONDS)); |
||||||
|
//服务器的逻辑
|
||||||
|
pipeline.addLast("handler", new EchoServerHandler()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue