Skip to content

Instantly share code, notes, and snippets.

@mkruisselbrink
Last active July 3, 2016 23:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mkruisselbrink/70c95b3068e1bbe9b668 to your computer and use it in GitHub Desktop.
Save mkruisselbrink/70c95b3068e1bbe9b668 to your computer and use it in GitHub Desktop.

There has been some discussion about support for the geolocation APIs from within service workers (and more general in the background), which made me wonder what some of the possible solutions for background access to geolocation information might look like in a potential future generic sensor API based geolocation API. Especially since it seems like a lot of this potential functionality would be useful for any sensor, not just geolocation.

So roughly the use cases I see for accessing a sensor from a service worker:

  1. Read the current (or recently cached) value from some sensor. In case of geolocation to get the current location in response to some other event.
  2. Log data from a sensor over some time period. For geolocation this would allow building apps like fitness trackers, where the app will want to start/stop recording location information, but doesn’t need to be constantly woken up while recording (unless the app is awake/visible anyway).
  3. Get notified when some sensor enters/leaves some range, some kind of sensor triggered alarms. For geolocation this would be the Geofencing API, but I think these kinds of triggers would make sense for many different types of sensors.

The first of these use cases is probably addressed sufficiently by the existing API in the form of Sensor.requestReading() and/or Sensor.reading, but the other two use cases don’t seem to really be supported by the currently proposed generic sensor API.

Log data from a sensor

For the second use case some kind of Sensor.startRecording() method might make sense, which could be used something like this:

// start recording a track, from a webapp
navigator.serviceWorker.ready.then(registration => {
  registration.sensors.startRecording(new GeolocationSensor({frequency: 0.1}), {tag: 'some identifier'})
    .then(recording => {
      // recording somehow represents the recording in progress
    }).catch(e => {
      // failed to start recording the sensor
    });
});

// check up on a track that is currently being recorded
navigator.serviceWorker.ready.then(registration => {
  registration.sensors.getRecording({tag: 'some identifier'})
    .then(recording => {
      recording.isActive.then(active => console.log('Recording is active: ' + active));
      recording.getReadings({/* options */}).then(readings => {
          // one possible option to getReadings could be to clear the readings that
          // are returned from the recording
          console.log('Logged track so far:');
          readings.forEach(reading => console.log(reading));
        });
    });
});

// stop recording for a particular track
navigator.serviceWorker.ready.then(registration => {
  registration.sensors.getRecording({tag: 'some identifier'})
    .then(recording => recording.stop())
    .then(readings => {
      readings.forEach(reading => console.log(reading));
    });
});

// in the service worker, get signalled about errors with the recording
self.addEventListener('sensorRecordingError', function(e) {
  console.log('Problems in recording ' + e.recording.tag);
  console.log('Which is recording sensor ' + e.recording.sensor.sensorId);
  e.recording.getReadings().then(readings => console.log('Logged ' + readings.length + ' readings'));
};

Triggered alarms

For the geofencing/triggers use cases, I imagine we'd let specs defining concrete Sensors also define specific triggers. These triggers can probably be either absolute (when the value enters/leaves this range) or relative (when the value changes by this much). In case of geolocation the triggers would be geographic regions as currently defined in the geofencing spec. In some sample code this might look something like this:

// Monitor a sensor:
navigator.serviceWorker.ready.then(registration => {
  registration.sensors.addTrigger(new GeolocationSensor(), {
    name: 'myfence',
    latitude: 37.421999,
    longitude: -122.084015,
    radius: 1000
  }).then(sensorTrigger => console.log('Now monitoring geofence'))
  .catch(e => console.log(e));
  // or maybe a different API:
  new GeolocationSensor().addTrigger({name: 'foo', ...}).then(...);
});

// respond to a trigger being triggered, in a SW
self.addEventListener('sensortrigger', function(e) {
  console.log('Triggered: ' + e.trigger.name);
  console.log('Type of trigger: ' + e.triggerType); /* 'enter' or 'leave' */
  // e.trigger.sensor is the sensor that was triggered
  
  // Maybe unregister the trigger
  if (shouldUnregister(e.trigger)) {
    e.waitUntil(e.trigger.remove());
  }
});

// deal with errors with the trigger, in a SW 
self.addEventListener('sensortriggererror', function(e) {
  console.log(e.trigger.name);
  console.log(e.trigger.sensor.sensorId);
  console.log(e.error);
});

// Look up existing registered triggers
navigator.serviceWorker.ready.then(registration => {
  registration.sensors.getTriggers({name: 'myfence'}).then(
    triggers => triggers.forEach(trigger => console.log(trigger)));
    
  registration.sensors.getTriggers({sensor: new GeolocationSensor()}).then(
    triggers => triggers.forEach(trigger => console.log(trigger)));
  
  // etc
});
@RikdeBoer
Copy link

Excellent!
Can't wait for this kind of functionality.
Basically being able to continue to receive and act on position (lat/lon) updates when the mobile device is currently on another web page or temporarily on another app.
With Geofencing gone in hibernation is there a group working on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment