diff --git a/server/lib/scene/scene.actions.js b/server/lib/scene/scene.actions.js index a7ade930f4..1d16e2723a 100644 --- a/server/lib/scene/scene.actions.js +++ b/server/lib/scene/scene.actions.js @@ -354,8 +354,19 @@ const actionsFunc = { deviceSeenRecently = true; } }); - // if no device was seen, the user has left home - if (deviceSeenRecently === false) { + + const user = self.stateManager.get('user', action.user); + if (deviceSeenRecently) { + if (user.current_house_id === null) { + // if at least one device was seen, the user is at home + logger.info( + `CheckUserPresence action: At least one device of the user "${action.user}" were seen in the last ${action.minutes} minutes.`, + ); + logger.info(`CheckUserPresence action: Set "${action.user}" to seen in house "${action.house}"`); + await self.house.userSeen(action.house, action.user); + } + } else if (user.current_house_id !== null) { + // if no device was seen, the user has left home logger.info( `CheckUserPresence action: No devices of the user "${action.user}" were seen in the last ${action.minutes} minutes.`, ); diff --git a/server/test/lib/scene/scene.executeActions.test.js b/server/test/lib/scene/scene.executeActions.test.js index 79c8261815..5788a3db98 100644 --- a/server/test/lib/scene/scene.executeActions.test.js +++ b/server/test/lib/scene/scene.executeActions.test.js @@ -685,10 +685,74 @@ describe('scene.executeActions', () => { ); assert.calledWith(house.userLeft, 'my-house', 'john'); }); - it('should execute action user.checkPresence and not call userLeft because user was seen', async () => { + + it('should execute action user.checkPresence and user left home', async () => { + stateManager.setState('deviceFeature', 'my-device', { + last_value_changed: Date.now() - 15 * 60 * 1000, + }); + stateManager.setState('user', 'john', { + current_house_id: 'house-id', + }); + const house = { + userSeen: fake.resolves(null), + userLeft: fake.resolves(null), + }; + const scope = {}; + await executeActions( + { stateManager, event, house }, + [ + [ + { + type: ACTIONS.USER.CHECK_PRESENCE, + user: 'john', + house: 'my-house', + minutes: 10, + device_features: ['my-device'], + }, + ], + ], + scope, + ); + assert.notCalled(house.userSeen); + assert.calledWith(house.userLeft, 'my-house', 'john'); + }); + it('should execute action user.checkPresence and user still out home', async () => { + stateManager.setState('deviceFeature', 'my-device', { + last_value_changed: Date.now() - 15 * 60 * 1000, + }); + stateManager.setState('user', 'john', { + current_house_id: null, + }); + const house = { + userSeen: fake.resolves(null), + userLeft: fake.resolves(null), + }; + const scope = {}; + await executeActions( + { stateManager, event, house }, + [ + [ + { + type: ACTIONS.USER.CHECK_PRESENCE, + user: 'john', + house: 'my-house', + minutes: 10, + device_features: ['my-device'], + }, + ], + ], + scope, + ); + assert.notCalled(house.userSeen); + assert.notCalled(house.userLeft); + }); + it('should execute action user.checkPresence and user back home', async () => { stateManager.setState('deviceFeature', 'my-device', { last_value_changed: Date.now(), }); + stateManager.setState('user', 'john', { + current_house_id: null, + }); const house = { userSeen: fake.resolves(null), userLeft: fake.resolves(null), @@ -709,11 +773,15 @@ describe('scene.executeActions', () => { ], scope, ); + assert.calledWith(house.userSeen, 'my-house', 'john'); assert.notCalled(house.userLeft); }); - it('should execute action user.checkPresence and call userLeft because user was not seen', async () => { + it('should execute action user.checkPresence and user still at home', async () => { stateManager.setState('deviceFeature', 'my-device', { - last_value_changed: Date.now() - 15 * 60 * 1000, + last_value_changed: Date.now(), + }); + stateManager.setState('user', 'john', { + current_house_id: 'house-id', }); const house = { userSeen: fake.resolves(null), @@ -735,7 +803,8 @@ describe('scene.executeActions', () => { ], scope, ); - assert.calledWith(house.userLeft, 'my-house', 'john'); + assert.notCalled(house.userSeen); + assert.notCalled(house.userLeft); }); it('should abort scene, house empty is not verified', async () => {