1.Jar package download

jt701-sdk-1.0.0.jar Download
If you need Jar package development source code, please contact the business application


2.Integrated Development Instructions

2.1.Integrated development language and framework description

jt701-sdk-1.0.0.jar is based on the Java language,SpringBoot2.x frame,use netty,fastjson,lombok

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 jt701-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>jt701-sdk</artifactId>
            <version>1.0.0</version>
        </dependency>

Call jt701-sdk-1.0.0.jar, the receiveData() method in the DataParser class
receiveData() method is overloaded

    /**
     * Parse Hex string raw data
     * @param strData hexadecimal string
     * @return
     */
    public static Object receiveData(String strData)
    {
        ByteBuf msgBodyBuf = ByteBufAllocator.DEFAULT.heapBuffer(strData.length()/2);
        msgBodyBuf.writeBytes(CommonUtil.hexStr2Byte(strData));
        return receiveData(msgBodyBuf);
    }

    /**
     * Parse byte[] raw data
     * @param bytes
     * @return
     */
    private static Object receiveData(byte[] bytes)
    {
        ByteBuf msgBodyBuf =ByteBufAllocator.DEFAULT.heapBuffer(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

Parsing method tool class ParserUtil

package com.jointech.sdk.jt701.utils;

import com.jointech.sdk.jt701.constants.Constant;
import com.jointech.sdk.jt701.model.*;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * <p>Description: Analysis method tool class</p>
 * @author HyoJung
 * @date 20210526
 */
public class ParserUtil {
    private ParserUtil()
    {}

    /**
     * Parse command response data
     * @param in rawdata
     * @return
     */
    public static Result decodeTextMessage(ByteBuf in)
    {
        //Define the location data entity class
        Result model = new Result();
        //packet head(
        in.readByte();
        //Field list
        List<String> itemList = new ArrayList<String>();
        //Transparent binary data
        ByteBuf msgBody = null;
        while (in.readableBytes() > 0) {
            //The 7th field of wireless gateway data upload (WLNET5, WLNET7) and the following are binary data
            if (itemList.size() >= 6 && Objects.equals("WLNET", itemList.get(3)) && Constant.WLNET_TYPE_LIST.contains(itemList.get(4))) {
                //Length up to the end ")"
                int lastItemLen = in.readableBytes() - 1;
                //unescape
                msgBody = Unpooled.buffer(lastItemLen);
                CommonUtil.unescape(in, msgBody, lastItemLen);
                in.readByte();
            } else {
                //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));
            }
        }
        //WLNET message type is composite
        String msgType = itemList.get(1);
        if (itemList.size() >= 5 && (Objects.equals("WLNET", itemList.get(3))||Objects.equals("OTA", itemList.get(3)))) {
            msgType = itemList.get(3) + itemList.get(4);
        }
        Object dataBody=null;
        if(msgType.equals("WLNET5")) {
            SensorData sensorData=parseWlnet5(msgBody);
            dataBody=sensorData;
            model.setReplyMsg(replyMessage(msgType,sensorData.getIndex()));
        }else if(msgType.equals("P45")) {
            dataBody=parseP45(itemList);
            model.setReplyMsg(replyMessage(msgType,itemList));
        }else {
            if(itemList.size()>0)
            {
                dataBody="(";
                for(String item :itemList) {
                    dataBody+=item+",";
                }
                dataBody=CommonUtil.trimEnd(dataBody.toString(),",");
                dataBody += ")";
            }
        }
        model.setDeviceID(itemList.get(0));
        model.setMsgType(msgType);
        model.setDataBody(dataBody);
        return model;
    }

    /**
     * Parse slave data
     * @param byteBuf
     * @return
     */
    private static SensorData parseWlnet5(ByteBuf byteBuf) {
        SensorData sensorData = new SensorData();
        //positioning time
        byte[] timeArr = new byte[6];
        byteBuf.readBytes(timeArr);
        String bcdTimeStr = ByteBufUtil.hexDump(timeArr);
        ZonedDateTime gpsZonedDateTime = parseBcdTime(bcdTimeStr);
        //latitude
        byte[] latArr = new byte[4];
        byteBuf.readBytes(latArr);
        String latHexStr = ByteBufUtil.hexDump(latArr);
        BigDecimal latFloat = new BigDecimal(latHexStr.substring(2, 4) + "." + latHexStr.substring(4)).divide(new BigDecimal("60"), 6, RoundingMode.HALF_UP);
        double lat = new BigDecimal(latHexStr.substring(0, 2)).add(latFloat).doubleValue();
        //longitude
        byte[] lngArr = new byte[5];
        byteBuf.readBytes(lngArr);
        String lngHexStr = ByteBufUtil.hexDump(lngArr);
        BigDecimal lngFloat = new BigDecimal(lngHexStr.substring(3, 5) + "." + lngHexStr.substring(5, 9)).divide(new BigDecimal("60"), 6, RoundingMode.HALF_UP);
        double lng = new BigDecimal(lngHexStr.substring(0, 3)).add(lngFloat).doubleValue();
        //bit indication
        int bitFlag = Byte.parseByte(lngHexStr.substring(9, 10), 16);
        //Positioning status
        int locationType = (bitFlag & 0x01) > 0 ? 1 : 0;
        //north latitude, south latitude
        if ((bitFlag & 0b0010) == 0) {
            lat = -lat;
        }
        //East longitude and West longitude
        if ((bitFlag & 0b0100) == 0) {
            lng = -lng;
        }
        //Speed
        int speed = (int) (byteBuf.readUnsignedByte() * 1.85);
        //Header(direction)
        int direction = byteBuf.readUnsignedByte() * 2;

        //slave time
        byte[] slaveMachineTimeArr = new byte[6];
        byteBuf.readBytes(slaveMachineTimeArr);
        String slaveMachineBcdTimeStr = ByteBufUtil.hexDump(slaveMachineTimeArr);
        ZonedDateTime slaveMachineZonedDateTime = parseBcdTime(slaveMachineBcdTimeStr);
        //slave sensor ID
        byte[] slaveMachineIdArr = new byte[5];
        byteBuf.readBytes(slaveMachineIdArr);
        String slaveMachineId = ByteBufUtil.hexDump(slaveMachineIdArr).toUpperCase();
        //slave data serial number
        int flowId = byteBuf.readUnsignedByte();
        //slave sensor battery level
        String voltage = new BigDecimal(byteBuf.readUnsignedShort()).divide(new BigDecimal("100"), 2, RoundingMode.HALF_UP).toString();
        //slave sensor battery percertage
        int power = byteBuf.readUnsignedByte();
        //RSSI
        int rssi = byteBuf.readUnsignedByte();
        //sensor type
        int sensorType = byteBuf.readUnsignedByte();
        //temperature value
        double temperature = -1000.0;
        //Humidity value
        int humidity = 0;
        //Event type
        int eventType = -1;
        //Device status
        int terminalStatus = -1;
        //unlock&lock times
        int lockTimes = -1;
        if (sensorType == 1) {
            //temperature
            temperature = parseTemperature(byteBuf.readShort());
            //Humidity
            humidity = byteBuf.readUnsignedByte();
            //Gateway saves the number of data
            int itemCount = byteBuf.readUnsignedShort();
            //gateway status
            int gatewayStatus = byteBuf.readUnsignedByte();
        } else if (sensorType == 4) {
            //event
            int event = byteBuf.readUnsignedShort();
            //Judgment event
            if (NumberUtil.getBitValue(event, 0) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_0.getValue());
            } else if (NumberUtil.getBitValue(event, 1) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_1.getValue());
            } else if (NumberUtil.getBitValue(event, 2) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_2.getValue());
            } else if (NumberUtil.getBitValue(event, 3) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_3.getValue());
            } else if (NumberUtil.getBitValue(event, 4) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_4.getValue());
            } else if (NumberUtil.getBitValue(event, 5) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_5.getValue());
            } else if (NumberUtil.getBitValue(event, 6) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_6.getValue());
            } else if (NumberUtil.getBitValue(event, 7) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_7.getValue());
            } else if (NumberUtil.getBitValue(event, 8) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_8.getValue());
            } else if (NumberUtil.getBitValue(event, 9) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_9.getValue());
            }else if (NumberUtil.getBitValue(event, 14) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_14.getValue());
            }
            //Device status
            terminalStatus = byteBuf.readUnsignedShort();
            //unlock times
            lockTimes = byteBuf.readUnsignedShort();
            //gateway status
            int gatewayStatus = byteBuf.readUnsignedByte();
        }else if (sensorType == 5||sensorType == 6)
        {
            //event
            int event = byteBuf.readUnsignedShort();
            //Judgment event
            if (NumberUtil.getBitValue(event, 0) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_15.getValue());
            } else if (NumberUtil.getBitValue(event, 1) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_16.getValue());
            } else if (NumberUtil.getBitValue(event, 2) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_17.getValue());
            } else if (NumberUtil.getBitValue(event, 3) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_6.getValue());
            } else if (NumberUtil.getBitValue(event, 4) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_18.getValue());
            } else if (NumberUtil.getBitValue(event, 5) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_19.getValue());
            } else if (NumberUtil.getBitValue(event, 6) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_3.getValue());
            } else if (NumberUtil.getBitValue(event, 7) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_0.getValue());
            } else if (NumberUtil.getBitValue(event, 8) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_1.getValue());
            } else if (NumberUtil.getBitValue(event, 9) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_20.getValue());
            }else if (NumberUtil.getBitValue(event, 10) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_21.getValue());
            }else if (NumberUtil.getBitValue(event, 11) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_22.getValue());
            }else if (NumberUtil.getBitValue(event, 12) == 1) {
                eventType = Integer.parseInt(EventTypeEnum.LockEvent_5.getValue());
            }
            //Device status
            terminalStatus = byteBuf.readUnsignedShort();
            //unlock times
            lockTimes = byteBuf.readUnsignedShort();
            //gateway status
            int gatewayStatus = byteBuf.readUnsignedByte();
        }
        sensorData.setGpsTime(gpsZonedDateTime.toString());
        sensorData.setLatitude(lat);
        sensorData.setLongitude(lng);
        sensorData.setLocationType(locationType);
        sensorData.setSpeed(speed);
        sensorData.setDirection(direction);
        sensorData.setSensorID(slaveMachineId);
        sensorData.setLockStatus(NumberUtil.getBitValue(terminalStatus, 0));
        sensorData.setLockRope(NumberUtil.getBitValue(terminalStatus, 0));
        sensorData.setLockTimes(lockTimes);
        sensorData.setIndex(flowId);
        sensorData.setVoltage(voltage);
        sensorData.setPower(power);
        sensorData.setRSSI(rssi);
        sensorData.setDateTime(slaveMachineZonedDateTime.toString());
        sensorData.setSensorType(sensorType);
        sensorData.setTemperature(temperature);
        sensorData.setHumidity(humidity);
        sensorData.setEvent(eventType);
        return sensorData;
    }

    /**
     * Parse P45
     * @param itemList
     * @return
     */
    private static LockEvent parseP45(List<String> itemList)
    {
        LockEvent model = new LockEvent();
        model.DateTime= parseBcdTime(itemList.get(2) + itemList.get(3)).toString();
        model.Latitude = Double.valueOf(itemList.get(4));
        if (itemList.get(5).equals("S"))
        {
            model.Latitude = -model.Latitude;
        }
        model.Longitude = Double.valueOf(itemList.get(6));
        if (itemList.get(5).equals("W"))
        {
            model.Longitude = -model.Longitude;
        }
        model.LocationType= itemList.get(8).equals("V") ? 0 : 1;
        model.Speed= Double.valueOf(itemList.get(9)).intValue();
        model.Direction = Integer.valueOf(itemList.get(10));
        model.Event = Integer.valueOf(itemList.get(11));
        //unlock verification
        int status= Integer.valueOf(itemList.get(12));
        model.RFIDNo = itemList.get(13);
        //Dynamic password unlock
        if (model.Event == 6)
        {
            if (status == 0)
            {
                //Incorrect unlock code
                model.Status = 0;
            }
            else if (status > 0 && status <= 10)
            {
                //normal unlock
                model.Status = 1;
                //Fence ID when unlocking inside the fence
                model.UnlockFenceID = status;
            }
            else if (status == 98)
            {
                //normal unlock
                model.Status = 1;
            }
            else if (status == 99)
            {
                //The device has enabled unlocking within the fence, and the current unlocking is not within the fence, refusing to unlock
                model.Status = 3;
            }
        }
        else if (model.Event == 4)
        {
            if (Integer.valueOf(itemList.get(14)) == 0)
            {
                //Incorrect unlock code
                model.Status = 0;
            }
            else
            {
                //normal unlock
                model.Status = 1;
            }
        }
        model.PsdErrorTimes = Integer.valueOf(itemList.get(15));
        model.Index = Integer.valueOf(itemList.get(16));
        if (itemList.size() > 17)
        {
            model.Mileage = Integer.valueOf(itemList.get(16));
        }
        return model;
    }

    /**
     * Parse slave data temperature
     *
     * @param temperatureInt
     * @return
     */
    private static double parseTemperature(int temperatureInt) {
        if (temperatureInt == 0xFFFF) {
            return 9999.9;
        }
        double temperature = ((short) (temperatureInt << 4) >> 4) * 0.1;
        if ((temperatureInt >> 12) > 0) {
            temperature = -temperature;
        }
        return temperature;
    }

    /**
     * Convert GPS time
     *
     * @param bcdTimeStr
     * @return
     */
    public static ZonedDateTime parseBcdTime(String bcdTimeStr) {
        if(bcdTimeStr.equals("000000000000"))
        {
            //The default time given is January 1, 2000 00:00:00
            bcdTimeStr="010100000000";
        }
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ddMMyyHHmmss");
        LocalDateTime localDateTime = LocalDateTime.parse(bcdTimeStr, formatter);
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, ZoneOffset.UTC);
        return zonedDateTime;
    }

    /**
     * Parse location data
     * @param in
     * @return
     */
    public static Result decodeBinaryMessage(ByteBuf in)
    {
        //protocol header
        in.readByte();
        //DeviceID
        byte[] terminalNumArr = new byte[5];
        in.readBytes(terminalNumArr);
        String terminalNum = ByteBufUtil.hexDump(terminalNumArr);
        //Protocol version
        int version = in.readUnsignedByte();
        short tempByte = in.readUnsignedByte();
        //Device type
        int terminalType = tempByte >> 4;
        //data type
        int dataType = tempByte & 0b00001111;
        //Data length
        int dataLen = in.readUnsignedShort();
        //GPS g time
        byte[] timeArr = new byte[6];
        in.readBytes(timeArr);
        String bcdTimeStr = ByteBufUtil.hexDump(timeArr);
        ZonedDateTime gpsZonedDateTime = parseBcdTime(bcdTimeStr);
        //latitude
        byte[] latArr = new byte[4];
        in.readBytes(latArr);
        String latHexStr = ByteBufUtil.hexDump(latArr);
        double lat = 0.0;
        BigDecimal latFloat = new BigDecimal(latHexStr.substring(2, 4) + "." + latHexStr.substring(4)).divide(new BigDecimal("60"), 6, RoundingMode.HALF_UP);
        lat = new BigDecimal(latHexStr.substring(0, 2)).add(latFloat).doubleValue();
        //longitude
        byte[] lngArr = new byte[5];
        in.readBytes(lngArr);
        String lngHexStr = ByteBufUtil.hexDump(lngArr);
        double lng=0.0;
        BigDecimal lngFloat = new BigDecimal(lngHexStr.substring(3, 5) + "." + lngHexStr.substring(5, 9)).divide(new BigDecimal("60"), 6, RoundingMode.HALF_UP);
        lng = new BigDecimal(lngHexStr.substring(0, 3)).add(lngFloat).doubleValue();
        //bit indication
        int bitFlag = Byte.parseByte(lngHexStr.substring(9, 10), 16);
        //Positioning status
        int locationType = (bitFlag & 0x01) > 0 ? 1 : 0;
        //north latitude, south latitude
        if ((bitFlag & 0b0010) == 0) {
            lat = -lat;
        }
        //East longitude and West longitude
        if ((bitFlag & 0b0100) == 0) {
            lng = -lng;
        }
        //Speed
        int speed = (int) (in.readUnsignedByte() * 1.85);
        //Header(direction)
        int direction = in.readUnsignedByte() * 2;
        //Mileage
        long mileage = in.readUnsignedInt();
        //Number of GPS satellites
        int gpsSignal = in.readByte();
        //Bind vehicle ID
        long vehicleId = in.readUnsignedInt();
        //Device status
        int terminalStatus = in.readUnsignedShort();
        //Whether the base station is located
        if (NumberUtil.getBitValue(terminalStatus, 0) == 1) {
            locationType = 2;
        }
        //Battery indicator
        int batteryPercent = in.readUnsignedByte();
        //2G CELL ID
        int cellId2G = in.readUnsignedShort();
        //LAC
        int lac = in.readUnsignedShort();
        //GSM Signal quality
        int cellSignal = in.readUnsignedByte();
        //fence Alarm ID
        int regionAlarmId = in.readUnsignedByte();
        //Device status3
        int terminalStatus3 = in.readUnsignedByte();
        //Wakeup source
        int fWakeSource=(terminalStatus3 & 0b0000_1111);
        //reserved
        in.readShort();
        //IMEI No.
        byte[] imeiArr = new byte[8];
        in.readBytes(imeiArr);
        String imei = ByteBufUtil.hexDump(imeiArr);
        //3G CELL ID High 16 bits
        int cellId3G = in.readUnsignedShort();
        int cellId=0;
        if(cellId3G>0){
            cellId=(cellId3G<<16)+cellId2G;
        }else{
            cellId=cellId2G;
        }
        //MCC
        int mcc = in.readUnsignedShort();
        //MNC
        int mnc = in.readUnsignedByte();
        //Data serial number
        int flowId = in.readUnsignedByte();
        //Parse alarm
        int fAlarm=parseLocationAlarm(terminalStatus);

        LocationData location=new LocationData();
        location.setProtocolType(version);
        location.setDeviceType(terminalType);
        location.setDataType(dataType);
        location.setDataLength(dataLen);
        location.setGpsTime(gpsZonedDateTime.toString());
        location.setLatitude(lat);
        location.setLongitude(lng);
        location.setLocationType(locationType);
        location.setSpeed(speed);
        location.setDirection(direction);
        location.setMileage(mileage);
        location.setGpsSignal(gpsSignal);
        location.setGSMSignal(cellSignal);
        location.setAlarm(fAlarm);
        location.setAlarmArea(regionAlarmId);
        location.setBattery(batteryPercent);
        location.setLockStatus(NumberUtil.getBitValue(terminalStatus, 7) == 1 ? 0 : 1);
        location.setLockRope(NumberUtil.getBitValue(terminalStatus, 6) == 1 ? 0 : 1);
        location.setBackCover(NumberUtil.getBitValue(terminalStatus, 13));
        location.setMCC(mcc);
        location.setMNC(mnc);
        location.setLAC(lac);
        location.setCELLID(cellId);
        location.setIMEI(imei);
        location.setAlarm(fWakeSource);
        location.setIndex(flowId);
        //Define the location data entity class
        Result model = new Result();
        model.setDeviceID(terminalNum);
        model.setMsgType("Location");
        model.setDataBody(location);
        if (version < 0x19) {
            model.setReplyMsg("(P35)");
        } else {
            model.setReplyMsg(String.format("(P69,0,%s)",flowId));
        }
        return model;
    }

    /**
     * Analyze and locate alarms
     * @param terminalStatus
     * @return
     */
    private static int parseLocationAlarm(int terminalStatus)
    {
        //Trigger alarm or not
        int fAlarm = -1;
        //Acknowledge or not
        if (NumberUtil.getBitValue(terminalStatus, 5) == 1) {
            //Judgment alarm
            if (NumberUtil.getBitValue(terminalStatus, 1) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_9.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 2) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_10.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 3) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_1.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 4) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_2.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 8) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_3.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 9) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_4.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 10) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_5.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 11) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_6.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 12) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_7.getValue());
            } else if (NumberUtil.getBitValue(terminalStatus, 14) == 1) {
                fAlarm = Integer.parseInt(AlarmTypeEnum.LOCK_ALARM_8.getValue());
            } else {
                fAlarm = -1;
            }
        }
        return fAlarm;
    }

    /**
     * Command response reply
     * @param msgType
     * @param itemList
     * @return
     */
    private static String replyMessage(String msgType,List<String> itemList)
    {
        String replyContent = null;
        switch (msgType)
        {
            case "P22":
                ZonedDateTime currentDateTime = ZonedDateTime.now(ZoneOffset.UTC);
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("ddMMyyHHmmss");
                replyContent = String.format("(P22,%s)", currentDateTime.format(formatter));
                break;
            case "P43":
                if (itemList.get(2).equals("0")) {
                    //reset Password
                    replyContent = String.format("(P44,1,888888)");
                }
                break;
            case "P45":
                replyContent = String.format("(P69,0,%s)", itemList.get(16));
                break;
            case "P52":
                if (itemList.get(2).equals("2")) {
                    replyContent = String.format("(P52,2,%s)", itemList.get(3));
                }
                break;
            default:
                break;
        }
        return replyContent;
    }

    /**
     * Command response reply
     * @param msgType
     * @param index
     * @return
     */
    public static String replyMessage(String msgType, int index)
    {
        String replyContent = null;
        switch (msgType)
        {
            case "WLNET5":
            case "WLNET7":
                replyContent = String.format("(P69,0,{0})", index);
                break;
            default:
                break;
        }
        return replyContent;
    }
}

public method class CommonUtil

package com.jointech.sdk.jt701.utils;

import io.netty.buffer.ByteBuf;

import java.nio.ByteBuffer;

/**
 * <p>Description:Used to store some public methods encountered in parsing </p>
 *
 * @author lenny
 * @version 1.0.1
 * @date 20210328
 */
public class CommonUtil {
    private CommonUtil()
    {

    }

    /**
     * Unescaped text to transparently transmit data
     *
     * @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 == 0x3D) {
                int nextByte = in.readUnsignedByte();
                if (nextByte == 0x14) {
                    frame.writeByte(0x3D ^ 0x14);
                } else if (nextByte == 0x15) {
                    frame.writeByte(0x3D ^ 0x15);
                } else if (nextByte == 0x00) {
                    frame.writeByte(0x3D ^ 0x00);
                } else if (nextByte == 0x11) {
                    frame.writeByte(0x3D ^ 0x11);
                } else {
                    frame.writeByte(b);
                    frame.writeByte(nextByte);
                }
                i += 2;
            } else {
                frame.writeByte(b);
                i++;
            }
        }
    }

    /**
     * remove last character from 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();
    }
}

Parse constants

package com.jointech.sdk.jt701.constants;

import java.util.Arrays;
import java.util.List;

/**
 * constant definition
 * @author HyoJung
 * @date 20210526
 */
public class Constant {
    private Constant(){}
    /**
     * binary message header
     */
    public static final byte BINARY_MSG_HEADER = '$';

    /**
     * text message header
     */
    public static final byte TEXT_MSG_HEADER = '(';

    /**
     * text message trailer
     */
    public static final byte TEXT_MSG_TAIL = ')';

    /**
     * text message separator
     */
    public static final byte TEXT_MSG_SPLITER = ',';

    /**
     * Instructions for transparently transmitting binary data
     */
    public static final List<String> WLNET_TYPE_LIST = Arrays.asList("5", "7");
}

2.4.Return message and description

(1)positioning data
Raw data:

2480405002251911003426032118530329532416031008941d0000000018070c0000000020e04f8b0c56001f00020f0f0f0f0f0f0f0f0f0f00f2028f0157

Return message:

{
    "DeviceID": "8040500225",
    "DataBody": {
        "GpsTime": "2021-03-26T18:53:03Z",
        "MNC": 1,
        "BackCover": 1,
        "Index": 87,
        "Latitude": -29.88736,
        "Awaken": 0,
        "Direction": 0,
        "Battery": 79,
        "GpsSignal": 12,
        "DataType": 1,
        "AlarmArea": 0,
        "Speed": 0,
        "LockStatus": 0,
        "Mileage": 6151,
        "IMEI": "0f0f0f0f0f0f0f0f",
        "MCC": 655,
        "Longitude": 31.014902,
        "LAC": 22016,
        "DeviceType": 1,
        "ProtocolType": 25,
        "Alarm": 2,
        "DataLength": 52,
        "CELLID": 15895308,
        "LockRope": 0,
        "LocationType": 1,
        "GSMSignal": 31
    },
    "ReplyMsg": "(P69,0,87)",
    "MsgType": "Location"
}

Return message description

{
    "DeviceID":DeviceID
    "MsgType":message type, Here is: Location, which means location data,
    "DataBody":message body
    {
        "ProtocolType": Protocol version,
        "DeviceType": Device type,
        "DataType": Data type number (1 means the real-time binary positioning data, 2 means alarm data, 3 means blind area regular binary positioning data, 4 means second-new binary positioning data)
        "DataLength": Datalength,
        "GpsTime": Positioning time (GMT time),
        "Latitude": Latitude (dd.dddd format),
        "Longitude": Longitude (dd.dddd format),
        "LocationType": Positioning type (0: no positioning; 1: GPS positioning; 2: base station positioning),
        "Speed": Speed (unit: km/h),
        "Direction": Direction (0~360; 0 and 360 indicate true north direction),
        "Mileage": Current mileage value (unit: km),
        "GpsSignal": Number of GPS satellites,
        "GSMSignal": GSM signal value,
        "Alarm": Alarm type ( - 1: No alarm information; 1: Lock rope cut; 2: Vibration; 3: Long time unlocking; 4: Unlock password is wrong for 5 consecutive times; 5: Swipe illegal card; 6: Low battery; 7: Back cover opening ; 8: Motor struck; 9: Enter fence alarm; 10: Exit fence alarm),
        "AlarmArea": If the alarm is related to the area, the value here is the area ID,
        "Battery": Battery value ( 0~100; 255: charging),
        "LockStatus": Lock motor status (1: ON; 0: OFF),
        "LockRope": Lock rope status (1: unplugged; 0: inserted),
        "BackCover": Back cover status (1: closed; 0: open),
        "MCC": country code,
        "MNC": carrier code,
        "LAC": location area code,
        "CELLID": base station number,
        "IMEI": IMEI number, all 0F is invalid,
        "Awaken": wakeup source ( 0 restart,
         1: RTC wake-up, 2: Vibrate, 3: Open back cover, 4: insert/pull out lock rope, 5: Connect external power, 6: Swipe card, 7: Door sensor, 8: VIP SMS, 9: Non-VIP SMS or spam),
        "Index": Data serial number
    },
    "ReplyMsg":Reply content (if it is an empty string, the platform no need to reply to this message)
}

(2)Sensors collect data(WLNET5)
Raw data(SensorType=1):

28383035303530303037332c312c3134312c574c4e45542c352c322c260321184709649672953949673d1408ff002603211847181020110986660133623c0100d71b00000029

Return message(SensorType=1):

{
    "DeviceID": "8050500073",
    "DataBody": {
        "SensorID": "1020110986",
        "SensorType": 1,
        "Speed": 471,
        "GpsTime": "2021-03-26T18:47:09Z",
        "Temperature": 21.5,
        "LockStatus": 1,
        "Index": 102,
        "Latitude": -65.612158,
        "Direction": 0,
        "Longitude": -395.61215,
        "DateTime": "2021-03-26T18:47:18Z",
        "RSSI": 60,
        "Humidity": 27,
        "Voltage": "3.07",
        "LockTimes": -1,
        "Event": -1,
        "LockRope": 1,
        "LocationType": 0,
        "Power": 98
    },
    "ReplyMsg": "(P69,0,102)",
    "MsgType": "WLNET5"
}

Raw data(SensorType=4):

28373030303331333330392C312C3038312C574C4E45542C352C322C05082115430722348250113550300F0000050821154304E0171E086925018D4E690400400000002A0029

Return message(SensorType=4):

{
    "DeviceID": "7000313309",
    "MsgType": "WLNET5",
    "DataBody": {
        "GpsTime": "2021-08-05T15:43:07",
        "Latitude": 22.580416666666668,
        "Longitude": 113.91716666666667,
        "LocationType": 1,
        "Speed": 0,
        "Direction": 0,
        "SensorID": "E0171E0869",
        "LockStatus": 0,
        "LockRope": 0,
        "LockTimes": 42,
        "Index": 37,
        "Voltage": "3.97",
        "Power": 78,
        "RSSI": -105,
        "DateTime": "2021-08-05T15:43:04",
        "SensorType": 4,
        "Temperature": 0.0,
        "Humidity": 0,
        "Event": 6
    },
    "ReplyMsg": "(P69,0,37)"
}

Return message description

{
    "DeviceID": DeviceID,
    "MsgType": message type, Here is: WLNET5, which means that the sensor transparently transmits data,
    "DataBody": message body
    {
        "GpsTime": Positioning time (GMT time),
        "Latitude": Latitude (dd.dddd format),
        "Longitude": Longitude (dd.dddd format),
        "LocationType": Positioning type (0: no positioning; 1: GPS positioning; 2: base station positioning),
        "Speed": Speed (unit: km/h); 0xFF means invalid speed,
        "Direction": direction (0~360; 0 and 360 indicate true north direction),
        "SensorID":sensor ID,
        "LockStatus": This is only valid if the slave type SensorType=4; 1: unlocked; 0: locked,
        "LockRope": This is only valid if the slave type SensorType=4; 1: the lock rope is pulled out; 0: the lock rope is inserted,
        "LockTimes": Number of unlocks (this value is only valid if SensorType=4),
        "Index": data serial number,
        "Voltage": Voltage value (unit: V),
        "Power": Sensor power (0~100; 255: charging),
        "RSSI":RSSI signal strength, the closer the negative number is to 0, the better the signal,
        "DateTime": Data collection time (GMT time),
        "SensorType": Sensor type (1: temperature and humidity sensor (JT126); 4: slave JT709;),
        "Temperature":Temperature value (only valid if SensorType=1),
        "Humidity": Humidity value (only valid if SensorType=1),
        "Event": Event type (-1: no slave event; 0: lock event; 1: Bluetooth unlock event; 2: NFC unlock event; 3: Lora unlock event; 4: slave lock clipping alarm event; 5: key-press wake-up event; 6 : Timing reporting event; 7: Charging reporting event)
    },
    "ReplyMsg": Reply content (if it is an empty string,  no need to reply to the message from platform))
}

(3)Lock event reporting data(P45)
Rawdata:

28373839303632393238342c5034352c3236303332312c3139343933392c32362e3237323033352c4e2c35302e3632313433352c452c412c302e30352c302c342c312c303030303030303030302c312c302c3129

Return messsage:

{
    "DeviceID": "7890629284",
    "MsgType": "P45",
    "DataBody": {
        "DateTime": "2021-03-26T19:49:39",
        "Latitude": 26.272035,
        "Longitude": 50.621435,
        "LocationType": 1,
        "Speed": 0,
        "Direction": 0,
        "Event": 4,
        "Status": 1,
        "UnlockFenceID": -1,
        "RFIDNo": "0000000000",
        "PsdErrorTimes": 0,
        "Index": 1,
        "Mileage": 0
    },
    "ReplyMsg": "(P69,0,1)"
}

Return message description:

{
    "DeviceID": Device ID,
    "MsgType": The message type, here is: P45, which means the switch lock event data upload,
    "DataBody": message body
    {
        "DateTime": event time (GMT time),
        "Latitude": Latitude (dd.dddd format),
        "Longitude": Longitude (dd.dddd format),
        "LocationType": Positioning type (0: no positioning; 1: GPS positioning; 2: base station positioning),
        "Speed": Speed (unit: km/h),
        "Direction": direction (0~360; 0 and 360 indicate true north direction),
        "Event": Event type (1: means swiping authorization card; 2: means swiping illegal card; 3: means swiping vehicle ID card binding; 4: means unlocking with password; 5: means terminal automatic lock record; 6: in dynamic password fence unlock; 7: Bluetooth unlock),
        "Status": Unlock verification (0: the unlock password is incorrect; 1: normal unlock; 2: because the fence is unlocked, it is not unlocked in the fence, and the unlock is rejected),
        "UnlockFenceID": (-1: Unlocking has nothing to do with the fence; 1~10: Identifies the corresponding unlocking fence ID),
        "RFIDNo": Swipe card number; if not "0000000000", it is invalid,
        "PsdErrorTimes": Number of incorrect unlock passwords,
        "Index": data serial number,
        "Mileage": Current mileage value (unit: km)
    },
    "ReplyMsg": Reply content (if it is an empty string, there is no need to reply to the message)
}

(4)Other commands reply data
Raw data:

28373839303632393238342c50333529

return message:

{
    "DeviceID": "7890629284",
    "MsgType": "P35",
    "DataBody": "(7890629284,P35)",
    "ReplyMsg": ""
}

Return message description:

{
    "DeviceID": Device ID,
    "MsgType": Message type (see more message types and descriptions, please refer to 3. Message types and message body content description),
    "DataBody": The content of the message body (except for the location data: Location; the sensor transparent transmission data: WLNET5; the lock event report: P45; the ASCII strings of the command content are directly returned here),
    "ReplyMsg": (If it is an empty string, there is no need to reply to the message)
}
文档更新时间: 2022-11-08 17:45   作者:admin