- From: Richard Maher <notifications@github.com>
- Date: Mon, 08 Feb 2016 16:41:32 -0800
- To: slightlyoff/ServiceWorker <ServiceWorker@noreply.github.com>
- Message-ID: <slightlyoff/ServiceWorker/issues/745/181645416@github.com>
I found this a useful layman's reference for hardware support of geofencing: -
http://gpsworld.com/putting-the-ultra-low-power-in-geofence/
Explains a lot to me especially about power consumption,
I maintain that the SW architecture, in combination with any Android support for position batching, that subsequently offloads geo-fence processing to a central server in order to determine alarm/other processing for ALL users, is a viable if not preferable alternative.
Whether or not a wake-lock or cpu-lock is a retrograde step in power consumption, its implementation and availability pays homage to the user's right to self-determination. Likewise the user should be empowered to authorize GPS tracking while the phone is off.
Surely a myopic cluster of GNSS ICs is a less than optimal solution for fleet management or social networking, and an instance of functionality-devolution gone too far? IMHO, other than for monitoring prisoners on probation, the current geofence solution is a textbook case of the tail wagging the dog.
A Service Worker should be able to subscribe to a PositionManager optionally specifying min distance and/or seconds between updates to the position. A positionChanged event will be sufficient to re-instantiate a terminated SW.
Below is how I throttle GeoLocation.watchPosition now: -
Tier3Toolbox.prototype.LocationThrottle =
function(initHndlr, moveHndlr, standHndlr, errorHndlr, userOptions)
{
if(!navigator.geolocation) {
throw new Error("Unsupported browser - No Geolocation support");
}
if (arguments.length < 4) {
throw new Error("Insufficient call arguments");
}
if (typeof initHndlr != "function" ||
typeof moveHndlr != "function" ||
typeof standHndlr != "function" ||
typeof errorHndlr != "function") {
throw new Error("The Init, Move, Stand, and Error handler parameters must be functions");
}
var lastPos, trackerId, loiterTimer, deltaMetres,
recalibrateTimer, lastOptions, lastDrop, replayTimer
;
var MAXSILENCE = 30;
var watchCount = 1;
var acceptCount = 1;
var lastUpdate = 0;
var initHndlr = initHndlr;
var moveHndlr = moveHndlr;
var standHndlr = standHndlr;
var errorHndlr = errorHndlr;
var options, defMaxSilence, timeDetent, spaceDetent,
loiterDetent, maxLocAge, accurate, maxSilence, lastOptions
;
function moveReplay()
{
replayTimer = null;
if ((lastDrop.timestamp > lastPos.timestamp)) {
lastDrop.timestamp = Date.now();
filterLocation(lastDrop);
}
}
function loiterLimit()
{
loiterTimer = null;
standHndlr.call(null);
}
var recalibrate =
function()
{
if (window.console) console.log("recalibrating");
recalibrateTimer = null;
if (trackerId) navigator.geolocation.clearWatch(trackerId);
getCurrent(initAcc);
}
var getCurrent =
function(success)
{
navigator.geolocation.getCurrentPosition(success,locError,{
enableHighAccuracy: false,
maximumAge: Number.POSITIVE_INFINITY,
timeout: 10000
});
}
var initLoc =
function(position)
{
lastPos = position;
initHndlr.call(null, position);
}
var initAcc =
function(position)
{
watchCount++;
trackerId = navigator.geolocation.watchPosition(filterLocation, locError, {
enableHighAccuracy: accurate,
maximumAge: maxLocAge
});
recalibrateTimer = setTimeout(recalibrate, maxSilence);
}
var start =
function(userOptions)
{
parseOptions(userOptions);
trackerId = navigator.geolocation.watchPosition(filterLocation, locError, {
enableHighAccuracy: accurate,
maximumAge: maxLocAge,
timeout: Number.POSITIVE_INFINITY
});
loiterTimer = setTimeout(loiterLimit, loiterDetent);
recalibrateTimer = setTimeout(recalibrate, maxSilence);
}
var parseOptions =
function(userOptions)
{
options = userOptions || lastOptions;
defMaxSilence = (("maxSilence" in options) ? options.maxSilence : MAXSILENCE );
timeDetent = (("minSilence" in options) ? options.minSilence : 0 ) * 1000;
spaceDetent = (("minProgress" in options) ? options.minProgress : 0 );
loiterDetent = (("maxSnail" in options) ? options.maxSnail : defMaxSilence ) * 1000;
maxLocAge = (("maxAge" in options) ? options.maxAge : 0 );
if (maxLocAge != Number.POSITIVE_INFINITY) maxLocAge *= 1000;
accurate = (("accurate" in options) ? options.accurate : true );
maxSilence = defMaxSilence * 1000;
lastOptions = options;
}
var locError =
function(error)
{
errorHndlr.call(null, error);
}
var filterLocation =
function(position)
{
if (!lastPos) return;
watchCount++;
if (position.timestamp <= lastPos.timestamp)
return;
var currTime = Date.now();
var dropping = false;
if (((position.timestamp - lastPos.timestamp) < timeDetent) ||
((currTime - lastUpdate ) < timeDetent)) {
dropping = true;
} else {
clearTimeout(recalibrateTimer);
recalibrateTimer = setTimeout(recalibrate, maxSilence);
}
deltaMetres = Tier3Toolbox.calculateDistance(
position.coords.latitude,
position.coords.longitude,
lastPos.coords.latitude,
lastPos.coords.longitude)
if (deltaMetres.toFixed() < spaceDetent) {
return;
}
if (dropping) {
lastDrop = position;
clearTimeout(replayTimer);
replayTimer = setTimeout(moveReplay, timeDetent);
return;
}
acceptCount++;
lastPos = position;
lastUpdate = currTime;
clearTimeout(loiterTimer);
loiterTimer = setTimeout(loiterLimit, loiterDetent);
moveHndlr.call(null, position, deltaMetres);
}
var stop =
function()
{
if (trackerId) navigator.geolocation.clearWatch(trackerId);
clearTimeout(recalibrateTimer);
clearTimeout(loiterTimer);
clearTimeout(replayTimer);
}
parseOptions(userOptions);
getCurrent(initLoc);
return {start : start, stop : stop};
};
---
Reply to this email directly or view it on GitHub:
https://github.com/slightlyoff/ServiceWorker/issues/745#issuecomment-181645416
Received on Tuesday, 9 February 2016 00:42:13 UTC