Skip to content

Instantly share code, notes, and snippets.

@i8beef
Last active March 20, 2023 03:28
Show Gist options
  • Save i8beef/ab6386f1bb8f25c154e51df9a465eb05 to your computer and use it in GitHub Desktop.
Save i8beef/ab6386f1bb8f25c154e51df9a465eb05 to your computer and use it in GitHub Desktop.

Ubiquiti UniFi Presence Detection

Uses a UniFi node to monitor a UniFi management instance for named devices and their "Last Seen" values to determine device presence on the network.

Usage

  1. Install the node-red-contrib-unifi package.
  2. Past into a new or existing flow.
  3. Modify the UniFi node settings.
  4. Change the list of devices in the "Determine device presence" node. It maps the final MQTT topic that will be used to announce presence to the device name setup in UniFi for a client. Could be easily changed to be based on MAC address, etc., but if you name the devices in UniFi you can then later change those names without changing this flow.
[{"id":"a79a3412.95bbc8","type":"comment","z":"198805b3.d752aa","name":"Presence","info":"","x":100,"y":1420,"wires":[]},{"id":"356d290f.2adc76","type":"inject","z":"198805b3.d752aa","name":"Every 5 seconds","topic":"","payload":"","payloadType":"date","repeat":"5","crontab":"","once":false,"x":130,"y":1460,"wires":[["2fe17f39.cb2e2"]]},{"id":"2fe17f39.cb2e2","type":"Unifi","z":"198805b3.d752aa","name":"","ip":"","port":8443,"site":"default","command":"20","x":310,"y":1460,"wires":[["9c4ebd18.14827"]]},{"id":"9c4ebd18.14827","type":"function","z":"198805b3.d752aa","name":"Determine device presence","func":"const lastSeenSeconds = 20;\nlet presenceCutoff = (Math.abs(new Date()) - (lastSeenSeconds * 1000)) / 1000; \nconst people = {\n \"presence/person1\": \"Identifier1\",\n \"presence/person2\": \"Identifier2\"\n};\n\nreturn Object.keys(people).map(function(topic) {\n let devices = msg.payload.filter(device => device.name === people[topic] && device.last_seen > presenceCutoff);\n return {\n topic: topic,\n retain: true,\n payload: devices.length > 0\n };\n});","outputs":"2","noerr":0,"x":520,"y":1460,"wires":[["1d706e57.f39ea2"],["84981.f0fe567f"]],"outputLabels":["michael presence","meredith presence"]},{"id":"1d706e57.f39ea2","type":"rbe","z":"198805b3.d752aa","name":"","func":"rbe","gap":"","start":"","inout":"out","x":750,"y":1440,"wires":[["e52f02f3.7cd59"]]},{"id":"84981.f0fe567f","type":"rbe","z":"198805b3.d752aa","name":"","func":"rbe","gap":"","start":"","inout":"out","x":750,"y":1480,"wires":[["e52f02f3.7cd59"]]}]
@Dud3z
Copy link

Dud3z commented Jan 1, 2019

mine is somehow not working. it jumps from true to false in the ammount of secconds i define in the function node in lastSeenSeconds.

@paulmona
Copy link

paulmona commented Feb 4, 2019

mine is somehow not working. it jumps from true to false in the ammount of secconds i define in the function node in lastSeenSeconds.

Mine does exactly this. Did you manage to get it to work?

@babis2k
Copy link

babis2k commented Feb 28, 2019

@Dud3z @paulmona
I had the same problem but I solved it. At node "Determine device presence" and line 11 change device.name to device.hostname and it will work.
If you want to trace device mac address change device.name to device.mac and at "presense/person#":"mac address".

@buzzshot
Copy link

Hi,
Not sure what i am doing wrong but every time i try to dump it to a debug i get this message.
AMnode: Determine device presencefunction : (error)
"TypeError: msg.payload[0].filter is not a function"
I have tried changing a few settings but still no go. Any help would be appreciated

@i8beef
Copy link
Author

i8beef commented Nov 11, 2019

I did not even realize you could leave comments in these...

  1. I use device.name because I actually name my devices in Unifi. This makes it easier to identify later instead of remembering MAC addresses, etc. If you don't name your devices, you'd have to key on something else like device.mac as @babis2k mentioned.
  2. @buzzshot make sure your UniFi node is set to command "ClientDevices"

@fsamuelsson
Copy link

Hello, i have implemented this in node red and got i to work :) but i also would like to display when the client was last seen, but i have no clue how to implenet this, anybody who can help with some creative code ?

@jensfr1
Copy link

jensfr1 commented Jun 7, 2020

Hey, how can I get a status to true if everyone left the house? Wondering what is the best way? I only want to set false in a variable if both persons are away to trigger an action.

Thanks,

@i8beef
Copy link
Author

i8beef commented Jun 7, 2020

Poll every X seconds into a function node and only return a message with payload = true when everyone's device "last_seen" is more than Y seconds in the past is probably the easiest.

@jensfr1
Copy link

jensfr1 commented Jun 8, 2020

Do you have an example? This is not something I do every day :-)

@quadhammer
Copy link

@Dud3z @paulmona
I had the same problem but I solved it. At node "Determine device presence" and line 11 change device.name to device.hostname and it will work.

Thanks for this. For me it was line 9:

let devices = msg.payload[0].filter(device => device.hostname === people[topic] && device.last_seen > presenceCutoff);

and that did the trick.

@i8beef
Copy link
Author

i8beef commented Dec 15, 2020

Whether that works or not depends on your setup if the hostname property is sticky and properly unique. The name property uses the name assigned in the Ubiquiti UI to the device, which will track the MAC address I believe, and would be a much safer bet. Alternatively, you could base it on the MAC address directly if you wanted, but it would just be harder to tell at a glance what device you are looking at. I prefer to just name everything in the Ubiauiti UI and get the benefit of knowing what device is which there as well.

@mondface
Copy link

i have changed it to
const lastSeenSeconds = 60;
now i have no more problems with jumping between on and off.

@i8beef
Copy link
Author

i8beef commented Dec 29, 2020

LastSeen is essentially there to be a debounce of disconnects, so a "short" blip will not trigger notifications. It needs to be balanced against "how quickly do I want to know about a disconnect?". Reconnect notifications would still be immediate, but it wouldn't consider a "missing" device as "disconnected" until that buffer has elapsed.

@sparky-Ol
Copy link

Hi,
i can connect to my UDM (green indicator and OK) via unifi node but the array i receive is empty : payload: array[0].
In the unifi node i changed my sitename, entered my credentials and selected Command: ClientDevices.
What might went wrong?

@quadhammer
Copy link

I'm not at my computer to check, but from memory the array thing had to be expanded, and perhaps you need to use a complete message object debug note, rather than just the message.payload one. Apologies if this is obvious, and you have already tried it.

@i8beef
Copy link
Author

i8beef commented Jan 23, 2021

Sorry, no idea off hand. If the message payload coming out of that is empty it sounds like theres something not right in your node setup, or something. might want to ask on the UniFi node's Github or something and see if they know.

@quadhammer
Copy link

The node-red-contrib-unifi package has stopped working for me too, so it's probably the culprit here.

@groenerik
Copy link

Thank you very much for this code!

To get it working here with Unifi Application: Network 7.2.97 and node-red v3.0.2 I needed to make two changes.

To remove a code verification error I changed the second line to :
let presenceCutoff = (Date.now() - (lastSeenSeconds * 1000)) / 1000;
new Date() appears to return an object in stead of a number.

Then during executing I got an error message and no results.
"TypeError: msg.payload[0].filter is not a function"

I could resolve it bij removing the [0] index from msg.payload[0].filter.
let devices = msg.payload.filter(device => device.name === people[topic]);

Apparently the structure of the Unifi output has changed over time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment