Skip to content

Track all connected clients, discover new devices live, and handle randomized MACs (#139) - #146

Open
shauneccles wants to merge 5 commits into
HarvsG:masterfrom
shauneccles:pr/139-track-devices
Open

Track all connected clients, discover new devices live, and handle randomized MACs (#139)#146
shauneccles wants to merge 5 commits into
HarvsG:masterfrom
shauneccles:pr/139-track-devices

Conversation

@shauneccles

Copy link
Copy Markdown

Closes #139.

On the released integration most connected clients never appear as device trackers. This makes the integration track every connected client, create entities for new devices live, and adds first-class handling for MAC-randomized clients.

What's in it (per commit)

  1. Track every connected clientupdate_device_trackers() skipped any client with no name and no alias, so unnamed IoT devices (bulbs, sensors) and some phones were dropped. Track them all; ClientDevInfo.update() already falls back to a MAC-derived name.
  2. Discover new devices on the poll + live attributes — the platform now subscribes to signal_device_new, so devices that join after setup get a tracker on the next 30 s poll instead of only on a reload. Also reads hostname/ip/mac live (they were cached at creation and went stale) and sets should_poll=False (state is dispatcher-pushed).
  3. Debug logging for client discovery — logs how many clients connected_clients returns and each newly discovered device, so "missing devices" reports are diagnosable from a debug log.
  4. Cancel the scan-interval poller on unloadsetup() never stored the async_track_time_interval unsub, so every reload leaked another poller. Registered via entry.async_on_unload.
  5. Handle MAC-randomized clients (configurable) — removing the name filter means phones using MAC randomization would pile up as stale trackers. Detect locally-administered (randomized) MACs, expose a mac_randomized attribute, and add a track_randomized_mac option (enabled / disabled / ignore). entity_registry_enabled_default composes with HA's ScannerEntity heuristic — defer to core for normal clients, honour the option for randomized ones.

Note for Wi-Fi 7 routers

This PR deliberately leaves interface-type resolution unchanged, so on Wi-Fi 7 routers (e.g. BE9300) it still relies on the setup-crash fix in #145. I left that out to avoid overlapping with #145 — see my comment there for a complementary iface-string idea.

Testing

Validated live against a GL-iNet MT6000 (firmware 4.x): all connected clients tracked with correct interface labels; a phone joining the network produced a tracker within the poll interval without a reload; the ignore option confirmed to keep a randomized MAC out of the registry entirely. Unit tests cover the randomized-MAC detection.

🤖 Generated with Claude Code

shauneccles and others added 5 commits June 21, 2026 13:08
update_device_trackers() skipped any client that had neither a name nor an
alias. Many IoT devices (bulbs, sensors) and some phones report blank
names, so most of the network was silently untracked. Track every
connected client instead; ClientDevInfo.update() already falls back to a
MAC-derived name for unnamed devices.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…sG#139)

Two device-tracker fixes:

1. New devices appeared only after a reload. update_device_trackers()
   fires signal_device_new when it discovers a previously unseen client,
   but async_setup_entry called update_router() once at setup and never
   subscribed to that signal. Connect update_router() to signal_device_new
   (via entry.async_on_unload) so new devices get entities on the 30s poll.

2. hostname/ip_address/mac_address were cached_property values snapshotted
   in __init__, so a device's reported IP stayed frozen at entity-creation
   time. Read them (and the name) live from the underlying ClientDevInfo,
   which async_on_demand_update refreshes each poll. Also set
   should_poll=False, since updates are pushed via the dispatcher (the old
   value of True contradicted its own "No polling needed" docstring).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Log how many clients connected_clients returns (and their MACs), and each
newly discovered tracked device. This makes "missing devices" reports (e.g.
issue HarvsG#139) diagnosable from a debug log without external probing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
router.setup() registered a SCAN_INTERVAL poller via
async_track_time_interval but never stored its unsub, so each config-entry
reload leaked another timer that kept polling the router forever (observed
as multiple concurrent pollers after a few reloads). Register the unsub
with entry.async_on_unload so it is cancelled on unload/reload.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removing the name filter means every connected client is tracked, including
phones that use MAC randomization. Those present a fresh address on each
(re)connection, so without handling they pile up as stale trackers.

- Detect locally-administered (randomized) MACs from the address itself
  (is_randomized_mac in utils.py); HA core provides no helper for this.
- Expose a `mac_randomized` attribute on every tracker.
- Add a `track_randomized_mac` option (options flow): "enabled" tracks them
  with the entity enabled by default, "disabled" registers them disabled by
  default (the default), "ignore" skips creating the entity entirely.
- entity_registry_enabled_default composes with HA's ScannerEntity heuristic:
  randomized MACs honour the option; every other client defers to core, which
  enables a tracker only when its MAC maps to a known device.
- Register the previously-unwired options update listener so option changes
  reload the entry and take effect.

Covered by unit tests for is_randomized_mac.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Initial device list is missing many items.

1 participant