-
-
Notifications
You must be signed in to change notification settings - Fork 37.4k
Add OpenRGB profile select entity #154732
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
Merged
Merged
Changes from all commits
Commits
Show all changes
21 commits
Select commit
Hold shift + click to select a range
c93b673
Add OpenRGB profile select entity
felipecrs 39d40ca
Move server device registration to select.py
felipecrs 67ccbdb
Merge branch 'dev' of https://github.com/home-assistant/core into ope…
felipecrs a321553
Remove now useless test
felipecrs efa6703
Align unique id separator
felipecrs f3f122b
Add comment about no way to retrieve data
felipecrs 24d3e60
Only import DeviceEntryType
felipecrs 80be89d
Merge branch 'dev' into openrgb-profiles
felipecrs 73ed447
Assume current profile until some state has changed
felipecrs f94b056
Merge branch 'dev' into openrgb-profiles
felipecrs 3003b91
Avoid calculating state hash when useless
felipecrs 1fc66c7
Merge branch 'dev' into openrgb-profiles
felipecrs 24bc83d
Merge branch 'dev' into openrgb-profiles
felipecrs e54ecbe
Merge branch 'dev' into openrgb-profiles
felipecrs f8b8950
Merge branch 'dev' into openrgb-profiles
felipecrs 82ed5eb
Merge branch 'dev' into openrgb-profiles
felipecrs b5b4738
Merge branch 'dev' of https://github.com/home-assistant/core into ope…
felipecrs a54db9e
Improve hashing mechanism
felipecrs bd00897
Merge branch 'dev' into openrgb-profiles
felipecrs 9b1d62c
Merge branch 'dev' into openrgb-profiles
felipecrs efda077
Move server device initialization back to __init__.py
felipecrs File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| """Select platform for OpenRGB integration.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| from homeassistant.components.select import SelectEntity | ||
| from homeassistant.core import HomeAssistant, callback | ||
| from homeassistant.exceptions import HomeAssistantError | ||
| from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback | ||
| from homeassistant.helpers.update_coordinator import CoordinatorEntity | ||
|
|
||
| from .const import CONNECTION_ERRORS, DOMAIN, UID_SEPARATOR | ||
| from .coordinator import OpenRGBConfigEntry, OpenRGBCoordinator | ||
|
|
||
| PARALLEL_UPDATES = 0 | ||
|
|
||
|
|
||
| async def async_setup_entry( | ||
| hass: HomeAssistant, | ||
| config_entry: OpenRGBConfigEntry, | ||
| async_add_entities: AddConfigEntryEntitiesCallback, | ||
| ) -> None: | ||
| """Set up the OpenRGB select platform.""" | ||
| coordinator = config_entry.runtime_data | ||
| async_add_entities([OpenRGBProfileSelect(coordinator, config_entry)]) | ||
|
|
||
|
|
||
| class OpenRGBProfileSelect(CoordinatorEntity[OpenRGBCoordinator], SelectEntity): | ||
| """Representation of an OpenRGB profile select entity.""" | ||
|
|
||
| _attr_translation_key = "profile" | ||
| _attr_has_entity_name = True | ||
|
|
||
| _state_hash: int | None = None | ||
| _pending_profile: str | None = None | ||
|
|
||
| def __init__( | ||
| self, coordinator: OpenRGBCoordinator, entry: OpenRGBConfigEntry | ||
| ) -> None: | ||
| """Initialize the select entity.""" | ||
| super().__init__(coordinator) | ||
| self._attr_unique_id = UID_SEPARATOR.join([entry.entry_id, "profile"]) | ||
| self._attr_device_info = { | ||
| "identifiers": {(DOMAIN, entry.entry_id)}, | ||
| } | ||
| self._update_attrs() | ||
|
|
||
| def _compute_state_hash(self) -> int: | ||
| """Compute a hash of device states.""" | ||
| return hash( | ||
| "\n".join(str(device.data) for device in self.coordinator.client.devices) | ||
| ) | ||
|
|
||
| @callback | ||
| def _update_attrs(self) -> None: | ||
| """Update the attributes based on the current profile list.""" | ||
| profiles = self.coordinator.client.profiles | ||
| self._attr_options = [profile.name for profile in profiles] | ||
|
|
||
| # If a profile was just applied, set it as current | ||
| if self._pending_profile is not None: | ||
| self._attr_current_option = self._pending_profile | ||
| self._pending_profile = None | ||
| self._state_hash = self._compute_state_hash() | ||
| # Only check for state changes if we have a current option to potentially clear | ||
| elif self._attr_current_option is not None: | ||
| current_hash = self._compute_state_hash() | ||
| # If state changed, we can no longer assume current profile | ||
| if current_hash != self._state_hash: | ||
| self._attr_current_option = None | ||
| self._state_hash = None | ||
|
|
||
| @callback | ||
| def _handle_coordinator_update(self) -> None: | ||
| """Handle updated data from the coordinator.""" | ||
| self._update_attrs() | ||
| super()._handle_coordinator_update() | ||
|
|
||
| @property | ||
| def available(self) -> bool: | ||
| """Return if the select is available.""" | ||
| return super().available and bool(self._attr_options) | ||
|
|
||
| async def async_select_option(self, option: str) -> None: | ||
| """Load the selected profile.""" | ||
| async with self.coordinator.client_lock: | ||
| try: | ||
| await self.hass.async_add_executor_job( | ||
| self.coordinator.client.load_profile, option | ||
| ) | ||
| except CONNECTION_ERRORS as err: | ||
| raise HomeAssistantError( | ||
| translation_domain=DOMAIN, | ||
| translation_key="communication_error", | ||
| translation_placeholders={ | ||
| "server_address": self.coordinator.server_address, | ||
| "error": str(err), | ||
| }, | ||
| ) from err | ||
| except ValueError as err: | ||
| raise HomeAssistantError( | ||
| translation_domain=DOMAIN, | ||
| translation_key="openrgb_error", | ||
| translation_placeholders={ | ||
| "error": str(err), | ||
| }, | ||
| ) from err | ||
|
|
||
| self._pending_profile = option | ||
| await self.coordinator.async_refresh() | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| # serializer version: 1 | ||
| # name: test_entities[select.test_computer_profile-entry] | ||
| EntityRegistryEntrySnapshot({ | ||
| 'aliases': set({ | ||
| }), | ||
| 'area_id': None, | ||
| 'capabilities': dict({ | ||
| 'options': list([ | ||
| ]), | ||
| }), | ||
| 'config_entry_id': <ANY>, | ||
| 'config_subentry_id': <ANY>, | ||
| 'device_class': None, | ||
| 'device_id': <ANY>, | ||
| 'disabled_by': None, | ||
| 'domain': 'select', | ||
| 'entity_category': None, | ||
| 'entity_id': 'select.test_computer_profile', | ||
| 'has_entity_name': True, | ||
| 'hidden_by': None, | ||
| 'icon': None, | ||
| 'id': <ANY>, | ||
| 'labels': set({ | ||
| }), | ||
| 'name': None, | ||
| 'options': dict({ | ||
| }), | ||
| 'original_device_class': None, | ||
| 'original_icon': None, | ||
| 'original_name': 'Profile', | ||
| 'platform': 'openrgb', | ||
| 'previous_unique_id': None, | ||
| 'suggested_object_id': None, | ||
| 'supported_features': 0, | ||
| 'translation_key': 'profile', | ||
| 'unique_id': '01J0EXAMPLE0CONFIGENTRY00||profile', | ||
| 'unit_of_measurement': None, | ||
| }) | ||
| # --- | ||
| # name: test_entities[select.test_computer_profile-state] | ||
| StateSnapshot({ | ||
| 'attributes': ReadOnlyDict({ | ||
| 'friendly_name': 'Test Computer Profile', | ||
| 'options': list([ | ||
| ]), | ||
| }), | ||
| 'context': <ANY>, | ||
| 'entity_id': 'select.test_computer_profile', | ||
| 'last_changed': <ANY>, | ||
| 'last_reported': <ANY>, | ||
| 'last_updated': <ANY>, | ||
| 'state': 'unavailable', | ||
| }) | ||
| # --- |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need the hash? Can't we check based on name?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Which name?
OpenRGB SDK does not expose data of the current profile. I crafted this method so that I can at least determine whether the applied profile is still active.
Please read this discussion for a better context.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I improved the hash function a little bit by reusing @jath03's idea.
Also, this will be simplified in future. The author of OpenRGB accepted the suggestion of tracking this within OpenRGB itself.