Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update FlexApiProtocolDecoder #4829

Open
wants to merge 33 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
6bcf572
fix: 4g network rsrp has higher priority than rssi.
Mar 10, 2022
e7ca53d
Merge pull request #1 from jackymlr/inVG
jackymlr Mar 10, 2022
58cc814
fix: 4g network rsrp has higher priority than rssi.
Mar 10, 2022
a420350
Merge pull request #2 from jackymlr/inVG
jackymlr Mar 10, 2022
cacefc2
fix: 4g network rsrp has higher priority than rssi base 4.15.
Mar 11, 2022
8494949
feat: payload some attribute may be null.
Mar 17, 2022
5b4874b
feat: payload some attribute may be null.
Mar 22, 2022
c2239f7
feat: update start log
Mar 22, 2022
42285a7
Merge branch 'traccar:master' into master
jackymlr Mar 29, 2022
d205a22
chore: remove debug log.
Mar 29, 2022
b0581da
Merge branch 'master' into 4.15.1
jackymlr Mar 29, 2022
0a4de58
Merge pull request #3 from jackymlr/4.15.1
jackymlr Mar 29, 2022
94b8e5a
chore: format code.
Mar 29, 2022
846efb0
Update Main.java
jackymlr Mar 29, 2022
dbdcd67
Update FlexApiProtocolDecoderTest.java
jackymlr Mar 29, 2022
467c804
chore: replace optional with if.
Apr 28, 2022
81008b6
chore: replace optional with if.
Apr 28, 2022
24e78de
Merge branch 'traccar:master' into master
jackymlr Apr 28, 2022
460da9d
chore: replace optional with if.
May 12, 2022
f4290ac
chore: parse summary.
May 18, 2022
065145a
chore: add if.
May 18, 2022
5248ba9
chore: add test.
May 18, 2022
bb186c6
chore: fix npe.
May 20, 2022
c0e678a
chore: add try catch.
May 27, 2022
582977c
chore: merge master.
May 30, 2022
6858521
Merge branch 'traccar:master' into master
jackymlr May 30, 2022
cc93199
chore: merge master.
May 30, 2022
c83deec
Merge branch 'master' into 4.15.1
jackymlr May 30, 2022
91f9639
Merge pull request #4 from jackymlr/4.15.1
jackymlr May 30, 2022
ab0ddca
chore: format code.
May 30, 2022
d584363
Update Main.java
jackymlr May 30, 2022
cae8be8
valid message completed
jackymlr Jun 29, 2023
10c3162
chore: change ts to ul_ts.
Jun 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
290 changes: 200 additions & 90 deletions src/main/java/org/traccar/protocol/FlexApiProtocolDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,60 +38,164 @@ public FlexApiProtocolDecoder(Protocol protocol) {
@Override
protected Object decode(
Channel channel, SocketAddress remoteAddress, Object msg) throws Exception {

String message = (String) msg;
JsonObject root = Json.createReader(new StringReader(message.substring(1, message.length() - 2))).readObject();

String topic = root.getString("topic");
String clientId = topic.substring(3, topic.indexOf('/', 3));
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, clientId);
if (deviceSession == null) {
return null;
}

Position position = new Position(getProtocolName());
position.setDeviceId(deviceSession.getDeviceId());

JsonObject payload = root.getJsonObject("payload");
try {

if (topic.contains("/gnss/")) {

position.setValid(true);
var completed = message.startsWith("$") && message.length() > 3 && message.charAt(message.length() - 3) == '}';
if (!completed) {
return null;
}
JsonObject root = Json.createReader(new StringReader(message.substring(1, message.length() - 2))).readObject();
String topic = root.getString("topic");
String clientId = topic.substring(3, topic.indexOf('/', 3));
DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, clientId);
if (deviceSession == null) {
return null;
}

if (payload.containsKey("time")) {
position.setTime(new Date(payload.getInt("time") * 1000L));
position.setLatitude(payload.getJsonNumber("lat").doubleValue());
position.setLongitude(payload.getJsonNumber("log").doubleValue());
} else {
position.setTime(new Date(payload.getInt("gnss.ts") * 1000L));
position.setLatitude(payload.getJsonNumber("gnss.latitude").doubleValue());
position.setLongitude(payload.getJsonNumber("gnss.longitude").doubleValue());
Position position = new Position(getProtocolName());
getLastLocation(position, new Date());
position.set(Position.KEY_ORIGINAL, message);
position.setTime(new Date());
position.setDeviceId(deviceSession.getDeviceId());

JsonObject payload = root.getJsonObject("payload");

if (topic.contains("/gnss/")) {
if (payload.containsKey("time")) {
getLastLocation(position, new Date(payload.getInt("time") * 1000L));
position.setTime(new Date(payload.getInt("time") * 1000L));
} else {
getLastLocation(position, new Date(payload.getInt("gnss.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("gnss.ul_ts") * 1000L));
}
parseGnss(position, payload);
} else if (topic.contains("/cellular1/")) {
if (payload.containsKey("modem1.ul_ts")) {
getLastLocation(position, new Date(payload.getInt("modem1.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("modem1.ul_ts") * 1000L));
}
parseCellular(position, payload);
} else if (topic.contains("/obd/")) {
if (payload.containsKey("obd.ul_ts")) {
getLastLocation(position, new Date(payload.getInt("obd.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("obd.ul_ts") * 1000L));
}
parseObd(position, payload);
} else if (topic.contains("/motion/")) {
if (payload.containsKey("motion.ul_ts")) {
getLastLocation(position, new Date(payload.getInt("motion.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("motion.ul_ts") * 1000L));
}
parseMotion(position, payload);
} else if (topic.contains("/io/")) {
if (payload.containsKey("io.ul_ts")) {
getLastLocation(position, new Date(payload.getInt("io.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("io.ul_ts") * 1000L));
}
parseIO(position, payload);

} else if (topic.contains("/sysinfo/")) {

getLastLocation(position, new Date(payload.getInt("sysinfo.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("sysinfo.ul_ts") * 1000L));
position.set("serial", payload.getString("sysinfo.serial_number"));
position.set(Position.KEY_VERSION_FW, payload.getString("sysinfo.firmware_version"));

} else if (topic.contains("/summary/")) {
getLastLocation(position, new Date(payload.getInt("summary.ul_ts") * 1000L));
position.setTime(new Date(payload.getInt("summary.ul_ts") * 1000L));
parseIO(position, payload);
parseObd(position, payload);
parseCellular(position, payload);
parseMotion(position, payload);
parseGnss(position, payload);

} else if (topic.contains("/event/notice")) {
getLastLocation(position, new Date(payload.getInt("starts_at") * 1000L));
position.setTime(new Date(payload.getInt("starts_at") * 1000L));
parseIO(position, payload);
parseObd(position, payload);
parseMotion(position, payload);
parseGnss(position, payload);
parseEvent(position, payload);
}
return position;
} catch (Exception e) {

position.setValid(payload.getInt("gnss.fix") > 0);
position.setAltitude(payload.getJsonNumber("gnss.altitude").doubleValue());
position.setSpeed(payload.getJsonNumber("gnss.speed").doubleValue());
position.setCourse(payload.getJsonNumber("gnss.heading").doubleValue());
e.printStackTrace();
}
Position position = new Position(getProtocolName());
getLastLocation(position, new Date());
position.set(Position.KEY_ORIGINAL, message);
position.setTime(new Date());
position.setValid(false);
return position;
}

position.set(Position.KEY_SATELLITES, payload.getInt("gnss.num_sv"));
position.set(Position.KEY_HDOP, payload.getJsonNumber("gnss.hdop").doubleValue());

} else if (topic.contains("/cellular1/")) {
private void parseEvent(Position position, JsonObject payload) {
if (payload.containsKey("type")) {
if ("IGON".equals(payload.getString("type"))) {
position.set(Position.KEY_IGNITION, true);
} else if ("IGOFF".equals(payload.getString("type"))) {
position.set(Position.KEY_IGNITION, false);
}
}
}

getLastLocation(position, new Date(payload.getInt("modem1.ts") * 1000L));
private void parseMotion(Position position, JsonObject payload) {
if (payload.containsKey("motion.ax")) {
position.set("ax", payload.getJsonNumber("motion.ax").doubleValue());
}
if (payload.containsKey("motion.ay")) {
position.set("ay", payload.getJsonNumber("motion.ay").doubleValue());
}
if (payload.containsKey("motion.az")) {
position.set("az", payload.getJsonNumber("motion.az").doubleValue());
}
if (payload.containsKey("motion.gx")) {
position.set("gx", payload.getJsonNumber("motion.gx").doubleValue());
}
if (payload.containsKey("motion.gy")) {
position.set("gy", payload.getJsonNumber("motion.gy").doubleValue());
}
if (payload.containsKey("motion.gz")) {
position.set("gz", payload.getJsonNumber("motion.gz").doubleValue());
}
}

position.set("imei", payload.getString("modem1.imei"));
position.set("imsi", payload.getString("modem1.imsi"));
private void parseCellular(Position position, JsonObject payload) {
if (payload.containsKey("modem1.imei")) {
position.set("IMEI", payload.getString("modem1.imei"));
}
if (payload.containsKey("modem1.rssi")) {
position.set(Position.KEY_RSSI, payload.getInt("modem1.rssi"));
}
if (payload.containsKey("modem1.imsi")) {
position.set("IMSI", payload.getString("modem1.imsi"));
}
if (payload.containsKey("modem1.iccid")) {
position.set(Position.KEY_ICCID, payload.getString("modem1.iccid"));
}


if (payload.containsKey("modem1.operator")) {
String operator = payload.getString("modem1.operator");
if (!operator.isEmpty()) {
CellTower cellTower = CellTower.from(
Integer.parseInt(operator.substring(0, 3)),
Integer.parseInt(operator.substring(3)),
Integer.parseInt(payload.getString("modem1.lac"), 16),
Integer.parseInt(payload.getString("modem1.cell_id"), 16),
payload.getInt("modem1.rssi"));
Integer.parseInt(payload.getString("modem1.cell_id"), 16));

if (payload.containsKey("modem1.rsrp")) {
cellTower.setSignalStrength(payload.getInt("modem1.rsrp"));
}
if (payload.containsKey("modem1.rssi")) {
cellTower.setSignalStrength(payload.getInt("modem1.rssi"));
}

switch (payload.getInt("modem1.network")) {
case 1:
cellTower.setRadioType("gsm");
Expand All @@ -107,67 +211,73 @@ protected Object decode(
}
position.setNetwork(new Network(cellTower));
}
}

} else if (topic.contains("/obd/")) {

getLastLocation(position, new Date(payload.getInt("obd.ts") * 1000L));

if (payload.containsKey("obd.speed")) {
position.set(Position.KEY_OBD_SPEED, payload.getJsonNumber("obd.speed").doubleValue());
}
if (payload.containsKey("obd.odo")) {
position.set(Position.KEY_OBD_ODOMETER, payload.getInt("obd.odo"));
}
if (payload.containsKey("obd.rpm")) {
position.set(Position.KEY_RPM, payload.getInt("obd.rpm"));
}
if (payload.containsKey("obd.vin")) {
position.set(Position.KEY_VIN, payload.getString("obd.vin"));
}

} else if (topic.contains("/motion/")) {

getLastLocation(position, new Date(payload.getInt("motion.ts") * 1000L));

position.set("ax", payload.getJsonNumber("motion.ax").doubleValue());
position.set("ay", payload.getJsonNumber("motion.ay").doubleValue());
position.set("az", payload.getJsonNumber("motion.az").doubleValue());
position.set("gx", payload.getJsonNumber("motion.gx").doubleValue());
position.set("gy", payload.getJsonNumber("motion.gy").doubleValue());
position.set("gz", payload.getJsonNumber("motion.gz").doubleValue());

} else if (topic.contains("/io/")) {
}

getLastLocation(position, new Date(payload.getInt("io.ts") * 1000L));
private void parseObd(Position position, JsonObject payload) {
if (payload.containsKey("obd.speed")) {
position.set(Position.KEY_OBD_SPEED, payload.getJsonNumber("obd.speed").doubleValue());
}
if (payload.containsKey("obd.odo")) {
position.set(Position.KEY_OBD_ODOMETER, payload.getInt("obd.odo"));
}
if (payload.containsKey("obd.rpm")) {
position.set(Position.KEY_RPM, payload.getInt("obd.rpm"));
}
if (payload.containsKey("obd.vin")) {
position.set(Position.KEY_VIN, payload.getString("obd.vin"));
}
}

if (payload.containsKey("io.IGT")) {
position.set(Position.KEY_IGNITION, payload.getInt("io.IGT") > 0);
}

for (String key : payload.keySet()) {
if (key.startsWith("io.AI")) {
position.set(Position.PREFIX_ADC + key.substring(5), payload.getJsonNumber(key).doubleValue());
} else if (key.startsWith("io.DI") && !key.endsWith("_pullup")) {
position.set(Position.PREFIX_IN + key.substring(5), payload.getInt(key) > 0);
} else if (key.startsWith("io.DO")) {
position.set(Position.PREFIX_OUT + key.substring(5), payload.getInt(key) > 0);
private void parseGnss(Position position, JsonObject payload) {
if (payload.containsKey("gnss.fix")) {
if (payload.getInt("gnss.fix") > 0 && payload.getInt("gnss.fix") != 5) {
position.setValid(true);
if (payload.containsKey("time")) {
position.setLatitude(payload.getJsonNumber("lat").doubleValue());
position.setLongitude(payload.getJsonNumber("log").doubleValue());
} else {
position.setLatitude(payload.getJsonNumber("gnss.latitude").doubleValue());
position.setLongitude(payload.getJsonNumber("gnss.longitude").doubleValue());
}
if (payload.containsKey("gnss.altitude")) {
position.setAltitude(payload.getJsonNumber("gnss.altitude").doubleValue());
}
if (payload.containsKey("gnss.speed")) {
position.setSpeed(payload.getJsonNumber("gnss.speed").doubleValue());
}
if (payload.containsKey("gnss.heading")) {
position.setCourse(payload.getJsonNumber("gnss.heading").doubleValue());
}
if (payload.containsKey("gnss.num_sv")) {
position.set(Position.KEY_SATELLITES, payload.getJsonNumber("gnss.num_sv").doubleValue());
}
if (payload.containsKey("gnss.hdop")) {
position.set(Position.KEY_HDOP, payload.getJsonNumber("gnss.hdop").doubleValue());
}
} else {
if (payload.containsKey("gnss.num_sv")) {
position.set(Position.KEY_SATELLITES, payload.getJsonNumber("gnss.num_sv").intValue());
}
}

} else if (topic.contains("/sysinfo/")) {

getLastLocation(position, new Date(payload.getInt("sysinfo.ts") * 1000L));

position.set("serial", payload.getString("sysinfo.serial_number"));
position.set(Position.KEY_VERSION_FW, payload.getString("sysinfo.firmware_version"));

} else {

return null;

}
}

return position;
private void parseIO(Position position, JsonObject payload) {
if (payload.containsKey("io.IGT")) {
position.set(Position.KEY_IGNITION, payload.getInt("io.IGT") > 0);
}
for (String key : payload.keySet()) {
if (key.startsWith("io.AI")) {
position.set(Position.PREFIX_ADC + key.substring(5), payload.getJsonNumber(key).doubleValue());
} else if (key.startsWith("io.DI") && !key.endsWith("_pullup")) {
position.set(Position.PREFIX_IN + key.substring(5), payload.getInt(key) > 0);
} else if (key.startsWith("io.DO")) {
position.set(Position.PREFIX_OUT + key.substring(5), payload.getInt(key) > 0);
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,4 @@ public void testDecode() throws Exception {

}

}
}