From 14c6c9506fad786563bbd73a327475723224d280 Mon Sep 17 00:00:00 2001 From: kyle Date: Mon, 9 Feb 2026 18:51:42 +0100 Subject: [PATCH] fix: optimize Traccar Client QR code with iOS background GPS settings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit QR enrollment was only setting id and interval, causing iOS to default to medium accuracy with stop_detection enabled — which pauses GPS updates when the phone appears stationary, causing 5-30 min gaps. Now sets accuracy=highest, stop_detection=false, distance=0, angle=30, heartbeat=300, buffer=true. Also updates driver instructions with required iPhone settings (Always location, Background App Refresh). Co-Authored-By: Claude Opus 4.6 --- backend/src/gps/gps.service.ts | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/backend/src/gps/gps.service.ts b/backend/src/gps/gps.service.ts index fefd416..5d93e6f 100644 --- a/backend/src/gps/gps.service.ts +++ b/backend/src/gps/gps.service.ts @@ -198,14 +198,20 @@ export class GpsService implements OnModuleInit { const settings = await this.getSettings(); // Build QR code URL for Traccar Client app - // Format: https://server:5055?id=DEVICE_ID&interval=SECONDS - // The Traccar Client app parses this as: server URL (origin) + query params (id, interval, etc.) + // All supported params: id, interval, accuracy, distance, angle, heartbeat, buffer, stop_detection, wakelock + // Key iOS settings: accuracy=highest + stop_detection=false prevents iOS from pausing GPS updates const devicePort = this.configService.get('TRACCAR_DEVICE_PORT') || 5055; const traccarPublicUrl = this.traccarClient.getTraccarUrl(); const qrUrl = new URL(traccarPublicUrl); qrUrl.port = String(devicePort); qrUrl.searchParams.set('id', actualDeviceId); qrUrl.searchParams.set('interval', String(settings.updateIntervalSeconds)); + qrUrl.searchParams.set('accuracy', 'highest'); // iOS: kCLDesiredAccuracyBestForNavigation + qrUrl.searchParams.set('distance', '0'); // Disable distance filter — rely on interval + qrUrl.searchParams.set('angle', '30'); // Send update on 30° heading change (turns) + qrUrl.searchParams.set('heartbeat', '300'); // 5 min heartbeat when stationary + qrUrl.searchParams.set('stop_detection', 'false'); // CRITICAL: prevent iOS from pausing GPS + qrUrl.searchParams.set('buffer', 'true'); // Buffer points when offline const qrCodeUrl = qrUrl.toString(); this.logger.log(`QR code URL for driver: ${qrCodeUrl}`); @@ -217,15 +223,21 @@ GPS Tracking Setup Instructions for ${driver.name}: - iOS: https://apps.apple.com/app/traccar-client/id843156974 - Android: https://play.google.com/store/apps/details?id=org.traccar.client -2. Open the app and configure: +2. Open the app and scan the QR code (or configure manually): - Device identifier: ${actualDeviceId} - Server URL: ${serverUrl} + - Location accuracy: Highest - Frequency: ${settings.updateIntervalSeconds} seconds - - Location accuracy: High + - Distance: 0 + - Angle: 30 -3. Tap "Service Status" to start tracking. +3. IMPORTANT iPhone Settings: + - Settings > Privacy > Location Services > Traccar Client > "Always" + - Settings > General > Background App Refresh > ON for Traccar Client + - Do NOT swipe the app away from the app switcher + - Low Power Mode should be OFF while driving -Note: GPS tracking is only active during shift hours (${settings.shiftStartHour}:00 - ${settings.shiftEndHour}:00). +4. Tap "Service Status" to start tracking. `.trim(); let signalMessageSent = false; @@ -286,6 +298,12 @@ Note: GPS tracking is only active during shift hours (${settings.shiftStartHour} qrUrl.port = String(devicePort); qrUrl.searchParams.set('id', device.deviceIdentifier); qrUrl.searchParams.set('interval', String(settings.updateIntervalSeconds)); + qrUrl.searchParams.set('accuracy', 'highest'); + qrUrl.searchParams.set('distance', '0'); + qrUrl.searchParams.set('angle', '30'); + qrUrl.searchParams.set('heartbeat', '300'); + qrUrl.searchParams.set('stop_detection', 'false'); + qrUrl.searchParams.set('buffer', 'true'); return { driverName: device.driver.name,