From aa3c250c2eeebb7a9025ef76e3562e706912174bb076a9446ed5efcfd8d6f6f5 Mon Sep 17 00:00:00 2001 From: localhorst Date: Mon, 30 Dec 2024 22:48:47 +0100 Subject: [PATCH 01/14] basic algo that computes virtual location based on TTN gateway locations --- server/src/index.ts | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/server/src/index.ts b/server/src/index.ts index 8104843..33715f6 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -8,6 +8,38 @@ import lpTtnEndDeviceUplinksRoutes from "./controller/lpTtnEndDeviceUplinksContr import ttnGatewayReceptionRoutes from "./controller/ttnGatewayReceptionController"; import wifiScanRoutes from "./controller/wifiScanController"; +interface LocationData { + rssi: number; + latitude: number; + longitude: number; +} + +function calculateTtnGatewayLocation(dataList: LocationData[]): { latitude: number, longitude: number } { + if (!dataList || dataList.length === 0) { + throw new Error("The data list is empty or undefined."); + } + + let totalWeight = 0; + let weightedLatitude = 0; + let weightedLongitude = 0; + + // Loop through the dataList and calculate weighted sums based on RSSI + dataList.forEach(point => { + const weight = 1 / Math.abs(point.rssi); // Higher RSSI (closer to 0) gives more weight + totalWeight += weight; + weightedLatitude += point.latitude * weight; + weightedLongitude += point.longitude * weight; + }); + + // Calculate the weighted average to get the virtual location + const virtualLocation = { + latitude: weightedLatitude / totalWeight, + longitude: weightedLongitude / totalWeight + }; + + return virtualLocation; +} + dotenv.config(); const app = express(); @@ -21,6 +53,17 @@ app.use("/api/wifi-scans", wifiScanRoutes); app.use("/api/ttn-gateway-receptions", ttnGatewayReceptionRoutes); app.use("/api/locations", locationRoutes); +const dataList: LocationData[] = [ + //sensecap_exporter_2024-10-18_12-52-30.json + { rssi: -108, latitude: 51.875759063444335, longitude: 4.448537528514863 }, + { rssi: -114, latitude: 51.8875851, longitude: 4.4919652 }, + { rssi: -106, latitude: 51.9102795122954, longitude: 4.48074765239573 }, + { rssi: -103, latitude: 51.9111671447754, longitude: 4.46313190460205 } +]; + +const virtualLocation = calculateTtnGatewayLocation(dataList); +console.log("TTN Gateway location:", virtualLocation); + app.listen(PORT, () => { - console.log(`๐Ÿš€ Server lรคuft auf http://localhost:${PORT}`); + console.log(`๐Ÿš€ Server runs here: http://localhost:${PORT}`); }); -- 2.47.1 From a4a8b6c3c189a2b83a5d6e4b529c045c2bfbdbc5ff9befd289006712f770a56b Mon Sep 17 00:00:00 2001 From: Philipp Schweizer Date: Mon, 30 Dec 2024 23:20:10 +0100 Subject: [PATCH 02/14] feat: added event and event handler --- server/src/config/eventEmitter.ts | 5 +++++ server/src/event/ttnMessageReceivedEvent.ts | 14 ++++++++++++++ .../eventHandler/ttnMessageReceivedEventHandler.ts | 13 +++++++++++++ server/src/index.ts | 1 + 4 files changed, 33 insertions(+) create mode 100644 server/src/config/eventEmitter.ts create mode 100644 server/src/event/ttnMessageReceivedEvent.ts create mode 100644 server/src/eventHandler/ttnMessageReceivedEventHandler.ts diff --git a/server/src/config/eventEmitter.ts b/server/src/config/eventEmitter.ts new file mode 100644 index 0000000..ea1baf4 --- /dev/null +++ b/server/src/config/eventEmitter.ts @@ -0,0 +1,5 @@ +import { EventEmitter } from "events"; + +class DomainEventEmitter extends EventEmitter {} + +export const domainEventEmitter = new DomainEventEmitter(); diff --git a/server/src/event/ttnMessageReceivedEvent.ts b/server/src/event/ttnMessageReceivedEvent.ts new file mode 100644 index 0000000..b6b6945 --- /dev/null +++ b/server/src/event/ttnMessageReceivedEvent.ts @@ -0,0 +1,14 @@ +export const TtnMessageReceivedEventName = "TtnMessageReceived"; +export type TtnMessageReceivedEvent = { + lp_ttn_end_device_uplinks_id: string; + wifis: { + mac: string; + rssi: number; + }[]; + ttnGateways: { + rssi: number; + latitude: number; + longitude: number; + altitude: number; + }[]; +}; diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts new file mode 100644 index 0000000..90c0007 --- /dev/null +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -0,0 +1,13 @@ +import { domainEventEmitter } from "../config/eventEmitter"; +import { + TtnMessageReceivedEvent, + TtnMessageReceivedEventName, +} from "../event/ttnMessageReceivedEvent"; + +domainEventEmitter.on( + TtnMessageReceivedEventName, + async (event: TtnMessageReceivedEvent) => { + console.log(event); + // TODO Hendrik ๐Ÿš€ + } +); diff --git a/server/src/index.ts b/server/src/index.ts index 8104843..0731bf6 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -1,6 +1,7 @@ import dotenv from "dotenv"; import express from "express"; import "reflect-metadata"; +import "./eventHandler/ttnMessageReceivedEventHandler"; const cors = require("cors"); import locationRoutes from "./controller/locationController"; -- 2.47.1 From 393eab2b451b235c866dc4dde8e5fd0a55e0c59f034e59b5a964ef4270cd2b43 Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 31 Dec 2024 13:19:13 +0100 Subject: [PATCH 03/14] calculate virtual location based on TTN GW --- README.md | 2 +- .../ttnMessageReceivedEventHandler.ts | 30 ++++++++++++- server/src/index.ts | 43 ------------------- 3 files changed, 30 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 9727bc4..e77d4fb 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ TODO ### Database **Change name of database and credentials as you like!** -- Create new database: `CREATE DATABASE locationhub;` +- Create new database: `CREATE DATABASE dev_locationhub;` - Create new user for database: `GRANT ALL PRIVILEGES ON dev_locationhub.* TO 'dbuser'@'localhost' IDENTIFIED BY '1234';` - Import tables: `/usr/bin/mariadb -u dbuser -p1234 dev_locationhub < server/sql/tables.sql` diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 90c0007..9192b80 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -8,6 +8,34 @@ domainEventEmitter.on( TtnMessageReceivedEventName, async (event: TtnMessageReceivedEvent) => { console.log(event); - // TODO Hendrik ๐Ÿš€ + + if (!event.ttnGateways || event.ttnGateways.length === 0) { + console.log("No TTN Gateway location received!") + } else { + let totalWeight = 0; + let weightedLatitude = 0; + let weightedLongitude = 0; + + event.ttnGateways.forEach(gw => { + const weight = 1 / Math.abs(gw.rssi); // Higher RSSI (closer to 0) gives more weight + totalWeight += weight; + weightedLatitude += gw.latitude * weight; + weightedLongitude += gw.longitude * weight; + }); + + // Calculate the weighted average to get the virtual location + const virtualLocation = { + latitude: weightedLatitude / totalWeight, + longitude: weightedLongitude / totalWeight + }; + + console.log("Tracker location based on TTN Gateway location:", virtualLocation); + } + + + + + } ); + diff --git a/server/src/index.ts b/server/src/index.ts index a7c0494..dcc61d9 100644 --- a/server/src/index.ts +++ b/server/src/index.ts @@ -10,38 +10,6 @@ import ttnRoutes from "./controller/ttnController"; import ttnGatewayReceptionRoutes from "./controller/ttnGatewayReceptionController"; import wifiScanRoutes from "./controller/wifiScanController"; -interface LocationData { - rssi: number; - latitude: number; - longitude: number; -} - -function calculateTtnGatewayLocation(dataList: LocationData[]): { latitude: number, longitude: number } { - if (!dataList || dataList.length === 0) { - throw new Error("The data list is empty or undefined."); - } - - let totalWeight = 0; - let weightedLatitude = 0; - let weightedLongitude = 0; - - // Loop through the dataList and calculate weighted sums based on RSSI - dataList.forEach(point => { - const weight = 1 / Math.abs(point.rssi); // Higher RSSI (closer to 0) gives more weight - totalWeight += weight; - weightedLatitude += point.latitude * weight; - weightedLongitude += point.longitude * weight; - }); - - // Calculate the weighted average to get the virtual location - const virtualLocation = { - latitude: weightedLatitude / totalWeight, - longitude: weightedLongitude / totalWeight - }; - - return virtualLocation; -} - dotenv.config(); const app = express(); @@ -56,17 +24,6 @@ app.use("/api/ttn-gateway-receptions", ttnGatewayReceptionRoutes); app.use("/api/locations", locationRoutes); app.use("/api/ttn", ttnRoutes); -const dataList: LocationData[] = [ - //sensecap_exporter_2024-10-18_12-52-30.json - { rssi: -108, latitude: 51.875759063444335, longitude: 4.448537528514863 }, - { rssi: -114, latitude: 51.8875851, longitude: 4.4919652 }, - { rssi: -106, latitude: 51.9102795122954, longitude: 4.48074765239573 }, - { rssi: -103, latitude: 51.9111671447754, longitude: 4.46313190460205 } -]; - -const virtualLocation = calculateTtnGatewayLocation(dataList); -console.log("TTN Gateway location:", virtualLocation); - app.listen(PORT, () => { console.log(`๐Ÿš€ Server runs here: http://localhost:${PORT}`); }); -- 2.47.1 From c27763fc11c068275f3508ab70cf3063e44a7fde3fd5c96249db1fa9bfdd6f9c Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 31 Dec 2024 14:00:32 +0100 Subject: [PATCH 04/14] add TTN Gateway based location to DB model --- server/sql/tables.sql | 2 ++ server/src/models/location.ts | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/server/sql/tables.sql b/server/sql/tables.sql index babf48b..5788884 100644 --- a/server/sql/tables.sql +++ b/server/sql/tables.sql @@ -46,6 +46,8 @@ CREATE TABLE IF NOT EXISTS location ( wifi_longitude DOUBLE, gnss_latitude DOUBLE, gnss_longitude DOUBLE, + ttn_gw_latitude DOUBLE, + ttn_gw_longitude DOUBLE, created_at_utc TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at_utc TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, FOREIGN KEY (lp_ttn_end_device_uplinks_id) REFERENCES lp_ttn_end_device_uplinks(lp_ttn_end_device_uplinks_id) diff --git a/server/src/models/location.ts b/server/src/models/location.ts index 1a79938..63668b5 100644 --- a/server/src/models/location.ts +++ b/server/src/models/location.ts @@ -8,6 +8,8 @@ export class Location extends Model { public wifi_longitude!: number; public gnss_latitude!: number; public gnss_longitude!: number; + public ttn_gw_latitude!: number; + public ttn_gw_longitude!: number; public created_at_utc!: Date; public updated_at_utc!: Date; } @@ -40,6 +42,14 @@ Location.init( type: DataTypes.NUMBER, allowNull: true, }, + ttn_gw_latitude: { + type: DataTypes.NUMBER, + allowNull: true, + }, + ttn_gw__longitude: { + type: DataTypes.NUMBER, + allowNull: true, + }, created_at_utc: { type: DataTypes.DATE, defaultValue: DataTypes.NOW, -- 2.47.1 From 4994b8a2462ef13976def46adef53b8f85fa4e5a2f1d3abb0d136963e95327a1 Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 31 Dec 2024 14:18:47 +0100 Subject: [PATCH 05/14] save TTN GW based location into DB --- .../ttnMessageReceivedEventHandler.ts | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 9192b80..57c67c2 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -3,12 +3,23 @@ import { TtnMessageReceivedEvent, TtnMessageReceivedEventName, } from "../event/ttnMessageReceivedEvent"; +import { container } from "tsyringe"; +import { LocationService } from "../services/locationService"; + +const locationService = container.resolve(LocationService); domainEventEmitter.on( TtnMessageReceivedEventName, async (event: TtnMessageReceivedEvent) => { console.log(event); + var wifi_based_latitude!: number; + var wifi_based_longitude!: number; + var gnss_based_latitude!: number; // Should this be set here? + var gnss_based_longitude!: number; // Should this be set here? + var ttn_gw_based_latitude!: number; + var ttn_gw_based_longitude!: number; + if (!event.ttnGateways || event.ttnGateways.length === 0) { console.log("No TTN Gateway location received!") } else { @@ -30,12 +41,23 @@ domainEventEmitter.on( }; console.log("Tracker location based on TTN Gateway location:", virtualLocation); + ttn_gw_based_latitude = virtualLocation.latitude; + ttn_gw_based_longitude = virtualLocation.longitude; } + { + // TODO: parse Wifi location here + } + + const newLocation = await locationService.createLocation({ + lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, + ttn_gw_latitude: ttn_gw_based_latitude, + ttn_gw_longitude: ttn_gw_based_longitude, + }); - + console.log(newLocation) } ); -- 2.47.1 From 68e3121f4185454a74bb5b5a2f52f927f12ee7d26bbe05aeb262fa624d483c90 Mon Sep 17 00:00:00 2001 From: localhorst Date: Tue, 31 Dec 2024 16:57:36 +0100 Subject: [PATCH 06/14] add gnss location to event --- server/src/controller/ttnController.ts | 2 ++ server/src/event/ttnMessageReceivedEvent.ts | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/server/src/controller/ttnController.ts b/server/src/controller/ttnController.ts index daabf42..d785888 100644 --- a/server/src/controller/ttnController.ts +++ b/server/src/controller/ttnController.ts @@ -78,6 +78,8 @@ router.post( latitude: g.latitude, longitude: g.longitude, })), + gnssLocation: + }; domainEventEmitter.emit(TtnMessageReceivedEventName, event); diff --git a/server/src/event/ttnMessageReceivedEvent.ts b/server/src/event/ttnMessageReceivedEvent.ts index b6b6945..811c664 100644 --- a/server/src/event/ttnMessageReceivedEvent.ts +++ b/server/src/event/ttnMessageReceivedEvent.ts @@ -11,4 +11,8 @@ export type TtnMessageReceivedEvent = { longitude: number; altitude: number; }[]; + gnssLocation: { + longitude: number; + altitude: number; + } }; -- 2.47.1 From 16d49c99406d48330d10a0d4771269d59ad4c4294ddaf6692df4de0d9962387b Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 1 Jan 2025 18:40:58 +0100 Subject: [PATCH 07/14] fix event sending --- server/src/controller/ttnController.ts | 6 +++--- server/src/event/ttnMessageReceivedEvent.ts | 4 ++-- .../eventHandler/ttnMessageReceivedEventHandler.ts | 13 +++++++------ 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/server/src/controller/ttnController.ts b/server/src/controller/ttnController.ts index d785888..4c68393 100644 --- a/server/src/controller/ttnController.ts +++ b/server/src/controller/ttnController.ts @@ -28,7 +28,8 @@ router.post( async (req: Request, res: Response) => { try { const message = req.body as TtnMessage; - const { lp_ttn_end_device_uplinks_id } = + // Create uplink record + const { lp_ttn_end_device_uplinks_id, latitude, longitude } = await lpTtnEndDeviceUplinksService.createUplink({ device_id: message.end_device_ids.device_id, application_ids: @@ -78,8 +79,7 @@ router.post( latitude: g.latitude, longitude: g.longitude, })), - gnssLocation: - + gnssLocation: { latitude, longitude } }; domainEventEmitter.emit(TtnMessageReceivedEventName, event); diff --git a/server/src/event/ttnMessageReceivedEvent.ts b/server/src/event/ttnMessageReceivedEvent.ts index 811c664..f92d05a 100644 --- a/server/src/event/ttnMessageReceivedEvent.ts +++ b/server/src/event/ttnMessageReceivedEvent.ts @@ -12,7 +12,7 @@ export type TtnMessageReceivedEvent = { altitude: number; }[]; gnssLocation: { - longitude: number; - altitude: number; + latitude: number | undefined; + longitude: number | undefined; } }; diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 57c67c2..66a880f 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -13,12 +13,12 @@ domainEventEmitter.on( async (event: TtnMessageReceivedEvent) => { console.log(event); - var wifi_based_latitude!: number; - var wifi_based_longitude!: number; - var gnss_based_latitude!: number; // Should this be set here? - var gnss_based_longitude!: number; // Should this be set here? - var ttn_gw_based_latitude!: number; - var ttn_gw_based_longitude!: number; + var wifi_based_latitude: number; + var wifi_based_longitude: number; + var gnss_based_latitude: number; + var gnss_based_longitude: number; + var ttn_gw_based_latitude: number | undefined = undefined; + var ttn_gw_based_longitude: number | undefined = undefined; if (!event.ttnGateways || event.ttnGateways.length === 0) { console.log("No TTN Gateway location received!") @@ -54,6 +54,7 @@ domainEventEmitter.on( lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, ttn_gw_latitude: ttn_gw_based_latitude, ttn_gw_longitude: ttn_gw_based_longitude, + //TODO: Add gnss location }); -- 2.47.1 From dae4403eaf913a175d27fc761aa6a1f539a835569389c0e0a5d21107c629c767 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 1 Jan 2025 19:14:21 +0100 Subject: [PATCH 08/14] save GNSS location in location element --- .../ttnMessageReceivedEventHandler.ts | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 66a880f..4385352 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -15,8 +15,8 @@ domainEventEmitter.on( var wifi_based_latitude: number; var wifi_based_longitude: number; - var gnss_based_latitude: number; - var gnss_based_longitude: number; + var gnss_based_latitude: number | undefined = undefined; + var gnss_based_longitude: number | undefined = undefined; var ttn_gw_based_latitude: number | undefined = undefined; var ttn_gw_based_longitude: number | undefined = undefined; @@ -50,14 +50,21 @@ domainEventEmitter.on( // TODO: parse Wifi location here } + if ((event.gnssLocation.latitude) && (event.gnssLocation.longitude)) { + gnss_based_latitude = event.gnssLocation.latitude; + gnss_based_longitude = event.gnssLocation.longitude; + } else { + console.log("No GNSS location received!") + } + const newLocation = await locationService.createLocation({ lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, ttn_gw_latitude: ttn_gw_based_latitude, ttn_gw_longitude: ttn_gw_based_longitude, - //TODO: Add gnss location + gnss_latitude: gnss_based_latitude, + gnss_longitude: gnss_based_longitude, }); - console.log(newLocation) } ); -- 2.47.1 From 50721114e3b077ed6a499c708f1b6545211f3bcb008fbb76f064edd26fa0f704 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 1 Jan 2025 21:39:34 +0100 Subject: [PATCH 09/14] store location created from all location sources --- server/.env.template | 2 +- server/package.json | 4 +- .../ttnMessageReceivedEventHandler.ts | 54 +++++++++++++++++-- 3 files changed, 53 insertions(+), 7 deletions(-) diff --git a/server/.env.template b/server/.env.template index d54c511..0151408 100644 --- a/server/.env.template +++ b/server/.env.template @@ -7,6 +7,6 @@ DB_PORT="" WIGLE_TOKEN="" WIGLE_BASE_URL="https://api.wigle.net" WIGLE_NETWORK_SEARCH="/api/v2/network/search" -GET_LOCATION_WIFI_MAX_AGE=1209600000 # 14 Tage in Millisekunden (14 * 24 * 60 * 60 * 1000) +GET_LOCATION_WIFI_MAX_AGE=1209600000 # 14 days in milliseconds (14 * 24 * 60 * 60 * 1000) GET_LOCATION_WIFI_MAX=10000 GET_LOCATION_WIFI_PRIMITIVE=true \ No newline at end of file diff --git a/server/package.json b/server/package.json index a71e8c3..d550a8e 100644 --- a/server/package.json +++ b/server/package.json @@ -13,11 +13,11 @@ "license": "ISC", "devDependencies": { "@types/express": "^5.0.0", + "@types/memoizee": "^0.4.11", "@types/node": "^22.10.2", "nodemon": "^3.1.9", "ts-node": "^10.9.2", - "typescript": "^5.7.2", - "@types/memoizee": "^0.4.11" + "typescript": "^5.7.2" }, "dependencies": { "cors": "^2.8.5", diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 4385352..84293a2 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -5,21 +5,25 @@ import { } from "../event/ttnMessageReceivedEvent"; import { container } from "tsyringe"; import { LocationService } from "../services/locationService"; +import { WifiScanService } from "../services/wifiScanService"; +import { getLocationForWifiMemoized } from "../proxy/wigle"; const locationService = container.resolve(LocationService); +const wifiScanService = container.resolve(WifiScanService); domainEventEmitter.on( TtnMessageReceivedEventName, async (event: TtnMessageReceivedEvent) => { console.log(event); - var wifi_based_latitude: number; - var wifi_based_longitude: number; + var wifi_based_latitude: number | undefined = undefined; + var wifi_based_longitude: number | undefined = undefined; var gnss_based_latitude: number | undefined = undefined; var gnss_based_longitude: number | undefined = undefined; var ttn_gw_based_latitude: number | undefined = undefined; var ttn_gw_based_longitude: number | undefined = undefined; + // Get location based on TTN Gateways if (!event.ttnGateways || event.ttnGateways.length === 0) { console.log("No TTN Gateway location received!") } else { @@ -45,11 +49,51 @@ domainEventEmitter.on( ttn_gw_based_longitude = virtualLocation.longitude; } + // Get location based on WiFi Scans + if (!event.wifis || event.wifis.length === 0) { + console.log("No WiFi scans received!") + } else { + let totalWeight = 0; + let weightedLatitude = 0; + let weightedLongitude = 0; - { - // TODO: parse Wifi location here + // Process Wi-Fi data to compute weighted location + await Promise.all( + event.wifis.map(async (wifi) => { + const apiResponse = await getLocationForWifiMemoized(wifi.mac); + if ((apiResponse != undefined) && (apiResponse?.totalResults > 0)) { + // Create new WiFi Scan entry if wigle.net reported location + const newWifiScan = wifiScanService.createWifiScan({ + lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, + mac: wifi.mac, + rssi: wifi.rssi, + latitude: apiResponse?.results[0]?.trilat, + longitude: apiResponse?.results[0]?.trilong, + }) + + // Calculate weight based on RSSI (higher signal strength gives more weight) + const weight = 1 / Math.abs((await newWifiScan).rssi); + totalWeight += weight; + + // Accumulate weighted latitude and longitude + weightedLatitude += (await newWifiScan).latitude * weight; + weightedLongitude += (await newWifiScan).longitude * weight; + } + }) + ); + + // Calculate the weighted average to get the virtual location + const virtualLocation = { + latitude: weightedLatitude / totalWeight, + longitude: weightedLongitude / totalWeight + }; + + console.log("Tracker location based on WiFi Scan location:", virtualLocation); + wifi_based_latitude = virtualLocation.latitude; + wifi_based_longitude = virtualLocation.longitude; } + // Get location based on GNSS if ((event.gnssLocation.latitude) && (event.gnssLocation.longitude)) { gnss_based_latitude = event.gnssLocation.latitude; gnss_based_longitude = event.gnssLocation.longitude; @@ -63,6 +107,8 @@ domainEventEmitter.on( ttn_gw_longitude: ttn_gw_based_longitude, gnss_latitude: gnss_based_latitude, gnss_longitude: gnss_based_longitude, + wifi_latitude: wifi_based_latitude, + wifi_longitude: wifi_based_longitude, }); console.log(newLocation) -- 2.47.1 From 718e093d3dbfdf3a474cd0b104937c43779d5f904203a786c357fa221013e425 Mon Sep 17 00:00:00 2001 From: localhorst Date: Wed, 1 Jan 2025 21:56:23 +0100 Subject: [PATCH 10/14] fix location model --- server/src/models/location.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/models/location.ts b/server/src/models/location.ts index 63668b5..4b3e708 100644 --- a/server/src/models/location.ts +++ b/server/src/models/location.ts @@ -46,7 +46,7 @@ Location.init( type: DataTypes.NUMBER, allowNull: true, }, - ttn_gw__longitude: { + ttn_gw_longitude: { type: DataTypes.NUMBER, allowNull: true, }, -- 2.47.1 From f341e6039f92c824cc6f4ebec1286a37b978b20d5cf0eae70f67a65d45cf6568 Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 2 Jan 2025 10:38:06 +0100 Subject: [PATCH 11/14] cleanup event definition --- server/src/event/ttnMessageReceivedEvent.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/event/ttnMessageReceivedEvent.ts b/server/src/event/ttnMessageReceivedEvent.ts index f92d05a..cbf068f 100644 --- a/server/src/event/ttnMessageReceivedEvent.ts +++ b/server/src/event/ttnMessageReceivedEvent.ts @@ -12,7 +12,7 @@ export type TtnMessageReceivedEvent = { altitude: number; }[]; gnssLocation: { - latitude: number | undefined; - longitude: number | undefined; + latitude?: number; + longitude?: number; } }; -- 2.47.1 From 6d20f4e54cf8b52c2a74cb160b82ab76913b487e3c60863cd822eea0b4317b3a Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 2 Jan 2025 11:38:27 +0100 Subject: [PATCH 12/14] cleanup --- .../ttnMessageReceivedEventHandler.ts | 197 +++++++++++------- 1 file changed, 124 insertions(+), 73 deletions(-) diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 84293a2..05a94c6 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -11,6 +11,119 @@ import { getLocationForWifiMemoized } from "../proxy/wigle"; const locationService = container.resolve(LocationService); const wifiScanService = container.resolve(WifiScanService); +const CalculateTtnGatewayLocation = async (event: TtnMessageReceivedEvent) => { + // Get location based on TTN Gateways + const virtualLocation = { + latitude: undefined as number | undefined, + longitude: undefined as number | undefined, + }; + + if (!event.ttnGateways || event.ttnGateways.length === 0) { + console.log("No TTN Gateway location received!") + } else { + let totalWeight = 0; + let weightedLatitude = 0; + let weightedLongitude = 0; + + event.ttnGateways.forEach(gw => { + const weight = 1 / Math.abs(gw.rssi); // Higher RSSI (closer to 0) gives more weight + totalWeight += weight; + weightedLatitude += gw.latitude * weight; + weightedLongitude += gw.longitude * weight; + }); + + // Calculate the weighted average to get the virtual location + const virtualLocation = { + latitude: weightedLatitude / totalWeight, + longitude: weightedLongitude / totalWeight + }; + + console.log("Tracker location based on TTN Gateway location:", virtualLocation); + } + return { + ttn_latitude: virtualLocation.latitude, + ttn_longitude: virtualLocation.longitude, + }; +}; + +const CalculateWifiLocation = async (event: TtnMessageReceivedEvent) => { + // Get location based on WiFi Scans + const virtualLocation = { + latitude: undefined as number | undefined, + longitude: undefined as number | undefined, + }; + + if (!event.wifis || event.wifis.length === 0) { + console.log("No WiFi scans received!") + } else { + // Process Wi-Fi data to compute weighted location + const wifiScans = await Promise.all( + event.wifis.map(async (wifi) => { + // Create new WiFi Scan entry if wigle.net reported location + const apiResponse = await getLocationForWifiMemoized(wifi.mac); + return { + lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, + mac: wifi.mac, + rssi: wifi.rssi, + latitude: apiResponse?.results[0]?.trilat, + longitude: apiResponse?.results[0]?.trilong, + }; + }) + ); + + await wifiScanService.createWifiScans(wifiScans); + + const { totalWeight, weightedLatitude, weightedLongitude } = + wifiScans.reduce( + (acc, { latitude, longitude, rssi }) => { + if (latitude && longitude && rssi !== 0) { + const weight = 1 / Math.abs(rssi); + + acc.totalWeight += weight; + acc.weightedLatitude += latitude * weight; + acc.weightedLongitude += longitude * weight; + } + + return acc; + }, + { + totalWeight: 0, + weightedLatitude: 0, + weightedLongitude: 0, + } + ); + + // Calculate the weighted average to get the virtual location + virtualLocation.latitude = weightedLatitude / totalWeight; + virtualLocation.longitude = weightedLongitude / totalWeight; + + console.log("Tracker location based on WiFi Scan location:", virtualLocation); + } + return { + wifi_latitude: virtualLocation.latitude, + wifi_longitude: virtualLocation.longitude, + }; +}; + +const CalculateGnssLocation = async (event: TtnMessageReceivedEvent) => { + // Default virtual location with undefined coordinates + const virtualLocation = { + latitude: undefined as number | undefined, + longitude: undefined as number | undefined, + }; + + if (virtualLocation.latitude === undefined || virtualLocation.longitude === undefined) { + console.log("No valid GNSS location received!"); + } + + return { + gnss_latitude: virtualLocation.latitude, + gnss_longitude: virtualLocation.longitude, + }; +}; + + + domainEventEmitter.on( TtnMessageReceivedEventName, async (event: TtnMessageReceivedEvent) => { @@ -23,83 +136,21 @@ domainEventEmitter.on( var ttn_gw_based_latitude: number | undefined = undefined; var ttn_gw_based_longitude: number | undefined = undefined; - // Get location based on TTN Gateways - if (!event.ttnGateways || event.ttnGateways.length === 0) { - console.log("No TTN Gateway location received!") - } else { - let totalWeight = 0; - let weightedLatitude = 0; - let weightedLongitude = 0; - - event.ttnGateways.forEach(gw => { - const weight = 1 / Math.abs(gw.rssi); // Higher RSSI (closer to 0) gives more weight - totalWeight += weight; - weightedLatitude += gw.latitude * weight; - weightedLongitude += gw.longitude * weight; - }); - - // Calculate the weighted average to get the virtual location - const virtualLocation = { - latitude: weightedLatitude / totalWeight, - longitude: weightedLongitude / totalWeight - }; - - console.log("Tracker location based on TTN Gateway location:", virtualLocation); - ttn_gw_based_latitude = virtualLocation.latitude; - ttn_gw_based_longitude = virtualLocation.longitude; + if (event.ttnGateways && event.ttnGateways.length > 0) { + const virtualLocation = await CalculateTtnGatewayLocation(event); + ttn_gw_based_latitude = virtualLocation.ttn_latitude; + ttn_gw_based_longitude = virtualLocation.ttn_longitude; } - // Get location based on WiFi Scans - if (!event.wifis || event.wifis.length === 0) { - console.log("No WiFi scans received!") - } else { - let totalWeight = 0; - let weightedLatitude = 0; - let weightedLongitude = 0; - - // Process Wi-Fi data to compute weighted location - await Promise.all( - event.wifis.map(async (wifi) => { - const apiResponse = await getLocationForWifiMemoized(wifi.mac); - if ((apiResponse != undefined) && (apiResponse?.totalResults > 0)) { - // Create new WiFi Scan entry if wigle.net reported location - const newWifiScan = wifiScanService.createWifiScan({ - lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, - mac: wifi.mac, - rssi: wifi.rssi, - latitude: apiResponse?.results[0]?.trilat, - longitude: apiResponse?.results[0]?.trilong, - }) - - // Calculate weight based on RSSI (higher signal strength gives more weight) - const weight = 1 / Math.abs((await newWifiScan).rssi); - totalWeight += weight; - - // Accumulate weighted latitude and longitude - weightedLatitude += (await newWifiScan).latitude * weight; - weightedLongitude += (await newWifiScan).longitude * weight; - } - }) - ); - - // Calculate the weighted average to get the virtual location - const virtualLocation = { - latitude: weightedLatitude / totalWeight, - longitude: weightedLongitude / totalWeight - }; - - console.log("Tracker location based on WiFi Scan location:", virtualLocation); - wifi_based_latitude = virtualLocation.latitude; - wifi_based_longitude = virtualLocation.longitude; + if (event.wifis && event.wifis.length > 0) { + const virtualLocation = await CalculateWifiLocation(event); + wifi_based_latitude = virtualLocation.wifi_latitude; + wifi_based_longitude = virtualLocation.wifi_longitude; } - // Get location based on GNSS - if ((event.gnssLocation.latitude) && (event.gnssLocation.longitude)) { - gnss_based_latitude = event.gnssLocation.latitude; - gnss_based_longitude = event.gnssLocation.longitude; - } else { - console.log("No GNSS location received!") - } + const virtualLocation = await CalculateGnssLocation(event); + gnss_based_latitude = virtualLocation.gnss_latitude; + gnss_based_longitude = virtualLocation.gnss_longitude; const newLocation = await locationService.createLocation({ lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id, -- 2.47.1 From 64b77c33b530366487521ed1fd18e85a91665b7e646f3502050b1fecbc1884ed Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 2 Jan 2025 14:44:59 +0100 Subject: [PATCH 13/14] cleanup and fix gnss location --- .../ttnMessageReceivedEventHandler.ts | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-) diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 05a94c6..19fb6fd 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -11,7 +11,7 @@ import { getLocationForWifiMemoized } from "../proxy/wigle"; const locationService = container.resolve(LocationService); const wifiScanService = container.resolve(WifiScanService); -const CalculateTtnGatewayLocation = async (event: TtnMessageReceivedEvent) => { +const CalculateTtnGatewayLocation = (event: TtnMessageReceivedEvent) => { // Get location based on TTN Gateways const virtualLocation = { latitude: undefined as number | undefined, @@ -105,25 +105,18 @@ const CalculateWifiLocation = async (event: TtnMessageReceivedEvent) => { }; }; -const CalculateGnssLocation = async (event: TtnMessageReceivedEvent) => { - // Default virtual location with undefined coordinates - const virtualLocation = { - latitude: undefined as number | undefined, - longitude: undefined as number | undefined, - }; - - if (virtualLocation.latitude === undefined || virtualLocation.longitude === undefined) { +const CalculateGnssLocation = (event: TtnMessageReceivedEvent) => { + // Get location based on reported GNSS + if (event.gnssLocation.latitude === undefined || event.gnssLocation.longitude === undefined) { console.log("No valid GNSS location received!"); } return { - gnss_latitude: virtualLocation.latitude, - gnss_longitude: virtualLocation.longitude, + gnss_latitude: event.gnssLocation.latitude, + gnss_longitude: event.gnssLocation.longitude, }; }; - - domainEventEmitter.on( TtnMessageReceivedEventName, async (event: TtnMessageReceivedEvent) => { @@ -137,7 +130,7 @@ domainEventEmitter.on( var ttn_gw_based_longitude: number | undefined = undefined; if (event.ttnGateways && event.ttnGateways.length > 0) { - const virtualLocation = await CalculateTtnGatewayLocation(event); + const virtualLocation = CalculateTtnGatewayLocation(event); ttn_gw_based_latitude = virtualLocation.ttn_latitude; ttn_gw_based_longitude = virtualLocation.ttn_longitude; } @@ -148,7 +141,7 @@ domainEventEmitter.on( wifi_based_longitude = virtualLocation.wifi_longitude; } - const virtualLocation = await CalculateGnssLocation(event); + const virtualLocation = CalculateGnssLocation(event); gnss_based_latitude = virtualLocation.gnss_latitude; gnss_based_longitude = virtualLocation.gnss_longitude; -- 2.47.1 From 7e42d3b8c971d1202c4dcfd9f82206bade1d569d4df0965092e45ddab1cf55f2 Mon Sep 17 00:00:00 2001 From: localhorst Date: Thu, 2 Jan 2025 14:56:00 +0100 Subject: [PATCH 14/14] fix ttn location parse --- server/src/eventHandler/ttnMessageReceivedEventHandler.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts index 19fb6fd..e682c01 100644 --- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts +++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts @@ -33,11 +33,8 @@ const CalculateTtnGatewayLocation = (event: TtnMessageReceivedEvent) => { }); // Calculate the weighted average to get the virtual location - const virtualLocation = { - latitude: weightedLatitude / totalWeight, - longitude: weightedLongitude / totalWeight - }; - + virtualLocation.latitude = weightedLatitude / totalWeight; + virtualLocation.longitude = weightedLongitude / totalWeight; console.log("Tracker location based on TTN Gateway location:", virtualLocation); } return { -- 2.47.1