diff --git a/prisma/migrations/20240523084115_create_positions_table/migration.sql b/prisma/migrations/20240523084115_create_positions_table/migration.sql new file mode 100644 index 0000000..e140d3a --- /dev/null +++ b/prisma/migrations/20240523084115_create_positions_table/migration.sql @@ -0,0 +1,22 @@ +-- CreateTable +CREATE TABLE `positions` ( + `id` BIGINT NOT NULL AUTO_INCREMENT, + `node_id` BIGINT NOT NULL, + `to` BIGINT NOT NULL, + `from` BIGINT NOT NULL, + `channel` INTEGER NULL, + `packet_id` BIGINT NULL, + `channel_id` VARCHAR(191) NULL, + `gateway_id` BIGINT NULL, + `latitude` INTEGER NULL, + `longitude` INTEGER NULL, + `altitude` INTEGER NULL, + `created_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + `updated_at` DATETIME(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + + INDEX `positions_created_at_idx`(`created_at`), + INDEX `positions_updated_at_idx`(`updated_at`), + INDEX `positions_node_id_idx`(`node_id`), + INDEX `positions_packet_id_idx`(`packet_id`), + PRIMARY KEY (`id`) +) DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 182f9bf..297422a 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -116,6 +116,31 @@ model DeviceMetric { @@map("device_metrics") } +model Position { + id BigInt @id @default(autoincrement()) + node_id BigInt + + to BigInt + from BigInt + channel Int? + packet_id BigInt? + channel_id String? + gateway_id BigInt? + + latitude Int? + longitude Int? + altitude Int? + + created_at DateTime @default(now()) + updated_at DateTime @default(now()) @updatedAt + + @@index(created_at) + @@index(updated_at) + @@index(node_id) + @@index(packet_id) + @@map("positions") +} + model ServiceEnvelope { id BigInt @id @default(autoincrement()) mqtt_topic String diff --git a/src/mqtt.js b/src/mqtt.js index 4c3262e..e7c7cfa 100644 --- a/src/mqtt.js +++ b/src/mqtt.js @@ -36,6 +36,11 @@ const optionsList = [ type: Boolean, description: "This option will save all received service envelopes to the database.", }, + { + name: "collect-positions", + type: Boolean, + description: "This option will save all received positions to the database.", + }, { name: "collect-text-messages", type: Boolean, @@ -99,6 +104,7 @@ const mqttBrokerUrl = options["mqtt-broker-url"] ?? "mqtt://mqtt.meshtastic.org" const mqttUsername = options["mqtt-username"] ?? "meshdev"; const mqttPassword = options["mqtt-password"] ?? "large4cats"; const collectServiceEnvelopes = options["collect-service-envelopes"] ?? false; +const collectPositions = options["collect-positions"] ?? false; const collectTextMessages = options["collect-text-messages"] ?? false; const collectWaypoints = options["collect-waypoints"] ?? true; const collectNeighbourInfo = options["collect-neighbour-info"] ?? false; @@ -360,6 +366,45 @@ client.on("message", async (topic, message) => { } } + if(!collectPositions){ + return; + } + + try { + + // find an existing position with duplicate information created in the last 60 seconds + const existingDuplicatePosition = await prisma.position.findFirst({ + where: { + node_id: envelope.packet.from, + packet_id: envelope.packet.id, + created_at: { + gte: new Date(Date.now() - 60000), // created in the last 60 seconds + }, + } + }); + + // create position if no duplicates found + if(!existingDuplicatePosition){ + await prisma.position.create({ + data: { + node_id: envelope.packet.from, + to: envelope.packet.to, + from: envelope.packet.from, + channel: envelope.packet.channel, + packet_id: envelope.packet.id, + channel_id: envelope.channelId, + gateway_id: envelope.gatewayId ? BigInt('0x' + envelope.gatewayId.replaceAll("!", "")) : null, // convert hex id "!f96a92f0" to bigint + latitude: position.latitudeI, + longitude: position.longitudeI, + altitude: position.altitude, + }, + }); + } + + } catch (e) { + console.error(e); + } + } else if(portnum === 4) {