add cli flag to limit position precision to x decimal places for v2.4 firmware and older

This commit is contained in:
liamcottle
2024-10-02 01:52:03 +13:00
parent 759567917a
commit 9bebc870bd
5 changed files with 3514 additions and 9 deletions

3407
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -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"
}
}

View File

@ -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;
// 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;
// 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

View 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;

View 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");
});