add mqtt listener

This commit is contained in:
2025-04-15 15:34:49 -04:00
parent 2da0ee24e4
commit f20031e2ea
9 changed files with 2521 additions and 0 deletions

View File

@ -0,0 +1,23 @@
class NodeIdUtil {
/**
* Converts the provided hex id to a numeric id, for example: !FFFFFFFF to 4294967295
* Anything else will be converted as is to a BigInt, for example "4294967295" to 4294967295
* @param hexIdOrNumber a node id in hex format with a prepended "!", or a numeric node id as a string or number
* @returns {bigint} the node id in numeric form
*/
static convertToNumeric(hexIdOrNumber) {
// check if this is a hex id, and convert to numeric
if(hexIdOrNumber.toString().startsWith("!")){
return BigInt('0x' + hexIdOrNumber.replaceAll("!", ""));
}
// convert string or number to numeric
return BigInt(hexIdOrNumber);
}
}
module.exports = NodeIdUtil;

View File

@ -0,0 +1,9 @@
const NodeIdUtil = require("./node_id_util");
test('can convert hex id to numeric id', () => {
expect(NodeIdUtil.convertToNumeric("!FFFFFFFF")).toBe(BigInt(4294967295));
});
test('can convert numeric id to numeric id', () => {
expect(NodeIdUtil.convertToNumeric(4294967295)).toBe(BigInt(4294967295));
});

View File

@ -0,0 +1,66 @@
class PositionUtil {
/**
* Obfuscates the provided latitude or longitude down to the provided precision in bits.
* This is based on the same logic in the official meshtastic firmware.
* https://github.com/meshtastic/firmware/blob/0a93261c0646f93aea518cc0599e547e9dc0e997/src/modules/PositionModule.cpp#L187
*/
static setPositionPrecision(latitudeOrLongitudeInteger, precision) {
// check if we should use the provided precision
if(precision > 0 && precision < 32){
// apply bitmask to reduce precision of position to wanted bits
latitudeOrLongitudeInteger = latitudeOrLongitudeInteger & (0xFFFFFFFF << (32 - precision));
// we want the imprecise position to be the middle of the possible location
latitudeOrLongitudeInteger += (1 << (31 - precision));
}
return latitudeOrLongitudeInteger;
}
/**
* 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,47 @@
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");
});
test('can set integer position precision to provided bits', () => {
// these tests are using the auckland sky tower position
// auckland sky tower: -36.84844007222091, 174.76221115261924
// the outputs we are expecting, are the same values returned by the code in the meshtastic firmware
// https://github.com/meshtastic/firmware/blob/0a93261c0646f93aea518cc0599e547e9dc0e997/src/modules/PositionModule.cpp#L187
// set precision to 32 bits (within 0 meters)
// -36.8484400, 174.7622111 -> -36.8484400, 174.7622111
expect(PositionUtil.setPositionPrecision(-368484400, 32)).toBe(-368484400);
expect(PositionUtil.setPositionPrecision(1747622111, 32)).toBe(1747622111);
// set precision to 16 bits (within ~364 meters)
// -36.8484400, 174.7622111 -> -36.8476160, 174.7615744
expect(PositionUtil.setPositionPrecision(-368484400, 16)).toBe(-368476160);
expect(PositionUtil.setPositionPrecision(1747622111, 16)).toBe(1747615744);
// set precision to 13 bits (within ~2.9 kilometers)
// -36.8484400, 174.7622111 -> -36.8312320, 174.7714048
expect(PositionUtil.setPositionPrecision(-368484400, 13)).toBe(-368312320);
expect(PositionUtil.setPositionPrecision(1747622111, 13)).toBe(1747714048);
// set precision to 11 bits (within ~11.6 kilometers)
// -36.8484400, 174.7622111 -> -36.8050176, 174.7976192
expect(PositionUtil.setPositionPrecision(-368484400, 11)).toBe(-368050176);
expect(PositionUtil.setPositionPrecision(1747622111, 11)).toBe(1747976192);
});