add cli flag to limit position precision to x decimal places for v2.4 firmware and older
This commit is contained in:
3407
package-lock.json
generated
3407
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -4,7 +4,7 @@
|
||||
"description": "",
|
||||
"main": "src/index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
"test": "jest"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
@ -18,6 +18,7 @@
|
||||
"protobufjs": "^7.2.6"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest": "^29.7.0",
|
||||
"prisma": "^5.10.2"
|
||||
}
|
||||
}
|
||||
|
47
src/mqtt.js
47
src/mqtt.js
@ -4,6 +4,7 @@ const mqtt = require("mqtt");
|
||||
const protobufjs = require("protobufjs");
|
||||
const commandLineArgs = require("command-line-args");
|
||||
const commandLineUsage = require("command-line-usage");
|
||||
const PositionUtil = require("./utils/position_util");
|
||||
|
||||
// create prisma db client
|
||||
const { PrismaClient } = require("@prisma/client");
|
||||
@ -113,6 +114,11 @@ const optionsList = [
|
||||
typeLabel: '<portnum> ...',
|
||||
description: "If provided, packets with these portnums will be dropped if they don't have a bitfield. (bitfield available from firmware v2.5+)",
|
||||
},
|
||||
{
|
||||
name: "old-firmware-position-precision",
|
||||
type: Number,
|
||||
description: "If provided, position packets from firmware v2.4 and older will be truncated to this many decimal places.",
|
||||
},
|
||||
{
|
||||
name: "purge-interval-seconds",
|
||||
type: Number,
|
||||
@ -214,6 +220,7 @@ const decryptionKeys = options["decryption-keys"] ?? [
|
||||
];
|
||||
const dropPacketsNotOkToMqtt = options["drop-packets-not-ok-to-mqtt"] ?? false;
|
||||
const dropPortnumsWithoutBitfield = options["drop-portnums-without-bitfield"] ?? null;
|
||||
const oldFirmwarePositionPrecision = options["old-firmware-position-precision"] ?? null;
|
||||
const purgeIntervalSeconds = options["purge-interval-seconds"] ?? 10;
|
||||
const purgeNodesUnheardForSeconds = options["purge-nodes-unheard-for-seconds"] ?? null;
|
||||
const purgeDeviceMetricsAfterSeconds = options["purge-device-metrics-after-seconds"] ?? null;
|
||||
@ -652,16 +659,16 @@ client.on("message", async (topic, message) => {
|
||||
}
|
||||
}
|
||||
|
||||
// get portnum from packet
|
||||
// get portnum from decoded packet
|
||||
const portnum = envelope.packet?.decoded?.portnum;
|
||||
|
||||
// check if we can see the decrypted packet data, so we can see if it has the "OK to MQTT" bitfield flag set
|
||||
if(envelope.packet.decoded != null){
|
||||
|
||||
// get bitfield from decoded packet
|
||||
// bitfield was added in v2.5 of meshtastic firmware
|
||||
// this value will be null for packets from v2.4.x and below, and will be an integer in v2.5.x and above
|
||||
const bitfield = envelope.packet.decoded.bitfield;
|
||||
const bitfield = envelope.packet?.decoded?.bitfield;
|
||||
|
||||
// check if we can see the decrypted packet data
|
||||
if(envelope.packet.decoded != null){
|
||||
|
||||
// check if bitfield is available (v2.5.x firmware or newer)
|
||||
if(bitfield != null){
|
||||
@ -780,8 +787,35 @@ client.on("message", async (topic, message) => {
|
||||
});
|
||||
}
|
||||
|
||||
// update node position in db
|
||||
// process position
|
||||
if(position.latitudeI != null && position.longitudeI){
|
||||
|
||||
// if bitfield is not available, we are on firmware v2.4 or below
|
||||
// if configured, truncate position packets to the provided number of decimal places
|
||||
if(bitfield == null && oldFirmwarePositionPrecision != null){
|
||||
|
||||
// convert lat/long to decimal as string
|
||||
// e.g: -123456789 -> -12.3456789
|
||||
const latitudeString = (position.latitudeI / 10000000).toString();
|
||||
const longitudeString = (position.longitudeI / 10000000).toString();
|
||||
|
||||
// truncate to desired length
|
||||
const truncatedLatitudeString = PositionUtil.truncateDecimalPlaces(latitudeString, oldFirmwarePositionPrecision);
|
||||
const truncatedLongitudeString = PositionUtil.truncateDecimalPlaces(longitudeString, oldFirmwarePositionPrecision);
|
||||
|
||||
// convert lat/long string back to integer from decimal
|
||||
// e.g: -12.3456789 -> -123456789
|
||||
// fixme: sometimes we may get xx.xx99999 recurring, but don't worry about that for now, since we are mangling the precision anyway...
|
||||
const truncatedLatitudeI = parseInt(parseFloat(truncatedLatitudeString) * 10000000);
|
||||
const truncatedLongitudeI = parseInt(parseFloat(truncatedLongitudeString) * 10000000);
|
||||
|
||||
// update position packet with truncated lat/long
|
||||
position.latitudeI = truncatedLatitudeI;
|
||||
position.longitudeI = truncatedLongitudeI;
|
||||
|
||||
}
|
||||
|
||||
// update node position in db
|
||||
try {
|
||||
await prisma.node.updateMany({
|
||||
where: {
|
||||
@ -797,6 +831,7 @@ client.on("message", async (topic, message) => {
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// don't collect position history if not enabled, but we still want to update the node above
|
||||
|
44
src/utils/position_util.js
Normal file
44
src/utils/position_util.js
Normal file
@ -0,0 +1,44 @@
|
||||
class PositionUtil {
|
||||
|
||||
/**
|
||||
* Truncates the provided latitude or longitude to a maximum of x decimal places
|
||||
* e.g: 12.3456789 with 2 decimal places would be 12.34
|
||||
* @param latitudeOrLongitudeString e.g: 12.3456789
|
||||
* @param numberOfDecimalPlaces how many decimal places to allow in the result
|
||||
* @returns {*|string|null}
|
||||
*/
|
||||
static truncateDecimalPlaces(latitudeOrLongitudeString, numberOfDecimalPlaces) {
|
||||
|
||||
// ensure value not null
|
||||
if(latitudeOrLongitudeString == null){
|
||||
return null;
|
||||
}
|
||||
|
||||
// split into left and right side of decimal point
|
||||
// e.g: -12.3456789 -> [-12, 3456789]
|
||||
var [ leftOfDecimalPoint, rightOfDecimalPoint ] = latitudeOrLongitudeString.split(".");
|
||||
|
||||
// check if decimal places available
|
||||
if(rightOfDecimalPoint != null){
|
||||
|
||||
// truncate decimal places to desired length
|
||||
rightOfDecimalPoint = rightOfDecimalPoint.substring(0, numberOfDecimalPlaces);
|
||||
|
||||
// return modified position with decimal places, if available
|
||||
if(rightOfDecimalPoint.length > 0){
|
||||
return [ leftOfDecimalPoint, rightOfDecimalPoint ].join(".");
|
||||
}
|
||||
|
||||
// no decimal places available anymore, return left side without dot
|
||||
return leftOfDecimalPoint;
|
||||
|
||||
}
|
||||
|
||||
// decimal places not available, return position as is
|
||||
return latitudeOrLongitudeString;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
module.exports = PositionUtil;
|
18
src/utils/position_util.test.js
Normal file
18
src/utils/position_util.test.js
Normal file
@ -0,0 +1,18 @@
|
||||
const PositionUtil = require("./position_util");
|
||||
|
||||
test('can truncate string position to provided decimal places', () => {
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 0)).toBe("12");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 1)).toBe("12.3");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 2)).toBe("12.34");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 3)).toBe("12.345");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 4)).toBe("12.3456");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 5)).toBe("12.34567");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 6)).toBe("12.345678");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3456789", 7)).toBe("12.3456789");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12.3", 7)).toBe("12.3");
|
||||
expect(PositionUtil.truncateDecimalPlaces(null, 2)).toBe(null);
|
||||
expect(PositionUtil.truncateDecimalPlaces("", 2)).toBe("");
|
||||
expect(PositionUtil.truncateDecimalPlaces("12", 2)).toBe("12");
|
||||
expect(PositionUtil.truncateDecimalPlaces("123", 2)).toBe("123");
|
||||
expect(PositionUtil.truncateDecimalPlaces("1234.", 2)).toBe("1234");
|
||||
});
|
Reference in New Issue
Block a user