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/.env.template b/server/.env.template
index 69702a9..9740f4c 100644
--- a/server/.env.template
+++ b/server/.env.template
@@ -7,6 +7,6 @@ DB_PORT=""
 WIGLE_TOKEN="" # Go to account and generate token "Encoded for use"
 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/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/controller/ttnController.ts b/server/src/controller/ttnController.ts
index daabf42..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,6 +79,7 @@ router.post(
           latitude: g.latitude,
           longitude: g.longitude,
         })),
+        gnssLocation: { latitude, longitude }
       };
 
       domainEventEmitter.emit(TtnMessageReceivedEventName, event);
diff --git a/server/src/event/ttnMessageReceivedEvent.ts b/server/src/event/ttnMessageReceivedEvent.ts
index b6b6945..cbf068f 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: {
+    latitude?: number;
+    longitude?: number;
+  }
 };
diff --git a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts
index 90c0007..e682c01 100644
--- a/server/src/eventHandler/ttnMessageReceivedEventHandler.ts
+++ b/server/src/eventHandler/ttnMessageReceivedEventHandler.ts
@@ -3,11 +3,156 @@ import {
   TtnMessageReceivedEvent,
   TtnMessageReceivedEventName,
 } 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);
+
+const CalculateTtnGatewayLocation = (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
+    virtualLocation.latitude = weightedLatitude / totalWeight;
+    virtualLocation.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 = (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: event.gnssLocation.latitude,
+    gnss_longitude: event.gnssLocation.longitude,
+  };
+};
 
 domainEventEmitter.on(
   TtnMessageReceivedEventName,
   async (event: TtnMessageReceivedEvent) => {
     console.log(event);
-    // TODO Hendrik ๐Ÿš€
+
+    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 = 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 = 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,
+      ttn_gw_latitude: ttn_gw_based_latitude,
+      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)
   }
 );
+
diff --git a/server/src/index.ts b/server/src/index.ts
index f0202a8..dcc61d9 100644
--- a/server/src/index.ts
+++ b/server/src/index.ts
@@ -25,5 +25,5 @@ app.use("/api/locations", locationRoutes);
 app.use("/api/ttn", ttnRoutes);
 
 app.listen(PORT, () => {
-  console.log(`๐Ÿš€ Server lรคuft auf http://localhost:${PORT}`);
+  console.log(`๐Ÿš€ Server runs here: http://localhost:${PORT}`);
 });
diff --git a/server/src/models/location.ts b/server/src/models/location.ts
index 1a79938..4b3e708 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,