architecture icon indicating copy to clipboard operation
architecture copied to clipboard

Allow components to register events in the websocket API

Open nielsfaber opened this issue 3 years ago • 6 comments

Context

The websocket API provides a powerful interface for the exchange of data between the HA core and endpoints, such as (but not limited to) the HA frontend. The websocket API uses the subscription and firing of events to signal that data in the HA core has changed and need to be re-fetched by the endpoints.

The current implementation uses a hard-coded list of events which are allowed to be subscribed. As a result it is currently not possible for a (custom or non-custom) component to define its own event, to be used as trigger for the refreshing of data using the web socket API, as for example is used in the shopping-list Lovelace card. Doing so would result in an Unauthorized error and the event subscription (and thus refreshing of the content) would fail, unless the user has administrator privileges.

The current list of events which are allowed for subscription is constraining for the further development of HA. As HA will grow, the amount of events will need to be extended, so the list will need to be maintained and will keep growing. Additionally, developers of custom_components have no way to declare their events, as the allowlist is maintained in core.

Proposal

The proposal is to replace the current ALLOWLIST by a class which offers basic register/unregister functionality, such that a component can, upon initialising, declare its event(s). This eliminates the need for maintaining a list in a central location and provides the developers of components with the control and responsibility of declaring their events (as already is the case for events - outside of the websocket API).

Consequences

  • The current allowed list of events is only used in one place, so it can be easily rewritten to a refer to the 'dynamic' class instead.
  • Small adjustments are needed in components which currently depend on the whitelist (frontend, persistent_notification, lovelace, shopping_list, area_registry, device_registry, entity_registry, ...) to have these register the event in the aforementioned class upon initialization
  • Care must be taken to avoid the race-condition where components would register their events to the class, before the websocket_api is initialized. This class may be defined outside of this component (e.g. in the core top-level).

nielsfaber avatar Jan 15 '21 16:01 nielsfaber

Some background on this feature: Admins can always subscribe to any event. The reason we have an allow list for non-admins is that we want to make sure that they are only allowed to subscribe to events that do not expose any sensitive information.

The idea is fine. Would be nice if we add registration of integration websocket APIs to it too.

We have a helper that can help manage this https://github.com/home-assistant/core/blob/dev/homeassistant/helpers/integration_platform.py

balloob avatar Jan 28 '21 13:01 balloob

@balloob Thanks for the response. I understand the function of the allowlist, I also think it’s purpose should be kept. The problem I’m raising is the fact that it’s a hard-coded list, which requires updating for every component which wants to use the Websocket API for non-admin functionality. In my case I’m maintaining 2 custom_components, I don’t see a way to have their events added to this list with the current implementation.

So can do we get started with this? Would you like me to create a PR for the changes, or can the dev team pick this up any time soon? It seems like a quick job to me, which will open some doors. For me the only problem is that I have not worked on core yet, but that can be changed.

nielsfaber avatar Jan 31 '21 17:01 nielsfaber

Yes please pick it up :) Feel free to tag me for a review on the PR when it's up. Working on core is a lot more fun than on custom stuff 😄

balloob avatar Feb 10 '21 19:02 balloob

I see the benefit in expanding the events websockets can subscribe too. But for me it would be 'much' more useful to be able to filter existing events. For example subscribing to the 'state-changed' event is like asking for a fire hose of unwanted events that really kills performance by sending tons of needless, unwanted events.

It would help 'tremendously' if i could subscribe to the 'state-changed' events with it filtered by 'entity-id'. That way i can get only the events i'm interested in. Other filters would be nice too, but at least by 'entity-id' please.

Regards

HeadHodge avatar Mar 02 '21 17:03 HeadHodge

I gave implementing this a try but also quickly gave up on it, and found a workaround to do this for my custom_components in the meantime. IMHO I still think the mentioned allowlist is still not a pretty part of HA. But I think its better if someone from the dev team works on this, because you have to touch quite some parts of code. The biggest problem is the possible race condition caused when an integration is loaded before the websocket_api.

nielsfaber avatar May 14 '21 17:05 nielsfaber

The helper I linked above takes care of that race condition.

balloob avatar May 15 '21 04:05 balloob

This architecture issue is old, stale, and possibly obsolete. Things changed a lot over the years. Additionally, we have been moving to discussions for these architectural discussions.

For that reason, I'm going to close this issue.

../Frenck

frenck avatar May 11 '23 14:05 frenck