Skip to content

Commit

Permalink
gladys autoWake up feature
Browse files Browse the repository at this point in the history
  • Loading branch information
Pierre-Gilles committed May 28, 2017
1 parent d5bf175 commit c7949c4
Show file tree
Hide file tree
Showing 12 changed files with 207 additions and 8 deletions.
14 changes: 14 additions & 0 deletions api/core/alarm/alarm.checkAllAutoWakeUp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const queries = require('./alarm.queries.js');
const Promise = require('bluebird');

module.exports = function checkAllAutoWakeUp(){

// first, get all auto alarms for today
return gladys.utils.sql(queries.getAutoWakeUpToday, [])
.then((alarms) => {

return Promise.map(alarms, function(alarm){
return gladys.alarm.checkAutoWakeUp(alarm);
});
});
};
109 changes: 109 additions & 0 deletions api/core/alarm/alarm.checkAutoWakeUp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
module.exports = checkAutoWakeUp;

function checkAutoWakeUp(alarm) {

var firstEvent = null;
var userPosition = null;
var now = new Date();
var travelTime = null;

// first, we get the first event of the user
return gladys.calendar.getFirstEventTodayUser(alarm.user)
.then((result) => {

firstEvent = result;

// if we are in the middle of the day, no need anymore to wake up the user
if(firstEvent.start < now) {
sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}" (${firstEvent.start}) has already started.`);
return Promise.reject(new Error('EVENT_ALREADY_STARTED'));
}

// then, we get the last known location of the user
return gladys.location.getUser({id: alarm.user});
})
.then((result) => {
userPosition = result;

sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user} last known position is (${userPosition.latitude},${userPosition.longitude}).`);

// if the event is not located, the duration to get there is 0
if(!firstEvent.location) {
sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}" has no location defined. Travel time is 0.`);
return {duration: 0};
}

var options = {
origin: `${userPosition.latitude},${userPosition.longitude}`,
destination: firstEvent.location
};

sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}" location = ${firstEvent.location}. Calculating travel time.`);

// we calculate the travel time to the event
return gladys.direction.travelTime(options);
})
.then((travel) => {
sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}". (${firstEvent.start}). Travel time = ${travel.duration} seconds.`);

travelTime = travel.duration;

// get user preferences
return gladys.user.getById({id: alarm.user});
})
.then((user) => {

sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}". (${firstEvent.start}). User Preferences, preparation time needed = ${user.preparationTimeAfterWakeUp} seconds.`);

var neededTime = travelTime + user.preparationTimeAfterWakeUp;

// get timestamp in seconds
var startTimestamp = new Date(firstEvent.start).getTime()/1000;

var wakeUpMomentEstimated = startTimestamp - neededTime;
var wakeUpMomentEstimatedDate = new Date(wakeUpMomentEstimated*1000);

sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}". Needed time = ${neededTime}. Wake Up moment estimated = ${wakeUpMomentEstimatedDate}.`);

var nowPlus10Minutes = now.getTime()/1000 + 10*60;
if(wakeUpMomentEstimated < nowPlus10Minutes) {
sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}". Wake up needed !`);
return ringAlarm(alarm);
} else {
sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}". Wake up not needed !`);

var retryIn = null;

// three case:
// - we are very far from the event => we check in two hours
// - we are far from the event => so we check in one hour
// - we are close from the event => so we check in 10 minutes
var difference = wakeUpMomentEstimated - nowPlus10Minutes;
if(difference > 3600*2){
retryIn = 3600*2;
} else if(difference > 3600){
retryIn = 3600;
} else {
retryIn = 600;
}

sails.log.debug(`Alarm.checkAutoWakeUp: User n°${alarm.user}, event "${firstEvent.name}". Scheduling another check in ${retryIn} seconds.`);

setTimeout(function(){
gladys.alarm.checkAutoWakeUp(alarm);
}, retryIn*1000);
}
});

}

function ringAlarm(alarm){
var event = {
code: 'alarm',
value: alarm.id,
scope: {
alarm: alarm.id
}
};
return gladys.event.create(event);
}
6 changes: 3 additions & 3 deletions api/core/alarm/alarm.create.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
module.exports = function create(alarm) {

if (!(alarm && ( (alarm.dayofweek && alarm.time) || alarm.cronrule || alarm.datetime)) ){
if (!(alarm && ( (alarm.dayofweek && alarm.time) || alarm.cronrule || alarm.datetime || alarm.autoWakeUp)) ){
return Promise.reject(new Error('Wrong parameters, missing arguments.'));
}

// create alarm in db
return Alarm.create(alarm)
.then(function(alarm) {

// if alarm is in the future and active, or is a cronrule we schedule the alarm
if (alarm.active && (new Date(alarm.datetime) > new Date() || alarm.dayofweek !== -1 || alarm.cronrule)) {
// if alarm is in the future, active and is not a autoWakeUp, or is a cronrule we schedule the alarm
if (alarm.active && !alarm.autoWakeUp && (new Date(alarm.datetime) > new Date() || alarm.dayofweek !== -1 || alarm.cronrule)) {

// schedule the alarm with gladys.schedule
return gladys.alarm.schedule(alarm);
Expand Down
8 changes: 6 additions & 2 deletions api/core/alarm/alarm.queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ module.exports = {
AND ((dayofweek = -1 AND datetime > SYSDATE()) OR dayofweek <> -1 OR cronrule IS NOT NULL)`,

deleteAlarm: `DELETE FROM alarm WHERE id = ?`,
get: 'SELECT * FROM alarm WHERE user = ?;'

get: 'SELECT * FROM alarm WHERE user = ?;',
getAutoWakeUpToday: `
SELECT * FROM alarm
WHERE autowakeup = 1
AND dayofweek = (DAYOFWEEK(NOW()) - 1 )
`
};
2 changes: 2 additions & 0 deletions api/core/alarm/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module.exports.checkAllAutoWakeUp = require('./alarm.checkAllAutoWakeUp.js');
module.exports.checkAutoWakeUp = require('./alarm.checkAutoWakeUp.js');
module.exports.command = require('./alarm.command.js');
module.exports.cancel = require('./alarm.cancel.js');
module.exports.create = require('./alarm.create.js');
Expand Down
6 changes: 4 additions & 2 deletions api/core/task/task.init.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ module.exports = function(cb){
.catch(function(){
sails.log.error('Cannot load gladys.brain.');
});


gladys.alarm.checkAllAutoWakeUp();

if(sails.config.environment !== 'production') {
return ;
Expand All @@ -27,19 +28,20 @@ module.exports = function(cb){

// tasks started only in prod


fs.chmod(sails.config.update.updateScript, '755', function(err, result){
if(err) return sails.log.error(err);
});


// start sunrise & sunset schedule each day at 00.01
// start auto wake up feature each day at 00.01
var rule = new schedule.RecurrenceRule();
rule.hour = 0;
rule.minute = 1;

var j = schedule.scheduleJob(rule, function(){
gladys.sun.init().catch(sails.log.warn);
gladys.alarm.checkAllAutoWakeUp().catch(sails.log.warn);
});

// schedule alarm
Expand Down
5 changes: 5 additions & 0 deletions api/models/Alarm.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ module.exports = {
type: 'string'
},

autoWakeUp: {
type: 'boolean',
defaultsTo: false
},

active: {
type: 'boolean',
defaultsTo: true
Expand Down
12 changes: 12 additions & 0 deletions assets/js/app/alarm/alarm.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
vm.alarms = [];
vm.createAlarm = createAlarm;
vm.createAlarmRecurring = createAlarmRecurring;
vm.createAlarmAutoWakeUp = createAlarmAutoWakeUp;
vm.createTimer = createTimer;
vm.destroyAlarm = destroyAlarm;
vm.createAlarmCron = createAlarmCron;
Expand Down Expand Up @@ -145,5 +146,16 @@
});
}

function createAlarmAutoWakeUp(){
vm.newAlarmAutoWakeUp.autoWakeUp = true;
return alarmService.create(vm.newAlarmAutoWakeUp)
.then(function(data){
getAlarms();
vm.newAlarmAutoWakeUp.name = '';
vm.newAlarmAutoWakeUp.dayofweek = -1;
$('#modalNewAlarm').modal('hide');
});
}

}
})();
3 changes: 3 additions & 0 deletions config/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,8 @@
"alarm-time-sleep": "Sleep time (in hours)",
"alarm-cron-rule": "Cron rules",
"alarm-cron-rule-text": "You can define here cron rules. The format is simple, for example if you want to schedule an alarm each hour, simply enter : '0 0 * * * *'. More informations here :",
"alarm-auto-alarm": "Auto Wake Up (Beta)",
"alarm-auto-alarm-text": "The goal of this feature is to wake you up at the right moment. It uses: The first event of the day in your calendar + travel time to destination + preparation time you need. Be sure you have everything set up ( calendar + a direction module + your geolocation ) before creating an auto alarm.",
"user-box-title": "Your user account",
"user-box-description": "You can manage here your Gladys account. This account is local, your user informations are never stored anywhere, just in your local machine.",
"user-name": "Name",
Expand All @@ -245,6 +247,7 @@
"user-email": "Email",
"user-password": "Password",
"user-gender": "Gender",
"user-preparation-time": "Preparation time you need in the morning (in seconds)",
"login-error-password-email-required": "Please enter an email and a password.",
"login-error-invalid-email": "Can't find this email.",
"login-error-invalid-username-password": "Invalid password.",
Expand Down
3 changes: 3 additions & 0 deletions config/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@
"alarm-time-sleep": "Temps de sommeil (en heures)",
"alarm-cron-rule": "Règles cron",
"alarm-cron-rule-text": "Vous pouvez définir ici des règles cron. Le format est classique, si vous vouler effectuer une tâche toutes les heures, simplement tapez : '0 0 * * * *'. Plus d'infos ici :",
"alarm-auto-alarm": "Auto Wake Up (Beta)",
"alarm-auto-alarm-text": "Le but de cette feature est de vous réveiller au bon moment automatiquement. Gladys utilise l'heure de votre premier rendez-vous, le temps nécessaire pour se rendre à ce rendez-vous en fonction du trafic, et le temps dont vous avez besoin pour vous préparer. Soyez sûr d'avoir: Un module de calcul d'itinénaire + un module de calendrier d'installé, ainsi que votre temps de préparation perso de défini. Gladys se base par ailleurs sur votre géolocalisation personnelle pour calculer l'itinéraire. Pensez à avoir un moyen de la définir.",
"user-box-title": "Votre compte utilisateur",
"user-box-description": "Gérer ici votre compte Gladys. Ce compte est local à votre système, n'est stocké nul part ailleurs que sur votre machine.",
"user-name": "Nom",
Expand All @@ -411,6 +413,7 @@
"user-email": "Email",
"user-password": "Mot de passe",
"user-gender": "Genre",
"user-preparation-time": "Temps de préparation le matin (en secondes)",
"login-error-password-email-required": "Veuillez rentrer un email et un mot de passe.",
"login-error-invalid-email": "Email introuvable.",
"login-error-invalid-username-password": "Mot de passe invalide.",
Expand Down
46 changes: 45 additions & 1 deletion views/alarm/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,21 @@
<tr>
<th><%= __('Name') %></th>
<th><%= __('Moment') %></th>
<th><%= __('Auto-wake-up') %></th>
<th><%= __('Action') %></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="alarm in vm.alarms" class="ng-cloak">
<td>{{alarm.name}}</td>
<td ng-show="alarm.dayofweek == -1 && !alarm.cronrule" >{{alarm.moment}}</td>
<td ng-show="alarm.dayofweek != -1 && !alarm.cronrule">{{alarm.moment}}, {{alarm.time}}</td>
<td ng-show="alarm.dayofweek != -1 && !alarm.cronrule && !alarm.autoWakeUp">{{alarm.moment}}, {{alarm.time}}</td>
<td ng-show="alarm.dayofweek != -1 && alarm.autoWakeUp">{{alarm.moment}}</td>
<td ng-show="alarm.cronrule">{{alarm.cronrule}}</td>
<td>
<span ng-show="alarm.autoWakeUp"><%= __('Yes') %></span>
<span ng-show="!alarm.autoWakeUp"><%= __('No') %></span>
</td>
<td><button ng-click="vm.destroyAlarm($index, alarm.id)" class= "btn btn-danger btn-sm"><%= __('Delete') %></button></td>
</tr>
<tr>
Expand Down Expand Up @@ -183,6 +189,44 @@
</div>
</div>
<!-- END OF BOX -->

<!-- NEW BOX -->
<div class="box box-default">
<div class="box-header with-border">
<h3 class="box-title"><%= __('alarm-auto-alarm') %></h3>
</div>

<div class="box-body">
<p><%= __('alarm-auto-alarm-text') %></p>
<div class="row">
<div class='col-md-2'>
<input type="text" class="form-control" ng-model="vm.newAlarmAutoWakeUp.name" placeholder="<%= __('Name') %>" />
</div>

<div class='col-md-2'>
<div class="form-group">
<select class="form-control" ng-model="vm.newAlarmAutoWakeUp.dayofweek">
<option selected value="1" ><%= __('Monday') %></option>
<option value="2"><%= __('Tuesday') %></option>
<option value="3"><%= __('Wednesday') %></option>
<option value="4"><%= __('Thursday') %></option>
<option value="5"><%= __('Friday') %></option>
<option value="6"><%= __('Saturday') %></option>
<option value="0"><%= __('Sunday') %></option>

</select>
</div>
</div>

<div class='col-md-4'>
<button class="btn btn-success" ng-click="vm.createAlarmAutoWakeUp()"><%= __('New') %></button>
</div>

</div>

</div>
</div>
<!-- END OF BOX -->

</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions views/partials/account.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<tr><td><%= __('user-firstname') %></td><td><input type="text" ng-model="vm.user.firstname" class="form-control" /></td></tr>
<tr><td><%= __('user-lastname') %></td><td><input type="text" ng-model="vm.user.lastname" class="form-control" /></td></td></tr>
<tr><td><%= __('user-email') %></td><td><input type="text" ng-model="vm.user.email" class="form-control" /></td></td></tr>
<tr><td><%= __('user-preparation-time') %></td><td><input type="text" ng-model="vm.user.preparationTimeAfterWakeUp" class="form-control" /></td></td></tr>
<tr><td><%= __('user-gender') %></td><td>
<select ng-model="vm.user.gender" class="form-control">
<option value="0" ng-selected="vm.user.gender === 0"><%= __('installation-male') %></option>
Expand Down

0 comments on commit c7949c4

Please sign in to comment.