1.Jar package download
jt705-sdk-1.0.0.jar Download
If you need Jar package development source code, please contact the business application
2.Integrated Development Instruction
2.1.Integrated development language and framework description
jt705-sdk-1.0.0.jar is based on the Java language,SpringBoot2.x frame,use netty,fastjson,lombok,commons-lang3
BaseEnum:base enumeration
Constant:custom constant
AlarmTypeEnum:Alarm enumeration
EventTypeEnum:event enumeration
LocationData:Location entity class
LockEvent:lock event entity class
Result:result entity class
SensorData:Slave data entity class
CommonUtil:public method class
NumberUtil:digital manipulation tools
ParserUtil:Parser method tool class
DataParser:Parser main method
2.2.Integration Instructions
Introduce jt705-sdk-1.0.0.jar into your gateway program as follows:
Introduce the jar package in pom.xml
<dependency>
<groupId>com.jointech.sdk</groupId>
<artifactId>jt705-sdk</artifactId>
<version>1.0.0</version>
</dependency>
Call jt705-sdk-1.0.0.jar, the receiveData() method in the DataParser class
receiveData() method is overloaded
package com.jointech.sdk.jt705;
import com.alibaba.fastjson.JSONArray;
import com.jointech.sdk.jt705.constants.Constant;
import com.jointech.sdk.jt705.utils.CommonUtil;
import com.jointech.sdk.jt705.utils.ParserUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
/**
* <p>Description: The body of the parsing method</p>
*
* @author lenny
* @version 1.0.1
*/
public class DataParser {
/**
* Parse Hex string raw data
* @param strData hexadecimal string
* @return
*/
public static Object receiveData(String strData) {
int length=strData.length()%2>0?strData.length()/2+1:strData.length()/2;
ByteBuf msgBodyBuf = Unpooled.buffer(length);
msgBodyBuf.writeBytes(CommonUtil.hexStr2Byte(strData));
return receiveData(msgBodyBuf);
}
/**
* Parse byte[] raw data
* @param bytes
* @return
*/
private static Object receiveData(byte[] bytes)
{
ByteBuf msgBodyBuf =Unpooled.buffer(bytes.length);
msgBodyBuf.writeBytes(bytes);
return receiveData(msgBodyBuf);
}
/**
* Parse ByteBuf raw data
* @param in
* @return
*/
private static Object receiveData(ByteBuf in)
{
Object decoded = null;
in.markReaderIndex();
int header = in.readByte();
if (header == Constant.TEXT_MSG_HEADER) {
in.resetReaderIndex();
decoded = ParserUtil.decodeTextMessage(in);
} else if (header == Constant.BINARY_MSG_HEADER) {
in.resetReaderIndex();
decoded = ParserUtil.decodeBinaryMessage(in);
} else {
return null;
}
return JSONArray.toJSON(decoded).toString();
}
}
2.3.Core code
ParserUtil:Parsing method tool class ParserUtil
package com.jointech.sdk.jt705.utils;
import com.jointech.sdk.jt705.constants.Constant;
import com.jointech.sdk.jt705.model.AlarmTypeEnum;
import com.jointech.sdk.jt705.model.LocationData;
import com.jointech.sdk.jt705.model.LockEvent;
import com.jointech.sdk.jt705.model.Result;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import org.apache.commons.lang3.StringUtils;
import java.time.ZonedDateTime;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Description: Analysis method tool class</p>
* @author HyoJung
*/
public class ParserUtil {
/**
* Parse Positioning data 0x0200
* @param in
* @return
*/
public static Result decodeBinaryMessage(ByteBuf in) {
//unexcape rawdata
ByteBuf msg = (ByteBuf) PacketUtil.decodePacket(in);
//message length
int msgLen = msg.readableBytes();
//packet header
msg.readByte();
//message ID
int msgId = msg.readUnsignedShort();
//message body properties
int msgBodyAttr = msg.readUnsignedShort();
//message body length
int msgBodyLen = msgBodyAttr & 0b00000011_11111111;
//Whether to subcontract
boolean multiPacket = (msgBodyAttr & 0b00100000_00000000) > 0;
//Remove the base length of the message body
int baseLen = Constant.BINARY_MSG_BASE_LENGTH;
//The following packet length is obtained according to the length of the message body and whether it is subcontracted
int ensureLen = multiPacket ? baseLen + msgBodyLen + 4 : baseLen + msgBodyLen;
if (msgLen != ensureLen) {
return null;
}
//array of deviceID
byte[] terminalNumArr = new byte[6];
msg.readBytes(terminalNumArr);
//Device ID (remove leading 0)
String terminalNumber = StringUtils.stripStart(ByteBufUtil.hexDump(terminalNumArr), "0");
//message serial number
int msgFlowId = msg.readUnsignedShort();
//total number of message packets
int packetTotalCount = 0;
//package serial number
int packetOrder = 0;
//subcontract
if (multiPacket) {
packetTotalCount = msg.readShort();
packetOrder = msg.readShort();
}
//message body
byte[] msgBodyArr = new byte[msgBodyLen];
msg.readBytes(msgBodyArr);
if(msgId==0x0200) {
//Parse the message body
LocationData locationData=parseLocationBody(Unpooled.wrappedBuffer(msgBodyArr));
locationData.setIndex(msgFlowId);
locationData.setDataLength(msgBodyLen);
//check code
int checkCode = msg.readUnsignedByte();
//packet end
msg.readByte();
//Get message response content
String replyMsg= PacketUtil.replyBinaryMessage(terminalNumArr,msgFlowId);
//Define the location data entity class
Result model = new Result();
model.setDeviceID(terminalNumber);
model.setMsgType("Location");
model.setDataBody(locationData);
model.setReplyMsg(replyMsg);
return model;
}else {
//Define the location data entity class
Result model = new Result();
model.setDeviceID(terminalNumber);
model.setMsgType("heartbeat");
model.setDataBody(null);
return model;
}
}
/**
* Parse instruction data
* @param in raw data
* @return
*/
public static Result decodeTextMessage(ByteBuf in) {
//The read pointer is set to the message header
in.markReaderIndex();
//Look for the end of the message, if not found, continue to wait for the next packet
int tailIndex = in.bytesBefore(Constant.TEXT_MSG_TAIL);
if (tailIndex < 0) {
in.resetReaderIndex();
return null;
}
//Define the location data entity class
Result model = new Result();
//packet header(
in.readByte();
//Field list
List<String> itemList = new ArrayList<String>();
while (in.readableBytes() > 0) {
//Query the subscript of comma to intercept data
int index = in.bytesBefore(Constant.TEXT_MSG_SPLITER);
int itemLen = index > 0 ? index : in.readableBytes() - 1;
byte[] byteArr = new byte[itemLen];
in.readBytes(byteArr);
in.readByte();
itemList.add(new String(byteArr));
}
String msgType = "";
if (itemList.size() >= 5) {
msgType = itemList.get(3) + itemList.get(4);
}
Object dataBody=null;
if(itemList.size()>0){
dataBody="(";
for(String item :itemList) {
dataBody+=item+",";
}
dataBody=CommonUtil.trimEnd(dataBody.toString(),",");
dataBody += ")";
}
String replyMsg="";
if(msgType.equals("BASE2")&&itemList.get(5).toUpperCase().equals("TIME")) {
replyMsg=PacketUtil.replyBASE2Message(itemList);
}
model.setDeviceID(itemList.get(0));
model.setMsgType(msgType);
model.setDataBody(dataBody);
model.setReplyMsg(replyMsg);
return model;
}
/**
* Parse and locate message body
* @param msgBodyBuf
* @return
*/
private static LocationData parseLocationBody(ByteBuf msgBodyBuf){
//alarm sign
long alarmFlag = msgBodyBuf.readUnsignedInt();
//Device status
long status = msgBodyBuf.readUnsignedInt();
//latitude
double lat = NumberUtil.multiply(msgBodyBuf.readUnsignedInt(), NumberUtil.COORDINATE_PRECISION);
//longitude
double lon = NumberUtil.multiply(msgBodyBuf.readUnsignedInt(), NumberUtil.COORDINATE_PRECISION);
//Altitude, in meters
int altitude = msgBodyBuf.readShort();
//Speed
double speed = NumberUtil.multiply(msgBodyBuf.readUnsignedShort(), NumberUtil.ONE_PRECISION);
//directioin
int direction = msgBodyBuf.readShort();
//GPS time
byte[] timeArr = new byte[6];
msgBodyBuf.readBytes(timeArr);
String bcdTimeStr = ByteBufUtil.hexDump(timeArr);
ZonedDateTime gpsZonedDateTime = CommonUtil.parseBcdTime(bcdTimeStr);
//Determine whether the south latitude and west longitude are based on the value of the status bit
if (NumberUtil.getBitValue(status, 2) == 1) {
lat = -lat;
}
if (NumberUtil.getBitValue(status, 3) == 1) {
lon = -lon;
}
//Positioning status
int locationType=NumberUtil.getBitValue(status, 18);
if(locationType==0)
{
locationType = NumberUtil.getBitValue(status, 1);
}
if(locationType==0)
{
locationType = NumberUtil.getBitValue(status, 6) > 0 ? 2 : 0;
}
//Alarm status
int lockRope=NumberUtil.getBitValue(status, 20);
//Lock status
int lockMotor=NumberUtil.getBitValue(status, 21);
//The lock state (judged by the combination of the lock button + motor;when lock button open (1) or motor unlock(1),lock state is unlocking(1);when lock button close(0) and motor locked(0),the lock state is locked
int lockStatus=0;
if(lockRope==1||lockMotor==1) {
lockStatus=1;
}
int backCover=NumberUtil.getBitValue(status, 7);
//Wake-up source
long awaken = (status>>24)&0b00001111;
int alarm=parseAlarm(alarmFlag);
LocationData locationData=new LocationData();
locationData.setGpsTime(gpsZonedDateTime.toString());
locationData.setLatitude(lat);
locationData.setLongitude(lon);
locationData.setLocationType(locationType);
locationData.setSpeed((int)speed);
locationData.setDirection(direction);
locationData.setAltitude(altitude);
locationData.setLockStatus(lockStatus);
locationData.setLockRope(lockRope);
locationData.setAwaken((int)awaken);
locationData.setBackCover(backCover);
locationData.setAlarm(alarm);
//Handling additional information
if (msgBodyBuf.readableBytes() > 0) {
parseExtraInfo(msgBodyBuf, locationData);
}
return locationData;
}
/**
* Parse additional information
*
* @param msgBody
* @param location
*/
private static void parseExtraInfo(ByteBuf msgBody, LocationData location) {
ByteBuf extraInfoBuf = null;
while (msgBody.readableBytes() > 1) {
int extraInfoId = msgBody.readUnsignedByte();
int extraInfoLen = msgBody.readUnsignedByte();
if (msgBody.readableBytes() < extraInfoLen) {
break;
}
extraInfoBuf = msgBody.readSlice(extraInfoLen);
switch (extraInfoId) {
//lock event
case 0x0B:
LockEvent event=new LockEvent();
//lock event
int type=extraInfoBuf.readUnsignedByte();
event.setType(type);
if(type==0x01||type==0x02||type==0x03||type==0x05||type==0x1E||type==0x1F){
//Unlock by password
byte[] passwordArr = new byte[6];
extraInfoBuf.readBytes(passwordArr);
String password=new String(passwordArr);
event.setPassword(password);
int unlockStatus=extraInfoBuf.readUnsignedByte();
if(unlockStatus==0xff){
event.setUnLockStatus(0);
}else{
if(unlockStatus>0&&unlockStatus<100){
event.setFenceId(unlockStatus);
}
event.setUnLockStatus(1);
}
}else if(type==0x06||type==0x07||type==0x08||type==0x10||type==0x11||type==0x18||type==0x19||type==0x20||type==0x28||type==0x29){
//Unlock by password
byte[] passwordArr = new byte[6];
extraInfoBuf.readBytes(passwordArr);
String password=new String(passwordArr);
event.setPassword(password);
event.setUnLockStatus(0);
}else if(type==0x22){
//RFID card No.
long cardId = extraInfoBuf.readUnsignedInt();
if(cardId!=0) {
event.setCardNo(String.format("%010d", cardId));
}
if(extraInfoBuf.readableBytes()>0) {
int unlockStatus = extraInfoBuf.readUnsignedByte();
if (unlockStatus == 0xff) {
event.setUnLockStatus(0);
} else {
if (unlockStatus > 0 && unlockStatus < 100) {
event.setFenceId(unlockStatus);
}
event.setUnLockStatus(1);
}
}else{
event.setUnLockStatus(1);
}
}else if(type==0x23||type==0x2A||type==0x2B){
//RFID card No.
long cardId = extraInfoBuf.readUnsignedInt();
if(cardId!=0) {
event.setCardNo(String.format("%010d", cardId));
}
}
location.setLockEvent(event);
break;
//Gyroscope three-axis data
case 0x0C:
int x=extraInfoBuf.readUnsignedShort();
int y=extraInfoBuf.readUnsignedShort();
int z=extraInfoBuf.readUnsignedShort();
x=x > 32768 ? (x - 65536) : x;
y=y > 32768 ? (y - 65536) : y;
z=z > 32768 ? (z - 65536) : z;
location.setPosture("x:"+x+";y:"+y+";z:"+z);
break;
//Wireless communication network signal strength
case 0x30:
int fCellSignal=extraInfoBuf.readByte();
location.setGSMSignal(fCellSignal);
break;
//number of satellites
case 0x31:
int fGPSSignal=extraInfoBuf.readByte();
location.setGpsSignal(fGPSSignal);
break;
//battery percentage
case 0xD4:
int fBattery=extraInfoBuf.readUnsignedByte();
location.setBattery(fBattery);
break;
//battery voltage
case 0xD5:
int fVoltage=extraInfoBuf.readUnsignedShort();
location.setVoltage(fVoltage*0.01);
break;
case 0xF9:
//Protocol version
int version=extraInfoBuf.readUnsignedShort();
location.setProtocolVersion(version);
break;
case 0xFD:
//LBS information
int mcc=extraInfoBuf.readUnsignedShort();
location.setMCC(mcc);
int mnc=extraInfoBuf.readUnsignedByte();
location.setMNC(mnc);
long cellId=extraInfoBuf.readUnsignedInt();
location.setCELLID((int)cellId);
int lac=extraInfoBuf.readUnsignedShort();
location.setLAC(lac);
break;
case 0xFC:
int fenceId = extraInfoBuf.readUnsignedByte();
location.setFenceId(fenceId);
break;
case 0xFE:
long mileage = extraInfoBuf.readUnsignedInt();
location.setMileage(mileage);
break;
default:
ByteBufUtil.hexDump(extraInfoBuf);
break;
}
}
}
/**
* Alarm Parsing
* @param alarmFlag
* @return
*/
private static int parseAlarm(long alarmFlag) {
int alarm=-1;
//Single trigger alarm
if(NumberUtil.getBitValue(alarmFlag, 1) == 1)
{
alarm = Integer.parseInt(AlarmTypeEnum.ALARM_1.getValue());
}else if(NumberUtil.getBitValue(alarmFlag, 7) == 1)
{
alarm = Integer.parseInt(AlarmTypeEnum.ALARM_2.getValue());
}else if(NumberUtil.getBitValue(alarmFlag, 16) == 1)
{
alarm = Integer.parseInt(AlarmTypeEnum.ALARM_3.getValue());
}else if(NumberUtil.getBitValue(alarmFlag, 17) == 1)
{
alarm = Integer.parseInt(AlarmTypeEnum.ALARM_4.getValue());
}else if(NumberUtil.getBitValue(alarmFlag, 18) == 1)
{
alarm = Integer.parseInt(AlarmTypeEnum.ALARM_5.getValue());
}
return alarm;
}
}
PacketUtil:Used to process preprocessed data and restore method encapsulation class
package com.jointech.sdk.jt705.utils;
import com.jointech.sdk.jt705.constants.Constant;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufUtil;
import io.netty.util.ReferenceCountUtil;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Random;
/**
* Parse package preprocessing (do unescaping)
* @author HyoJung
*/
public class PacketUtil {
/**
* Parse message packets
*
* @param in
* @return
*/
public static Object decodePacket(ByteBuf in) {
//The readable length cannot be less than the base length
if (in.readableBytes() < Constant.BINARY_MSG_BASE_LENGTH) {
return null;
}
//Prevent illegal code stream attacks, the data is too large to be abnormal data
if (in.readableBytes() > Constant.BINARY_MSG_MAX_LENGTH) {
in.skipBytes(in.readableBytes());
return null;
}
//Look for the end of the message, if not found, continue to wait for the next packet
in.readByte();
int tailIndex = in.bytesBefore(Constant.BINARY_MSG_HEADER);
if (tailIndex < 0) {
in.resetReaderIndex();
return null;
}
int bodyLen = tailIndex;
//Create a ByteBuf to store the reversed data
ByteBuf frame = ByteBufAllocator.DEFAULT.heapBuffer(bodyLen + 2);
frame.writeByte(Constant.BINARY_MSG_HEADER);
//The data between the header and the end of the message is escaped
unescape(in, frame, bodyLen);
in.readByte();
frame.writeByte(Constant.BINARY_MSG_HEADER);
//The length after the reverse escape cannot be less than the base length
if (frame.readableBytes() < Constant.BINARY_MSG_BASE_LENGTH) {
ReferenceCountUtil.release(frame);
return null;
}
return frame;
}
/**
* In the message header, message body and check code, 0x7D 0x02 is reversed to 0x7E, and 0x7D 0x01 is reversed to 0x7D
*
* @param in
* @param frame
* @param bodyLen
*/
public static void unescape(ByteBuf in, ByteBuf frame, int bodyLen) {
int i = 0;
while (i < bodyLen) {
int b = in.readUnsignedByte();
if (b == 0x7D) {
int nextByte = in.readUnsignedByte();
if (nextByte == 0x01) {
frame.writeByte(0x7D);
} else if (nextByte == 0x02) {
frame.writeByte(0x7E);
} else {
//abnormal data
frame.writeByte(b);
frame.writeByte(nextByte);
}
i += 2;
} else {
frame.writeByte(b);
i++;
}
}
}
/**
* In the message header, message body and check code, 0x7E is escaped as 0x7D 0x02, and 0x7D is escaped as 0x7D 0x01
*
* @param out
* @param bodyBuf
*/
public static void escape(ByteBuf out, ByteBuf bodyBuf) {
while (bodyBuf.readableBytes() > 0) {
int b = bodyBuf.readUnsignedByte();
if (b == 0x7E) {
out.writeShort(0x7D02);
} else if (b == 0x7D) {
out.writeShort(0x7D01);
} else {
out.writeByte(b);
}
}
}
/**
* Reply content
* @param terminalNumArr
* @param msgFlowId
* @return
*/
public static String replyBinaryMessage(byte[] terminalNumArr,int msgFlowId) {
//Remove the length of the head and tail
int contentLen = Constant.BINARY_MSG_BASE_LENGTH + 4;
ByteBuf bodyBuf = ByteBufAllocator.DEFAULT.heapBuffer(contentLen-2);
ByteBuf replyBuf = ByteBufAllocator.DEFAULT.heapBuffer(25);
try {
//Message ID
bodyBuf.writeShort(0x8001);
//Data Length
bodyBuf.writeShort(0x0005);
//Device ID
bodyBuf.writeBytes(terminalNumArr);
Random random = new Random();
//Generate random numbers from 1-65534
int index = random.nextInt() * (65534 - 1 + 1) + 1;
//Current message serial number
bodyBuf.writeShort(index);
//Reply message serial number
bodyBuf.writeShort(msgFlowId);
//Reply message ID
bodyBuf.writeShort(0x0200);
//Response result
bodyBuf.writeByte(0x00);
//check code
int checkCode = CommonUtil.xor(bodyBuf);
bodyBuf.writeByte(checkCode);
//packet header
replyBuf.writeByte(Constant.BINARY_MSG_HEADER);
//The read pointer is reset to the starting position
bodyBuf.readerIndex(0);
//escape
PacketUtil.escape(replyBuf, bodyBuf);
//packet end
replyBuf.writeByte(Constant.BINARY_MSG_HEADER);
return ByteBufUtil.hexDump(replyBuf);
} catch (Exception e) {
ReferenceCountUtil.release(replyBuf);
return "";
}
}
/**
* Timing command reply
* @param itemList
*/
public static String replyBASE2Message(List<String> itemList) {
try {
//set date format
ZonedDateTime currentDateTime = ZonedDateTime.now(ZoneOffset.UTC);
String strBase2Reply = String.format("(%s,%s,%s,%s,%s,%s)", itemList.get(0), itemList.get(1)
, itemList.get(2), itemList.get(3), itemList.get(4), DateTimeFormatter.ofPattern("yyyyMMddHHmmss").format(currentDateTime));
return strBase2Reply;
}catch (Exception e) {
return "";
}
}
}
NumberUtil:digital manipulation tools
package com.jointech.sdk.jt705.utils;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
/**
* digital tools
* @author HyoJung
* @date 20210526
*/
public class NumberUtil {
/**
* Coordinate accuracy
*/
public static final BigDecimal COORDINATE_PRECISION = new BigDecimal("0.000001");
/**
* Coordinate factor
*/
public static final BigDecimal COORDINATE_FACTOR = new BigDecimal("1000000");
/**
* One decimal place precision
*/
public static final BigDecimal ONE_PRECISION = new BigDecimal("0.1");
private NumberUtil() {
}
/**
* Format message ID (convert to 0xXXXX)
*
* @param msgId Message ID
* @return return format string
*/
public static String formatMessageId(int msgId) {
return String.format("0x%04x", msgId);
}
/**
* format short numbers
*
* @param num number
* @return format string
*/
public static String formatShortNum(int num) {
return String.format("0x%02x", num);
}
/**
* Convert 4-digit hexadecimal string
*
* @param num digits
* @return format string
*/
public static String hexStr(int num) {
return String.format("%04x", num).toUpperCase();
}
/**
* Parse the value of type short and get the number of digits whose value is 1
*
* @param number
* @return
*/
public static List<Integer> parseShortBits(int number) {
List<Integer> bits = new ArrayList<>();
for (int i = 0; i < 16; i++) {
if (getBitValue(number, i) == 1) {
bits.add(i);
}
}
return bits;
}
/**
* Parse the value of type int and get the number of digits whose value is 1
*
* @param number
* @return
*/
public static List<Integer> parseIntegerBits(long number) {
List<Integer> bits = new ArrayList<>();
for (int i = 0; i < 32; i++) {
if (getBitValue(number, i) == 1) {
bits.add(i);
}
}
return bits;
}
/**
* Get the value of the index-th bit in binary
*
* @param number
* @param index
* @return
*/
public static int getBitValue(long number, int index) {
return (number & (1 << index)) > 0 ? 1 : 0;
}
/**
* bit list to int
*
* @param bits
* @param len
* @return
*/
public static int bitsToInt(List<Integer> bits, int len) {
if (bits == null || bits.isEmpty()) {
return 0;
}
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
char value = bits.contains(i) ? '1' : '0';
chars[len - 1 - i] = value;
}
int result = Integer.parseInt(new String(chars), 2);
return result;
}
/**
* bit list to long
*
* @param bits
* @param len
* @return
*/
public static long bitsToLong(List<Integer> bits, int len) {
if (bits == null || bits.isEmpty()) {
return 0L;
}
char[] chars = new char[len];
for (int i = 0; i < len; i++) {
char value = bits.contains(i) ? '1' : '0';
chars[len - 1 - i] = value;
}
long result = Long.parseLong(new String(chars), 2);
return result;
}
/**
* BigDecimal Multiplication
*
* @param longNum
* @param precision
* @return
*/
public static double multiply(long longNum, BigDecimal precision) {
return new BigDecimal(String.valueOf(longNum)).multiply(precision).doubleValue();
}
/**
* BigDecimal Multiplication
*
* @param longNum
* @param precision
* @return
*/
public static double multiply(int longNum, BigDecimal precision) {
return new BigDecimal(String.valueOf(longNum)).multiply(precision).doubleValue();
}
}
CommonUtil:public method class
package com.jointech.sdk.jt705.utils;
import io.netty.buffer.ByteBuf;
import java.nio.ByteBuffer;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
/**
* <p>Description: Used to store some public methods encountered in parsing</p>
*
* @author lenny
* @version 1.0.1
* @date 20210328
*/
public class CommonUtil {
/**
* remove the last character of a string
* @param inStr Input string
* @param suffix characters to remove
* @return
*/
public static String trimEnd(String inStr, String suffix) {
while(inStr.endsWith(suffix)){
inStr = inStr.substring(0,inStr.length()-suffix.length());
}
return inStr;
}
/**
* Hexadecimal to byte[]
* @param hex
* @return
*/
public static byte[] hexStr2Byte(String hex) {
ByteBuffer bf = ByteBuffer.allocate(hex.length() / 2);
for (int i = 0; i < hex.length(); i++) {
String hexStr = hex.charAt(i) + "";
i++;
hexStr += hex.charAt(i);
byte b = (byte) Integer.parseInt(hexStr, 16);
bf.put(b);
}
return bf.array();
}
/**
* Convert GPS time
*
* @param bcdTimeStr
* @return
*/
public static ZonedDateTime parseBcdTime(String bcdTimeStr) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmss");
LocalDateTime localDateTime = LocalDateTime.parse(bcdTimeStr, formatter);
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneOffset.UTC);
return zonedDateTime;
}
/**
* Each byte is XORed
*
* @param buf
* @return
*/
public static int xor(ByteBuf buf) {
int checksum = 0;
while (buf.readableBytes() > 0) {
checksum ^= buf.readUnsignedByte();
}
return checksum;
}
}
BaseEnum:base enumeration
package com.jointech.sdk.jt705.base;
import java.io.Serializable;
/**
* base enumeration
* @author HyoJung
*/
public interface BaseEnum <T> extends Serializable {
T getValue();
}
Constant:custom constant
package com.jointech.sdk.jt705.constants;
/**
* constant definition
* @author HyoJung
* @date 20210526
*/
public class Constant {
private Constant(){}
/**
* binary message header
*/
public static final byte BINARY_MSG_HEADER = 0x7E;
/**
* Base length without message body
*/
public static final int BINARY_MSG_BASE_LENGTH = 15;
/**
* message length
*/
public static final int BINARY_MSG_MAX_LENGTH = 102400;
/**
* text message header
*/
public static final byte TEXT_MSG_HEADER = '(';
/**
* text message tail
*/
public static final byte TEXT_MSG_TAIL = ')';
/**
* text message delimiter
*/
public static final byte TEXT_MSG_SPLITER = ',';
}
AlarmTypeEnum:Device alarm type enumeration
package com.jointech.sdk.jt705.model;
import com.jointech.sdk.jt705.base.BaseEnum;
import lombok.Getter;
/**
* alarm type enumeration
* @author HyoJung
*/
public enum AlarmTypeEnum implements BaseEnum<String> {
ALARM_1("Speeding alarm", "1"),
ALARM_2("Low Battery alarm", "2"),
ALARM_3("Main unit Cover opening alarm", "3"),
ALARM_4("Enter fence alarm", "4"),
ALARM_5("Exit fence alarm", "5");
@Getter
private String desc;
private String value;
AlarmTypeEnum(String desc, String value) {
this.desc = desc;
this.value = value;
}
@Override
public String getValue() {
return value;
}
public static AlarmTypeEnum fromValue(Integer value) {
String valueStr = String.valueOf(value);
for (AlarmTypeEnum alarmTypeEnum : values()) {
if (alarmTypeEnum.getValue().equals(valueStr)) {
return alarmTypeEnum;
}
}
return null;
}
}
LocationData:Positiondata Entity Classes
package com.jointech.sdk.jt705.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.io.Serializable;
/**
* <p>Description: Positiondata Entity Classes</p>
*
* @author lenny
* @version 1.0.1
*/
@Data
public class LocationData implements Serializable {
/**
* Message body
*/
@JSONField(name = "DataLength")
public int DataLength;
/**
* Posintioning time
*/
@JSONField(name = "GpsTime")
public String GpsTime;
/**
* latitude
*/
@JSONField(name = "Latitude")
public double Latitude;
/**
* longitude
*/
@JSONField(name = "Longitude")
public double Longitude;
/**
* Positioning type
*/
@JSONField(name = "LocationType")
public int LocationType;
/**
* Speed
*/
@JSONField(name = "Speed")
public int Speed;
/**
* Direction(Header)
*/
@JSONField(name = "Direction")
public int Direction;
/**
* Mileage
*/
@JSONField(name = "Mileage")
public long Mileage;
/**
* Altitude
*/
@JSONField(name = "Altitude")
public int Altitude;
/**
* GPS signal
*/
@JSONField(name = "GpsSignal")
public int GpsSignal;
/**
* GSM signal quatity
*/
@JSONField(name = "GSMSignal")
public int GSMSignal;
/**
* Battery level
*/
@JSONField(name = "Battery")
public int Battery;
/**
* Batttery voltage
*/
@JSONField(name = "Voltage")
public double Voltage;
/**
* Lock status
*/
@JSONField(name = "LockStatus")
public int LockStatus;
/**
* Lock rope status
*/
@JSONField(name = "LockRope")
public int LockRope;
/**
* Back Cover status
*/
@JSONField(name = "BackCover")
public int BackCover;
/**
* Protocol version
*/
@JSONField(name = "ProtocolVersion")
public int ProtocolVersion;
/**
* Fence ID
*/
@JSONField(name = "FenceId")
public int FenceId;
/**
* MCC
*/
@JSONField(name = "MCC")
public int MCC;
/**
* MNC
*/
@JSONField(name = "MNC")
public int MNC;
/**
* LAC
*/
@JSONField(name = "LAC")
public int LAC;
/**
* CELLID
*/
@JSONField(name = "CELLID")
public long CELLID;
/**
* Awaken
*/
@JSONField(name = "Awaken")
public int Awaken;
/**
* Alarm
*/
@JSONField(name = "Alarm")
public int Alarm;
/**
* Lock&unlock event
*/
@JSONField(name = "LockEvent")
public LockEvent LockEvent;
/**
* attitude
*/
@JSONField(name = "Posture")
public String Posture;
/**
* Data Serial number
*/
@JSONField(name = "Index")
public int Index;
}
LockEvent:lock event entity class
package com.jointech.sdk.jt705.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
/**
* lock event
* @author HyoJung
*/
@Data
public class LockEvent {
/**
* Event type
*/
@JSONField(name = "Type")
public int Type;
/**
* Swipe RFID card number
*/
@JSONField(name = "CardNo")
public String CardNo;
/**
* Unlock password
*/
@JSONField(name = "Password")
public String Password;
/**
* Unlocking status(1:success;0:failed)
*/
@JSONField(name = "UnLockStatus")
public int UnLockStatus=0;
/**
* Fence ID related to unlocking
*/
@JSONField(name = "FenceId")
public int FenceId=-1;
}
Result:result entity class
package com.jointech.sdk.jt705.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
import java.io.Serializable;
/**
* result entity class
* @author HyoJung
* @date 20210526
*/
@Data
public class Result implements Serializable {
@JSONField(name = "DeviceID")
private String DeviceID;
@JSONField(name = "MsgType")
private String MsgType;
@JSONField(name = "DataBody")
private Object DataBody;
@JSONField(name = "ReplyMsg")
private String ReplyMsg;
}
2.4.Return messages and instructions
(1)heartbeat data
Rawdata:
7E000200007501804283100001267E
Return message:
{"DeviceID":"750180428310","MsgType":"heartbeat"}
Return message description
{"DeviceID":DeviceID,"MsgType":Messagetype(heartbeat:heartbeat)}
(2)Position data
Rawdata(without lock&unlock event):
7E020000428560090010140E56000000002234004201588F9506CA3D93000B00120000201210073024D40127D502017B30011E310106FE040000001BFD090000000000000000000C0600000000FFDFD47E
Return message:
{
"DeviceID": "856009001014",
"DataBody": {
"GpsTime": "2020-12-10T07:30:24Z",
"MNC": 0,
"FenceId": 0,
"BackCover": 0,
"Index": 3670,
"Latitude": 22.581141,
"Awaken": 2,
"ProtocolVersion": 0,
"Direction": 0,
"Posture": "x:0;y:0;z:-33",
"Battery": 39,
"GpsSignal": 6,
"Voltage": 3.79,
"Speed": 1,
"LockStatus": 1,
"Mileage": 27,
"MCC": 0,
"Longitude": 113.917331,
"LAC": 0,
"Alarm": -1,
"DataLength": 66,
"CELLID": 0,
"LockRope": 1,
"LocationType": 1,
"Altitude": 11,
"GSMSignal": 30
},
"ReplyMsg": "7e80010005856009001014d81b0e56020000f57e",
"MsgType": "Location"
}
Return message description
{
"DeviceID": "790011000094",
"DataBody": {
"GpsTime": Positioning time(UTC time),
"Latitude": latitude(WGS84),
"Longitude": longitude(WGS84),
"MCC": MCC,
"MNC": MNC,
"LAC": LAC,
"CELLID": CELLID,
"FenceId": Geo-Fence ID,
"BackCover": BackCover status(1:Open;0:Close),
"Index": Data Serial number,
"Awaken":Wake-up source (1: RTC alarm wake-up, 2: Gsens vibration wake-up 3: open back cover wake-up 4: rope-cut wake-up 5: charging wake-up 6: swipe card wake-up 7: Lora wake-up 8: VIP number wake-up 9: non-VIP wake-up 10: Bluetooth wake-up )
"ProtocolVersion":Protocol version,
"Direction": True North is 0, clockwise0-360,
"Battery": Battery percentage(0~100%),
"GpsSignal":Number of satellites currently received by GPS,
"Voltage": Battery Voltage,unit: V,
"Speed": Speed, unit:km/h,
"LockStatus": DeviceLock Status(0:locked;1:unlock),
"LockRope": Lock rope status(0:Inserted;1:Pull out),
"Mileage": Mileage,Unit:km,
"Alarm": Alarm type (1: Overspeed alarm; 2: Low power alarm; 3: Back cover open alarm; 4: Entering the fence alarm; 5: Exiting the fence alarm),
"DataLength": Data length(Bytes),
"LocationType": Positioning mode (0: no positioning; 1: GPS positioning; 2: base station positioning),
"Altitude": Altitude,unit:km,
"GSMSignal":GSM signal,
"Posture":Attitude (x: plus 180 degrees, minus 180 degrees; y: plus 90 degrees, minus 90 degrees; z: plus 180 degrees, minus 180 degrees)
},
"ReplyMsg": The content of the device that needs to be replied to (empty means no reply is required)(platform response),
"MsgType": Data type(Location:Position data)
}
Rawdata(data with lock&lock event):
7E0200004C8560090010140E54000000000224004201588F9506CA3D93000B00120000201210073017D40127D502017B30011E310106FE040000001BFD090000000000000000000B0805383838383838650C0600000000FFC5A27E
Return message:
{
"DeviceID": "856009001014",
"DataBody": {
"GpsTime": "2020-12-10T07:30:17Z",
"MNC": 0,
"FenceId": 0,
"BackCover": 0,
"Index": 3668,
"Latitude": 22.581141,
"Awaken": 2,
"ProtocolVersion": 0,
"Direction": 0,
"Posture": "x:0;y:0;z:-59",
"Battery": 39,
"GpsSignal": 6,
"Voltage": 3.79,
"LockEvent": {
"Type": 5,
"FenceId": -1,
"UnLockStatus": 1,
"Password": "888888"
},
"Speed": 1,
"LockStatus": 1,
"Mileage": 27,
"MCC": 0,
"Longitude": 113.917331,
"LAC": 0,
"Alarm": -1,
"DataLength": 76,
"CELLID": 0,
"LockRope": 0,
"LocationType": 1,
"Altitude": 11,
"GSMSignal": 30
},
"ReplyMsg": "7e80010005856009001014c8750e54020000897e",
"MsgType": "Location"
}
Return message description
{
"DeviceID": "790011000094",
"DataBody": {
"GpsTime": Positioning time(UTC time),
"Latitude": latitude(WGS84),
"Longitude": longitude(WGS84),
"MCC": MCC,
"MNC": MNC,
"LAC": LAC,
"CELLID": CELLID,
"FenceId": Geo-Fence ID,
"BackCover": BackCover status(1:Open;0:Close),
"Index": Data Serial number,
"Awaken":Wake-up source (1: RTC alarm wake-up, 2: Gsens vibration wake-up 3: open back cover wake-up 4: rope-cut wake-up 5: charging wake-up 6: swipe card wake-up 7: Lora wake-up 8: VIP number wake-up 9: non-VIP wake-up 10: Bluetooth wake-up )
"ProtocolVersion":Protocol version,
"Direction": True North is 0, clockwise0-360,
"Battery": Battery percentage(0~100%),
"GpsSignal":Number of satellites currently received by GPS,
"Voltage": Battery Voltage,unit: V,
"Speed": Speed, unit:km/h,
"LockStatus": DeviceLock Status(0:locked;1:unlock),
"LockRope": Lock rope status(0:Inserted;1:Pull out),
"Mileage": Mileage,Unit:KM,
"Alarm": Alarm type (1: Overspeed alarm; 2: Low power alarm; 3: Back cover open alarm; 4: Entering the fence alarm; 5: Exiting the fence alarm),
"LockEvent": {
"Type": Event type(Refer to below Table1),
"FenceId": Fence ID associated with the event (-1: no fence related),
"UnLockStatus": Unlock status (1: unlock successful; 0: unlock failed),
"Password": Unlock password
"CardNo":If the event type is swipe to unlock, here is the RFID card number
},
"DataLength": Data length(Bytes),
"LocationType": Positioning mode (0: no positioning; 1: GPS positioning; 2: base station positioning),
"Altitude": Altitude,unit:km,
"GSMSignal":GSM signal,
"Posture":Attitude (x: plus 180 degrees, minus 180 degrees; y: plus 90 degrees, minus 90 degrees; z: plus 180 degrees, minus 180 degrees)
},
"ReplyMsg": The content of the device that needs to be replied to (empty means no reply is required)(platform response),
"MsgType": Data type(Location:Position data)
}
(3)Command data parse
Rawdata:
283835363030393030313035382C362C3030312C424153452C322C323032313037323430353531353529
Retrun message:
{
"DeviceID": "856009001058",
"DataBody": "(856009001058,6,001,BASE,2,20210724055155)",
"ReplyMsg": "",
"MsgType": "BASE2"
}
Retrun message description
{
"DeviceID":DeviceID,
"DataBody":Message content,
"ReplyMsg": Reply to the device's message (empty means no reply is required)(platform response),
"MsgType": command type
}
Table1
EventID(HEX) | EventID | Event description |
---|---|---|
0x01 | 1 | Static password remote unlock |
0x02 | 2 | Dynamic password remote unlocking |
0x03 | 3 | Dynamic password on-site (Bluetooth or WIFI) APP unlock |
0x05 | 5 | Indicates static password on-site (Bluetooth or WIFI) APP unlocking |
0x06 | 6 | Wrong static password remote unlock |
0x07 | 7 | Wrong dynamic password remote unlock |
0x08 | 8 | Wrong dynamic password on-site (Bluetooth or WIFI) APP unlock |
0x0B | 11 | Long unlock event |
0x0C | 12 | Lock rope cutting event |
0x0D | 13 | Lock events (automatic locked) |
0x10 | 16 | The remote execution of unlocking is abnormal, and the unlocking is not executed without positioning |
0x11 | 17 | The remote execution of unlocking is abnormal, and the unlocking will not be executed if it is positioned outside the fence |
0x12 | 18 | Abnormal motor |
0x18 | 24 | Unlocking is abnormal in Bluetooth execution, and unlocking is not performed without positioning |
0x19 | 25 | The Bluetooth unlocking is abnormal, and the unlocking is not performed if it is positioned outside the fence |
0x1C | 28 | Unlock and pull out the lock rope |
0x1E | 30 | SMS static password remote unlock |
0x1F | 31 | SMS dynamic password remote unlock |
0x20 | 32 | Wrong SMS dynamic password |
0x22 | 34 | Swipe the authorization card to unlock the event |
0x23 | 35 | Swipe illegal card unlock event |
0x28 | 40 | Wrong static password on-site (Bluetooth or WIFI) APP unlock |
0x29 | 41 | Wrong SMS static password to unlock |
0x2A | 42 | RFID performs unlocking abnormally, and does not perform unlocking without positioning |
0x2B | 43 | RFID performs unlocking abnormally, if it is positioned outside the fence, it does not perform unlocking |