Skip to content

Commit

Permalink
Fix issue #412: Area behavior has been completely rewritten (#419)
Browse files Browse the repository at this point in the history
* Fix #412: Completely rewrote the area detection algorithm
* Return area name instead of area id in value field in GET /event
  • Loading branch information
Pierre-Gilles authored Sep 18, 2018
1 parent c6f1cb6 commit d5067f0
Show file tree
Hide file tree
Showing 13 changed files with 205 additions and 41 deletions.
37 changes: 12 additions & 25 deletions api/core/area/area.changeArea.js
Original file line number Diff line number Diff line change
@@ -1,40 +1,27 @@
var queries = require('./area.queries.js');
const queries = require('./area.queries.js');
const Promise = require('bluebird');

module.exports = function enterArea(location) {

return Promise.all([
gladys.area.inArea(location),
gladys.area.userIn({id: location.user})
])
.spread((areas, lastAreasUser) => {

module.exports = function enterArea(location){
return gladys.area.inArea(location)
.then(function(areas){
return [getLastAreas(location.user), areas];
})
.spread(function(lastAreasUser, areas){

areas.forEach(function(area){
sails.log.info(`User ${location.user} detected in area ${area.name}`);
});

// we remove the areas where the user was already in
var newAreas = removeDuplicateArea(lastAreasUser, areas);
var leftAreas = findLeftAreas(lastAreasUser, areas);

return {newAreas, leftAreas};
});
});
};


/**
* Return the last area where the user was located before
*/
function getLastAreas(userId){
return gladys.utils.sql(queries.lastLocationUser, [userId])
.then(function(locations){

// if the user was never located before
if(locations.length === 0) {
return [];
} else {
return gladys.area.inArea(locations[0]);
}
});
}

function findLeftAreas(lastAreasUser, areas){

var leftAreas = [];
Expand Down
15 changes: 12 additions & 3 deletions api/core/area/area.queries.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ module.exports = {
// see here for explanations: http://vinsol.com/blog/2011/08/30/geoproximity-search-with-mysql/
inArea: `
SELECT area.*,
( 6371 * 2 * ASIN(SQRT(POWER(SIN(RADIANS(? - ABS(area.latitude))), 2)
+ COS(RADIANS(?)) * COS(RADIANS(ABS(area.latitude)))
( 6371 * 2 * ASIN(
SQRT( POWER(SIN(RADIANS(? - area.latitude)), 2) + COS(RADIANS(?)) * COS(RADIANS(area.latitude))
* POWER(SIN(RADIANS(? - area.longitude)), 2))) * 1000) AS distance
FROM area
WHERE area.user = ?
Expand All @@ -19,5 +19,14 @@ module.exports = {
LIMIT 1;
`,
delete: 'DELETE FROM area WHERE id = ?;',
get: 'SELECT * FROM area WHERE user = ?;'
get: 'SELECT * FROM area WHERE user = ?;',
getLastAreaEventPerArea: `
SELECT MAX(DATETIME) as datetime, value, eventtype.code as code
FROM event
JOIN eventtype ON eventtype.id = event.eventtype
WHERE ( eventtype.code = 'enter-area' OR eventtype.code = 'left-area')
AND event.user = ?
GROUP BY value, eventtype.code
ORDER BY datetime DESC;
`
};
56 changes: 56 additions & 0 deletions api/core/area/area.userIn.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
const Promise = require('bluebird');
const queries = require('./area.queries.js');

/**
* @public
* @description This function return all areas the user is currently in
* @name gladys.area.userIn
* @param {Object} user
* @param {String} user.id The id of the user
* @returns [{area}] areas
* @example
* var user = {
* id: 1
* };
*
* gladys.area.userIn(user)
* .then((areas) => {
* // areas is an array of areas where the user is in currently
* })
* .catch((err) => {
* // something bad happened ! :/
* });
*/

module.exports = function userIn(user) {

// Getting all areas + events linked to areas
// The goal here is to rebuild the history of entering/leaving areas
return Promise.all([
gladys.utils.sql(queries.get, [user.id]),
gladys.utils.sql(queries.getLastAreaEventPerArea, [user.id])
])
.spread((areas, events) => {

var areasWhereTheUserIsStillIn = [];

areas.forEach((area) => {
var found = false;
var i = 0;

// we see if the last event seen about this area was an "enter-area" event,
// "left-area", or no event at all
while(!found && i < events.length) {
if(parseInt(events[i].value) === area.id) {
found = true;
if(events[i].code === 'enter-area') {
areasWhereTheUserIsStillIn.push(area);
}
}
i++;
}
});

return areasWhereTheUserIsStillIn;
});
};
1 change: 1 addition & 0 deletions api/core/area/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ module.exports.changeArea = require('./area.changeArea.js');
module.exports.create = require('./area.create.js');
module.exports.get = require('./area.get.js');
module.exports.update = require('./area.update.js');
module.exports.userIn = require('./area.userIn.js');
module.exports.delete = require('./area.delete.js');
11 changes: 10 additions & 1 deletion api/core/event/event.get.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,14 @@ module.exports = function(options){
options.skip = parseInt(options.skip) || 0;
options.take = parseInt(options.take) || 50;

return gladys.utils.sql(queries.getByUser, [options.user.id, options.take, options.skip]);
return gladys.utils.sql(queries.getByUser, [options.user.id, options.take, options.skip])
.then((events) => {
return events.map((event) => {
if(event.areaName !== null) {
event.value = event.areaName;
}
delete event.areaName;
return event;
});
});
};
9 changes: 7 additions & 2 deletions api/core/event/event.queries.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
module.exports = {
getByUser: `
SELECT * FROM event
SELECT eventtype.name, event.id, eventtype.iconColor, eventtype.faIcon,
event.id, event.datetime, event.value, event.eventtype, area.name as areaName
FROM event
JOIN eventtype ON (event.eventtype = eventtype.id)
WHERE user = ? ORDER BY datetime DESC LIMIT ? OFFSET ?;`,
LEFT JOIN area ON area.id = event.value AND eventtype.category = 'area'
WHERE event.user = ?
ORDER BY datetime DESC
LIMIT ? OFFSET ?;`,
getByCode: 'SELECT * FROM eventtype WHERE code = ?;',
getByEventType: `SELECT * FROM event WHERE eventtype = ? ORDER BY datetime DESC LIMIT ? OFFSET ?;`,
getById: 'SELECT * FROM eventtype WHERE id = ?;',
Expand Down
6 changes: 4 additions & 2 deletions api/core/location/location.create.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ module.exports = function create (location) {
// we check if the user did not enter a new area
return gladys.area.changeArea(location)
.then(function(result){

console.log(result);

// foreach area the user entered in, we emit a new event
var insertNewAreaEvents = Promise.map(result.newAreas, function(area){
return gladys.event.create({
code: 'enter-area',
user: location.user,
value: area.name,
value: area.id,
scope: area
});
});
Expand All @@ -49,7 +51,7 @@ module.exports = function create (location) {
return gladys.event.create({
code: 'left-area',
user: location.user,
value: area.name,
value: area.id,
scope: area
});
});
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"istanbul": "^0.4.5",
"jshint-stylish": "^2.2.1",
"mocha": "^3.5.0",
"should": "^13.0.1",
"should": "13.2.3",
"supertest": "^3.0.0"
},
"main": "app.js",
Expand Down
8 changes: 8 additions & 0 deletions test/fixtures/area.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,13 @@
"longitude": -72,
"radius": 100,
"user": 1
},
{
"id": 3,
"name": "Pepper Pots work",
"latitude": 44,
"longitude": -72,
"radius": 100,
"user": 2
}
]
21 changes: 21 additions & 0 deletions test/fixtures/event.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,26 @@
"datetime": "2015-05-12 18:00:00",
"user": 1,
"house": 1
},
{
"id": 7,
"eventtype": 5,
"value": 3,
"datetime": "2015-05-12 18:00:00",
"user": 2
},
{
"id": 8,
"eventtype": 5,
"value": 1,
"datetime": "2016-05-12 18:00:00",
"user": 1
},
{
"id": 9,
"eventtype": 6,
"value": 1,
"datetime": "2017-05-12 18:00:00",
"user": 1
}
]
18 changes: 14 additions & 4 deletions test/fixtures/eventtype.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@
"id": 1,
"code": "test",
"name": "test",
"service": "test",
"service": "test",
"category": "test",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
{
"id": 2,
"code": "wakeup",
"name": "Gladys updated",
"service": "test",
"service": "test",
"category": "test",
"faIcon": "fa fa-wrench",
"iconColor": "bg-black"
},
Expand All @@ -20,6 +22,7 @@
"code": "devicetype-new-value",
"name": "DeviceType new Value",
"service": "DeviceType",
"category": "device",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
Expand All @@ -28,22 +31,25 @@
"code": "house-mode-changed",
"name": "House Mode changed",
"service": "mode",
"category": "house",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
{
"id": 5,
"code": "enter-area",
"name": "House Mode changed",
"service": "mode",
"service": "area",
"category": "area",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
{
"id": 6,
"code": "left-area",
"name": "House Mode changed",
"service": "mode",
"service": "area",
"category": "area",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
Expand All @@ -52,6 +58,7 @@
"code": "back-at-home",
"name": "User is back at home !",
"service": "house",
"category": "house",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
Expand All @@ -60,6 +67,7 @@
"code": "user-seen-at-home",
"name": "User has been seen at home !",
"service": "house",
"category": "house",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
Expand All @@ -68,6 +76,7 @@
"code": "left-home",
"name": "User has left home !",
"service": "house",
"category": "house",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
},
Expand All @@ -76,6 +85,7 @@
"code": "going-to-sleep",
"name": "User is going to sleep",
"service": "house",
"category": "user",
"faIcon": "fa fa-desktop",
"iconColor": "bg-black"
}
Expand Down
Loading

0 comments on commit d5067f0

Please sign in to comment.