I want to share my presence flow which was inspired from Rob’s and April’s. However I decided it can be simplified by replacing a lot of nodes with a BooleanLogic Ultimate node that performs an OR operation. The idea behind this is that if any of the sensors (in my case my phone’s position and network presence, but there can be as many sensors as you want) is detected, I am at home. If all but one drop the presence status should not change since I’m still probably at home (eg. network presence dissapears at night when the phone goes to sleep).
Just like Rob’s and April’s, my flow has 2 outputs for leaving and arriving and also sets 3 global variables that can be checked any time when needed.
The lower flows are for debugging only and simply display or set the current global variables, or inject geo/wifi presence. Same with the “Debug” function node on the right, it just outputs the calculated presence to the debug panel so I can see a history of changes and check everything worked as it was supposed to. These can all be removed.
For clarity this is what the flow looks without the debug stuff:
The change nodes “Set presence” can also be removed if you don’t want global variables.
Instead of using the included UniFi node I used node-red-contrib-unifi-os
because the included didn’t want to work for me and the current (fixed) version required Node Red 3.
Owntracks function node:
const region = 'Home';
let presence = Array.isArray(msg.payload.inregions)
&& msg.payload.inregions.includes(region);
if (msg.payload.lat !== undefined) {
node.status({
fill: presence ? 'green' : 'red',
shape: 'dot',
text: presence ? 'Home' : 'Away',
});
return {
topic: msg.topic,
payload: presence,
};
}
UniFi function node:
const mac = 'AA:BB:CC:DD:EE:FF';
const device = 'phone';
const person = 'mihai';
const lastSeenSeconds = 30;
let presenceCutoff = (new Date() - (lastSeenSeconds * 1000)) / 1000;
let matches = msg.payload.data.filter(
device =>
device.mac.toLowerCase() === mac.toLowerCase()
&& device.last_seen > presenceCutoff
);
let presence = matches.length > 0;
node.status({
fill: presence ? 'green' : 'red',
shape: 'dot',
text: presence > 0 ? 'Home' : 'Away',
});
return {
topic: `${msg.inputMsg.topic}/${device}/${person}`,
payload: presence,
};