feat: tracker location based on multiple location providers #5
@@ -11,19 +11,13 @@ import { getLocationForWifiMemoized } from "../proxy/wigle";
|
|||||||
const locationService = container.resolve(LocationService);
|
const locationService = container.resolve(LocationService);
|
||||||
const wifiScanService = container.resolve(WifiScanService);
|
const wifiScanService = container.resolve(WifiScanService);
|
||||||
|
|
||||||
domainEventEmitter.on(
|
const CalculateTtnGatewayLocation = async (event: TtnMessageReceivedEvent) => {
|
||||||
TtnMessageReceivedEventName,
|
|
||||||
async (event: TtnMessageReceivedEvent) => {
|
|
||||||
console.log(event);
|
|
||||||
|
|
||||||
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
|
// 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) {
|
if (!event.ttnGateways || event.ttnGateways.length === 0) {
|
||||||
|
localhorst marked this conversation as resolved
Outdated
|
|||||||
console.log("No TTN Gateway location received!")
|
console.log("No TTN Gateway location received!")
|
||||||
} else {
|
} else {
|
||||||
@@ -45,62 +39,119 @@ domainEventEmitter.on(
|
|||||||
};
|
};
|
||||||
|
|
||||||
console.log("Tracker location based on TTN Gateway location:", virtualLocation);
|
console.log("Tracker location based on TTN Gateway location:", virtualLocation);
|
||||||
ttn_gw_based_latitude = virtualLocation.latitude;
|
|
||||||
ttn_gw_based_longitude = virtualLocation.longitude;
|
|
||||||
}
|
}
|
||||||
|
return {
|
||||||
|
ttn_latitude: virtualLocation.latitude,
|
||||||
|
ttn_longitude: virtualLocation.longitude,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const CalculateWifiLocation = async (event: TtnMessageReceivedEvent) => {
|
||||||
// Get location based on WiFi Scans
|
// 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) {
|
if (!event.wifis || event.wifis.length === 0) {
|
||||||
console.log("No WiFi scans received!")
|
console.log("No WiFi scans received!")
|
||||||
} else {
|
} else {
|
||||||
let totalWeight = 0;
|
|
||||||
let weightedLatitude = 0;
|
|
||||||
let weightedLongitude = 0;
|
|
||||||
|
|
||||||
// Process Wi-Fi data to compute weighted location
|
// Process Wi-Fi data to compute weighted location
|
||||||
await Promise.all(
|
const wifiScans = await Promise.all(
|
||||||
event.wifis.map(async (wifi) => {
|
event.wifis.map(async (wifi) => {
|
||||||
|
localhorst marked this conversation as resolved
Outdated
Pheanox
commented
Der Wifi eintrag wird nur die die Datenbank geschrieben, wenn es eine Location gibt, sollte dieser nicht auch ohne reingeschrieben werden mit latitude und longitude undefined? Ansonsten würde ich es in drei steps unterteilen: Api Call, Datenbank entry erstellen, totalWeight + weightedLatitude + weightedLongitude ausrechnen. Ich glaube das macht es übersichtlicher ist aber vermutlich Geschmackssache. Mein Vorschlag: ` const wifiScans = await Promise.all(
Der Wifi eintrag wird nur die die Datenbank geschrieben, wenn es eine Location gibt, sollte dieser nicht auch ohne reingeschrieben werden mit latitude und longitude undefined? Ansonsten würde ich es in drei steps unterteilen: Api Call, Datenbank entry erstellen, totalWeight + weightedLatitude + weightedLongitude ausrechnen. Ich glaube das macht es übersichtlicher ist aber vermutlich Geschmackssache. Mein Vorschlag:
` const wifiScans = await Promise.all(
event.wifis.map(async (wifi) => {
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,
}
);
const virtualLocation = {
latitude: weightedLatitude / totalWeight,
longitude: weightedLongitude / totalWeight,
};`
|
|||||||
const apiResponse = await getLocationForWifiMemoized(wifi.mac);
|
|
||||||
if ((apiResponse != undefined) && (apiResponse?.totalResults > 0)) {
|
|
||||||
// Create new WiFi Scan entry if wigle.net reported location
|
// Create new WiFi Scan entry if wigle.net reported location
|
||||||
const newWifiScan = wifiScanService.createWifiScan({
|
const apiResponse = await getLocationForWifiMemoized(wifi.mac);
|
||||||
|
return {
|
||||||
lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id,
|
lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id,
|
||||||
mac: wifi.mac,
|
mac: wifi.mac,
|
||||||
|
localhorst marked this conversation as resolved
Outdated
Pheanox
commented
await wifiScanService.createWifiScan await wifiScanService.createWifiScan
|
|||||||
rssi: wifi.rssi,
|
rssi: wifi.rssi,
|
||||||
latitude: apiResponse?.results[0]?.trilat,
|
latitude: apiResponse?.results[0]?.trilat,
|
||||||
longitude: apiResponse?.results[0]?.trilong,
|
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;
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
await wifiScanService.createWifiScans(wifiScans);
|
||||||
|
|
||||||
|
localhorst marked this conversation as resolved
Outdated
Pheanox
commented
await kann weg await kann weg
|
|||||||
|
const { totalWeight, weightedLatitude, weightedLongitude } =
|
||||||
|
wifiScans.reduce(
|
||||||
|
(acc, { latitude, longitude, rssi }) => {
|
||||||
|
if (latitude && longitude && rssi !== 0) {
|
||||||
|
const weight = 1 / Math.abs(rssi);
|
||||||
|
localhorst marked this conversation as resolved
Outdated
Pheanox
commented
await kann weg await kann weg
|
|||||||
|
|
||||||
|
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
|
// Calculate the weighted average to get the virtual location
|
||||||
const virtualLocation = {
|
virtualLocation.latitude = weightedLatitude / totalWeight;
|
||||||
latitude: weightedLatitude / totalWeight,
|
virtualLocation.longitude = weightedLongitude / totalWeight;
|
||||||
longitude: weightedLongitude / totalWeight
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log("Tracker location based on WiFi Scan location:", virtualLocation);
|
console.log("Tracker location based on WiFi Scan location:", virtualLocation);
|
||||||
wifi_based_latitude = virtualLocation.latitude;
|
}
|
||||||
wifi_based_longitude = virtualLocation.longitude;
|
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!");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get location based on GNSS
|
return {
|
||||||
if ((event.gnssLocation.latitude) && (event.gnssLocation.longitude)) {
|
gnss_latitude: virtualLocation.latitude,
|
||||||
gnss_based_latitude = event.gnssLocation.latitude;
|
gnss_longitude: virtualLocation.longitude,
|
||||||
gnss_based_longitude = event.gnssLocation.longitude;
|
};
|
||||||
} else {
|
};
|
||||||
console.log("No GNSS location received!")
|
|
||||||
|
|
||||||
|
|
||||||
|
domainEventEmitter.on(
|
||||||
|
TtnMessageReceivedEventName,
|
||||||
|
async (event: TtnMessageReceivedEvent) => {
|
||||||
|
console.log(event);
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.wifis && event.wifis.length > 0) {
|
||||||
|
const virtualLocation = await CalculateWifiLocation(event);
|
||||||
|
wifi_based_latitude = virtualLocation.wifi_latitude;
|
||||||
|
wifi_based_longitude = virtualLocation.wifi_longitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
const virtualLocation = await CalculateGnssLocation(event);
|
||||||
|
gnss_based_latitude = virtualLocation.gnss_latitude;
|
||||||
|
gnss_based_longitude = virtualLocation.gnss_longitude;
|
||||||
|
|
||||||
const newLocation = await locationService.createLocation({
|
const newLocation = await locationService.createLocation({
|
||||||
lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id,
|
lp_ttn_end_device_uplinks_id: event.lp_ttn_end_device_uplinks_id,
|
||||||
ttn_gw_latitude: ttn_gw_based_latitude,
|
ttn_gw_latitude: ttn_gw_based_latitude,
|
||||||
|
|||||||
Das ! kann weg.
Bzw. kann alles weg, wird nicht verwendet