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": "",
|
"description": "",
|
||||||
"main": "src/index.js",
|
"main": "src/index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "jest"
|
||||||
},
|
},
|
||||||
"author": "",
|
"author": "",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
@ -18,6 +18,7 @@
|
|||||||
"protobufjs": "^7.2.6"
|
"protobufjs": "^7.2.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"jest": "^29.7.0",
|
||||||
"prisma": "^5.10.2"
|
"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 protobufjs = require("protobufjs");
|
||||||
const commandLineArgs = require("command-line-args");
|
const commandLineArgs = require("command-line-args");
|
||||||
const commandLineUsage = require("command-line-usage");
|
const commandLineUsage = require("command-line-usage");
|
||||||
|
const PositionUtil = require("./utils/position_util");
|
||||||
|
|
||||||
// create prisma db client
|
// create prisma db client
|
||||||
const { PrismaClient } = require("@prisma/client");
|
const { PrismaClient } = require("@prisma/client");
|
||||||
@ -113,6 +114,11 @@ const optionsList = [
|
|||||||
typeLabel: '<portnum> ...',
|
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+)",
|
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",
|
name: "purge-interval-seconds",
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -214,6 +220,7 @@ const decryptionKeys = options["decryption-keys"] ?? [
|
|||||||
];
|
];
|
||||||
const dropPacketsNotOkToMqtt = options["drop-packets-not-ok-to-mqtt"] ?? false;
|
const dropPacketsNotOkToMqtt = options["drop-packets-not-ok-to-mqtt"] ?? false;
|
||||||
const dropPortnumsWithoutBitfield = options["drop-portnums-without-bitfield"] ?? null;
|
const dropPortnumsWithoutBitfield = options["drop-portnums-without-bitfield"] ?? null;
|
||||||
|
const oldFirmwarePositionPrecision = options["old-firmware-position-precision"] ?? null;
|
||||||
const purgeIntervalSeconds = options["purge-interval-seconds"] ?? 10;
|
const purgeIntervalSeconds = options["purge-interval-seconds"] ?? 10;
|
||||||
const purgeNodesUnheardForSeconds = options["purge-nodes-unheard-for-seconds"] ?? null;
|
const purgeNodesUnheardForSeconds = options["purge-nodes-unheard-for-seconds"] ?? null;
|
||||||
const purgeDeviceMetricsAfterSeconds = options["purge-device-metrics-after-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;
|
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
|
// get bitfield from decoded packet
|
||||||
// bitfield was added in v2.5 of meshtastic firmware
|
// 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
|
// 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)
|
// check if bitfield is available (v2.5.x firmware or newer)
|
||||||
if(bitfield != null){
|
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(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 {
|
try {
|
||||||
await prisma.node.updateMany({
|
await prisma.node.updateMany({
|
||||||
where: {
|
where: {
|
||||||
@ -797,6 +831,7 @@ client.on("message", async (topic, message) => {
|
|||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't collect position history if not enabled, but we still want to update the node above
|
// 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