Migrate unifi_direct from DeviceScanner to ScannerEntity and add ConfigFlow#171991
Migrate unifi_direct from DeviceScanner to ScannerEntity and add ConfigFlow#171991PaulVanSchayck wants to merge 28 commits into
Conversation
There was a problem hiding this comment.
It seems you haven't yet signed a CLA. Please do so here.
Once you do that we will be able to review and accept this pull request.
Thanks!
|
Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍 |
|
Hey there @tofuSCHNITZEL, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR modernizes the unifi_direct integration by adding a config flow and refactoring device tracking to use a DataUpdateCoordinator, along with new tests and generated metadata updates.
Changes:
- Added config flow support (including YAML import) and marked the integration as
config_flow: true. - Reworked device tracker to be config-entry based and coordinator-driven.
- Introduced test suite + fixtures for config flow and device tracker behavior.
Reviewed changes
Copilot reviewed 12 out of 14 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
homeassistant/components/unifi_direct/__init__.py |
Sets up/unloads the integration via config entries and forwards to platforms. |
homeassistant/components/unifi_direct/config_flow.py |
Implements UI + YAML import config flow for UniFi AP Direct. |
homeassistant/components/unifi_direct/coordinator.py |
Adds coordinator and connection validation helpers. |
homeassistant/components/unifi_direct/const.py |
Introduces integration constants. |
homeassistant/components/unifi_direct/device_tracker.py |
Migrates legacy YAML setup to import + adds coordinator-backed tracker entities. |
homeassistant/components/unifi_direct/manifest.json |
Declares config_flow and sets integration_type to device. |
homeassistant/components/unifi_direct/strings.json |
Adds issue translations for YAML import connection failures. |
homeassistant/generated/config_flows.py |
Registers unifi_direct as having a config flow (generated). |
homeassistant/generated/integrations.json |
Updates integration metadata for config flow and type (generated). |
tests/components/unifi_direct/conftest.py |
Adds fixtures for config entry and UniFiAP mocking. |
tests/components/unifi_direct/test_config_flow.py |
Adds config flow tests (success + cannot_connect + import). |
tests/components/unifi_direct/test_device_tracker.py |
Adds device tracker entity creation + legacy YAML import tests. |
tests/components/unifi_direct/__init__.py |
Adds test package marker/docstring. |
CODEOWNERS |
Adds code ownership for the new test directory. |
| """Initialize the coordinator using a config entry.""" | ||
| self.config_entry = config_entry | ||
| self.host = config_entry.data[CONF_HOST] | ||
| self.username = config_entry.data[CONF_USERNAME] | ||
| self.password = config_entry.data[CONF_PASSWORD] | ||
| self.port = config_entry.data.get(CONF_PORT, DEFAULT_SSH_PORT) | ||
|
|
||
| self.ap = UniFiAP( |
There was a problem hiding this comment.
test_device_tracker_entities_created already tests the controller
| self.host = config_entry.data[CONF_HOST] | ||
| self.username = config_entry.data[CONF_USERNAME] | ||
| self.password = config_entry.data[CONF_PASSWORD] | ||
| self.port = config_entry.data.get(CONF_PORT, DEFAULT_SSH_PORT) | ||
|
|
||
| self.ap = UniFiAP( | ||
| target=self.host, | ||
| username=self.username, | ||
| password=self.password, | ||
| port=self.port, | ||
| ) |
There was a problem hiding this comment.
you don't need the parameters after assignment right? might as well just pick them from the config entry directly
| @pytest.fixture | ||
| def mock_unifiap() -> Generator[MagicMock]: | ||
| """Mock UniFiAP to return known clients.""" | ||
| with patch("homeassistant.components.unifi_direct.coordinator.UniFiAP") as mock: | ||
| ap_instance = MagicMock() | ||
| ap_instance.get_clients.return_value = MOCK_DEVICE_DATA | ||
| mock.return_value = ap_instance | ||
| yield mock | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def mock_unifiap_validate() -> Generator[MagicMock]: | ||
| """Mock UniFiAP for validate connection path.""" | ||
| with patch("homeassistant.components.unifi_direct.coordinator.UniFiAP") as mock: | ||
| ap_instance = MagicMock() | ||
| ap_instance.get_clients.return_value = MOCK_DEVICE_DATA | ||
| mock.return_value = ap_instance | ||
| yield mock |
There was a problem hiding this comment.
This isn't fixed yet, you can combine these, cheak mealie for an example
|
I'm seeing the following in my log file, without having enabled any extra logging I'm wondering if something is wrong with the log setup, and I should somehow mark |
| def __init__(self, coordinator: UniFiDirectDataUpdateCoordinator, mac: str) -> None: | ||
| """Initialize the tracked device.""" | ||
| super().__init__(coordinator) | ||
| self._mac = mac | ||
| device = coordinator.data.get(mac, {}) | ||
| self._attr_name = device.get("hostname") or mac |
There was a problem hiding this comment.
I don't think that's needed. ScannerEntity already defines a unique_id(), and uses the mac address for that. This is a globally unique identifier.
| def validate_connection_data(data: dict[str, Any]) -> None: | ||
| """Validate connection using a config-style dict. | ||
|
|
||
| Kept for config flow compatibility. | ||
| """ |
Breaking change
This PR introduces ConfigFlow support for unifi_direct. It also has automatic migration from the existing yaml.
Proposed change
Migrate unifi_direct from DeviceScanner to ScannerEntity and add ConfigFlow.
Type of change
Additional information
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: