Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Address post-merge reviews for KNX integration #123038

Merged
merged 3 commits into from
Aug 2, 2024
Merged

Address post-merge reviews for KNX integration #123038

merged 3 commits into from
Aug 2, 2024

Conversation

farmio
Copy link
Contributor

@farmio farmio commented Aug 1, 2024

Proposed change

1163e34 -> #122342 (comment)
Entities now get passed a reference to the KNXModule object instead of the XKNX object. This is used to pass an added entities unique_id to self._knx_module.config_store (instead of passing the Entity reference) and additionaly avoids calling hass.data[DOMAIN] in available() property. The PR has grown quite big because of that since all platforms had to be changed. Adding UI Entitiy variants additionally to YAML variants will be easier now though.
This is where the relevant stuff happens:

self.async_on_remove(
async_dispatcher_connect(
self.hass,
SIGNAL_ENTITY_REMOVE.format(self._attr_unique_id),
self.async_remove,
)
)
and changes in storage/config_store.py.

the other commits are a minor typing improvement and some cleanup regarding the previous commit

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

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

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
  • 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.

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.

To help with the load of incoming pull requests:

@home-assistant
Copy link

home-assistant bot commented Aug 1, 2024

Hey there @Julius2342, @marvin-w, mind taking a look at this pull request as it has been labeled with an integration (knx) you are listed as a code owner for? Thanks!

Code owner commands

Code owners of knx can trigger bot actions by commenting:

  • @home-assistant close Closes the pull request.
  • @home-assistant rename Awesome new title Renames the pull request.
  • @home-assistant reopen Reopen the pull request.
  • @home-assistant unassign knx Removes the current integration label and assignees on the pull request, add the integration domain after the command.
  • @home-assistant add-label needs-more-information Add a label (needs-more-information, problem in dependency, problem in custom component) to the pull request.
  • @home-assistant remove-label needs-more-information Remove a label (needs-more-information, problem in dependency, problem in custom component) on the pull request.

@@ -34,11 +34,11 @@ async def async_setup_entry(
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up the KNX binary sensor platform."""
xknx: XKNX = hass.data[DOMAIN].xknx
knx_module: KNXModule = hass.data[DOMAIN]
Copy link
Member

Choose a reason for hiding this comment

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

For a future improvement; this could be moved to the runtime_data property of the config entry (removing the need to use hass.data overall)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Unfortunately there are some places in the integration where I do need it, but don't have a config_entry handle.
Device triggers
https://github.com/home-assistant/core/blob/dev/homeassistant/components/knx/device_trigger.py#L66-L70
Services
https://github.com/home-assistant/core/blob/dev/homeassistant/components/knx/services.py#L225-L227
Websockets
https://github.com/home-assistant/core/blob/dev/homeassistant/components/knx/websocket.py#L122-L128

For Websockets we could probably pass an instance before registering.
But services shall be registered in async_setup() so that is too early and for device triggers I don't know either.

@frenck frenck added this to the 2024.8.0 milestone Aug 2, 2024
@frenck frenck merged commit 42234e6 into dev Aug 2, 2024
26 checks passed
@frenck frenck deleted the knx-2024-8-review branch August 2, 2024 10:53
Comment on lines -111 to 112
await self.entities.pop(unique_id).async_remove()
async_dispatcher_send(self.hass, SIGNAL_ENTITY_REMOVE.format(unique_id))
self.async_add_entity[platform](unique_id, data)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MartinHjelmare would I need to await the entities async_remove() (eg. by passing a future with the dispatcher) before adding the entity again? Or is it safe to do it like this way?

Copy link
Member

Choose a reason for hiding this comment

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

You should wait for the entity remove to complete before adding it again.

Copy link
Member

@MartinHjelmare MartinHjelmare Aug 3, 2024

Choose a reason for hiding this comment

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

I think it may be better to contain all this code within the platform since then we can access the platform helper and use its methods. Eg, we could get the platform helper with async_get_current_platform and then look up the entity instance via the entity_id and operate directly on the entity. Probably define a common function that can be imported in each platform and used.

The storage should just be responsible for holding the stored config and singnaling the changes of the config. The platforms are responsible for actuating the changes in the config to the entities.

Copy link
Member

@MartinHjelmare MartinHjelmare Aug 3, 2024

Choose a reason for hiding this comment

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

We don't have to use the dispatcher either. The important thing is to split the abstraction correctly between storage and platforms.

Eg, we could create a small class with abstract methods that each platform is responsible to implement where the abstract interface has methods for adding a new config item (entity) and removing a config item (entity) and updating a config item (entity). Then the platforms register this instance to the storage.

Copy link
Contributor Author

@farmio farmio Aug 3, 2024

Choose a reason for hiding this comment

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

So like extending what already happens here

self._knx_module.config_store.entities.add(self._attr_unique_id)
I think I see what you mean now 🙃

Would you know of any integration that does this already, so I can have a look at an example?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So how can this platform helper instance remove an entity (call Entity.async_remove())? Would it also need to dispatch a signal to the entity instance or can it have a reference to the entity itself (like the storage did before)?

Should it be instantiated in the platforms async_setup_entry()?

Copy link
Member

@MartinHjelmare MartinHjelmare Aug 3, 2024

Choose a reason for hiding this comment

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

It can work on the entity directly since it can access the EntityPlatform instance that holds all the entities of the platform.

Copy link
Member

Choose a reason for hiding this comment

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

There's also EntityPlatform.async_remove_entity.

Copy link
Member

Choose a reason for hiding this comment

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

Should it be instantiated in the platforms async_setup_entry()?

Yes.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in #123128
Thanks for your suggestions! 👍

@github-actions github-actions bot locked and limited conversation to collaborators Aug 5, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants