guytracker
Posts: 197
Joined: Thu Apr 30, 2009 6:58 pm
Location: South Africa
Contact: Website

Fatigue alerts

Tue Dec 08, 2015 6:49 pm

I have installed the event script for Fatigue alerts (http://gpsgate.com/blogComment/fatigue_script) and it looks like it should work well. However, I need to set it to trigger an alert for a driving period of longer than 2 hours without a 15 minutes break.

Can someone assist please?

User avatar
Mattias
GpsGate
Posts: 135
Joined: Wed Dec 16, 2009 3:59 pm
Location: Sweden

RE: Fatigue alerts

Tue Dec 08, 2015 10:53 pm

Hi,

That feature is not supported in the current script. If you are familiar with scripting it should be pretty easy to add though.

First you need to set "minContinuousRest" to 0. See the Customization part of the blog on how to do this.
Then try something like this script (Disclaimer: I have not tested this):

Code: Select all

var driving = fields.get('Engine on', false) == true;

// ---- Do not edit below this line ----

var minContinuousRest = session.user.getCustomFieldValue('minContinuousRest') || 3 * 60;
var minDailyRest = session.user.getCustomFieldValue('minDailyRest') || 11 * 60;
var minDailyRestExemption = session.user.getCustomFieldValue('minDailyRestExemption') || 9 * 60;
var maxRestExemptions = session.user.getCustomFieldValue('maxRestExemptions') || 3;
var maxDailyDriving = session.user.getCustomFieldValue('maxDailyDriving') || 9 * 60;
var maxDailyDrivingExemption = session.user.getCustomFieldValue('maxDailyDrivingExemption') || 10 * 60;
var maxDrivingExemptions = session.user.getCustomFieldValue('maxDrivingExemptions') || 2;
var drivingExemptionResetTime = session.user.getCustomFieldValue('drivingExemptionResetTime') || 24 * 60 * 7;
var maxWeeklyDriving = session.user.getCustomFieldValue('maxWeeklyDriving') || 56 * 60;
var maxFortnightlyDriving = session.user.getCustomFieldValue('maxFortnightlyDriving') || 90 * 60;

var addDay = function (state, startTime) {
	var day = { startTime: startTime, dailyDriving: 0, dailyRest: 0 };
	if (state.days.length > 13) {
		state.days.pop(); // remove the last/oldest
	}
	state.days.unshift(day); // add at the beginning
	state.currentStartTime = startTime.getTime();
	stopwatch.start('timeSinceStart');
	return state.days[0];
};

var calcDriving = function (state, offset, limit) {
	var driving = 0;
	var currentWeek = 0;
	for (var i = offset; i < Math.min(limit, state.days.length); ++i) {
		var day = state.days[i];
		var dayWeek = getWeekNumber(day.startTime);
		if (dayWeek != currentWeek && currentWeek > 0) {
			break;
		}
		driving += day.dailyDriving;
		currentWeek = dayWeek;
	}
	return driving;
};

var getWeekNumber = function (d) {
	d = new Date(+d);
	d.setHours(0, 0, 0);
	d.setDate(d.getDate() + 4 - (d.getDay() || 7));
	return Math.ceil((((d - new Date(d.getFullYear(), 0, 1)) / 8.64e7) + 1) / 7);
};

if (trackPoint.valid) {
	var now = trackPoint.utcTimestamp;
	var state = context.state;

	if (state == '') {
		state = {
			days: [],
			currentStartTime: null,
			currentDriving: 0, // NEW
			currentRest: 0,
			lastDrivingStatus: false,
			drivingExemptions: { lastUpdateTime: 0, count: maxDrivingExemptions },
			restExemptions: { currentWeek: getWeekNumber(now), lastUpdateTime: 0, count: maxRestExemptions }
		};
		stopwatch.start('drivingExemptions');
	}
	else {
		// deserialize date objects
		for (var i = 0; i < state.days.length; ++i) {
			var day = state.days[i];
			day.startTime = new Date(day.startTime);
		}
	}

	if (state.days.length == 0) {
		addDay(state, now);
	}

	var currentDay = state.days[0];
	var timeSinceStart = stopwatch.stop('timeSinceStart').totalMinutes;
	var timeSinceLastUpdate = stopwatch.stop('lastUpdateTime').totalMinutes;
	var twentyFourHours = 24 * 60; // (24 hours converted to minutes)

	// Start new day every 24 hours
	// And check rest
	if (timeSinceStart >= twentyFourHours) {
		// Only count rest over 'minContinuousRest' threshold (same as below)
		if (state.currentRest >= minContinuousRest) {
			currentDay.dailyRest += state.currentRest;
		}
		state.currentRest = 0;

		// Reset rest exemptions every new (static) week
		var currentWeek = getWeekNumber(now);
		if (state.restExemptions.currentWeek != currentWeek) {
			state.restExemptions.currentWeek = currentWeek;
			state.restExemptions.count = maxRestExemptions;
		}

		var restExemptionCurrentDay = state.restExemptions.lastUpdateTime == state.currentStartTime;

		// Create event if daily rest is below accepted value
		if (currentDay.dailyRest < minDailyRest && !restExemptionCurrentDay && state.restExemptions.count <= 0) {
			context.startEvent('fatigue5');
			context.setVariable('Reason', 'minDailyRest', 'fatigue5');
		}

		// Decrement rest exemptions if daily rest is below accepted value
		if (currentDay.dailyRest < minDailyRest && !restExemptionCurrentDay) {
			state.restExemptions.lastUpdateTime = state.currentStartTime;
			state.restExemptions.count -= 1;
		}

		currentDay = addDay(state, now);

		context.endAllEvents();
		timeSinceLastUpdate = 0;
	}

	if (state.lastDrivingStatus) {
		// Increment daily driving
		currentDay.dailyDriving += timeSinceLastUpdate;
		state.currentDriving += timeSinceLastUpdate; // NEW

		// Only count rest over 'minContinuousRest' threshold (same as above)
		if (state.currentRest >= minContinuousRest) {
			currentDay.dailyRest += state.currentRest;
		}
		state.currentRest = 0;
	}
	else {
		// Increment daily rest
		state.currentRest += timeSinceLastUpdate;
		
		// Reset driving when rest > 15 minutes // NEW
		if (state.currentRest <= 15) { // NEW
			state.currentDriving = 0; // NEW
		} // NEW
	}

	stopwatch.start('lastUpdateTime');
	state.lastDrivingStatus = driving;

	// Reset driving exemptions every rolling (dynamic) week
	var drivingExemptionTime = stopwatch.stop('drivingExemptions').totalMinutes;
	if (drivingExemptionTime >= drivingExemptionResetTime) {
		stopwatch.start('drivingExemptions');
		state.drivingExemptions.count = maxDrivingExemptions;
	}

	var drivingExemptionCurrentDay = state.drivingExemptions.lastUpdateTime == state.currentStartTime;

	var weeklyDriving = calcDriving(state, 0, 7);
	var fortnightlyDriving = weeklyDriving + calcDriving(state, 7, 14);

	// Create event if all driving exemptions are exhausted
	if (currentDay.dailyDriving > maxDailyDriving && !drivingExemptionCurrentDay && state.drivingExemptions.count <= 0) {
		context.startEvent('fatigue1');
		context.setVariable('Reason', 'drivingExemptions', 'fatigue1');
	}
	// Create event if total daily driving is above accepted value
	if (currentDay.dailyDriving > maxDailyDrivingExemption) {
		context.startEvent('fatigue2');
		context.setVariable('Reason', 'maxDailyDriving', 'fatigue2');
	}
	// Create event if weekly driving is above accepted value
	if (weeklyDriving > maxWeeklyDriving) {
		context.startEvent('fatigue3');
		context.setVariable('Reason', 'maxWeeklyDriving', 'fatigue3');
	}
	// Create event if fortnightly driving is above accepted value
	if (fortnightlyDriving > maxFortnightlyDriving) {
		context.startEvent('fatigue4');
		context.setVariable('Reason', 'maxFortnightlyDriving', 'fatigue4');
	}
	// Trigger an alert for a driving period of longer than 2 hours without a 15 minutes break // NEW
	if (state.currentDriving > 120) { // NEW
		context.startEvent('fatigue6'); // NEW
		context.setVariable('Reason', 'drivingPeriod', 'fatigue6'); // NEW
	} // NEW

	// Decrement driving exemptions if daily driving is above accepted value
	if (currentDay.dailyDriving > maxDailyDriving && !drivingExemptionCurrentDay) {
		state.drivingExemptions.lastUpdateTime = state.currentStartTime;
		state.drivingExemptions.count -= 1;
	}

	context.setVariable('DailyRest', currentDay.dailyRest);
	context.setVariable('RestExemptionsLeft', state.restExemptions.count);
	context.setVariable('DailyDriving', currentDay.dailyDriving);
	context.setVariable('WeeklyDriving', weeklyDriving);
	context.setVariable('FortnightlyDriving', fortnightlyDriving);
	context.setVariable('DrivingExemptionsLeft', state.drivingExemptions.count);

	context.setState(state);
}

return false;
My changes includes adding a "currentDriving" property to the state object, updating that when driving/resting, and then lastly checking currentDriving.
All new lines of code has a "// NEW" comment.

Regards,
Mattias

Return to “GpsGate for Developers”