Skip to content

Add IntelliDwell Sprinkler Controller core integration and tests - #177408

Open
TannerNelson16 wants to merge 4 commits into
home-assistant:devfrom
TannerNelson16:add-intellidwell-sprinkler
Open

Add IntelliDwell Sprinkler Controller core integration and tests#177408
TannerNelson16 wants to merge 4 commits into
home-assistant:devfrom
TannerNelson16:add-intellidwell-sprinkler

Conversation

@TannerNelson16

@TannerNelson16 TannerNelson16 commented Jul 27, 2026

Copy link
Copy Markdown

Breaking change

Proposed change

Type of change

  • Dependency upgrade
  • Bugfix (non-breaking change which fixes an issue)
  • New integration (thank you!)
  • New feature (which adds functionality to an existing integration)
  • Deprecation (breaking change to happen in the future)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

Checklist

  • I understand the code I am submitting and can explain how it works.
  • The code change is tested and works locally.
  • Local tests pass. Your PR cannot be merged unless tests pass
  • There is no commented out code in this PR.
  • I have followed the development checklist
  • I have followed the perfect PR recommendations
  • The code has been formatted using Ruff (ruff format homeassistant tests)
  • Tests have been added to verify that the new code works.
  • Any generated code has been carefully reviewed for correctness and compliance with project standards.

If user exposed functionality or configuration variables are added/changed:

If the code communicates with devices, web services, or third-party tools:

  • The manifest file has all fields filled out correctly.
    Updated and included derived files by running: python3 -m script.hassfest.
  • New or updated dependencies have been added to requirements_all.txt.
    Updated by running python3 -m script.gen_requirements_all.
  • For the updated dependencies a diff between library versions and ideally a link to the changelog/release notes is added to the PR description.

To help with the load of incoming pull requests:

Copilot AI review requested due to automatic review settings July 27, 2026 18:32

@home-assistant home-assistant Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @TannerNelson16

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!

@home-assistant

Copy link
Copy Markdown
Contributor

Please take a look at the requested changes, and use the Ready for review button when you are done, thanks 👍

Learn more about our pull request process.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a core integration for locally polling and controlling IntelliDwell sprinkler controllers.

Changes:

  • Adds config-entry setup, polling coordinator, and config flow.
  • Exposes ten sprinkler zones as switches.
  • Adds config-flow and switch tests.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 15 comments.

Show a summary per file
File Description
homeassistant/components/intellidwell/__init__.py Adds client and coordinator lifecycle.
homeassistant/components/intellidwell/config_flow.py Adds host-based configuration.
homeassistant/components/intellidwell/const.py Defines integration constants.
homeassistant/components/intellidwell/manifest.json Declares integration metadata.
homeassistant/components/intellidwell/switch.py Implements zone switches.
tests/components/intellidwell/__init__.py Initializes the test package.
tests/components/intellidwell/conftest.py Enables custom integrations during tests.
tests/components/intellidwell/test_config_flow.py Tests configuration flows.
tests/components/intellidwell/test_switch.py Tests switch setup and commands.
Comments suppressed due to low confidence (4)

homeassistant/components/intellidwell/switch.py:80

  • Propagate a Home Assistant service error when turning a zone off fails. Logging and swallowing every exception makes the service call report success even though the controller rejected or never received the command.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "off")
        except Exception as err:
            _LOGGER.error("Error turning off zone %s: %s", self.zone_index + 1, err)

tests/components/intellidwell/test_config_flow.py:29

  • Patch setup through the core integration package. The current nonexistent target prevents the successful config-flow test from running.
        "homeassistant_integration.intellidwell.async_setup_entry",

tests/components/intellidwell/test_switch.py:48

  • Patch set_relay through the core integration module. The current target does not exist, so this turn-on test errors before calling the service.
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"

tests/components/intellidwell/test_switch.py:62

  • Keep get_status mocked while invoking the turn-off service. The coordinator refresh after set_relay otherwise performs another real request to 1.1.1.1.
        await hass.services.async_call(

"name": "IntelliDwell Sprinkler Controller",
"codeowners": ["@TannerNelson16"],
"config_flow": true,
"documentation": "https://docs.intellidwell.net/sprinkler/",
"domain": "intellidwell",
"name": "IntelliDwell Sprinkler Controller",
"codeowners": ["@TannerNelson16"],
"config_flow": true,
"config_flow": true,
"documentation": "https://docs.intellidwell.net/sprinkler/",
"iot_class": "local_polling",
"requirements": ["aiohttp>=3.9.0"],
"documentation": "https://docs.intellidwell.net/sprinkler/",
"iot_class": "local_polling",
"requirements": ["aiohttp>=3.9.0"],
"version": "2.1.0"
@@ -0,0 +1,10 @@
{
"domain": "intellidwell",
"name": "IntelliDwell Sprinkler Controller",
)

with patch(
"homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er

from homeassistant_integration.intellidwell.const import DOMAIN
}

with patch(
"homeassistant_integration.intellidwell.IntelliDwellClient.get_status",

# Test turn off switch 2
with patch(
"homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"
with patch(
"homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"
) as mock_set_relay:
await hass.services.async_call(
Copilot AI review requested due to automatic review settings July 27, 2026 18:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (16)

homeassistant/components/intellidwell/init.py:60

  • Handle invalid responses as update failures too. validate_input establishes that get_status() can raise IntelliDwellInvalidResponseError; allowing it to escape here bypasses coordinator retry/unavailable handling during later polls and initial setup.
        except IntelliDwellConnectionError as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err

homeassistant/components/intellidwell/switch.py:72

  • Let command failures propagate to the service caller. Catching every exception and only logging it reports a successful turn-on even though the controller rejected or never received the command.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "on")
        except Exception as err:
            _LOGGER.error("Error turning on zone %s: %s", self.zone_index + 1, err)
        

homeassistant/components/intellidwell/switch.py:80

  • Let command failures propagate to the service caller. Catching every exception and only logging it reports a successful turn-off even though the controller rejected or never received the command.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "off")
        except Exception as err:
            _LOGGER.error("Error turning off zone %s: %s", self.zone_index + 1, err)

homeassistant/components/intellidwell/manifest.json:6

  • Use the Home Assistant integration documentation URL. Core manifest validation requires documentation links to begin with https://www.home-assistant.io/integrations/, so hassfest rejects this external vendor URL.
  "documentation": "https://docs.intellidwell.net/sprinkler/",

homeassistant/components/intellidwell/manifest.json:8

  • Declare and exactly pin the package that provides pyintellidwell. The integration imports that package but it is absent from the manifest and requirements_all.txt, while this loose aiohttp pin is rejected for core requirements; the integration therefore cannot import in a clean installation.
  "requirements": ["aiohttp>=3.9.0"],

homeassistant/components/intellidwell/manifest.json:3

  • Complete the PR template before review. The proposed-change section is blank, no change type is selected, and all applicable checklist items remain unchecked, so the description does not document or attest to this new integration.
  "name": "IntelliDwell Sprinkler Controller",

tests/components/intellidwell/test_config_flow.py:9

  • Import the core integration namespace so this test can be collected. homeassistant_integration does not exist in this repository and would test an external/custom package rather than the code in this PR.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_config_flow.py:26

  • Patch the core integration module. This target points at the nonexistent homeassistant_integration namespace, so patch() fails before the flow is exercised.
        "homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",

tests/components/intellidwell/test_config_flow.py:29

  • Patch the core integration setup function. This nonexistent namespace causes the success-flow test to fail before configuration completes.
        "homeassistant_integration.intellidwell.async_setup_entry",

tests/components/intellidwell/test_config_flow.py:50

  • Patch the core integration module. This target points at the nonexistent homeassistant_integration namespace, so the connection-error test never reaches validation.
        "homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",

tests/components/intellidwell/test_switch.py:9

  • Import the core integration namespace so this test can be collected. homeassistant_integration does not exist in this repository and would test an external/custom package rather than the code in this PR.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_switch.py:28

  • Patch the core integration module. This target points at the nonexistent homeassistant_integration namespace, so setup is not isolated from the real client.
        "homeassistant_integration.intellidwell.IntelliDwellClient.get_status",

tests/components/intellidwell/test_switch.py:48

  • Patch the core integration module. This nonexistent target prevents the turn-on assertion from running.
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"

tests/components/intellidwell/test_switch.py:60

  • Patch the core integration module. This nonexistent target prevents the turn-off assertion from running.
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"

tests/components/intellidwell/test_switch.py:30

  • Keep get_status mocked through the service calls. This context ends immediately after setup, but both switch methods request a coordinator refresh, causing the test to make real network requests to 1.1.1.1.
    with patch(
        "homeassistant_integration.intellidwell.IntelliDwellClient.get_status",
        return_value=status_data,
    ):

homeassistant/components/intellidwell/manifest.json:9

  • Remove the custom-integration version field. version is only accepted by CUSTOM_INTEGRATION_MANIFEST_SCHEMA; the core manifest schema rejects it as an extra key.
  "version": "2.1.0"

Comment on lines +48 to +52
super().__init__(
hass,
_LOGGER,
name=f"IntelliDwell Sprinkler Coordinator ({client.host})",
update_interval=timedelta(seconds=5),
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, config_entry.entry_id)},
name="IntelliDwell Sprinkler Controller",
manufacturer="Intellidwell",
},
"error": {
"cannot_connect": "Failed to connect, please check your network connection and try again.",
"unknown": "Unexpected error occurred."
Copilot AI review requested due to automatic review settings July 27, 2026 18:46

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (17)

homeassistant/components/intellidwell/manifest.json:3

  • Complete the PR description before requesting review. The Proposed change is empty, no Type of change is selected, and every checklist item remains unchecked, so the description does not identify or attest to this new integration.
  "name": "IntelliDwell Sprinkler Controller",

homeassistant/components/intellidwell/manifest.json:6

  • Point this core manifest at its Home Assistant integration documentation. Core manifests are rejected unless the URL begins with https://www.home-assistant.io/integrations/ (script/hassfest/manifest.py:138-145), so the current vendor URL fails hassfest.
  "documentation": "https://docs.intellidwell.net/sprinkler/",

homeassistant/components/intellidwell/manifest.json:7

  • Declare this config-flow integration as a hub. New core config-flow integrations not in the legacy allowlist must include integration_type, otherwise hassfest reports an error (script/hassfest/integration_type.py:74-97).
  "iot_class": "local_polling",

homeassistant/components/intellidwell/manifest.json:8

  • Declare the imported pyintellidwell distribution with an exact version pin and regenerate the requirement files. aiohttp>=3.9.0 neither installs the module imported by this integration nor satisfies the core == pin requirement (script/hassfest/requirements.py:407-411), so imports and hassfest will fail.
  "requirements": ["aiohttp>=3.9.0"],

homeassistant/components/intellidwell/manifest.json:9

  • Remove the version key from this core manifest. version is accepted only by the custom-integration schema (script/hassfest/manifest.py:322-328), so this extra key makes the core manifest invalid.
  "version": "2.1.0"

homeassistant/components/intellidwell/switch.py:71

  • Propagate a failed turn-on operation to the service caller. This catch currently logs every client failure and then returns successfully, falsely reporting that the zone was turned on; re-raise the error (ideally as a translated HomeAssistantError) instead.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "on")
        except Exception as err:
            _LOGGER.error("Error turning on zone %s: %s", self.zone_index + 1, err)

homeassistant/components/intellidwell/switch.py:80

  • Propagate a failed turn-off operation to the service caller. Swallowing the exception makes the service call succeed even though the controller rejected or never received the command.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "off")
        except Exception as err:
            _LOGGER.error("Error turning off zone %s: %s", self.zone_index + 1, err)

tests/components/intellidwell/test_config_flow.py:9

  • Import the integration from its actual core package. homeassistant_integration does not exist in this repository, so test collection fails before any config-flow test runs.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_config_flow.py:29

  • Patch the actual core integration modules. Both homeassistant_integration... targets are nonexistent, so entering this context raises ModuleNotFoundError instead of exercising successful configuration.
        "homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",
        return_value={"relay_states": [0] * 10},
    ), patch(
        "homeassistant_integration.intellidwell.async_setup_entry",

tests/components/intellidwell/test_config_flow.py:50

  • Patch the connection method under the core integration namespace. The current nonexistent target prevents the cannot-connect test from reaching the flow.
        "homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",

tests/components/intellidwell/test_switch.py:9

  • Import the integration from its actual core package. The nonexistent homeassistant_integration namespace makes this test module fail during collection.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_switch.py:28

  • Patch get_status under the core integration namespace. This target cannot be resolved, so switch setup is never tested.
        "homeassistant_integration.intellidwell.IntelliDwellClient.get_status",

tests/components/intellidwell/test_switch.py:30

  • Keep the status mock active while exercising the switch services. Each service method awaits async_request_refresh(), but this mock ends after setup, causing the test to call the real 1.1.1.1 controller during turn-on and turn-off.
    with patch(
        "homeassistant_integration.intellidwell.IntelliDwellClient.get_status",
        return_value=status_data,
    ):

tests/components/intellidwell/test_switch.py:48

  • Patch set_relay under the core integration namespace. The current target does not exist and prevents the turn-on assertion from running.
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"

tests/components/intellidwell/test_switch.py:60

  • Patch set_relay under the core integration namespace. The current target does not exist and prevents the turn-off assertion from running.
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"

homeassistant/components/intellidwell/init.py:60

  • Treat invalid controller responses as an expected coordinator update failure. The config flow explicitly recognizes IntelliDwellInvalidResponseError, but polling does not, so the same device response is logged as an unexpected traceback instead of a normal UpdateFailed.
        except IntelliDwellConnectionError as err:
            raise UpdateFailed(f"Error communicating with API: {err}") from err

homeassistant/components/intellidwell/switch.py:53

  • Use the product's established IntelliDwell capitalization in device metadata.
            manufacturer="Intellidwell",

@TannerNelson16
TannerNelson16 marked this pull request as ready for review July 27, 2026 18:57
@home-assistant
home-assistant Bot dismissed their stale review July 27, 2026 18:57

Stale

Copilot AI review requested due to automatic review settings July 27, 2026 19:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 7 comments.

Comments suppressed due to low confidence (17)

homeassistant/components/intellidwell/manifest.json:3

  • Complete the pull request description before further review. The Proposed change is empty, no change type is selected, and all checklist items remain unchecked, so the required template has not been filled in for this new integration.
  "name": "IntelliDwell Sprinkler Controller",

homeassistant/components/intellidwell/manifest.json:5

  • Declare this as a device integration. Hassfest rejects new core config-flow integrations without an integration_type (script/hassfest/integration_type.py:74-97).
  "config_flow": true,

homeassistant/components/intellidwell/manifest.json:6

  • Use the Home Assistant integration documentation URL. Core manifest validation requires URLs under https://www.home-assistant.io/integrations/, so the vendor URL makes hassfest fail.
  "documentation": "https://docs.intellidwell.net/sprinkler/",

homeassistant/components/intellidwell/manifest.json:8

  • Declare the library that the integration imports. Installing this integration currently installs only aiohttp, so from pyintellidwell import ... fails on a normal Home Assistant installation even though the generated requirements file lists pyintellidwell.
  "requirements": ["aiohttp>=3.9.0"],

homeassistant/components/intellidwell/manifest.json:9

  • Remove the custom-integration version field. The core integration manifest schema does not allow this key, so hassfest rejects this manifest.
  "version": "2.1.0"

tests/components/intellidwell/test_switch.py:9

  • Import the core integration namespace. homeassistant_integration is not a package in this repository, so this import prevents the switch test module from being collected.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_switch.py:28

  • Patch the core integration namespace. The current target cannot be resolved because homeassistant_integration does not exist.
        "homeassistant_integration.intellidwell.IntelliDwellClient.get_status",

tests/components/intellidwell/test_switch.py:49

  • Patch both the core client command and the refresh request. After set_relay, the entity requests a coordinator refresh, so correcting only the namespace would make this test perform a real request to 1.1.1.1.
    with patch(
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"
    ) as mock_set_relay:

tests/components/intellidwell/test_switch.py:61

  • Patch both the core client command and the refresh request. After set_relay, the entity requests a coordinator refresh, so correcting only the namespace would make this test perform a real request to 1.1.1.1.
    with patch(
        "homeassistant_integration.intellidwell.IntelliDwellClient.set_relay"
    ) as mock_set_relay:

tests/components/intellidwell/test_config_flow.py:9

  • Import the core integration namespace. homeassistant_integration is not a package in this repository, so this import prevents the config-flow test module from being collected.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_config_flow.py:29

  • Patch the core integration modules in the success test. Both current targets use the nonexistent homeassistant_integration namespace, so the context manager fails before the flow is configured.
        "homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",
        return_value={"relay_states": [0] * 10},
    ), patch(
        "homeassistant_integration.intellidwell.async_setup_entry",

tests/components/intellidwell/test_config_flow.py:50

  • Patch the core config-flow module. The current target uses the nonexistent homeassistant_integration namespace, so this error-path test cannot run.
        "homeassistant_integration.intellidwell.config_flow.IntelliDwellClient.get_status",

homeassistant/components/intellidwell/switch.py:71

  • Let turn-on failures propagate to the service caller. Catching every exception and only logging it reports a successful service call even when the sprinkler command failed; translate known client errors to HomeAssistantError or allow them to propagate.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "on")
        except Exception as err:
            _LOGGER.error("Error turning on zone %s: %s", self.zone_index + 1, err)

homeassistant/components/intellidwell/switch.py:80

  • Let turn-off failures propagate to the service caller. Catching every exception and only logging it reports a successful service call even when the sprinkler command failed; translate known client errors to HomeAssistantError or allow them to propagate.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "off")
        except Exception as err:
            _LOGGER.error("Error turning off zone %s: %s", self.zone_index + 1, err)

tests/components/intellidwell/test_switch.py:39

  • Remove this narration comment. The state lookups and assertions immediately below already make the intent clear.
    # Verify states

tests/components/intellidwell/test_switch.py:46

  • Remove this narration comment. The service name and entity ID immediately below already describe the turn-on case.
    # Test turn on switch 1

tests/components/intellidwell/test_switch.py:58

  • Remove this narration comment. The service name and entity ID immediately below already describe the turn-off case.
    # Test turn off switch 2

"codeowners": ["@TannerNelson16"],
"config_flow": true,
"documentation": "https://docs.intellidwell.net/sprinkler/",
"iot_class": "local_polling",
"domain": "intellidwell",
"name": "IntelliDwell Sprinkler Controller",
"codeowners": ["@TannerNelson16"],
"config_flow": true,
coordinator = IntelliDwellCoordinator(hass, client)
await coordinator.async_config_entry_first_refresh()

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator
errors: dict[str, str] = {}
if user_input is not None:
host = user_input[CONF_HOST]
self._async_abort_entries_match({CONF_HOST: host})
Comment on lines +53 to +55
except Exception: # pylint: disable=broad-except
_LOGGER.exception("Unexpected exception")
errors["base"] = "unknown"
client = IntelliDwellClient(host, session=session)

coordinator = IntelliDwellCoordinator(hass, client)
await coordinator.async_config_entry_first_refresh()
assert await hass.config_entries.async_setup(entry.entry_id)
await hass.async_block_till_done()

# Verify switches were created
Copilot AI review requested due to automatic review settings July 27, 2026 19:48

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (12)

homeassistant/components/intellidwell/manifest.json:6

  • Point this core integration at its Home Assistant documentation URL; the core manifest validator rejects vendor documentation URLs (script/hassfest/manifest.py:138-145).
  "documentation": "https://docs.intellidwell.net/sprinkler/",

homeassistant/components/intellidwell/manifest.json:8

  • Add a Bronze quality-scale declaration and quality_scale.yaml; hassfest requires every new core integration to reach Bronze (script/hassfest/quality_scale.py:2120-2138).
  "iot_class": "local_polling",
  "requirements": ["pyintellidwell==1.0.0"],

homeassistant/components/intellidwell/manifest.json:9

  • Remove the custom-integration version key; it is not accepted by the core manifest schema (script/hassfest/manifest.py:204-299,342-348).
  "version": "2.1.0"

homeassistant/components/intellidwell/manifest.json:5

  • Regenerate and include the config-flow metadata files; config_flow: true currently has no IntelliDwell entry in homeassistant/generated/config_flows.py or integrations.json, which hassfest reports as stale (script/hassfest/config_flow.py:210-230).
  "config_flow": true,

homeassistant/components/intellidwell/init.py:52

  • Pass the config entry explicitly into the coordinator and then to DataUpdateCoordinator; omitting it is reported as an error for core integrations (homeassistant/helpers/update_coordinator.py:95-108).
        super().__init__(
            hass,
            _LOGGER,
            name=f"IntelliDwell Sprinkler Coordinator ({client.host})",
            update_interval=timedelta(seconds=5),

homeassistant/components/intellidwell/init.py:31

  • Store the coordinator in a typed entry.runtime_data and read it from there in the platform; new Bronze integrations must implement the runtime-data rule.
    hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator

homeassistant/components/intellidwell/switch.py:71

  • Let relay-command failures propagate so the service call reports failure instead of logging an error and returning success.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "on")
        except Exception as err:
            _LOGGER.error("Error turning on zone %s: %s", self.zone_index + 1, err)

homeassistant/components/intellidwell/switch.py:80

  • Let relay-command failures propagate so the service call reports failure instead of logging an error and returning success.
        try:
            await self.coordinator.client.set_relay(self.zone_index, "off")
        except Exception as err:
            _LOGGER.error("Error turning off zone %s: %s", self.zone_index + 1, err)

homeassistant/components/intellidwell/switch.py:53

  • Use the product's established IntelliDwell capitalization in the user-visible manufacturer name.
            manufacturer="Intellidwell",

tests/components/intellidwell/test_config_flow.py:9

  • Replace this import and every patch target in this file with homeassistant.components.intellidwell; homeassistant_integration is not a package in core, so the test fails during collection.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_switch.py:9

  • Replace this import and every patch target in this file with homeassistant.components.intellidwell; homeassistant_integration is not a package in core, so the test fails during collection.
from homeassistant_integration.intellidwell.const import DOMAIN

tests/components/intellidwell/test_switch.py:30

  • Keep get_status mocked while exercising both switch services; each command requests a coordinator refresh after this context exits, so the test otherwise contacts 1.1.1.1.
    with patch(
        "homeassistant_integration.intellidwell.IntelliDwellClient.get_status",
        return_value=status_data,
    ):

Copilot AI review requested due to automatic review settings July 27, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (11)

tests/components/intellidwell/test_config_flow.py:72

  • Remove this narrative comment because the successful response patch and create-entry assertions already describe the second attempt.
    # Second attempt: connection succeeds — entry should be created.

tests/components/intellidwell/test_switch.py:152

  • Mock all coordinator endpoints in this setup-failure test. _async_update_data() starts get_status(), get_rain_delay(), and get_schedules() concurrently, so the two unpatched calls can perform real network I/O and make the test flaky or fail under socket blocking.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/util/init.py:65

  • Remove this unrelated syntax-only change from the IntelliDwell integration PR. Python 3.14 supports the existing exception syntax, and this edit does not contribute to the integration or its tests.
    except (ValueError, TypeError):

homeassistant/components/intellidwell/coordinator.py:51

  • Mark failed auxiliary fetches unavailable instead of returning fabricated defaults. If rain-delay or schedule parsing raises one of these exceptions, the fallback status lacks those keys, yet the number reports 0 and every schedule switch reports enabled, which can misrepresent the controller state.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Mark entity-device-class as todo until the applicable duration metadata is implemented. The rain-delay number has a day unit but no NumberDeviceClass.DURATION, so this Gold rule is not currently complete.
  entity-device-class: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon-translations as todo until entity icons are moved to icons.json. The integration currently hardcodes icons in number.py:41 and switch.py:111, so this Gold rule is not complete.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the repeated controller entity setup into a shared base entity before marking common-modules done. The identical DeviceInfo construction is duplicated at switch.py:63-69, switch.py:126-132, and number.py:58-64, so metadata changes can easily drift across platforms.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption reason to include the rain-delay number entity. The integration creates both switch and number entities, so the current quality-scale declaration is factually inaccurate.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/manifest.json:3

  • Complete and correct the PR description before merging this integration. The Proposed change section is empty, two mutually exclusive Type of change boxes are selected, and the checked dependency-release comparison item has no corresponding link.
  "name": "IntelliDwell Sprinkler Controller",

tests/components/intellidwell/test_config_flow.py:58

  • Remove this narrative comment because the exception patch and following assertions already make the failed first attempt explicit.

This issue also appears on line 72 of the same file.

    # First attempt: connection fails — form should re-display with an error.

homeassistant/components/intellidwell/switch.py:148

  • Add coverage for dictionary-shaped schedule responses. The existing switch test only supplies a list, leaving this alternate key-lookup path entirely unverified.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (11)

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption rationale because the integration also creates a rain-delay number entity in number.py.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Change this rule to todo until the hard-coded number and schedule-switch icons are moved to an icons.json translation file; integrations that mark it done provide that file (for example, homeassistant/components/huum/icons.json).
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:69

  • Mark this rule exempt because each config entry always represents one fixed controller; single-device integrations use an exemption (for example, homeassistant/components/airgradient/quality_scale.yaml:65-68).
  dynamic-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Change this rule to todo or assign the rain-delay number the available duration device class. NumberDeviceClass.DURATION supports days (homeassistant/components/number/const.py:545-552), while number.py:46 currently only sets the unit.
  entity-device-class: done

homeassistant/components/intellidwell/quality_scale.yaml:81

  • Mark this rule exempt because a fixed single-device config entry cannot accumulate stale discovered devices; this matches integrations such as homeassistant/components/airgradient/quality_scale.yaml:80-83.
  stale-devices: done

tests/components/intellidwell/test_switch.py:152

  • Mock the other two coordinator requests in this failure test as well. _async_update_data starts get_status, get_rain_delay, and get_schedules together, so the latter two currently make real requests to 1.1.1.1 and can continue after get_status raises, making this test flaky and network-dependent.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/util/init.py:65

  • Remove this unrelated syntax-only change from the IntelliDwell integration PR so the change set remains scoped to the new integration.
    except (ValueError, TypeError):

homeassistant/components/intellidwell/coordinator.py:51

  • Treat extra-endpoint parse failures as an unsuccessful update, or explicitly mark the missing rain-delay and schedule data unknown. Returning status-only data keeps the coordinator successful, so the number reports 0 and every missing schedule reports on even though those values were not fetched.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark this rule exempt because this is a polling-only integration with no event subscriptions; polling integrations use that status consistently (for example, homeassistant/components/rainbird/quality_scale.yaml:27-29 and homeassistant/components/freshr/quality_scale.yaml:24-26).

This issue also appears in the following locations of the same file:

  • line 69
  • line 71
  • line 72
  • line 78
  • line 81
  entity-event-setup: done

homeassistant/components/intellidwell/switch.py:130

  • Reuse one shared IntelliDwell device-info definition instead of repeating this block for the schedule entity; it duplicates the zone entity metadata at switch.py:63-69, so future model or URL changes can diverge.
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, config_entry.entry_id)},
            name="IntelliDwell Sprinkler Controller",
            manufacturer="IntelliDwell",
            model="Sprinkler Controller V2",

homeassistant/components/intellidwell/number.py:62

  • Reuse shared IntelliDwell device metadata here instead of maintaining a third copy of the same DeviceInfo block from switch.py:63-69 and switch.py:126-132.
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, config_entry.entry_id)},
            name="IntelliDwell Sprinkler Controller",
            manufacturer="IntelliDwell",
            model="Sprinkler Controller V2",

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (15)

tests/components/intellidwell/test_switch.py:152

  • Mock every request started by the coordinator in this setup-failure test. _async_update_data() starts all three calls with asyncio.gather, so the unpatched rain-delay and schedules methods can perform real network I/O against 1.1.1.1 even though get_status() raises.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/components/intellidwell/coordinator.py:51

  • Treat an auxiliary API failure as an update failure instead of publishing incomplete coordinator data. Returning only get_status() marks the refresh successful while the rain-delay entity falls back to 0 and schedule switches fall back to enabled, exposing incorrect device state.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/util/init.py:65

  • Remove this unrelated syntax-only edit from the IntelliDwell integration PR. Python 3.14 supports the original form, and this change is not required by the new integration or its dependency.
    except (ValueError, TypeError):

homeassistant/components/intellidwell/config_flow.py:32

  • Validate every API endpoint required by the initial coordinator refresh before creating the entry. A controller can pass get_status() but fail get_rain_delay() or get_schedules(), after which setup enters retry even though the config flow reported success.
        await client.get_status()

homeassistant/components/intellidwell/switch.py:149

  • Move schedule-response normalization into pyintellidwell and consume one typed representation here. Supporting list/dict payloads plus string/integer keys in the integration is protocol parsing and a library workaround, which Home Assistant integrations should not own.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )
            if isinstance(zone_info, dict):

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Extract the shared entity metadata before marking common-modules complete. The same DeviceInfo construction is duplicated in both switch classes and the number class, so this Bronze rule is not yet satisfied; a common coordinator property or base entity should own it.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark entity-event-setup exempt because this integration registers no entity events. done claims an event setup implementation that is absent from the integration.
  entity-event-setup: done

homeassistant/components/intellidwell/quality_scale.yaml:50

  • Mark test coverage as pending or add coverage for the untested runtime branches. The tests never exercise unloading, invalid/partial coordinator responses, or the dictionary schedule representation, so test-coverage: done is not supported.
  test-coverage: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption rationale to include the rain-delay number entity. The integration does not create only switches, so the stated reason is factually inaccurate and does not establish why every entity should remain enabled by default.
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon translations pending until the hard-coded entity icons are moved to icons.json. This integration has no icons.json, while number.py and switch.py set _attr_icon directly, so the rule is not implemented.
  icon-translations: done

tests/components/intellidwell/test_config_flow.py:58

  • Remove this narrative comment because the patch and following assertions already make the failed first attempt explicit. It restates straightforward test code without explaining a non-obvious constraint.
    # First attempt: connection fails — form should re-display with an error.

tests/components/intellidwell/test_config_flow.py:72

  • Remove this narrative comment because the successful retry and entry assertions directly describe the second attempt. It restates straightforward test code without adding rationale.
    # Second attempt: connection succeeds — entry should be created.

homeassistant/components/intellidwell/number.py:46

  • Declare this number as a duration using Home Assistant's device-class and unit enums. Duration number entities use NumberDeviceClass.DURATION with UnitOfTime.DAYS (for example, homeassistant/components/renson/number.py:24-34); the raw unit also contradicts the claimed entity-device-class completion.
    _attr_native_unit_of_measurement = "d"

homeassistant/components/intellidwell/quality_scale.yaml:69

  • Mark dynamic-devices exempt because this integration creates one fixed controller device per config entry. There is no runtime device-discovery path implementing this rule.
  dynamic-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:81

  • Mark stale-devices exempt because this integration has no dynamically discovered child devices to remove. done currently claims stale-device cleanup behavior that is not implemented.
  stale-devices: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (15)

tests/components/intellidwell/test_switch.py:152

  • Mock every coordinator request in this setup-failure test. _async_update_data() starts get_rain_delay() and get_schedules() alongside get_status(), so leaving those methods unpatched performs real network I/O against 1.1.1.1 and makes the test nondeterministic.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/components/intellidwell/quality_scale.yaml:69

  • Mark the dynamic-device rule exempt for this single-controller integration. The integration creates one fixed device and has no discovery path for adding devices dynamically; the established single-device exemption is shown in homeassistant/components/peblar/quality_scale.yaml:62-65.
  dynamic-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Do not claim the entity-device-class rule until the duration metadata is implemented. The rain-delay number uses a day unit but omits NumberDeviceClass.DURATION; the corresponding established implementation is homeassistant/components/renson/number.py:24-33.
  entity-device-class: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption rationale to include the rain-delay number. number.py creates a number entity, so the current statement that only switches are created is factually incorrect.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon translations as incomplete or add an icons.json. The number and schedule switch icons are hardcoded in Python, while integrations satisfying this rule define translation-key icons as in homeassistant/components/peblar/icons.json.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:81

  • Mark stale-device handling exempt for this single-controller integration. There is no dynamic device inventory from which stale devices could be removed; homeassistant/components/peblar/quality_scale.yaml:77-80 uses the applicable exemption.
  stale-devices: done

homeassistant/util/init.py:65

  • Revert this unrelated syntax-only change. The original exception syntax is valid on Home Assistant's Python 3.14 baseline, and changing shared utility code is not required to add IntelliDwell or its dependency.
    except (ValueError, TypeError):

homeassistant/components/intellidwell/coordinator.py:51

  • Fail the coordinator update instead of returning an incomplete payload. If either auxiliary endpoint raises one of these parsing errors, this branch omits rain_delay and schedules while reporting a successful update; the number then shows zero and missing schedule switches show enabled rather than preserving the last valid state.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark this rule exempt because the integration does not explicitly subscribe to events. Polling integrations use this exemption pattern in homeassistant/components/peblar/quality_scale.yaml:25-28 and homeassistant/components/rainbird/quality_scale.yaml:27-29; CoordinatorEntity handles its own listener lifecycle.

This issue also appears in the following locations of the same file:

  • line 69
  • line 71
  • line 72
  • line 78
  • line 81
  entity-event-setup: done

homeassistant/components/intellidwell/switch.py:151

  • Return an unknown state when schedule data is absent or malformed. Ten schedule switches are always created, so a shorter response—such as the two-item fixture in test_switches—currently makes every remaining zone report enabled without an enabled value.
        if not isinstance(self.coordinator.data, dict):
            return True
        schedules = self.coordinator.data.get("schedules", [])

homeassistant/components/intellidwell/number.py:75

  • Reject fractional rain-delay values instead of silently truncating them. The number.set_value service accepts any float and only clamps its range (homeassistant/components/number/__init__.py:99,122-127), so requesting 2.9 currently sends 2 days despite the caller's value.
        """Set rain delay days (0 to 5)."""
        days = int(value)

homeassistant/components/intellidwell/switch.py:130

  • Extract a shared IntelliDwell coordinator entity for the common device metadata. This identical DeviceInfo block is repeated in both switch classes and number.py:58-64, so model, manufacturer, identifiers, and URL can drift; the claimed common-modules rule should keep this single-sourced.
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, config_entry.entry_id)},
            name="IntelliDwell Sprinkler Controller",
            manufacturer="IntelliDwell",
            model="Sprinkler Controller V2",

requirements_all.txt:2273

  • Add a pyintellidwell 1.0.0 release or source-comparison link to the PR description. The dependency checklist item is checked as completed, but the description contains no release, changelog, or comparison link for this newly added requirement.
pyintellidwell==1.0.0

homeassistant/components/intellidwell/manifest.json:10

  • Select only “New integration” in the PR description’s type checklist. pyintellidwell is a required part of this new integration, not a separate dependency-upgrade change, and the template explicitly permits only one selected type.
  "quality_scale": "bronze",
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/init.py:42

  • Add a test that unloads the config entry and verifies its entities are removed. This new lifecycle path is currently never exercised even though the quality-scale file claims both config-entry unloading and test coverage are complete.
async def async_unload_entry(
    hass: HomeAssistant, entry: IntelliDwellConfigEntry
) -> bool:
    """Unload a config entry."""
    return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (9)

tests/components/intellidwell/test_switch.py:152

  • Mock all three coordinator requests during this failure test. _async_update_data() starts get_rain_delay() and get_schedules() alongside get_status(), so these unpatched calls still perform real network I/O against 1.1.1.1 and can leak pending requests or make the test flaky.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/components/intellidwell/coordinator.py:51

  • Raise UpdateFailed instead of treating an incomplete refresh as successful. If either auxiliary endpoint raises one of these exceptions, this returns status without rain_delay or schedules, so the coordinator stays available while entities publish fabricated defaults.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/switch.py:151

  • Return an unknown state when schedule data is absent instead of reporting it as enabled. Missing, short, or malformed schedule responses all reach this fallback, causing affected switches to appear on without an enabled value.
        return True

homeassistant/components/intellidwell/number.py:62

  • Move the shared device metadata into the coordinator or a common entity base. This identical DeviceInfo block is repeated here and twice in switch.py:63-69,126-132, so device identity changes must be kept synchronized across three implementations.
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, config_entry.entry_id)},
            name="IntelliDwell Sprinkler Controller",
            manufacturer="IntelliDwell",
            model="Sprinkler Controller V2",

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark entity-event-setup as exempt for this polling integration. Polling coordinators do not register entity event subscriptions; established entries use this exemption, for example freshr/quality_scale.yaml:24-26 and rainbird/quality_scale.yaml:27-29.
  entity-event-setup: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon-translations as todo until translated icons are implemented. There is no icons.json, and number.py:41 and switch.py:111 still hard-code entity icons, so the rule is not currently complete.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption rationale to account for the number entity. The integration creates IntelliDwellRainDelayNumber, so the current claim that only switches are created is factually incorrect.
      Only switch entities are created.

homeassistant/util/init.py:65

  • Revert this unrelated syntax-only change. The PR is scoped to adding IntelliDwell, while this alters a global utility that the integration does not depend on and changes syntax that is valid on Home Assistant's minimum Python 3.14.
    except (ValueError, TypeError):

homeassistant/components/intellidwell/manifest.json:10

  • Complete the PR description for this new dependency and select only the New integration type. The Proposed change section is empty, both Dependency upgrade and New integration are checked, and the checked release/compare-link requirement has no corresponding link.
  "requirements": ["pyintellidwell==1.0.0"]

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark this rule as todo or provide an exemption that matches the entities created; the integration also creates a rain-delay number, so “Only switch entities are created” is factually incorrect and cannot justify this exemption.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

tests/components/intellidwell/test_switch.py:152

  • Mock all three coordinator requests in this failure test. _async_update_data starts get_rain_delay() and get_schedules() concurrently with get_status(), and asyncio.gather does not cancel them when the status mock raises, so these unpatched calls can perform real network I/O against 1.1.1.1.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon translations as todo until the entity icons are moved to icons.json. The integration has no icons.json and instead hard-codes icons in number.py:41 and switch.py:111, so this rule is not implemented.
  icon-translations: done

homeassistant/components/intellidwell/coordinator.py:51

  • Treat malformed extra data as a failed update, or explicitly track per-field availability. Returning only get_status() marks the coordinator successful without rain_delay or schedules, so the number reports a fabricated zero and every schedule switch reports enabled instead of becoming unavailable.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Mark common-modules as todo until the shared entity setup is extracted. The same DeviceInfo construction is duplicated in number.py:58-64 and twice in switch.py:63-69,126-132; a common entity base or coordinator property is needed to keep this metadata single-source.

This issue also appears in the following locations of the same file:

  • line 72
  • line 78
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:50

  • Mark test-coverage as todo until the untested branches are covered. The suite never executes the coordinator’s malformed-extra-data fallback (coordinator.py:49-51), the schedule dictionary/non-dictionary handling (switch.py:138-150), or config-entry unloading, so the Silver rule is not yet demonstrated.
  test-coverage: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (7)

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption because the integration also creates a rain-delay number entity in number.py; the stated reason is factually false, so this rule should remain todo unless all entities are evaluated and a valid exemption is documented.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

tests/components/intellidwell/test_switch.py:152

  • Mock all coordinator requests in this failure test. _async_update_data starts get_status, get_rain_delay, and get_schedules concurrently, so leaving the latter two unpatched allows real requests to 1.1.1.1 to continue after get_status raises, making the test perform external I/O and potentially hang or fail nondeterministically.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/components/intellidwell/coordinator.py:51

  • Wrap failures from the fallback get_status() call as UpdateFailed. Exceptions raised inside an except block are not handled by the preceding handlers, so a connection/invalid-response/parsing failure here reaches DataUpdateCoordinator as an unexpected exception and can emit a traceback on every five-second poll instead of using its normal unavailable/recovery logging.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon translations as todo until the entity icons are moved to icons.json. Both platforms currently set _attr_icon in Python and this integration has no icons.json, so the Gold rule is not implemented.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Mark the device-class rule as todo or add NumberDeviceClass.DURATION to the rain-delay number. That entity represents a duration in days but defines no device class, so this Gold rule is not yet complete.
  entity-device-class: done

homeassistant/components/intellidwell/coordinator.py:51

  • Avoid publishing status-only data as a successful full update. When either extra request raises one of these parsing errors, this return omits rain_delay and schedules; the coordinator remains available, so number.py reports a false zero-day delay and switch.py reports every schedule as enabled, overwriting previously valid states. Preserve the prior extra values, model their availability separately, or fail the update instead.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared entity setup into a common entity base before marking this Bronze rule done. The identical DeviceInfo block is currently duplicated in switch.py:63-69, switch.py:126-132, and number.py:58-64, so metadata changes must be kept synchronized across three classes; established integrations such as rainbird/number.py:52-54 expose shared device info from their coordinator/base entity.
  common-modules: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (9)

homeassistant/components/intellidwell/quality_scale.yaml:66

  • Mark the unimplemented documentation rules todo or expand the linked documentation PR. That page has no data-update, example, limitation, troubleshooting, or use-case sections, and its supported-function list omits both the rain-delay number and schedule switches.
  docs-data-update: done
  docs-examples: done
  docs-known-limitations: done
  docs-supported-devices: done
  docs-supported-functions: done

tests/components/intellidwell/test_config_flow.py:72

  • Remove this narrating comment; the success mock and create-entry assertions immediately below already describe the recovery attempt.
    # Second attempt: connection succeeds — entry should be created.

homeassistant/components/intellidwell/switch.py:21

  • Serialize all client calls through one shared coordinator lock. PARALLEL_UPDATES = 1 only protects switch actions from other switch actions; number actions and scheduled refreshes can still overlap them, despite the firmware warning that concurrent HTTP requests can exhaust sockets and crash the ESP32.
PARALLEL_UPDATES = 1

homeassistant/components/intellidwell/coordinator.py:51

  • Fail the refresh instead of returning incomplete coordinator data. This path omits rain_delay and schedules, so the number reports a false zero and every schedule switch reports enabled while all entities remain available.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption rationale or the entity behavior. number.py creates a rain-delay number, so “Only switch entities are created” is factually incorrect and cannot justify this exemption.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Extract the shared entity setup before marking common-modules complete. The identical DeviceInfo construction is currently repeated in number.py and both switch classes, while this Bronze rule requires common entity behavior to live in entity.py.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Do not mark the device-class rule complete while the rain-delay entity lacks a duration device class. number.py exposes a value measured in days but does not set NumberDeviceClass.DURATION.
  entity-device-class: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Do not mark icon translations complete while icons remain hardcoded. Both platforms set _attr_icon, and the integration has no icons.json, whereas this rule requires icons to be defined by translation key.
  icon-translations: done

tests/components/intellidwell/test_config_flow.py:58

  • Remove this narrating comment; the mock and assertions immediately below already express the failed first attempt and expected form error.

This issue also appears on line 72 of the same file.

    # First attempt: connection fails — form should re-display with an error.

Comment on lines +41 to +46
status_data, rain_delay_data, schedules_data = await asyncio.gather(
self.client.get_status(),
self.client.get_rain_delay(),
self.client.get_schedules(),
return_exceptions=False,
)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (11)

tests/components/intellidwell/test_switch.py:152

  • Mock all coordinator requests in this failure test. The coordinator starts get_status, get_rain_delay, and get_schedules concurrently, so the two unpatched methods perform real network I/O and can make this test slow or flaky.
    with patch(
        "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
        side_effect=IntelliDwellConnectionError,
    ):

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the brands rule before declaring Bronze quality. A Bronze integration cannot leave one of its Bronze rules as todo, so the manifest currently overstates the integration's achieved tier.
  appropriate-polling: done
  brands: todo

homeassistant/components/intellidwell/coordinator.py:51

  • Treat malformed auxiliary responses as a failed coordinator update. Returning status-only data drops rain_delay and schedules, while the entities publish those missing values as 0/enabled and remain available, producing false states.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/number.py:75

  • Reject non-integral rain-delay values instead of silently truncating them. The number service validates only the 0–5 range, so a call with 4.9 reaches this method and is unexpectedly sent to the controller as 4 days.
    async def async_set_native_value(self, value: float) -> None:
        """Set rain delay days (0 to 5)."""
        days = int(value)

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared entity metadata into an entity.py base class before marking common-modules done. The same CoordinatorEntity setup and DeviceInfo block is duplicated across both switch classes and the number class; homeassistant/components/prana/entity.py:13-37 demonstrates the established pattern.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:64

  • Mark these documentation rules todo until the linked documentation implements them. The linked page contains no data-update interval, automation example, or known-limitations section, so these done statuses are inaccurate.
  docs-data-update: done
  docs-examples: done
  docs-known-limitations: done

homeassistant/components/intellidwell/quality_scale.yaml:67

  • Mark these documentation rules todo until the linked page is completed. It documents only relay zone switches, omitting the rain-delay number and schedule switches, and it has no troubleshooting guidance.
  docs-supported-functions: done
  docs-troubleshooting: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Remove this invalid exemption or mark the rule todo. The rule has no exemption and the explanation is also factually incorrect because number.py creates a rain-delay number entity.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark icon-translations todo until the icons are moved to icons.json. The number and schedule switch currently set _attr_icon directly, and this integration has no icons.json, which does not satisfy the icon-translations rule.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Mark entity-device-class todo or add the applicable duration device class. The rain-delay number exposes a day unit but does not set NumberDeviceClass.DURATION, unlike the established duration-number pattern in homeassistant/components/renson/number.py:32-33.
  entity-device-class: done

homeassistant/components/intellidwell/init.py:42

  • Add a config-entry unload test for this new integration. Both nearby new integrations test the loaded-to-unloaded transition (tests/components/prana/test_init.py:19-25 and tests/components/aidot/test_init.py:20-26), while this implementation and its config-entry-unloading: done claim are currently uncovered.
async def async_unload_entry(
    hass: HomeAssistant, entry: IntelliDwellConfigEntry
) -> bool:
    """Unload a config entry."""
    return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (11)

tests/components/intellidwell/test_switch.py:152

  • Mock every coordinator request in this failure test. _async_update_data() starts get_status(), get_rain_delay(), and get_schedules() concurrently, so leaving the latter two unpatched can perform real network I/O and make the test flaky.
    with (
        patch(
            "homeassistant.components.intellidwell.IntelliDwellClient.get_status",
            side_effect=IntelliDwellConnectionError,

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the required branding work before declaring Bronze. manifest.json claims Bronze while this mandatory Bronze rule remains todo; the linked documentation PR also confirms that no Brands PR has been opened.
  brands: todo

homeassistant/components/intellidwell/switch.py:35

  • Build entities from the controller's configured relay roles instead of treating all ten relays as zones. IntelliDwell supports a configured master-valve relay; exposing it as a normal zone lets users bypass its automatic sequencing, and its schedule control has no effect because firmware skips scheduling that relay.
    entities: list[SwitchEntity] = [
        IntelliDwellZoneSwitch(coordinator, config_entry, zone_index)
        for zone_index in range(10)
    ]

homeassistant/components/intellidwell/quality_scale.yaml:38

  • Remove the invalid action-exceptions exemption. The rule explicitly includes platform actions, and this integration implements number and switch actions even though it has no custom services.
  action-exceptions:
    status: exempt
    comment: |
      Integration does not provide custom services.

homeassistant/components/intellidwell/coordinator.py:51

  • Treat malformed auxiliary responses as update failures instead of returning status-only data. This fallback marks the coordinator successful while omitting rain_delay and schedules, so the entities publish fabricated defaults (0 days and enabled schedules) rather than becoming unavailable.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Add a shared base entity before marking common-modules done. DeviceInfo and coordinator setup are duplicated across number.py and both switch classes, while this Bronze rule requires common entity behavior to live in entity.py.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Do not mark icon translations done while icons are hardcoded. number.py:41 and switch.py:111 use _attr_icon, and the integration has no icons.json, so this rule is not implemented.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:67

  • Mark unsupported documentation rules todo until the linked docs are completed. PR 47101 contains no examples, known-limitations, or troubleshooting content and its supported-functions section omits both the rain-delay number and schedule switches.
  docs-examples: done
  docs-known-limitations: done
  docs-supported-devices: done
  docs-supported-functions: done
  docs-troubleshooting: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption to account for the number entity. The integration creates IntelliDwellRainDelayNumber, so the stated reason that only switches are created is factually incorrect and does not establish whether non-primary entities should be disabled by default.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

requirements_all.txt:2273

  • Correct and complete the PR template for this dependency addition. This line introduces pyintellidwell rather than upgrading it, but the description checks both “Dependency upgrade” and “New integration,” leaves Proposed change empty, and claims a release/changelog link that is not provided.
pyintellidwell==1.0.0

homeassistant/components/intellidwell/config_flow.py:34

  • Validate every endpoint required by the first coordinator refresh before creating the entry. The flow currently succeeds after only get_status(), but setup immediately requires rain-delay and schedule requests too, so a controller missing either endpoint is accepted and then remains in SETUP_RETRY.
    try:
        await client.get_status()
    except (IntelliDwellConnectionError, IntelliDwellInvalidResponseError) as err:
        raise CannotConnect from err

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (12)

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the branding rule before declaring Bronze. brands: todo is a required Bronze rule, so script/hassfest/quality_scale.py:2232-2249 rejects the manifest’s Bronze tier and the current hassfest check fails.
  brands: todo

homeassistant/components/intellidwell/coordinator.py:51

  • Keep failed auxiliary fetches as failed/partial data instead of returning a successful status-only update. This path drops rain_delay and schedules, so the coordinator remains available while the number falsely becomes 0 and every schedule switch falsely becomes enabled.
        except (ValueError, KeyError, TypeError) as err:
            _LOGGER.debug("Error fetching extra data: %s", err)
            return await self.client.get_status()

requirements_all.txt:2273

  • Update the PR description to select only “New integration” and describe the proposed change. This line adds a new package, while the description also selects “Dependency upgrade,” leaves Proposed change empty, and claims a version comparison was supplied when none is present.
# homeassistant.components.intellidwell
pyintellidwell==1.0.0

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Add a shared base entity before marking common-modules done. The identical DeviceInfo and entity-name setup is currently repeated in both switch classes and the number class; the rule specifically establishes entity.py for this shared logic.
  common-modules: done

homeassistant/components/intellidwell/number.py:76

  • Raise ServiceValidationError for this invalid action input. The number platform only validates the range, so fractional values reach this branch; exposing a raw ValueError turns user input into an internal service failure instead of a user-facing validation error.
        if not value.is_integer():
            raise ValueError("Rain delay value must be a whole number of days")

homeassistant/components/intellidwell/number.py:47

  • Declare this rain-delay number as NumberDeviceClass.DURATION. Days are a supported duration unit (homeassistant/components/number/const.py:545-552), and the current implementation contradicts the entity-device-class: done claim.
    _attr_native_min_value = 0
    _attr_native_max_value = 5
    _attr_native_step = 1
    _attr_native_unit_of_measurement = "d"
    _attr_mode = NumberMode.BOX

homeassistant/components/intellidwell/switch.py:112

  • Classify schedule-enable switches as EntityCategory.CONFIG. These entities change persistent schedule configuration rather than operating a zone; the analogous RainMachine enable switch uses this category (homeassistant/components/rainmachine/switch.py:352-356).
    """Representation of an IntelliDwell Zone Schedule Enable switch."""

    _attr_has_entity_name = True
    _attr_icon = "mdi:calendar-clock"

homeassistant/components/intellidwell/quality_scale.yaml:66

  • Update the linked documentation before marking supported functions done. The documentation PR lists only ten zone switches and only the switch platform, while this integration also adds ten schedule-enable switches and a rain-delay number.
  docs-known-limitations: done
  docs-supported-devices: done
  docs-supported-functions: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Implement icon translations before marking this rule done. The entities still set _attr_icon directly and the integration has no icons.json, which is the mechanism required by the icon-translations rule.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:64

  • Mark these documentation rules incomplete or add the required sections. The linked documentation has no polling/data-update description, automation example or blueprint, or known-limitations section, so these three done statuses are not substantiated.
  docs-data-update: done
  docs-examples: done
  docs-known-limitations: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption and status. The rule has no exemption for integrations that only expose switches, and this integration also creates a number entity, so the stated justification is factually incorrect.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:68

  • Mark these documentation rules todo or add the required content. The linked documentation contains neither troubleshooting guidance nor concrete use-case examples, despite both rules being marked done.
  docs-troubleshooting: done
  docs-use-cases: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (17)

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the branding requirement before declaring Bronze. brands is a mandatory Bronze rule with no exceptions, but it remains todo, so the manifest's quality_scale: bronze claim is not yet satisfied.
  brands: todo

homeassistant/components/intellidwell/quality_scale.yaml:38

  • Do not exempt action-exceptions for these platform actions. The rule explicitly includes switch and number platform actions, which this integration provides, so the absence of custom services is not a valid exemption; mark it done only after all library action failures are translated to Home Assistant exceptions.
  action-exceptions:
    status: exempt
    comment: |
      Integration does not provide custom services.

homeassistant/components/intellidwell/quality_scale.yaml:63

  • Mark these documentation rules todo until the linked documentation implements them. The linked docs PR contains no data-update explanation or usage examples, so these done statuses are inaccurate.
  docs-data-update: done
  docs-examples: done

homeassistant/components/intellidwell/quality_scale.yaml:68

  • Update the linked documentation or mark the unimplemented rules todo. It has no known-limitations, troubleshooting, or use-case sections, and its supported-functions section omits both the rain-delay number and schedule switches.
  docs-known-limitations: done
  docs-supported-devices: done
  docs-supported-functions: done
  docs-troubleshooting: done
  docs-use-cases: done

homeassistant/components/intellidwell/switch.py:36

  • Exclude the configured master-valve relay from zone switch creation. The controller allows one of these relay indices to be designated as the master valve; exposing it as a normal zone lets a user turn it off directly while another zone remains active, cutting off watering and bypassing the controller's automatic master-valve handling.
    entities: list[SwitchEntity] = [
        IntelliDwellZoneSwitch(coordinator, config_entry, zone_index)
        for zone_index in range(10)
    ]

homeassistant/components/intellidwell/switch.py:41

  • Do not create a schedule switch for the configured master-valve relay. The controller's scheduler explicitly skips that relay, so this entity can accept enable/disable commands while having no scheduling effect.
            IntelliDwellScheduleSwitch(coordinator, config_entry, zone_index)
            for zone_index in range(10)
        ]

homeassistant/components/intellidwell/manifest.json:10

  • Correct and complete the PR description for this new integration. It currently leaves Proposed change empty and checks both Dependency upgrade and New integration, even though this requirement is being introduced rather than upgraded; the template requires exactly one type and a substantive description.
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/quality_scale.yaml:12

  • Publish and link the pyintellidwell client source before marking dependency transparency done. No public client source, tagged 1.0.0 release, or public publishing pipeline is linked or discoverable; the available controller firmware is a different project and carries a non-commercial restriction, so this mandatory Bronze rule is not met.
  dependency-transparency: done

homeassistant/components/intellidwell/coordinator.py:46

  • Fetch the controller endpoints serially instead of opening three requests together. The IntelliDwell firmware documents serialized HTTP handling as necessary to avoid ESP32 socket exhaustion, but this five-second polling path starts all three requests concurrently.
            status_data, rain_delay_data, schedules_data = await asyncio.gather(
                self.client.get_status(),
                self.client.get_rain_delay(),
                self.client.get_schedules(),
                return_exceptions=False,
            )

homeassistant/components/intellidwell/switch.py:46

  • Model irrigation zones as water valves rather than generic switches. The established sprinkler implementation uses ValveEntity with ValveDeviceClass.WATER (homeassistant/components/hydrawise/valve.py:22-26,54-59), preserving valve semantics and the corresponding UI and voice behavior that these new switch entities lose.
class IntelliDwellZoneSwitch(CoordinatorEntity[IntelliDwellCoordinator], SwitchEntity):

homeassistant/components/intellidwell/manifest.json:5

  • Regenerate and commit the Home Assistant metadata for this new config flow. homeassistant/generated/config_flows.py and homeassistant/generated/integrations.json still omit intellidwell, and hassfest validates both generated files against this manifest declaration (script/hassfest/config_flow.py:210-236).
  "config_flow": true,

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Add a shared IntelliDwell entity base before marking common-modules done. The same DeviceInfo construction is duplicated in switch.py:64, switch.py:128, and number.py:58, while this rule calls for shared entity behavior to live in entity.py.
  common-modules: done

homeassistant/components/intellidwell/number.py:46

  • Set NumberDeviceClass.DURATION on the rain-delay entity. This number uses a duration unit and the quality file marks entity-device-class done, but without the duration device class Home Assistant lacks the corresponding duration semantics and unit conversion.
    _attr_native_unit_of_measurement = "d"

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption reason to cover the entities actually created. The integration also creates a rain-delay number, so “Only switch entities are created” is factually incorrect.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Use icons.json before marking icon translations done. No icon translation file is added, while the schedule and rain-delay entities still set _attr_icon directly, so this Gold rule is not implemented.
  icon-translations: done

tests/components/intellidwell/test_number.py:124

  • Describe the exception asserted by this test. The test expects ServiceValidationError, not ValueError, so the current docstring misstates the behavior under test.
    """Test ValueError raised when setting float value for rain delay."""

tests/components/intellidwell/test_number.py:129

  • Extract the repeated config-entry setup into a shared fixture. This block duplicates the setup in the two preceding tests and similar setup in test_switch.py, while the newly added conftest.py is otherwise empty.
    entry = MockConfigEntry(
        domain=DOMAIN,
        data={CONF_HOST: "1.1.1.1"},
        entry_id="mock_entry_num_invalid",
    )

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (14)

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the brands rule before declaring this integration Bronze. A todo Bronze rule means the integration does not yet qualify for the quality_scale: bronze level declared in manifest.json.
  brands: todo

homeassistant/components/intellidwell/quality_scale.yaml:64

  • Mark these documentation rules todo until the linked documentation PR implements them. PR 47101 contains no data-update/polling section, blueprint example, or known-limitations section, despite these three rules being marked complete.
  docs-data-update: done
  docs-examples: done
  docs-known-limitations: done

homeassistant/components/intellidwell/coordinator.py:45

  • Serialize the three controller requests instead of starting them concurrently. IntelliDwell’s own web client queues safeFetch calls one at a time to prevent ESP32 socket exhaustion, but this coordinator opens three requests together every five seconds, risking controller instability and failed updates.
            status_data, rain_delay_data, schedules_data = await asyncio.gather(
                self.client.get_status(),
                self.client.get_rain_delay(),
                self.client.get_schedules(),
                return_exceptions=False,

homeassistant/components/intellidwell/switch.py:46

  • Model sprinkler zones as water valves rather than generic switches. These entities open and close irrigation valves, so SwitchEntity loses the water-valve semantics, supported open/close features, and UI/voice behavior established by homeassistant/components/hydrawise/valve.py:22-26,54-59.
class IntelliDwellZoneSwitch(CoordinatorEntity[IntelliDwellCoordinator], SwitchEntity):

homeassistant/components/intellidwell/switch.py:35

  • Exclude the configured master-valve relay from the zone entity list. IntelliDwell designates one of these ten indexes as the master valve, so exposing it as a normal zone lets users operate it independently of the firmware’s automatic master-valve control.
        IntelliDwellZoneSwitch(coordinator, config_entry, zone_index)
        for zone_index in range(10)

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared coordinator and device setup into an IntelliDwellEntity base class, or mark this rule todo. The identical DeviceInfo initialization is currently duplicated in switch.py:64-70, switch.py:128-134, and number.py:58-64, so common-modules is not yet complete.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:66

  • Document every exposed entity before marking docs-supported-functions complete. The linked documentation describes only the ten zone relay switches and omits the rain-delay number and ten schedule switches created by this integration.
  docs-supported-functions: done

homeassistant/components/intellidwell/quality_scale.yaml:67

  • Mark docs-troubleshooting todo until troubleshooting guidance is added. The linked documentation PR has no troubleshooting section or resolution for a common setup/runtime issue.
  docs-troubleshooting: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Add icon translations or mark this rule todo. The entities currently hard-code _attr_icon in number.py and switch.py, and the integration provides no icons.json, so the icon-translations rule is not implemented.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Add NumberDeviceClass.DURATION to the rain-delay number or mark this rule todo. The entity represents a duration in days but currently has no device class, so entity-device-class is not complete.
  entity-device-class: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct the exemption reason to describe why no entity should be disabled by default. The current reason says the integration creates only switches, but number.py also creates the rain-delay number entity.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/switch.py:151

  • Add coverage for dictionary-shaped schedule data or remove this unsupported branch. All schedule tests supply a list, leaving this branch (along with other fallback/error paths) uncovered, so the integration does not substantiate the test-coverage: done claim requiring over 95% module coverage.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )
            if isinstance(zone_info, dict):

homeassistant/components/intellidwell/coordinator.py:50

  • Add a coordinator test for malformed-response exceptions. The existing setup-failure test covers only IntelliDwellConnectionError, so this distinct ValueError/KeyError/TypeError path and its UpdateFailed conversion are unverified despite test-coverage being marked complete.
        except (ValueError, KeyError, TypeError) as err:
            raise UpdateFailed(f"Invalid response from API: {err}") from err

homeassistant/components/intellidwell/switch.py:40

  • Exclude the configured master-valve relay from the schedule-switch list. The controller firmware rejects schedule operations for the master-valve index, so this entity is created but every enable/disable command fails.
            IntelliDwellScheduleSwitch(coordinator, config_entry, zone_index)
            for zone_index in range(10)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (10)

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Centralize the shared device metadata before marking common-modules done. The same DeviceInfo construction is duplicated in both switch classes and the number class; established integrations such as Rain Bird expose it once from the coordinator (homeassistant/components/rainbird/coordinator.py:105).
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark this rule todo or provide a valid exemption. The stated reason is factually incorrect because number.py creates a rain-delay number entity in addition to the switch entities.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Do not mark icon translations done without an icons.json. Both custom icons are currently hard-coded with _attr_icon; integrations satisfying this rule, such as prana, define translation-key icons in homeassistant/components/prana/icons.json.
  icon-translations: done

homeassistant/components/intellidwell/config_flow.py:51

  • Normalize the host before checking for an existing entry. DNS hostnames are case-insensitive, so values such as SPRINKLER.LOCAL and sprinkler.local currently bypass this exact-string match and create duplicate entries.
            host = user_input[CONF_HOST]
            self._async_abort_entries_match({CONF_HOST: host})

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the Bronze brands requirement before declaring this integration Bronze. This is the only integration currently marking brands as todo, while existing Bronze integrations such as prana mark every Bronze requirement done or exempt.

This issue also appears in the following locations of the same file:

  • line 9
  • line 72
  • line 78
  brands: todo

homeassistant/components/intellidwell/manifest.json:2

  • Complete the PR description and select only the New integration change type. The Proposed change section is empty and both Dependency upgrade and New integration are checked, contrary to the PR template's exactly-one requirement.
  "domain": "intellidwell",

homeassistant/components/intellidwell/coordinator.py:54

  • Keep response assembly inside the guarded block. These lines run in the else, so malformed status_data or rain_delay_data raises an uncaught TypeError/AttributeError instead of UpdateFailed, causing initial setup to fail rather than retry.
            status_data["rain_delay"] = rain_delay_data.get("days_remaining", 0)
            status_data["schedules"] = schedules_data

tests/components/intellidwell/test_config_flow.py:72

  • Remove this narrating comment. The following mock and assertions already make the successful retry and expected entry creation explicit.
    # Second attempt: connection succeeds — entry should be created.

tests/components/intellidwell/test_config_flow.py:58

  • Remove this narrating comment. The following mock and assertions already make both the failed attempt and expected form error explicit.
    # First attempt: connection fails — form should re-display with an error.

tests/components/intellidwell/conftest.py:1

  • Use this conftest.py for shared config-entry and client-response fixtures. The same entry creation and three-method patch block is repeated across the switch, number, and unload tests, so every response-shape change currently requires synchronized edits in several files.
"""Fixtures for IntelliDwell Sprinkler Controller tests."""

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the brands rule before declaring Bronze. script/hassfest/quality_scale.py:2237-2250 rejects a declared tier when any rule at or below that tier remains todo, so the current quality_scale: bronze manifest will fail hassfest while this Bronze rule is unmet.
  brands: todo

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Introduce a shared IntelliDwell entity base before marking common-modules done. The identical DeviceInfo setup is repeated in switch.py:64-70, switch.py:128-134, and number.py:58-64; the established pattern is a common coordinator entity such as homeassistant/components/intelliclima/entity.py:19-38, which prevents device metadata from diverging across platforms.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption or mark the rule todo. The integration also creates IntelliDwellRainDelayNumber, so the stated rationale that only switch entities are created is factually incorrect.
  entity-disabled-by-default:
    status: exempt
    comment: |
      Only switch entities are created.

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Move the custom entity icons to icons.json before marking icon translations done. Both number.py:41 and switch.py:113 hard-code _attr_icon, whereas integrations satisfying this rule define translation-key icons in icons.json (for example, homeassistant/components/prana/icons.json:1-56).
  icon-translations: done

homeassistant/components/intellidwell/manifest.json:10

  • Correct the PR template to select only “New integration.” This requirement is introduced with a new domain rather than replacing an existing dependency version, so checking both “Dependency upgrade” and “New integration” violates the template’s exactly-one-type requirement.
  "requirements": ["pyintellidwell==1.0.0"]

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

homeassistant/components/intellidwell/quality_scale.yaml:8

  • Complete the brands rule before declaring Bronze quality. Bronze requires every Bronze rule to be done or validly exempt, so leaving this as todo makes the manifest's "quality_scale": "bronze" claim inaccurate.
  brands: done

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared device metadata into a common entity base or coordinator property before marking common-modules complete. The same DeviceInfo construction is duplicated in switch.py:64, switch.py:128, and number.py:58, so model or URL changes must currently be kept in sync across three implementations.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Correct this exemption to account for the rain-delay number entity. number.py creates IntelliDwellRainDelayNumber, so “Only switch entities are created” is false; either give a valid reason that no entity should be disabled by default or mark/implement the rule appropriately.
  entity-disabled-by-default: done
  entity-translations: done
  exception-translations: todo
  icon-translations: done

homeassistant/components/intellidwell/switch.py:153

  • Report an unknown state when schedule data for this zone is absent or malformed. The platform always creates 10 schedule switches, but the added test supplies only two schedule records; zones 3–10 therefore become available and incorrectly show on because this fallback returns True. Return None for missing data (and update the return annotation) instead of asserting that the schedule is enabled.
        return True

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (8)

homeassistant/components/intellidwell/manifest.json:9

  • Declare the integration's Bronze quality tier in the manifest. New integrations with quality_scale.yaml must set a manifest quality scale; otherwise hassfest reports “New integrations are required to at least reach the Bronze tier” (script/hassfest/quality_scale.py:2184-2197).
  "iot_class": "local_polling",
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark icon-translations as todo or add translated icons. No icons.json is included, while the icons remain hardcoded in number.py:41 and switch.py:113, so this rule is not done.
  icon-translations: done

homeassistant/components/intellidwell/quality_scale.yaml:69

  • Mark dynamic-devices exempt because this integration creates one static controller device. This matches the quality-scale representation used by static device integrations such as rainbird/quality_scale.yaml:52-54.
  dynamic-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:78

  • Mark stale-devices exempt because the integration has only the config-entry controller device and cannot accumulate stale devices. Static-device integrations represent this as an exemption, for example rainbird/quality_scale.yaml:63-65.
  stale-devices: done

homeassistant/components/intellidwell/manifest.json:9

  • Update the PR description to describe the proposed integration and include the dependency release/compare link. This line adds a new dependency, but the description leaves “Proposed change” empty and checks that a dependency diff/link was supplied without providing one; it also selects both “Dependency upgrade” and “New integration” despite the template requiring exactly one type.
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared entity/device metadata into a common entity module. DeviceInfo construction and identifiers are duplicated in number.py:58-64 and twice in switch.py:64-70,128-134, so the integration does not currently satisfy the common-modules rule marked done here.
  common-modules: done

homeassistant/components/intellidwell/number.py:46

  • Add NumberDeviceClass.DURATION and use UnitOfTime.DAYS for this duration entity. The core number contract explicitly supports days for duration values (homeassistant/components/number/const.py:545-552), and established duration numbers use this pair (for example, renson/number.py:24-34); without it, the entity-device-class: done claim is not met.
    _attr_native_min_value = 0
    _attr_native_max_value = 5
    _attr_native_step = 1
    _attr_native_unit_of_measurement = "d"

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark this rule exempt because the polling integration does not subscribe to entity events. The established quality-scale representation for this case is an exemption (for example, rainbird/quality_scale.yaml:27-29), not done.

This issue also appears in the following locations of the same file:

  • line 69
  • line 75
  • line 78
  entity-event-setup: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (7)

homeassistant/components/intellidwell/manifest.json:9

  • Declare the integration's Bronze quality tier in the manifest. With this new quality_scale.yaml present but no manifest tier, hassfest rejects the integration as not reaching Bronze (script/hassfest/quality_scale.py:2183-2197).
  "iot_class": "local_polling",
  "requirements": ["pyintellidwell==1.0.0"]

tests/components/intellidwell/test_config_flow.py:72

  • Remove this comment because it only narrates the immediately following test setup and assertions.
    # Second attempt: connection succeeds — entry should be created.

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Deduplicate the shared entity/device setup before marking common-modules complete. The same DeviceInfo construction is repeated in both switch classes and the number class, so model or URL changes can easily drift; place it on the coordinator or a shared entity base instead.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark icon translations as incomplete until the entity icons are moved to icons.json. The number and schedule switch still set _attr_icon directly, so this Gold rule is not currently implemented.
  icon-translations: done

homeassistant/components/intellidwell/switch.py:151

  • Add coverage for mapping-shaped schedule data or remove this unsupported branch. Every schedule fixture currently returns a list, leaving the alternate key lookup and enabled-state behavior unverified despite test-coverage being marked complete.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )
            if isinstance(zone_info, dict):

tests/components/intellidwell/test_number.py:124

  • Update the docstring to name the exception this test actually verifies. ServiceValidationError inherits from HomeAssistantError, not ValueError, so the current description is inaccurate.
    """Test ValueError raised when setting float value for rain delay."""

tests/components/intellidwell/test_config_flow.py:58

  • Remove this comment because it only narrates the immediately following test setup and assertions.

This issue also appears on line 72 of the same file.

    # First attempt: connection fails — form should re-display with an error.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (9)

tests/components/intellidwell/test_config_flow.py:72

  • Remove this narrating comment; the mock and following assertions already make the successful retry explicit.
    # Second attempt: connection succeeds — entry should be created.

homeassistant/components/intellidwell/coordinator.py:54

  • Move response normalization into the try block so malformed payloads are converted to UpdateFailed. The assignments in this else run after the exception handlers, so the listed TypeError/KeyError handling cannot catch failures they raise; an invalid payload instead reaches the coordinator's generic handler and emits an unexpected traceback on every poll.
        else:
            status_data["rain_delay"] = rain_delay_data.get("days_remaining", 0)
            status_data["schedules"] = schedules_data
            return status_data

homeassistant/components/intellidwell/switch.py:153

  • Report an absent schedule as disabled or unknown instead of enabled. Empty and short schedule responses are accepted during setup (and are used by the new tests), but these defaults make every missing schedule entity misleadingly appear on.
        return True

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared entity/device setup into a common module or mark this rule todo. The identical DeviceInfo construction is currently repeated in number.py:58-64 and twice in switch.py:64-70,128-134, so the Bronze common-modules rule is not yet satisfied.
  common-modules: done

tests/components/intellidwell/test_config_flow.py:58

  • Remove this narrating comment; the mock and following assertions already make the failed first attempt explicit.

This issue also appears on line 72 of the same file.

    # First attempt: connection fails — form should re-display with an error.

tests/components/intellidwell/test_switch.py:220

  • Parameterize this case with test_turn_on_connection_error; the two tests duplicate setup, patching, service invocation, and assertions while varying only the service and expected message.
async def test_turn_off_connection_error(hass: HomeAssistant) -> None:
    """Test that turn_off raises HomeAssistantError on IntelliDwellConnectionError."""

homeassistant/components/intellidwell/quality_scale.yaml:38

  • Mark this rule todo (or verify it as done) instead of exempting it. The integration exposes standard number and switch actions in number.py:73 and switch.py:82,94,156,168; the action-exceptions rule applies to standard entity actions, not only custom services.
  action-exceptions:
    status: exempt
    comment: |
      Integration does not provide custom services.

homeassistant/components/intellidwell/quality_scale.yaml:71

  • Mark this rule todo or add NumberDeviceClass.DURATION to the rain-delay entity. The entity represents a duration in days but currently declares only a raw unit (number.py:46), unlike duration numbers such as renson/number.py:32-33.
  entity-device-class: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark this rule todo or move the hard-coded entity icons into icons.json. No icon translation file is added, while both platforms set _attr_icon directly (number.py:41 and switch.py:113), so the claimed rule is not implemented.
  icon-translations: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

homeassistant/components/intellidwell/manifest.json:2

  • Correct the PR description to classify this solely as a new integration and fill in the Proposed change section. It currently selects both Dependency upgrade and New integration even though this manifest introduces a new domain and its initial requirement; the PR template requires exactly one type.
  "domain": "intellidwell",

homeassistant/components/intellidwell/quality_scale.yaml:72

  • Move the hard-coded entity icons to icons.json, or leave this rule as todo. Both platforms assign _attr_icon in Python and this integration has no icon translation file, so icon-translations is not implemented.
  icon-translations: done

homeassistant/components/intellidwell/switch.py:153

  • Do not report a missing schedule entry as enabled. The platform always creates ten switches, while valid update data can contain fewer schedule records (including the empty and two-item responses used by these tests), so zones absent from the payload currently appear on and can trigger automations incorrectly; expose them as unavailable/off or only create backed entities.
        return True

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared entity setup into a common entity module before marking this Bronze rule done. The identical DeviceInfo and entity-name setup is repeated in both platforms and twice in switch.py, whereas the rule requires shared platform code to be centralized.
  common-modules: done

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

homeassistant/components/intellidwell/quality_scale.yaml:66

  • Mark this rule exempt for a single-device integration rather than done; the integration always represents one controller and has no dynamically discovered devices to add.
  dynamic-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark this rule exempt for a single-device integration rather than done; a config entry cannot accumulate stale child devices, so there is no stale-device removal behavior here.
  stale-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:72

  • Mark this rule todo or move the custom icons into icons.json; both entity platforms currently hard-code _attr_icon, so the integration does not implement icon translations.
  icon-translations: done

tests/components/intellidwell/test_number.py:124

  • Update the docstring to name the exception the test actually verifies; the implementation and assertion use ServiceValidationError, not ValueError.
    """Test ValueError raised when setting float value for rain delay."""

homeassistant/components/intellidwell/switch.py:132

  • Centralize this repeated DeviceInfo; the identical controller metadata is copied in both switch classes and the number entity, so a model, identifier, or URL change can leave entities attached to inconsistent devices. Comparable coordinator integrations expose shared device metadata once (for example, homeassistant/components/rainbird/coordinator.py:105-120).
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, config_entry.entry_id)},
            name="IntelliDwell Sprinkler Controller",
            manufacturer="IntelliDwell",
            model="Sprinkler Controller V2",

homeassistant/components/intellidwell/switch.py:153

  • Return an unknown state when schedule data is absent instead of reporting the schedule as enabled; a successful response can contain fewer entries (the added tests use both partial and empty schedule lists), so zones without a record currently appear on with no supporting device data.
        return True

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

homeassistant/components/intellidwell/coordinator.py:54

  • Keep response normalization inside the protected block and handle invalid mappings there. As written, the else runs outside the try, so a malformed status_data or rain_delay_data raises an uncaught TypeError/AttributeError instead of UpdateFailed, bypassing coordinator availability handling.
        except (ValueError, KeyError, TypeError) as err:
            raise UpdateFailed(f"Invalid response from API: {err}") from err
        else:
            status_data["rain_delay"] = rain_delay_data.get("days_remaining", 0)
            status_data["schedules"] = schedules_data

tests/components/intellidwell/test_number.py:124

  • Update the docstring to name the exception the test actually verifies; this test expects ServiceValidationError, not ValueError.
    """Test ValueError raised when setting float value for rain delay."""

homeassistant/components/intellidwell/switch.py:152

  • Add coverage for dictionary-shaped schedule payloads or remove this unsupported branch. The switch tests only exercise list payloads, so string/integer key lookup and enabled-state handling here can regress despite test-coverage being marked done.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )
            if isinstance(zone_info, dict):
                return zone_info.get("enabled", True)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (6)

homeassistant/components/intellidwell/manifest.json:10

  • Select only “New integration” in the PR description. This requirement is newly introduced for the integration rather than upgraded from an existing version, while the template currently has both “Dependency upgrade” and “New integration” selected despite requiring exactly one type.
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/coordinator.py:54

  • Keep response processing inside the try block. The else suite is outside these handlers, so malformed status or rain-delay data can raise TypeError/AttributeError directly instead of UpdateFailed, bypassing coordinator unavailable/retry handling.
        else:
            status_data["rain_delay"] = rain_delay_data.get("days_remaining", 0)
            status_data["schedules"] = schedules_data

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Introduce a shared IntelliDwell entity base before marking this rule done. switch.py contains the same DeviceInfo block twice and number.py repeats it again; the Bronze common-modules rule requires this cross-platform entity logic to be centralized (for example in entity.py).
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:72

  • Mark this rule todo or move the entity icons into icons.json. number.py:42 and switch.py:113 hard-code MDI icons, so icon-translations: done is currently inaccurate.
  icon-translations: done

homeassistant/components/intellidwell/manifest.json:3

  • Fill in the PR’s “Proposed change” section with a description of this integration. The section is currently empty, so the required PR template does not describe the new domain or its purpose.

This issue also appears on line 10 of the same file.

  "domain": "intellidwell",
  "name": "IntelliDwell Sprinkler Controller",

tests/components/intellidwell/test_switch.py:220

  • Parameterize the relay connection-error cases instead of duplicating the test body. This test and test_turn_on_connection_error differ only by service name and expected message, so keeping separate copies makes future action-test changes easy to apply inconsistently.
async def test_turn_off_connection_error(hass: HomeAssistant) -> None:
    """Test that turn_off raises HomeAssistantError on IntelliDwellConnectionError."""

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (3)

homeassistant/components/intellidwell/quality_scale.yaml:9

  • Move the shared entity/device setup into a common entity module before marking this rule done. DeviceInfo construction is duplicated in number.py:59-65 and switch.py:64-70,128-134, so this Bronze rule is not currently satisfied and the copies can drift.
  common-modules: done

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark this rule exempt because these polling entities do not explicitly subscribe to events. Coordinator-based integrations with the same behavior use an exemption, for example homewizard/quality_scale.yaml:26-29 and airgradient/quality_scale.yaml:26-29; done inaccurately claims an event-subscription implementation.
  entity-event-setup: done

homeassistant/components/intellidwell/coordinator.py:54

  • Keep response assembly inside its own guarded block so malformed payloads are converted to UpdateFailed. Exceptions from these lines occur in the else block after the handlers have finished; for example, a non-mapping rain-delay response raises AttributeError and is logged as an unexpected coordinator error instead of the intended invalid-response failure.
        else:
            status_data["rain_delay"] = rain_delay_data.get("days_remaining", 0)
            status_data["schedules"] = schedules_data
            return status_data

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (8)

homeassistant/components/intellidwell/quality_scale.yaml:75

  • Mark stale-device removal exempt for this single-controller integration. Since the integration never discovers child devices, it has no stale devices to remove; homeassistant/components/peblar/quality_scale.yaml:77-80 uses this exemption for the same topology.
  stale-devices: done

homeassistant/components/intellidwell/quality_scale.yaml:66

  • Mark dynamic device handling exempt for this single, statically configured controller. No runtime device discovery is implemented; homeassistant/components/peblar/quality_scale.yaml:62-65 establishes the exemption used for this case.
  dynamic-devices: done

homeassistant/components/intellidwell/config_flow.py:63

  • Normalize the host before duplicate detection and storage. DNS hostnames are case-insensitive, so entries such as Controller.local and controller.local currently bypass _async_abort_entries_match and create duplicate polling entities for the same controller.
            host = user_input[CONF_HOST]
            self._async_abort_entries_match({CONF_HOST: host})

homeassistant/components/intellidwell/quality_scale.yaml:35

  • Wrap invalid-response failures from every setter in HomeAssistantError. The coordinator recognizes IntelliDwellInvalidResponseError, but the relay, schedule, and rain-delay actions catch only connection errors, so an invalid controller response escapes as a raw dependency exception and makes this done claim inaccurate.

This issue also appears in the following locations of the same file:

  • line 66
  • line 75
  action-exceptions: done

homeassistant/components/intellidwell/quality_scale.yaml:26

  • Mark this rule exempt because these polling entities do not subscribe to entity-specific events. This follows the established polling-integration pattern in homeassistant/components/rainbird/quality_scale.yaml:27-29; claiming done implies event setup/teardown behavior that is not implemented.
  entity-event-setup: done

homeassistant/components/intellidwell/switch.py:152

  • Add coverage for dictionary-shaped schedule responses. The separate string-key and integer-key lookup is new behavior, but every schedule fixture uses a list, so key/index regressions in this branch are undetected.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )
            if isinstance(zone_info, dict):
                return zone_info.get("enabled", False)

homeassistant/components/intellidwell/manifest.json:10

  • Correct the PR type to select only “New integration.” This requirement is being added for the new integration rather than upgraded from an existing version, while the PR description currently selects both “Dependency upgrade” and “New integration” despite the template allowing only one.
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/switch.py:69

  • Centralize the shared DeviceInfo and reuse it from every entity. This identical block is repeated in both switch classes and the number class, so any model, identifier, or URL correction must stay synchronized across three places; homeassistant/components/rainbird/coordinator.py:105-120 and its entities show the established shared-coordinator pattern.
        self._attr_device_info = DeviceInfo(
            identifiers={(DOMAIN, config_entry.entry_id)},
            name="IntelliDwell Sprinkler Controller",
            manufacturer="IntelliDwell",
            model="Sprinkler Controller V2",
            configuration_url=f"http://{coordinator.client.host}",

… switch connection error tests, and mark icon-translations todo

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (4)

homeassistant/components/intellidwell/manifest.json:10

  • Select only “New integration” in the PR’s Type of change section. Both “Dependency upgrade” and “New integration” are checked, but this line adds a new dependency rather than upgrading an existing one, and the PR template requires exactly one selection.
  "requirements": ["pyintellidwell==1.0.0"]

homeassistant/components/intellidwell/manifest.json:3

  • Fill in the PR’s Proposed change section with a concise description of this integration. That required template section is currently empty, so reviewers cannot verify the intended behavior and scope of the new integration represented by this manifest.
  "domain": "intellidwell",
  "name": "IntelliDwell Sprinkler Controller",

tests/components/intellidwell/conftest.py:1

  • Add shared config-entry and API-mock fixtures here instead of repeating the setup blocks. The same MockConfigEntry plus three client-method patches are copied across test_switch.py, test_number.py, and test_init.py, so a setup or response-shape change currently requires edits in at least six places.
"""Fixtures for IntelliDwell Sprinkler Controller tests."""

homeassistant/components/intellidwell/switch.py:152

  • Cover or remove the dictionary schedule-response path. Every get_schedules mock returns a list, so this branch is never exercised even though test-coverage is marked done; a regression in dictionary-key handling would therefore pass the integration tests.
        elif isinstance(schedules, dict):
            zone_info = schedules.get(str(self.zone_index)) or schedules.get(
                self.zone_index
            )
            if isinstance(zone_info, dict):
                return zone_info.get("enabled", False)

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants