1.SDK下载
JT701SDK(JT701SDK_V2.rar) 下载地址
Jt701SDK测试工具(JT701SDK_Test.rar) 下载地址
如果需要测试工具及SDK开发源码,请与商务申请
2.集成开发说明
2.1.集成开发语言及框架说明
JT701SDK(Jt701DataParser.dll)及测试工具(Test.exe)是基于C#语言,.NET Framework 4.6.1目标框架开发的。该SDK的集成开发环境也是需要依赖于C#语言以及.NET Framework 4.6.1目标框架。
2.2.集成说明
(1)将Jt701DataParser.dll引入到自己的网关程序中,引入方法如下:
鼠标右键项目下的”引用”,选择”添加引用(R)…”
选择下图中”浏览(B)…”,找到你解压JT701SDK20210327.rar后的文件夹,选中Jt701DataParser.dll与对应的Json字符串序列化/反序列化包Newtonsoft.Json.dll即可完成对SDK的引用
(2)调用Jt701DataParser.dll中的解析方法receiveData
receiveData()是一个重载方法,你可以传入16进制字符串或者byte[],一般我们网关程序接收到的设备数据是以二进制流进行传输的,所以我们这里建议使用此重载方法receiveData(byte[] bytes);
当然如果你想通过16进制字符串进行测试,也可以使用receiveData(string strData);
strData:就是我们接收到的设备数据转成16进制后的字符串,
例如定位数据:2480405003701911003426032115595533197294020020085d0586000010e10c0000000020e043600a526d1700020f0f0f0f0f0f0f0f0f0f0eaa028f018b
指令数据:28373839303632393238342c5034352c3236303332312c3138353334322c32362e3138313239362c4e2c35302e3332393738382c452c562c302e30302c302c352c302c303030303030303030302c302c302c3029
2.3.核心代码
Jt701DataParser.dll
(1)解析类DataParser.cs
public class DataParser
{
private static byte[] endbytes = null;// 上一次未处理的剩余字节
/// <summary>
/// 解析16进制原始数据
/// </summary>
/// <param name="strData"></param>
/// <returns></returns>
public static string receiveData(string strData)
{
byte[] bytes = Common.HexStringToBytes(strData);
return receiveData(bytes);
}
/// <summary>
/// 解析2进制原始数据
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static string receiveData(byte[] bytes)
{
byte[] newBytes = null;
if (endbytes!=null && endbytes.Length > 0)
{
newBytes = new byte[endbytes.Length + bytes.Length];
bytes = Common.CombineBytes(endbytes, bytes);
}
else
{
newBytes = new byte[bytes.Length];
newBytes = bytes;
}
int i = 0;//初始化byte[]下标
byte[] parserBytes = null;//去除正确包头之前的数据后的数据
foreach (var item in newBytes)
{
if (item == '$')
{
parserBytes = new byte[newBytes.Length - i];
parserBytes = newBytes.Skip(i).Take(newBytes.Length - i).ToArray();
return parserLocation(parserBytes);
}
else if (item == '(')
{
parserBytes = new byte[newBytes.Length - i];
parserBytes = newBytes.Skip(i).Take(newBytes.Length - i).ToArray();
return parserCommand(parserBytes);
}
i++;
}
return null;
}
/// <summary>
/// 解析定位数据
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
private static string parserLocation(byte[] bytes)
{
//定义定位数据实体类
Result model = new Result();
try
{
//跳过包头,然后解析设备ID
model.DeviceID= Common.ByteToHexStr(bytes.Skip(1).Take(5).ToArray());
model.MsgType = "Location";
LocationData location = new LocationData();
location.ProtocolType = bytes[6];
location.DeviceType = bytes[7] & 0x0F;
location.DataType = (bytes[7]>>4) & 0x0F;
//得到数据长度
location.DataLength = Common.SwapUInt16(BitConverter.ToUInt16(bytes, 8));
//获取时间段,转成我们识别的"yyyy-MM-dd HH:mm:ss"格式
location.GpsTime = Common.GetDataTime(bytes.Skip(10).Take(6).ToArray());
//纬度信息解析
LatLon latLon = Common.GetLatLon(bytes.Skip(16).Take(9).ToArray());
location.Latitude = latLon.Latitude;//纬度
location.Longitude = latLon.Longitude;//经度
location.LocationType = latLon.LocationType;//定位状态
//解析速度
location.Speed = (int)(bytes[25]*1.85);
//解析方向
location.Direction = bytes[26] * 2;
//解析里程
location.Mileage = Common.SwapUInt32(BitConverter.ToUInt32(bytes, 27));//里程
//解析GPS卫星个数
location.GpsSignal = bytes[31];
//解析设备状态
DeviceStatus deviceStatus = Common.GetDeviceStatus(bytes.Skip(36).Take(2).ToArray(), location.LocationType);
//解析是否基站定位(GPS定位>基站定位>不定位)
location.LocationType = deviceStatus.LocationType;
//解析报警类型
location.Alarm = deviceStatus.Alarm;
//解析锁绳状态
location.LockRope = deviceStatus.LockRope;
//解析锁状态
location.LockStatus = deviceStatus.LockStatus;
//解析后盖状态
location.BackCover = deviceStatus.BackCover;
//获取电量(255为充电中)
location.Battery = bytes[38];
//解析小区码CellID低2位数据
string strLowCellID = Common.ByteToHexStr(bytes.Skip(39).Take(2).ToArray());
//解析小区码LAC
location.LAC = Common.SwapUInt16(BitConverter.ToUInt16(bytes, 41));
//解析GSM信号值
location.GSMSignal = bytes[43];
//解析区域ID
location.AlarmArea = bytes[44];
//得到唤醒源
location.Awaken = bytes[45];
//得到IMEI号
location.IMEI = Common.ByteToHexStr(bytes.Skip(48).Take(8).ToArray());
////解析小区码CellID高2位数据
string strHightCellID = Common.ByteToHexStr(bytes.Skip(56).Take(2).ToArray());
location.CELLID = Convert.ToInt64(strHightCellID + strLowCellID, 16);
location.MCC = Common.SwapUInt16(BitConverter.ToUInt16(bytes, 58));
location.MNC = bytes[60];
location.Index= bytes[61];
model.DataBody = location;
if (location.ProtocolType < 0x19)
{
model.ReplyMsg= "(P35)";
}
else
{
model.ReplyMsg = string.Format("(P69,0,{0})", location.Index);
}
}
catch (Exception ex)
{
return null;
}
return JsonConvert.SerializeObject(model);
}
/// <summary>
/// 解析指令数据
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
private static string parserCommand(byte[] bytes)
{
Result result = new Result();
byte[] newBytes = null;
int tailIndex = Common.BytesIndexOf(bytes,0x29)+1;
if (tailIndex > 0)
{
if (bytes.Length > tailIndex)
{
endbytes = bytes.Skip(tailIndex).Take(bytes.Length - tailIndex).ToArray();
}
newBytes= bytes.Skip(0).Take(tailIndex).ToArray();
}
else
{
endbytes = new byte[bytes.Length];
endbytes = bytes;
}
if (newBytes!=null && newBytes.Length > 0)
{
//转换成()带括号的数据
string msgAscii = Common.ByteToASCII(newBytes);
//按逗号拆分字符串
char[] p = new char[] { ',' };
//返回的数组中,包含空字符串
string[] msgArrays = msgAscii.Replace("(", "").Replace(")", "").Split(p, StringSplitOptions.None);
result.DeviceID = msgArrays[0];
string msgType = string.Empty;
if (msgArrays.Length > 5 && msgArrays[3] == "WLNET")
{
msgType = msgArrays[3] + msgArrays[4];
}
else
{
msgType = msgArrays[1];
}
result.MsgType = msgType;
if (msgType.Equals("WLNET5"))
{
SensorData sensorData = parserWLNET5(msgArrays, newBytes);
result.DataBody = sensorData;
result.ReplyMsg = Common.replyMessage(msgType, sensorData.Index);
}
else
{
if (msgType.Equals("P45"))
{
LockEvent lockEvent = parserP45(msgArrays);
result.DataBody = lockEvent;
}
else
{
result.DataBody = msgAscii;
}
result.ReplyMsg = Common.replyMessage(msgType, msgArrays);
}
return JsonConvert.SerializeObject(result);
}
else
{
return null;
}
}
/// <summary>
/// WLNET5透传数据解析
/// </summary>
/// <param name="msgArrays"></param>
/// <param name="bytes"></param>
/// <returns></returns>
private static SensorData parserWLNET5(string [] msgArrays, byte[] inbytes)
{
byte[] bytes = Common.unescape(inbytes, inbytes.Length).ToArray();
if (bytes.Length > 30)
{
//透传数据之外的消息头长度
int headLength = string.Format("({0},{1},{2},{3},{4},{5},", msgArrays[0], msgArrays[1], msgArrays[2], msgArrays[3], msgArrays[4], msgArrays[5]).Length;
SensorData sensor = new SensorData();
byte[] wlnetBytes = new byte[bytes.Length - headLength];
//得到无限网关透传数据
wlnetBytes = bytes.Skip(headLength).Take(bytes.Length - headLength).ToArray();
//获取时间段,转成我们识别的"yyyy-MM-dd HH:mm:ss"格式
sensor.GpsTime = Common.GetDataTime(wlnetBytes.Skip(0).Take(6).ToArray());
//纬度信息解析
LatLon latLon = Common.GetLatLon(wlnetBytes.Skip(6).Take(9).ToArray());
sensor.Latitude = latLon.Latitude;//纬度
sensor.Longitude = latLon.Longitude;//经度
sensor.LocationType = latLon.LocationType;//定位状态
//解析速度
sensor.Speed = (int)(wlnetBytes[15]*1.85);
//解析方向
sensor.Direction = wlnetBytes[16] * 2;
sensor.DateTime = Common.GetDataTime(wlnetBytes.Skip(17).Take(6).ToArray());
sensor.SensorID = Common.ByteToHexStr(wlnetBytes.Skip(23).Take(5).ToArray());
sensor.Index = wlnetBytes[28];
sensor.Voltage = (Common.SwapUInt16(BitConverter.ToUInt16(wlnetBytes, 29)) / 100.0).ToString("f2");
sensor.Power = wlnetBytes[31];
sensor.RSSI = -wlnetBytes[32];
sensor.SensorType = wlnetBytes[33];
int fEventType = -1;
if (sensor.SensorType == 1)
{
sensor.Temperature = Common.SwapUInt16(BitConverter.ToUInt16(wlnetBytes, 34)) * 0.1;
sensor.Humidity = wlnetBytes[36];
}
else if (sensor.SensorType == 4)
{
fEventType = Common.SwapUInt16(BitConverter.ToUInt16(wlnetBytes, 34));
if ((fEventType & 0x0001) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_0;
}
else if ((fEventType & 0x0002) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_1;
}
else if ((fEventType & 0x0004) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_2;
}
else if ((fEventType & 0x0008) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_3;
}
else if ((fEventType & 0x0010) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_4;
}
else if ((fEventType & 0x0020) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_5;
}
else if ((fEventType & 0x0040) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_6;
}
else if ((fEventType & 0x0080) > 0)
{
fEventType = (int)EventTypeEnum.LockEvent_7;
}
else
{
fEventType = -1;
}
sensor.Event = fEventType;
sensor.LockRope = (Common.SwapUInt16(BitConverter.ToUInt16(wlnetBytes, 36)) & 0x0001);
sensor.LockStatus = sensor.LockRope;
sensor.LockTimes = Common.SwapUInt16(BitConverter.ToUInt16(wlnetBytes, 38));
}
return sensor;
}
else
{
return null;
}
}
/// <summary>
/// P45开关锁事件解析
/// </summary>
/// <param name="msgArrays"></param>
/// <returns></returns>
private static LockEvent parserP45(string[] msgArrays)
{
LockEvent model = new LockEvent();
model.DateTime= Common.GetDataTime(msgArrays[2] + msgArrays[3]);
model.Latitude = double.Parse(msgArrays[4]);
if (msgArrays[5].Equals("S"))
{
model.Latitude = -model.Latitude;
}
model.Longitude = double.Parse(msgArrays[6]);
if (msgArrays[7].Equals("W"))
{
model.Longitude = -model.Longitude;
}
model.LocationType= msgArrays[8].Equals("V") ? 0 : 1;
model.Speed= (int)double.Parse(msgArrays[9]);
model.Direction = int.Parse(msgArrays[10]);
model.Event = int.Parse(msgArrays[11]);
//开锁验证
int status= int.Parse(msgArrays[12]);
model.RFIDNo = msgArrays[13];
//动态密码开锁
if (model.Event == 6)
{
if (status == 0)
{
model.Status = 0;//开锁密码不正确
}
else if (status > 0 && status <= 10)
{
model.Status = 1;//正常开锁
model.UnlockFenceID = status;//围栏内开锁时候的围栏ID
}
else if (status == 98)
{
model.Status = 1;//正常开锁
}
else if (status == 99)
{
model.Status = 3;//设备开启了围栏内开锁,且当前开锁并未在围栏内,拒绝开锁
}
}
else if (model.Event == 4)
{
if (int.Parse(msgArrays[14]) == 0)
{
model.Status = 0;//开锁密码不正确
}
else
{
model.Status = 1;//正常开锁
}
}
model.PsdErrorTimes = int.Parse(msgArrays[15]);
model.Index = int.Parse(msgArrays[16]);
if (msgArrays.Length > 17)
{
model.Mileage = long.Parse(msgArrays[17]);
}
return model;
}
}
(2)工具类Common.cs
public static class Common
{
/// <summary>
/// 16进制格式字符串转字节数组
/// </summary>
/// <param name="hexString"></param>
/// <returns></returns>
public static byte[] HexStringToBytes(string hexString)
{
hexString = Regex.Replace(hexString, @".{2}", "$0 ");
//以 ' ' 分割字符串,并去掉空字符
string[] chars = hexString.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
byte[] returnBytes = new byte[chars.Length];
//逐个字符变为16进制字节数据
for (int i = 0; i < chars.Length; i++)
{
returnBytes[i] = Convert.ToByte(chars[i], 16);
}
return returnBytes;
}
/// <summary>
/// 合并数组
/// </summary>
/// <param name="bytes1"></param>
/// <param name="bytes2"></param>
/// <returns></returns>
public static byte[] CombineBytes(byte[] bytes1, byte[] bytes2)
{
List<byte> tmp = new List<byte>(bytes1.Length + bytes2.Length);
tmp.AddRange(bytes1);
tmp.AddRange(bytes2);
byte[] merged = tmp.ToArray();
return merged;
}
/// <summary>
/// 报告指定的 System.Byte[] 在此实例中的第一个匹配项的索引。
/// </summary>
/// <param name="srcBytes">被执行查找的 System.Byte[]。</param>
/// <param name="searchBytes">要查找的 System.Byte[]。</param>
/// <returns>如果找到该字节数组,则为 searchBytes 的索引位置;如果未找到该字节数组,则为 -1。如果 searchBytes 为 null 或者长度为0,则返回值为 -1。</returns>
public static int BytesIndexOf(byte[] srcBytes, byte searchBytes)
{
if (srcBytes == null) { return -1; }
if (srcBytes.Length == 0) { return -1; }
for (int i = 0; i < srcBytes.Length; i++)
{
if (srcBytes[i] == searchBytes)
{
return i;
}
}
return -1;
}
/// <summary>
/// 16进制字符串转ASCII
/// </summary>
/// <param name="Data"></param>
/// <param name="istrans"></param>
/// <returns></returns>
public static string HexStrToAsciiString(string Data, bool istrans)
{
if (istrans)
{
Data = Regex.Replace(Data, @"(?is)(?<=^([0-9a-f]{2})+)(?!$)", " ");
Data = Data.Replace("3D 11", "2C ").Replace("3D 14", "28 ").Replace("3D 15", "29 ").Replace("3D 00", "3D ").Replace(" ", "");
}
int count = Data.Length / 2;
string strContent = "";
char[] num = new char[count];
for (int i = 0; i < count; i++)
{
string str = Data.Substring(i * 2, 2);
byte by = Convert.ToByte(Convert.ToInt32(str, 16));
num[i] = Convert.ToChar(by);
strContent += num[i].ToString();
}
return strContent;
}
/// <summary>
/// 二进制转ASCII
/// </summary>
/// <param name="bt"></param>
/// <returns></returns>
public static string ByteToASCII(byte[] bt)
{
string lin = "";
for (int i = 0; i < bt.Length; i++)
{
lin = lin + bt[i] + " ";
}
string[] ss = lin.Trim().Split(new char[] { ' ' });
char[] c = new char[ss.Length];
int a;
for (int i = 0; i < c.Length; i++)
{
a = Convert.ToInt32(ss[i]);
c[i] = Convert.ToChar(a);
}
string b = new string(c);
return b;
}
/// <summary>
/// 应答回复
/// </summary>
/// <param name="msgType"></param>
/// <param name="strArry"></param>
/// <returns></returns>
public static string replyMessage(string msgType,string [] strArry)
{
string replyContent = string.Empty;
switch (msgType)
{
case "P22":
replyContent = string.Format("(P22,{0})", DateTime.UtcNow.ToString("ddMMyyHHmmss"));
break;
case "P43":
if (strArry[2].Equals("0"))
{
replyContent = string.Format("{0}", "P44,1,888888");//密码重置
}
break;
case "P45":
replyContent = string.Format("(P69,0,{0})", strArry[16]);
break;
case "P52":
if (strArry[2].Equals("2"))
{
replyContent = string.Format("(P52,2,{0})", strArry[3]);
}
break;
default:
break;
}
return replyContent;
}
/// <summary>
/// 应答回复
/// </summary>
/// <param name="msgType"></param>
/// <param name="index"></param>
/// <returns></returns>
public static string replyMessage(string msgType, int index)
{
string replyContent = string.Empty;
switch (msgType)
{
case "WLNET5":
case "WLNET7":
replyContent = string.Format("(P69,0,{0})", index);
break;
default:
break;
}
return replyContent;
}
/// <summary>
/// 时间格式转换
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static DateTime GetDataTime(byte[] bytes)
{
return DateTime.ParseExact(ByteToHexStr(bytes), "ddMMyyHHmmss", System.Globalization.CultureInfo.CurrentCulture);
}
public static DateTime GetDataTime(string strdate)
{
return DateTime.ParseExact(strdate, "ddMMyyHHmmss", System.Globalization.CultureInfo.CurrentCulture);
}
/// <summary>
/// 字节数组转16进制字符串
/// </summary>
/// <param name="byteDatas"></param>
/// <returns></returns>
public static string ByteToHexStr(byte[] byteDatas)
{
StringBuilder builder = new StringBuilder();
for (int i = 0; i < byteDatas.Length; i++)
{
builder.Append(string.Format("{0:X2}", byteDatas[i]));
}
return builder.ToString().Trim();
}
public static LatLon GetLatLon(byte[] bytes)
{
try
{
LatLon model = new LatLon();
model.Latitude = GetLatLong60(bytes.Skip(0).Take(4).ToArray());
model.Longitude = GetLatLong60(bytes.Skip(4).Take(5).ToArray());
model.LocationType = bytes[8] & 0x01;
if ((bytes[8] & 0x02) == 0)
{
model.Latitude = -model.Latitude;
}
if ((bytes[8] & 0x04) == 0)
{
model.Longitude = -model.Longitude;
}
return model;
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 经纬度计算
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static double GetLatLong60(byte[] bytes)
{
try
{
string locStr = ByteToHexStr(bytes);
if (locStr.Length < 9)
{
locStr = locStr.PadLeft(9, '0');
}
else
{
locStr = locStr.Substring(0, 9);
}
var head = Convert.ToDouble(locStr.Remove(3));
var bodyStr = locStr.Substring(3, locStr.Length - 3);
var body = Convert.ToDouble(bodyStr) / 10000;
head += body / 60;
return head;
}
catch (Exception ex)
{
return 0;
}
}
public static ushort SwapUInt16(ushort v)
{
return (ushort)(((v & 0xff) << 8) | ((v >> 8) & 0xff));
}
public static uint SwapUInt32(uint v)
{
return (uint)(((SwapUInt16((ushort)v) & 0xffff) << 0x10) |
(SwapUInt16((ushort)(v >> 0x10)) & 0xffff));
}
/// <summary>
/// 获取设备状态
/// </summary>
/// <param name="bytes"></param>
/// <returns></returns>
public static DeviceStatus GetDeviceStatus(byte[] bytes, int locationType)
{
try
{
DeviceStatus model = new DeviceStatus();
//低8位
if (locationType == 0)
{
model.LocationType = bytes[0] & 0x01;
}
else
{
model.LocationType = locationType;
}
if ((bytes[1] & 0x02)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_9;
}
if ((bytes[1] & 0x04)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_10;
}
if ((bytes[1] & 0x08)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_1;
}
if ((bytes[1] & 0x10)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_2;
}
else
{
model.Alarm = -1;
}
model.LockRope = (bytes[1] & 0x40) > 0 ? 0 : 1;
model.LockStatus = (bytes[1] & 0x80) > 0 ? 0 : 1;
//高8位
if ((bytes[0] & 0x01)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_3;
}
if ((bytes[0] & 0x02)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_4;
}
if ((bytes[0] & 0x04)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_5;
}
if ((bytes[0] & 0x08)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_6;
}
if ((bytes[0] & 0x10)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_7;
}
model.BackCover = (bytes[1] & 0x20) > 0 ? 1 : 0;
if ((bytes[0] & 0x40)>0)
{
model.Alarm = (int)AlarmTypeEnum.LOCK_ALARM_8;
}
return model;
}
catch (Exception ex)
{
return null;
}
}
/// <summary>
/// 转义
/// </summary>
/// <param name="inBytes"></param>
/// <param name="bodyLen"></param>
/// <returns></returns>
public static List<byte> unescape(byte[] inBytes, int bodyLen)
{
List<byte> list = new List<byte>();
int i = 0;
while (i < bodyLen)
{
int b = inBytes[i];
if (b == 0x3D)
{
int nextByte = inBytes[i+1]; ;
if (nextByte == 0x14)
{
list.Add(0x3D ^ 0x14);
}
else if (nextByte == 0x15)
{
list.Add(0x3D ^ 0x15);
}
else if (nextByte == 0x00)
{
list.Add(0x3D ^ 0x00);
}
else if (nextByte == 0x11)
{
list.Add(0x3D ^ 0x11);
}
else
{
list.Add(BitConverter.GetBytes(b)[0]);
list.Add(BitConverter.GetBytes(nextByte)[0]);
}
i += 2;
}
else
{
list.Add(BitConverter.GetBytes(b)[0]);
i++;
}
}
return list;
}
}
2.4.返回消息及说明
(1)定位数据
原始数据:
2480405002251911003426032118530329532416031008941d0000000018070c0000000020e04f8b0c56001f00020f0f0f0f0f0f0f0f0f0f00f2028f0157
返回消息:
{
"DeviceID": "8040500225",
"MsgType": "Location",
"DataBody": {
"ProtocolType": 25,
"DeviceType": 1,
"DataType": 1,
"DataLength": 52,
"GpsTime": "2021-03-26T18:53:03",
"Latitude": -29.88736,
"Longitude": 31.014901666666667,
"LocationType": 1,
"Speed": 0,
"Direction": 0,
"Mileage": 6151,
"GpsSignal": 12,
"GSMSignal": 31,
"Alarm": -1,
"AlarmArea": 0,
"Battery": 79,
"LockStatus": 0,
"LockRope": 0,
"BackCover": 1,
"MCC": 655,
"MNC": 1,
"LAC": 22016,
"CELLID": 15895308,
"IMEI": "0F0F0F0F0F0F0F0F",
"Awaken": 2,
"Index": 87
},
"ReplyMsg": "(P69,0,87)"
}
返回消息描述
{
"DeviceID":设备ID
"MsgType":消息类型, 此处为: Location,表示定位数据,
"DataBody":消息体内容
{
"ProtocolType": 协议版本号,
"DeviceType": 终端类型号,
"DataType": 数据类型号( 1 表明最新二进制定位数据, 2 表示报警数据, 3 表示盲区常规二进制定位数据, 4 表示次新二进制定位数据),
"DataLength": 数据长度,
"GpsTime": 定位时间( GMT时间),
"Latitude": 纬度(dd.dddd格式),
"Longitude": 经度(dd.dddd格式),
"LocationType": 定位类型( 0: 不定位; 1: GPS定位; 2: 基站定位),
"Speed": 速度( 单位: km / h),
"Direction": 方向( 0~360; 0 与360表示正北方向),
"Mileage": 当前里程值(单位:km),
"GpsSignal": GPS卫星个数,
"GSMSignal": GSM信号值,
"Alarm": 报警类型( - 1: 无告警信息; 1: 锁绳剪断; 2: 震动; 3: 长时间开锁; 4: 开锁密码连续5次错误; 5: 刷非法卡; 6: 低电量; 7: 开后盖; 8: 卡锁; 9: 进区域报警; 10: 出区域报警),
"AlarmArea": 如果告警与区域有关, 则此处值为区域的ID,
"Battery": 电量值( 0~100; 255: 充电中),
"LockStatus": 锁电机状态( 1: 开; 0: 关),
"LockRope": 锁绳状态( 1: 拔出; 0: 插入),
"BackCover": 后盖状态( 1: 关闭; 0: 开启),
"MCC": 国家代码,
"MNC": 运营商代码,
"LAC": 位置区域码,
"CELLID": 基站编号,
"IMEI": IMEI号码, 全是0F无效,
"Awaken": 唤醒源( 0 重启,
1: RTC唤醒, 2: 震动, 3: 开后盖, 4: 锁绳, 5: 接外电, 6: 刷卡, 7: 门磁, 8: VIP短信, 9: 非VIP短信或垃圾短信),
"Index": 数据流水号
},
"ReplyMsg":回复内容( 如果为空字符串, 则不需要给终端回复内容)
}
(2)传感器采集数据(WLNET5)
原始数据(SensorType=1):
28383035303530303037332c312c3134312c574c4e45542c352c322c260321184709649672953949673d1408ff002603211847181020110986660133623c0100d71b00000029
返回消息(SensorType=1):
{
"DeviceID": "8050500073",
"MsgType": "WLNET5",
"DataBody": {
"GpsTime": "2021-03-26T18:47:09",
"Latitude": -65.612158333333326,
"Longitude": -395.61215,
"LocationType": 0,
"Speed": 471,
"Direction": 0,
"SensorID": "1020110986",
"LockStatus": 0,
"LockRope": 0,
"LockTimes": 0,
"Index": 102,
"Voltage": "3.07",
"Power": 98,
"RSSI": -60,
"DateTime": "2021-03-26T18:47:18",
"SensorType": 1,
"Temperature": 21.5,
"Humidity": 27,
"Event": -1
},
"ReplyMsg": "(P69,0,102)"
}
原始数据(SensorType=4):
28373030303331333330392C312C3038312C574C4E45542C352C322C05082115430722348250113550300F0000050821154304E0171E086925018D4E690400400000002A0029
返回消息(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)"
}
返回消息描述
{
"DeviceID": 设备ID,
"MsgType": 消息类型, 此处为: WLNET5,表示传感器透传数据,
"DataBody": 消息体内容
{
"GpsTime": 定位时间(GMT时间),
"Latitude": 纬度(dd.dddd格式),
"Longitude": 经度(dd.dddd格式),
"LocationType": 定位类型( 0: 不定位; 1: GPS定位; 2: 基站定位),
"Speed": 速度( 单位: km / h);0xFF表示速度无效,
"Direction": 方向( 0~360; 0 与360表示正北方向),
"SensorID": 传感器ID,
"LockStatus": 如果从机类型SensorType=4,此是才有效;1:开锁;0:关锁,
"LockRope": 如果从机类型SensorType=4,此是才有效;1:锁绳拔出;0:锁绳插入,
"LockTimes": 开锁次数(如果SensorType=4此值才有效),
"Index": 数据流水号,
"Voltage": 电压值(单位:V),
"Power": 传感器电量(0~100;255: 充电中),
"RSSI": RSSI信号强度,是负数越接近0信号越好,
"DateTime": 数据采集时间(GMT时间),
"SensorType": 传感器类型(1:温湿度传感器(JT126);4:从机JT709;),
"Temperature":温度值(如果SensorType=1此值才有效),
"Humidity": 湿度值(如果SensorType=1此值才有效),
"Event": 事件类型(-1:无从机事件;0:关锁事件;1:蓝牙开锁事件;2:NFC开锁事件;3:Lora开锁事件;4:从机锁剪断报警事件;5:按键唤醒事件;6:定时上报事件;7:充电上报事件)
},
"ReplyMsg": 回复内容(如果为空字符串,则不需要给终端回复内容)
}
(3)锁事件上报数据(P45)
原始数据:
28373839303632393238342c5034352c3236303332312c3139343933392c32362e3237323033352c4e2c35302e3632313433352c452c412c302e30352c302c342c312c303030303030303030302c312c302c3129
返回消息:
{
"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)"
}
返回消息描述:
{
"DeviceID": 设备ID,
"MsgType": 消息类型, 此处为: P45,表示开关锁事件数据上传,
"DataBody": 消息体内容
{
"DateTime": 事件时间(GMT时间),
"Latitude": 纬度(dd.dddd格式),
"Longitude": 经度(dd.dddd格式),
"LocationType": 定位类型( 0: 不定位; 1: GPS定位; 2: 基站定位),
"Speed": 速度( 单位: km / h),
"Direction": 方向( 0~360; 0 与360表示正北方向),
"Event": 事件类型(1:表示刷授权卡;2:表示刷非法卡;3:表示刷车辆ID卡绑定;4:表示为凭密码开锁;5:表示终端自动关锁记录;6: 动态密码围栏内开锁;7: 蓝牙开锁),
"Status": 开锁验证(0:开锁密码不正确;1:正常开锁;2:因为开启了围栏开锁,未在围栏内开锁,开锁被拒绝),
"UnlockFenceID": (-1:开锁与围栏无关;1~10:标识对应的开锁围栏ID),
"RFIDNo": 刷卡卡号;如果未“0000000000”,则无效,
"PsdErrorTimes": 开锁密码错误次数,
"Index": 数据流水号,
"Mileage": 当前里程值(单位:km)
},
"ReplyMsg": 回复内容(如果为空字符串,则不需要给终端回复内容)
}
(4)其他指令回复数据
原始数据:
28373839303632393238342c50333529
返回消息:
{
"DeviceID": "7890629284",
"MsgType": "P35",
"DataBody": "(7890629284,P35)",
"ReplyMsg": ""
}
返回消息描述:
{
"DeviceID": 设备ID,
"MsgType": 消息类型(参见更多的消息类型及其描述,请参阅3.消息类型及消息体内容描述),
"DataBody": 消息体内容(除定位数据:Location;传感器透传数据:WLNET5;锁事件上报:P45外;其他此处均直接返回指令内容的ASCII字符串),
"ReplyMsg": 回复内容(如果为空字符串,则不需要给终端回复内容)
}
3.消息类型及消息体内容描述
3.1.P01:查询终端当前的版本号
消息体内容:(示例)(7591225008,P01,JT701D_20200720_China_Jointech_SIM7600,77%)
消息体内容描述:7591225008:设备ID
P01:消息类型
JT701D_20200720_China_Jointech_SIM7600:协议版本
77%:当前设备电量
P03:低电休眠控制
消息体内容:(示例)(7560704001,P03,1,30)
消息体描述:7560704001:设备ID
P03:消息类型
1:生效;0:不生效
30:设置电量低于30的时候进入休眠,默认31%,可设定范围5%~90%
P04:设置/查询数据上传间隔和休眠自动唤醒间隔
消息体内容:(示例)(7570101998,P04,30,30)
消息体描述:7570101998:设备ID
P04:消息类型
30:数据上传间隔,单位秒钟,默认30秒,取值范围5-600
30:休眠自动唤醒间隔,单位分钟,默认30分钟,取值范围30-1440
P06:设置/查询监控中心IP与端口、APN
消息体内容:(示例)(7570101998,P06,211.162.111.225,10906,CMNET,user,password,1)
消息体描述:7570101998:设备ID
P06:消息类型
211.162.111.225:监控中心的IP地址
10906:监控中心端口地址,最大65530
CMNET:接入点名称(最长50个字节)
User:APN用户名(最长50个字节)
Password:APN密码(最长50个字节)
1:0表示卡1,1表示卡2
P10:设置/查询终端使用地点与国际标准时间的时差
消息体内容:(示例)(7570101998,P10,480)
消息体描述:7570101998:设备ID
P10:消息类型
480:时差值,以分钟为单位.如北京时间与标准时时差为8小时,即为480分钟,取值范围-12*60-13*60,默认0
P11:设置/查询VIP手机号码
消息体内容:(示例)(7570101998,P11,1,8613910102345)
消息体描述:7570101998:设备ID
P11:消息类型
1:VIP手机号码索引,取值为1-5,允许有五组VIP手机号码
8613910102345:手机号码,不能超过15位数字,前面需加国际区号,中国为86或者+86.
P12:设置/查询VIP号码是否允许报警
消息体内容:(示例)(7570101998,P12,1,1,1,1,1)
消息体描述:7570101998:设备ID
P12:消息类型
1,1,1,1,1:分别对应5个VIP号码是否允许报警;1表示允许对应的VIP号码报警,0表示不允许此VIP号码报警
P13:恢复出厂设置
消息体内容:(示例)(7570101998,P13)
消息体描述:7570101998:设备ID
P13:消息类型
P14:读取终端的IMEI号
消息体内容:(示例)(7570101998,P14,012207004451636)
消息体描述:7570101998:设备ID
P14:消息类型
012207004451636:终端的IMEI号
P15:终端重启指令
消息体内容:(示例)(7570101998,P15)
消息体描述:7570101998:设备ID
P15:消息类型
P22:GPS无效的时候,监控中心对终端授时
消息体内容:(示例)(7570101998,P22,1)
消息体描述:7570101998:设备ID
P22:消息类型
1:1表示授时成功,0表示失败,2表示主动请求授时
P22:设置/取消短信、电话可唤醒工作模式
消息体内容:(示例)(7570101998,P23,1)
消息体描述:7570101998:设备ID
P23:消息类型
1:1表示设置成功,0表示设置失败.
P24:区域是否有效,及区域名称设置指令
消息体内容:(示例)(7570101998,P24,10,1,area10)
消息体描述:7570101998:设备ID
P24:消息类型
10:表示第10个区域.
1:表示有效 ,0表示无效
area10:表示区域名称,最大长度为16个字节.
P29:设置或者查询区域的详细节点信息
消息体内容:(示例)(7570101998,P29,8,15,1,10,11323.1234…)
消息体描述:7570101998:设备ID
P29:消息类型
8:表示第八个区域
15:表示总点数
1:表示当前页
10:表示当前页的点数.余下的为各个点的经度与纬度
P30:清除相关的区域
消息体内容:(示例)(7570101998,P30,1)
消息体描述:7570101998:设备ID
P30:消息类型
1:1表示清除成功,0表示清除失败.
P31:区域信息设置完毕
消息体内容:(示例)(7570101998,P31)
消息体描述:7570101998:设备ID
P31:消息类型
P32:主动进入休眠指令
消息体内容:(示例)(7570101998,P32)
消息体描述:7570101998:设备ID
P32:消息类型
P37:查询/设置G-sensor相关参数
消息体内容:(示例)(7570101998,P37,500)
消息体描述:7570101998:设备ID
P37:消息类型
500:运动检测门限值,范围是63到500,单位是mg;如果设置为0则为关闭G-sensor相关全部功能;关闭G-sensor功能后,如需重新开启G-sensor功能只需重新设置有效的G-sensor参数即可.默认值126
P38:开锁报警时间间隔设置指令
消息体内容:(示例)(7570101998,P38,120)
消息体描述:7570101998:设备ID
P38:消息类型
120:开锁报警时间间隔设置,即从锁电机处于开锁状态时刻算起,如果该状态持续保持超过120分钟,则可触发开锁报警,范围是3到180,单位是分钟;默认为120分钟.
P40:查询/设置GPRS通道和短消息通道的报警开关
消息体内容:(示例)(7570101998,P40,1,1,1,1,1,1,1,1,1,1,1)
消息体描述:7570101998:设备ID
P40:消息类型
1,1,1,1,1,1,1,1,1,1,1:从左至右依次为锁挂绳剪断报警、刷非法卡报警、开锁状态保持一段时间报警、指令开锁密码连续输错5次报警、震动报警、进区域报警、出区域报警的开关、低电报警、开后盖报警、卡锁报警;每个报警开关参数可以取值为0,1,2,3,并且可以任意组合,0表示GPRS和SMS报警都关闭,1表示只开启GPRS报警,2表示只开启SMS报警,3表示GPRS和SMS报警都开启.
P41:增删开锁授权号指令
消息体内容:(示例1)(7570101998,P41,1,30)
消息体描述:7570101998:设备ID
P41:消息类型
1:1表示增加授权卡号操作;2表示删除授权号,3表示删除所有的授权号
30:30表示当前已存授权卡号总个数;
消息体内容:(示例2)(7570101998,P41,2,3,0013953759, 0013953758, 0013953757)
消息体描述:7570101998:设备ID
P41:消息类型
2:查询第2组数据;一共分3组,分别为1~3,查询时每次最多返回20个ID号
3:3表示有3个ID号
0013953759, 0013953758, 0013953757表示该组存储的授权号列表
P42:现场刷卡授权模式配置指令
消息体内容:(示例1)(7570101998,P42,0)
消息体描述:7570101998:设备ID
P42:消息类型
1:1表示打开批量增加终端开锁授权号功能, 0表示关闭批量增加终端开锁授权号功能。
消息体内容:(示例2)(7570101998,P41,2,0013953759,0013953751)
消息体描述:7570101998:设备ID
P42:消息类型
2:表示终端已存了2个开锁授权号.
0013953759,0013953751:授权卡号.
P44:远程开锁密码修改指令
消息体内容:(示例1)(7570101998,P44,1)
消息体描述:7570101998:设备ID
P44:消息类型
1:1:表示修改密码是否成功,1表示成功,0表示失败。
消息体内容:(示例2)(7570101998,P44,888888)
消息体描述:7570101998:设备ID
P44:消息类型
888888:当前的设备可开锁的动态密码
P50:电源开关生效控制设置
消息体内容:(示例)(7570101998,P50,1)
消息体描述:7570101998:设备ID
P44:消息类型
1:1表示开关有效,默认是1;0表示停用开关.
P52:动态密码指令
消息体内容:(示例1)(7570101998,P52,0,405935,326387)
消息体描述:7570101998:设备ID
P52:消息类型
0:指令操作;查询当前产生的动态密码和当前用来开锁的动态密码
405935:表示,还没有被系统确认的动态密码
326387:表示目前用来开锁的动态密码
消息体内容:(示例2)(7570101998,P52,1,1,0)
消息体描述:7570101998:设备ID
P52:消息类型
1:1表示设置动态密码功能
1:1查询是否开启动态密码功能;0:表示关闭动态密码功能
0:1表示动态密码开锁必须在区域内才能开锁,即表明如果想要开锁,必须设置区域,0表示动态密码开锁跟区域无关,只要符合动态密码开锁的其它条件就可以开锁
消息体内容:(示例3)(7570101998,P52,2,405935)
消息体描述:7570101998:设备ID
P52:消息类型
2:回复上传的动态密码确认指令
405935:需要被确认的动态密码
消息体内容:(示例4)(7570101998,P52,3,1,0)
消息体描述:7570101998:设备ID
P52:消息类型
3:发送动态密码开锁
1:1,代表成功,0是失败
0:代表失败次数
P54:查询/设置是否关闭休眠模式指令(设备不休眠)
消息体内容:(示例)(7570101998,P54,0,0)
消息体描述:7570101998:设备ID
P54:消息类型
0:0 查询;1 设置
0:0 需要休眠 , 1 开启不休眠
P58:查询和设置RFID卡是否关联电子围栏 (默认关联电子围栏)
消息体内容:(示例)(7570101998,P58,1,1)
消息体描述:7570101998:设备ID
P58:消息类型
1:1表示设置,0表示查询
1:1:关联电子围栏,必须在区域内才能刷卡开锁;0表示刷卡开锁跟区域无关,只要符刷卡开锁的条件就可以开锁
P61:设置或查询电量低报警提示的阀值
消息体内容:(示例)(7570101998,P61,30)
消息体描述:7570101998:设备ID
P61:消息类型
30:当前阀值
P62:设置或查询里程统计相关参数
消息体内容:(示例)(7570101998,P62,1,10)
消息体描述:7570101998:设备ID
P62:消息类型
1:操作参数类型;1:设置一个速度值,低于这个速度里程不会统计;2:同步当前设备里程值
10:当操作参数类型为1,此时为速度值,单位km/h;当操作参数类型为2,此时为里程值,单位km
P63:静态飘移处理功能设置
消息体内容:(示例)(7570101998,P63,1)
消息体描述:7570101998:设备ID
P63:消息类型
1:1开启,0关闭(默认)
P68:查询SIM卡的IMSI/ICCID号
消息体内容:(示例)(7570101998,P65,2,898600220909A0206023)
消息体描述:7570101998:设备ID
P65:消息类型
2:1:查询IMSI, 2:查询ICCID
898600220909A0206023:SIM卡的IMSI/ICCID号
P70:启用/关闭VIP号码功能
消息体内容:(示例)(7570101998,P70,1)
消息体描述:7570101998:设备ID
P70:消息类型
1:0:关闭状态;1:开启状态
WLNET1:查询/设置要监听的从机设备ID号
消息体内容:(示例)(700160818000,1,001,WLNET,1,20,0217270000,,,,,,,,,)
消息体描述:700160818000:设备ID
WLNET,1:组合消息类型WLNET1
20:表示当前配置20个从机设备ID号,如果为配置0个ID号表示清除所有配置的ID号
0217270000,,,,,,,,,:从机ID号
WLNET2:查询/设置从机工作时间间隔
消息体内容:(示例)(700160818000,1,001,WLNET,2,20)
消息体描述:700160818000:设备ID
WLNET,2:组合消息类型WLNET2
20:20:从机工作时间间隔为20分钟,单位分钟,最小1分钟,最大1440一天,默认5分钟
WLNET3:查询/设置从机发送功率
消息体内容:(示例)(700160818000,1,001,WLNET,3,2)
消息体描述:700160818000:设备ID
WLNET,3:组合消息类型WLNET3
2:从机从机发送功率,1~3分别是低中高三个发送功率模式,默认是1低功率
WLNET4:查询/设置从机发送功率
消息体内容:(示例)(700160818000,1,001,WLNET,4,170828,170829)
消息体描述:700160818000:设备ID
WLNET,4:组合消息类型WLNET4
170828:网关版本
170829:传感器的软件版本
WLNET6:查询/设置从机温度门限参数
消息体内容:(示例)(700160818000,1,001,WLNET,6,1,2,10,120,30,15,12)
消息体描述:700160818000:设备ID
WLNET,6:组合消息类型WLNET6
1:指令功能:0表示查询;1:表示设置
2:参数类型:1表示温度相关参数,2表示设置数据上传方式
10:低温门限值:默认0值无效,温度以1度为单位10~175有效,-40~125度,门限值 – 50 = 实际值,如10- 50 = -40℃。
120:高温门限值:默认0值无效,温度以1度为单位10~175有效,-40~125度,门限值 – 50 = 实际值,如120- 50 = 70℃
30:温度变化时间值:多长时间内温度变化多少的时间值,单位分钟,默认0值无效,一般20~60参考值,最大240,4小时
15:温度变化值:默认0值无效,15表示1.5度,最大250、25度,也就是如30分钟内变化1.5度就报警
12:每天定点上传多少个点:默认0值当前一个点,12表示每天12个点2小时一个点,最多24个点,一般12或24个点参考值