Skip to content

Allow area, device, and entity selectors to optionally support multiple selections like target selector#63138

Merged
emontnemery merged 5 commits intohome-assistant:devfrom
r-t-s:entity_selector
Mar 3, 2022
Merged

Allow area, device, and entity selectors to optionally support multiple selections like target selector#63138
emontnemery merged 5 commits intohome-assistant:devfrom
r-t-s:entity_selector

Conversation

@r-t-s
Copy link
Copy Markdown
Contributor

@r-t-s r-t-s commented Dec 31, 2021

Proposed change

Changes to the Area, Device, and Entity selectors to allow them to select multiple entities.
The user interface is similar to the Area, Device and Entity selector component of the target selector.
Single or multi select is configured with the optional multiple option on the selector configuration.
The selectors can now potentially return a list of area, device, or entity IDs.

This is motivated by the need to have multiple entity selector so a blueprint can trigger on multiple entities.
But brings a consistent UI for the Area, Device, Entity, and Target selector.

The associated User Interface PR #11059

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)
  • Breaking change (fix/feature causing existing functionality to break)
  • Code quality improvements to existing code or addition of tests

Additional information

  • This PR fixes or closes issue: fixes #
  • This PR is related to issue:
  • Link to documentation pull request: #20961

Checklist

  • 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
  • The code has been formatted using Black (black --fast homeassistant tests)
  • Tests have been added to verify that the new code works.

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 link to the changelog, or at minimum a diff between library versions is added to the PR description.
  • Untested files have been added to .coveragerc.

The integration reached or maintains the following Integration Quality Scale:

  • No score or internal
  • 🥈 Silver
  • 🥇 Gold
  • 🏆 Platinum

To help with the load of incoming pull requests:

@r-t-s r-t-s requested a review from a team as a code owner December 31, 2021 14:59
@probot-home-assistant probot-home-assistant bot added core new-feature small-pr PRs with less than 30 lines. labels Dec 31, 2021
@r-t-s r-t-s changed the title Allow area, device, and entity selectors to optionally support multile selections like target selector Allow area, device, and entity selectors to optionally support multiple selections like target selector Dec 31, 2021
@@ -125,6 +127,8 @@ class DeviceSelector(Selector):
vol.Optional("model"): str,
# Device has to contain entities matching this selector
vol.Optional("entity"): EntitySelector.CONFIG_SCHEMA,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This selector is changing. Please inline the old config schema.

CC @emontnemery

Comment on lines 148 to 157
vol.Optional("entity"): EntitySelector.CONFIG_SCHEMA,
vol.Optional("device"): DeviceSelector.CONFIG_SCHEMA,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This selector is changing. Please inline the old config schema.

{
vol.Optional("entity"): EntitySelector.CONFIG_SCHEMA,
vol.Optional("device"): DeviceSelector.CONFIG_SCHEMA,
# Allow multiple area selection
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Please remove comments. It's clear what multiple means 😄

@balloob
Copy link
Copy Markdown
Member

balloob commented Feb 21, 2022

Please update the __call__ methods of the selectors to validate that it's a list of valid entity/device/area. Also add tests for this. Your current tests are incorrect.

@frenck
Copy link
Copy Markdown
Member

frenck commented Feb 22, 2022

@r-t-s Please do not squash commits, it makes it really hard to follow changes during the review. Thanks! 👍

)

return entity_id
result = cv.entity_ids_or_uuids(data)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

When multiple is set to true, we should only validate it as multiple entities, and only validate as single if multiple is false.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was keeping with the interface for entity_id in a trigger. It accepts a single or a list. Currently in the selector I only return a single entity if one is selected, and a list if enabled and more than 1 is selected. I believe the entity_id in the target selector behaves the same way.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

That is not always the case, selectors can also be used in places that can't handle lists.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

They selector config must specify multiple and the user must pick more than one to get a list. So we should be OK.
The question is should we always return a list (even an empty list) if multiple is specified.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes we should always return a list if multiple is set to true and a string if not.

However, your current code is not checking if multiple is set, but just validates first as a single, then as multiple. We should just check the value of multiple.

result: str | list[str]

def validate(e_or_u: str) -> None:
if "domain" in self.config:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Use guard clauses to keep the code readable.

if 'domain' not in self.config:
    return


def validate(e_or_u: str) -> None:
if "domain" in self.config:
if valid_entity_id(e_or_u):
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why would you not raise if it's not a valid entity ID ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Because it could be a uuid the previous validation was a little obscure ... and I needed to test each result in the list.

"integration": "zha",
"manufacturer": "IKEA of Sweden",
"model": "TRADFRI remote control",
"multiple": False,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Let's not update all tests but also leave some where we don't specify multiple, to verify the default is False.

Copy link
Copy Markdown
Contributor

@emontnemery emontnemery Mar 2, 2022

Choose a reason for hiding this comment

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

That's exactly what happens; "multiple" has False as default value so it's added to the validated blueprint input 👍
The changes just adjusts the test because the validated blueprint input has changed.


def validate(e_or_u: str) -> str:
if not valid_entity_id(e_or_u):
return e_or_u
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Should we still verify it looks like a uuid ?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Oh nm you do that before passing to validate.

return e_or_u

if not self.config["multiple"]:
return validate(cv.entity_id_or_uuid(cv.string(data)))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks like you could move cv.entity_id_or_uuid(cv.string(data)) inside validate too ?

Is cv.string necessary on top of cv.entity_id_or_uuid ?

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.

Fixed 👍

return validate(data)
if not isinstance(data, list):
raise vol.Invalid("Value should be a list")
return [validate(item) for item in data]
Copy link
Copy Markdown
Member

@balloob balloob Mar 2, 2022

Choose a reason for hiding this comment

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

If you do vol.Schema([validate]) it will give a nicer error message, something like "value at index X invalid: XX". Not sure if that really matters.

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.

Yeah, that's a bit better indeed 👍

before:
voluptuous.error.MultipleInvalid: Entity light.def456 belongs to domain light, expected sensor for dictionary value @ data['selection']
after:
voluptuous.error.MultipleInvalid: Entity light.def456 belongs to domain light, expected sensor @ data['selection'][1]

Copy link
Copy Markdown
Contributor

@emontnemery emontnemery left a comment

Choose a reason for hiding this comment

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

Thanks @r-t-s, this is great 👍

@emontnemery emontnemery merged commit 1558028 into home-assistant:dev Mar 3, 2022
@github-actions github-actions bot locked and limited conversation to collaborators Mar 4, 2022
@r-t-s r-t-s deleted the entity_selector branch March 7, 2022 14:24
@r-t-s r-t-s restored the entity_selector branch March 14, 2022 12:38
@r-t-s r-t-s deleted the entity_selector branch September 3, 2022 15:31
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants