Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable heartbeat to be sent automatically with async and Http Requests #1245

Closed
danielgomezrico opened this issue Mar 8, 2024 · 6 comments
Closed
Labels

Comments

@danielgomezrico
Copy link

danielgomezrico commented Mar 8, 2024

We need to keep calling our server with the latest know location every x seconds, even if the device is stationary, and we are using config async to call a service for that.

What we need to know how to do is that when the motion stops, the HTTP server stops being called and the heartbeat starts sending signals to the headless service or the listener. But they are not been sent to the HTTP server, it just beats.

It does make sense to me that this is the default behavior since it is beat, right? But for our use case, we still have to call the service when the beat is called, and so, how can we set up the library to still call the HTTP service even for heartbeat locations?

Your Environment

  • Plugin version: 4.13.5
  • Platform: iOS And Android
  • OS version: ios 12 > and android 9 >
  • Device manufacturer / model:
  • Flutter info (flutter doctor): flutter 3.16.4 and dart 3.2.3
  • Plugin config:
Config(
      // Run setup
      autoSync: true,
      foregroundService: true,
      stopOnTerminate: false,
      startOnBoot: true,
      desiredAccuracy: Config.DESIRED_ACCURACY_HIGH,
      reset: true,
      enableHeadless: true,

      // Force updates every x milliseconds ignoring distance
      disableMotionActivityUpdates: true,
      allowIdenticalLocations: true,
      useSignificantChangesOnly: false,
      activityRecognitionInterval: 0,
      isMoving: true,
      disableElasticity: remoteConfig.disableElasticity,
      distanceFilter: remoteConfig.distanceFilter,
      heartbeatInterval: 10,
      locationUpdateInterval: remoteConfig.locationUpdateIntervalMilliseconds,
      fastestLocationUpdateInterval: remoteConfig.locationUpdateIntervalMilliseconds,
      preventSuspend:  true,

      // Url Request
      url: url,
      httpRootProperty: '.',
      headers: { 'Content-Type': 'application/json' },
      params: { 'reference_type': 'id' },

      // Logging
      debug: true,
      logLevel: Config.LOG_LEVEL_VERBOSE,
    );

Expected Behavior

The HTTP service is executed for the URL in the setup for the new locations and for all heartbeat events

Actual Behavior

The HTTP service is executed for the URL in the setup only for the new locations.

The heartbeat listeners and headless function are executed, but not the automatic HTTP service that is set up via the config.

Steps to Reproduce

  1. Run the service
  2. Check that it starts emitting, but it stops at some time with:
Logs with the latest HTTP service call and motion change false
00:15:40.770  I  [c.t.l.service.TrackingService k] 
                 ╔═════════════════════════════════════════════
                 ║ TrackingService motionchange: false
                 ╠═════════════════════════════════════════════
00:15:40.822  D  [c.t.l.service.AbstractService a] 
                   ⚙️︎   FINISH [TrackingService startId: 32, eventCount: 0, sticky: false]
00:15:40.855  I  [c.t.l.d.s.SQLiteLocationDAO persist] 
                   ✅  INSERT: 05f6927e-c313-47c5-b318-9b8ab512ab0d
00:15:41.531  D  app_time_stats: avg=136.28ms min=38.60ms max=639.05ms count=10
00:15:41.547  I  [c.t.l.http.HttpService flush] 
                 ╔═════════════════════════════════════════════
                 ║ HTTP Service (count: 1)
                 ╠═════════════════════════════════════════════
00:15:41.576  D  [c.t.l.service.AbstractService f] 
                   ⚙️︎  TrackingService.stopSelfResult(32): true
00:15:41.577  D  [c.t.l.service.AbstractService onDestroy] 
                   🔴  TrackingService stopped
00:15:41.670  I  [c.t.l.u.BackgroundTaskManager$Task start] ⏳ startBackgroundTask: 32
00:15:41.687  D  [c.t.l.d.s.SQLiteLocationDAO first] 
                   ✅  Locked 1 records
00:15:41.687  I  [c.t.l.http.HttpService a] 
                   🔵  HTTP POST: 05f6927e-c313-47c5-b318-9b8ab512ab0d
00:15:41.895  I  [c.t.l.http.HttpService$f onResponse] 
                   🔵  Response: 201
00:15:41.899  D  [c.t.l.d.s.SQLiteLocationDAO destroy] 
                   ✅  DESTROY: 05f6927e-c313-47c5-b318-9b8ab512ab0d
00:15:41.902  I  [c.t.l.u.BackgroundTaskManager$Task stop] ⏳ stopBackgroundTask: 32
00:15:41.903  I  Worker result SUCCESS for Work [ id=a4d849a1-3934-4240-8d91-732184f88b28, tags={ com.transistorsoft.locationmanager.util.BackgroundTaskWorker } ]

And then theres only heartbeat but no HTTP requests:

Logs only with heartbeat
00:16:00.219  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:16:00.235  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:16:00.266  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:16:00.285  D  app_time_stats: avg=22.18ms min=10.58ms max=41.29ms count=45
00:16:01.294  D  app_time_stats: avg=67.17ms min=11.02ms max=616.79ms count=15
00:16:02.076  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:16:02.077  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:16:02.297  D  app_time_stats: avg=16.70ms min=9.67ms max=24.78ms count=60
00:16:03.310  D  app_time_stats: avg=16.86ms min=6.84ms max=28.86ms count=60
00:16:04.310  D  app_time_stats: avg=16.66ms min=11.58ms max=25.74ms count=60
00:16:05.326  D  app_time_stats: avg=16.65ms min=9.22ms max=24.42ms count=61
00:16:06.327  D  app_time_stats: avg=16.96ms min=9.69ms max=31.58ms count=59
00:16:07.334  D  app_time_stats: avg=17.34ms min=7.72ms max=28.11ms count=58
00:16:08.344  D  app_time_stats: avg=21.87ms min=13.13ms max=40.10ms count=46
00:16:09.350  D  app_time_stats: avg=22.80ms min=13.77ms max=44.83ms count=44
00:16:10.276  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:16:10.283  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:16:10.329  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:16:10.365  D  app_time_stats: avg=23.03ms min=12.22ms max=72.97ms count=44
00:16:11.366  D  app_time_stats: avg=66.66ms min=10.84ms max=609.68ms count=15
00:16:12.103  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:16:12.103  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:16:12.110  W  mediaplayer went away with unhandled events
00:16:12.368  D  app_time_stats: avg=16.68ms min=9.84ms max=24.01ms count=60
00:16:13.375  D  app_time_stats: avg=16.49ms min=8.08ms max=24.33ms count=61
00:16:14.377  D  app_time_stats: avg=16.96ms min=8.74ms max=33.34ms count=59
00:16:15.392  D  app_time_stats: avg=16.64ms min=8.20ms max=27.34ms count=61
00:16:16.410  D  app_time_stats: avg=16.67ms min=9.37ms max=21.69ms count=61
00:16:17.415  D  app_time_stats: avg=17.61ms min=8.38ms max=35.06ms count=57
00:16:18.417  D  app_time_stats: avg=20.39ms min=10.09ms max=33.76ms count=49
00:16:19.453  D  app_time_stats: avg=20.28ms min=11.69ms max=55.07ms count=51
00:16:20.434  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:16:20.453  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:16:20.486  D  app_time_stats: avg=23.32ms min=12.05ms max=78.11ms count=44
00:16:20.512  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:16:21.504  D  app_time_stats: avg=71.65ms min=9.83ms max=626.78ms count=14
00:16:22.314  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:16:22.315  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:16:22.320  W  mediaplayer went away with unhandled events
00:16:22.509  D  app_time_stats: avg=16.66ms min=10.26ms max=21.44ms count=60
00:16:23.525  D  app_time_stats: avg=16.63ms min=12.71ms max=22.39ms count=61
00:16:24.526  D  app_time_stats: avg=16.96ms min=8.50ms max=30.68ms count=59
00:16:25.526  D  app_time_stats: avg=13.31ms min=1.05ms max=26.86ms count=60
00:16:26.543  D  app_time_stats: avg=1.32ms min=0.74ms max=2.88ms count=61
00:16:27.559  D  app_time_stats: avg=3.95ms min=0.81ms max=32.70ms count=58
00:16:28.573  D  app_time_stats: avg=20.64ms min=11.80ms max=43.06ms count=49
00:16:29.579  D  app_time_stats: avg=22.29ms min=10.38ms max=55.26ms count=45
00:16:30.524  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:16:30.529  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:16:30.543  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:16:30.602  D  app_time_stats: avg=22.19ms min=10.29ms max=52.74ms count=46
00:16:31.610  D  app_time_stats: avg=59.21ms min=8.44ms max=600.03ms count=17
00:16:32.274  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:16:32.274  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:16:32.278  W  mediaplayer went away with unhandled events
00:16:32.626  D  app_time_stats: avg=16.65ms min=8.18ms max=23.43ms count=61
00:16:33.629  D  app_time_stats: avg=16.98ms min=10.46ms max=36.77ms count=59
00:16:34.641  D  app_time_stats: avg=16.84ms min=4.86ms max=29.33ms count=60
00:16:35.644  D  app_time_stats: avg=16.70ms min=11.19ms max=21.57ms count=60
00:16:36.646  D  app_time_stats: avg=16.68ms min=6.88ms max=25.72ms count=60
00:16:37.646  D  app_time_stats: avg=18.49ms min=11.31ms max=35.68ms count=54
00:16:38.679  D  app_time_stats: avg=23.42ms min=11.58ms max=54.96ms count=44
00:16:39.685  D  app_time_stats: avg=20.45ms min=10.95ms max=45.34ms count=49
00:16:40.561  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:16:40.576  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:16:40.604  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:16:40.709  D  app_time_stats: avg=26.19ms min=6.56ms max=64.96ms count=39
00:16:41.712  D  app_time_stats: avg=71.48ms min=11.66ms max=621.98ms count=14
00:16:42.442  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:16:42.443  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:16:42.449  W  mediaplayer went away with unhandled events
00:16:42.726  D  app_time_stats: avg=5.18ms min=0.84ms max=25.05ms count=61
00:16:43.742  D  app_time_stats: avg=1.37ms min=0.87ms max=4.13ms count=61
00:16:44.744  D  app_time_stats: avg=1.59ms min=0.82ms max=8.78ms count=60
00:16:45.758  D  app_time_stats: avg=6.17ms min=0.79ms max=20.23ms count=59
00:16:46.759  D  app_time_stats: avg=16.67ms min=13.41ms max=20.24ms count=60
00:16:47.767  D  app_time_stats: avg=17.67ms min=11.54ms max=30.72ms count=57
00:16:48.773  D  app_time_stats: avg=23.35ms min=13.71ms max=46.93ms count=43
00:16:49.779  D  app_time_stats: avg=24.44ms min=10.52ms max=73.16ms count=41
00:16:50.627  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:16:50.635  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:16:50.672  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:16:50.850  D  app_time_stats: avg=25.42ms min=12.37ms max=81.13ms count=42
00:16:51.863  D  app_time_stats: avg=50.55ms min=14.38ms max=642.50ms count=20
00:16:52.424  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:16:52.424  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:16:52.432  W  mediaplayer went away with unhandled events
00:16:52.874  D  app_time_stats: avg=16.56ms min=6.21ms max=26.57ms count=61
00:16:53.876  D  app_time_stats: avg=16.68ms min=10.83ms max=25.30ms count=60
00:16:54.877  D  app_time_stats: avg=16.67ms min=13.52ms max=20.43ms count=60
00:16:55.895  D  app_time_stats: avg=9.35ms min=0.70ms max=25.58ms count=61
00:16:56.911  D  app_time_stats: avg=4.87ms min=0.86ms max=18.48ms count=59
00:16:57.917  D  app_time_stats: avg=21.36ms min=11.03ms max=92.52ms count=47
00:16:58.932  D  app_time_stats: avg=21.12ms min=9.76ms max=52.61ms count=48
00:16:59.933  D  app_time_stats: avg=22.70ms min=13.13ms max=57.00ms count=44
00:17:00.664  I  [c.t.l.scheduler.ScheduleEvent a] 
                 ╔═════════════════════════════════════════════
                 ║ ⏰ OneShot event fired: HEARTBEAT
                 ╠═════════════════════════════════════════════
00:17:00.685  I  [c.t.l.s.TSScheduleManager oneShot] 
                   ⏰ Scheduled OneShot: HEARTBEAT in 10000ms (jobID: -1307475748)
00:17:00.726  D  [c.t.l.service.HeartbeatService onHeartbeat] ❤️
00:17:00.942  D  app_time_stats: avg=26.36ms min=12.13ms max=79.45ms count=38
00:17:01.943  D  app_time_stats: avg=47.48ms min=9.66ms max=627.82ms count=21
00:17:02.511  V  resetDrmState:  mDrmInfo=null mDrmProvisioningThread=null mPrepareDrmInProgress=false mActiveDrmScheme=false
00:17:02.512  V  cleanDrmObj: mDrmObj=null mDrmSessionId=null
00:17:02.958  D  app_time_stats: avg=17.18ms min=10.67ms max=33.90ms count=59
00:17:03.958  D  app_time_stats: avg=16.62ms min=10.40ms max=21.99ms count=60
00:17:04.958  D  app_time_stats: avg=16.93ms min=6.08ms max=30.88ms count=59
00:17:05.959  D  app_time_stats: avg=16.66ms min=12.26ms max=20.15ms count=60
00:17:06.959  D  app_time_stats: avg=16.65ms min=14.83ms max=19.21ms count=60
00:17:07.967  D  app_time_stats: avg=17.65ms min=10.71ms max=29.35ms count=57
00:17:08.990  D  app_time_stats: avg=20.03ms min=12.75ms max=37.22ms count=51
00:17:10.001  D  app_time_stats: avg=22.40ms min=11.80ms max=37.47ms count=45
00:17:10.732  I  [c.t.l.scheduler.ScheduleEvent a] 

Context

My company needs to have the location of the hole travel with times less than 5 minutes between each call, and even if the car is stopped, so we are trying to fetch them every 10 seconds or 30 to try to make it into that time window.

@christocracy
Copy link
Member

We need to keep calling our server with the latest know location every x seconds, even if the device is stationary

Why?? You're fighting an uphill battle. The OS doesn't want you to do this.

This sort of behaviour is the reason that https://dontkillmyapp.com exists.

If the plug-in says the device is stationary, it's pointless to keep reporting "here I am", "here I am", "here I am", wasting the device battery.

@christocracy
Copy link
Member

You're responsible for requesting your own location in your onHeartbeat by calling .getCurrentPosition. The plug-in does NOT turn on location-services at all while stationary. The location provided to onHeartbeat is the "last known location".

You'll never get what you want on iOS and Android is becoming more strict with "exact" timers.

@danielgomezrico
Copy link
Author

Thanks for answering, that totally makes sense, but our business is related to moving other companies' packages. One of our providers is now requiring us to report the location in a time window less than 5 minutes per point in the hole of travel. We are struggling to make that happen. Do you think that trying to do this will make the OS to kill the service? Even if we are not accessing the GPS but just the latest known position and sending it back?

@christocracy
Copy link
Member

The easiest thing to do, is simply call .changePace(true) with a really large stopTimeout, forcing location-services to stay on, preventing the plug-in from entering the stationary state.

With location-services ON, your app continues to spin the CPU and your code is completely alive to run your own Dart timers to call .getCurrentPosition.

Be sure to call .changePace(false) when a "delivery" is complete or you'll kill the battery.

@danielgomezrico
Copy link
Author

Thanks! I will try that!

Copy link

This issue is stale because it has been open for 30 days with no activity.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants