Skip to main content

UniFi WiFi Presence

This driver turns your Ubiquiti UniFi network into a presence sensor. It polls the UniFi Network Controller (UDM, UDM Pro, UDR, Cloud Key Gen2+, or a self-hosted controller) for the list of connected clients and flips a person tracker zone to present the moment that person's phone associates with the wifi — and to away once the phone has been off the network for a grace period. No app to install on the phones, no GPS, no cloud: if the phone joins the wifi, they're home.

Trackers can be tied directly to GEM user accounts: give a user a wifi_macs attribute holding their phone's MAC and the driver auto-creates a tracker zone for them under the Location subsystem. People without GEM accounts (kids, guests, housekeeper) get hand-made zones with the MAC as the zone address.

Where this sits versus OwnTracks

The OwnTracks driver gives you named geofence regions ("at work", "at school") from a phone app publishing GPS. This driver answers only one question — on the home network or not — but needs nothing installed on the phone and detects arrival within seconds of the phone joining wifi. They coexist happily; both feed the same person-tracker conventions.

Prerequisites

  • A UniFi Network Controller managing the wifi the phones join, reachable from the GEM host over HTTPS.
  • Preferred — an API key minted on the controller (UniFi UI → Settings → Control Plane → Integrations, or Admins & Users → API keys). This uses Ubiquiti's official, versioned Network Integration API and requires Network App 9.3 or newer. The key is shown once — copy it when you mint it.
  • Fallback — a local admin account, for controllers too old for the Integration API. Ubiquiti SSO / remote accounts will not work with the legacy local API — create a dedicated local account. The driver only ever reads, so a restricted/read-only local admin is ideal.
  • Each phone's wifi MAC address as your network sees it — see the private-address note below.
Private wifi addresses (MAC randomization)

Modern iOS and Android connect with a per-network "private" MAC, not the hardware MAC printed in the phone's About screen. The per-network address is stable for your SSID by default, so it works fine — but you must use that address. Read it from the phone's wifi settings while connected to your network, or run the device's get_clients command and pick the phone out of the list. On iOS 18+ make sure Private Wi-Fi Address is set to Fixed (not Rotating) for the home network, or the address changes periodically and presence breaks.

Setup steps

  1. Add the device. In the GEM admin console open DevicesAdd Device and choose UniFi WiFi Presence.
  2. Fill in the connection fields:
    • Controller IP / Host — the UniFi controller, not an access point.
    • Controller Port443 for UniFi OS consoles, 8443 for standalone self-hosted controllers.
    • API Key (preferred) — paste the key minted on the controller. Username/password can stay empty; they are ignored when a key is set. Stored encrypted.
    • Admin Username / Admin Password (legacy fallback) — only for controllers without the Integration API (Network App older than 9.3). The password is stored encrypted. In this mode also check UniFi OS Console: on for UDM / UDM Pro / UDR / Cloud Key G2+, off for a standalone self-hosted controller.
    • Site — leave default unless the controller is multi-site. With an API key the driver matches this against the controller's site names automatically (single-site controllers just work).
  3. Save and enable. The driver validates the key (or logs in) and starts polling the client list (every 15 s by default).
  4. Find the phone MACs. Run the get_clients command on the device (Commands tab) while the phones are on wifi — it lists every client with MAC, hostname, and network.
  5. Associate MACs with people — either way works, and they can be mixed:
    • Linked to a GEM user (recommended): add a wifi_macs attribute to the user (target auth_user) containing their phone's MAC. Comma-separate several MACs to also count a watch or tablet. Within one sync pass the driver creates a tracker zone for that user under Location, labeled with their name and carrying a user_id attribute pointing back at the account. The zone's tracked MACs follow the user's wifi_macs from then on — edit the attribute, never the zone address.
    • Stand-alone person: create a zone by hand on this device with address = the phone MAC (aa:bb:cc:dd:ee:ff), under the Location subsystem. Extra devices for the same person go in the zone's mac_addresses attribute.
  6. Verify. Toggle wifi off on a phone, run get_tracked, and watch seen_seconds_ago climb; turn wifi back on and the zone flips to present within one poll.
The Location subsystem is created for you

Like the OwnTracks driver, auto-created tracker zones live under a Location subsystem that the driver creates the first time it needs it. A new subsystem appearing after setup is expected.

How presence is decided

  • Arrival is immediate. A tracked MAC appearing in the controller's client list flips the zone to present on the next poll — at the default 15 s interval, effectively as the phone walks in the door.
  • Departure is debounced. Phones nap off wifi to save power, so a missing MAC does not mean gone. The zone flips to away only after every tracked MAC has been off the network for Away Timeout (default 300 s). Don't set it below ~120 s or sleeping phones will flap.
  • Wired clients don't count unless Count Wired Clients is enabled — a desktop that stays on all night is not a person.
  • VPN / Teleport clients never count (API-key mode) — a phone connected remotely over VPN is away, not home.
  • On each transition the driver stamps last_arrival or last_departure (the departure time is backdated to the final sighting, not the moment the grace timer expired).

Attribute reference

Device attributes

AttributeRequiredDefaultPurpose
ipController IP or hostname.
api_key✓*Official Integration API key (Network App 9.3+). Preferred. Stored encrypted.
username / password✓*Legacy local admin credentials — the fallback when no API key is set. Password stored encrypted.
port443443 UniFi OS, 8443 standalone.
unifi_ostrueLegacy mode only: off for standalone self-hosted controllers. Ignored with an API key.
sitedefaultController site — short-name in legacy mode, matched against site names in API-key mode.
status_interval15000Milliseconds between client-list polls. Arrival latency is at most one interval.
away_timeout300Seconds off the network before a person flips to away.
include_wiredfalseCount ethernet clients as presence too.
sync_userstrueAuto-create tracker zones from GEM users carrying wifi_macs.

* One of the two auth modes is required: either api_key, or username + password.

User attribute

AttributeTargetPurpose
wifi_macsauth_userComma-separated MACs of this user's personal devices. Setting it is what links a person to a tracker zone.

Zone attributes

AttributeWritten whenMeaning
state / presenceOn transitionpresent or away. state is what triggers and UIs read; presence mirrors it for person-tracker consumers like voice "who's home?" queries.
last_arrivalGoing presentISO timestamp of the arrival.
last_departureGoing awayISO timestamp of the final wifi sighting.
ssidOn change while presentThe wifi network the phone was last seen on.
mac_addressesYou set itExtra MACs that also count as this person.
user_idZone auto-creationThe linked GEM user account.

Commands

CommandPurpose
get_clientsList everything currently on the network (MAC, hostname, IP, SSID, signal) — the tool for finding a phone's MAC.
get_trackedEvery tracked person with their MACs, current state, and seconds since last sighting.
sync_usersRe-read wifi_macs from GEM users now and create any missing tracker zones (otherwise runs automatically every few minutes).
loginForce a fresh controller login (legacy mode) or re-validate the API key and site (API-key mode).

Using presence in automation

Tracker zones are ordinary zones, so the standard surfaces apply:

  • "They just got home" — an Attribute Trigger on the person's zone, firing when state becomes present, running a welcome-home macro (lights, climate, disarm prompt). Trigger debounce, day, and hour masks all apply.
  • "Everyone left" — a trigger on state becoming away, gated on the other trackers' zones also reading away, arming security and setting back climate.
  • Voice — the AI assistant's "who's home?" / "is Nathan home?" answers read these zones automatically; no extra wiring.
  • History — presence transitions land in attribute history like any other state change, so arrivals and departures are queryable in History.

What this driver does not do

  • No location beyond home/away. There are no named regions — for "at work" / "at school" answers, pair it with OwnTracks.
  • No writes to the controller. It never changes network configuration; the account can be read-only.
  • No zone cleanup. A person whose wifi_macs is cleared keeps their zone (it drops to disconnected as a flag). Retired trackers are deleted by hand.

Troubleshooting

  • API key rejected (401/403). Re-mint the key on the controller and confirm the Network App is 9.3 or newer — older controllers have no Integration API, so clear api_key and use a local admin username/password instead.
  • Login fails with 400/401 (no API key set). The account is a Ubiquiti SSO / remote account — the legacy local API requires a local admin account on the controller. Or skip the problem entirely and mint an API key.
  • "Site not found" in API-key mode. The driver matches the Site field against the controller's site names; the error message lists the names it found. Single-site controllers resolve automatically.
  • A phone never shows present. Compare get_clients output against the MAC you configured while the phone is on wifi. Nine times out of ten it's the private-address mismatch described above.
  • Presence flaps between present and away. The phone is aggressively power-napping off wifi, or its private address is rotating. Raise away_timeout to 600+, and pin the phone's private address to Fixed for this SSID.
  • No zone appears for a user. The user needs a wifi_macs attribute with at least one valid MAC, the account must be enabled, and sync_users must be on. Run the sync_users command and watch the log for the create.
  • get_clients is empty. Wrong Site short-name (it is literally default on single-site controllers), or the standalone/UniFi OS toggle doesn't match the controller type.
  • OwnTracks — GPS-region presence, complementary to this driver.
  • Users — where the wifi_macs attribute lives.
  • Zones · Attributes — the tracker zones and their state.
  • Triggers and Macros — turn presence into action.