-
-
Notifications
You must be signed in to change notification settings - Fork 37.5k
Add state trigger to light component #148416
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
47 commits
Select commit
Hold shift + click to select a range
89a9ab6
Add method to track entity state changes from target selectors
abmantis 5d553e5
Use class to manage subscriptions
abmantis 0ead4c0
Move target selector extractor method to common module
abmantis 0335c9e
Use common method in triggers.py
abmantis a971313
Merge branch 'dev' of github.com:home-assistant/core into track_entit…
abmantis 695f47c
Add missed components
abmantis 2d931c5
Simplify tracker class
abmantis 72a982b
Merge branch 'dev' of github.com:home-assistant/core into track_entit…
abmantis 7a57ab4
Update import
abmantis 4cc97d2
Implement review suggestion on triggering all test entities
abmantis 67a7cf8
Rename class; add comment
abmantis 9376715
Move to target.py
abmantis 5e47462
Add state trigger to light component
abmantis ee2c7ca
Merge branch 'dev' of github.com:home-assistant/core into target_trigger
abmantis 1b85a92
Cleanup comments
abmantis 5d792de
Merge fix
abmantis 4a12c18
Remove behavior from yaml
abmantis b9246c4
Merge branch 'dev' of github.com:home-assistant/core into target_trigger
abmantis a6d0532
Add test
abmantis f52a362
Cleanup comments
abmantis 0bd5231
Add any state test
abmantis 3d98bc9
Move target selector to toplevel; add strings and icons
abmantis 93e570a
Merge branch 'dev' of github.com:home-assistant/core into target_trigger
abmantis 09328aa
Add list of targeted entities to target state event
abmantis 35b54b7
Merge tests
abmantis 801591f
Add behavior conf
abmantis 9e8372c
Merge branch 'dev' of github.com:home-assistant/core into target_trigger
abmantis e2e7c56
Add behavior to strings
abmantis 5257307
Fix translations test
abmantis 13d3401
Merge branch 'dev_target_triggers_conditions' of github.com:home-assi…
abmantis 2af652a
Change state to select selector
abmantis ba79225
Merge branch 'dev_target_triggers_conditions' of github.com:home-assi…
abmantis 43c2283
Apply suggestions from code review
abmantis 80cd461
Fix non-light domain entities on trigger
abmantis 7adfb42
Merge branch 'dev_target_triggers_conditions' of github.com:home-assi…
abmantis 29fd422
Update trigger method names
abmantis 789e5da
Fix targets key
abmantis 06f1d3b
Type consts
abmantis e59567d
Use TARGET_SELECTION_SCHEMA
abmantis 05bc556
Merge branch 'dev_target_triggers_conditions' of github.com:home-assi…
abmantis b877471
Fix translations
abmantis beea8e4
Move reverse state to test params
abmantis 4b77a5b
Merge branch 'dev_target_triggers_conditions' of github.com:home-assi…
abmantis 24abe55
Change to options config
abmantis 7dcf015
Use TARGET_FIELDS
abmantis d323212
Merge branch 'dev_target_triggers_conditions' of github.com:home-assi…
abmantis df0d907
Update to modernized schema
abmantis 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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -25,5 +25,10 @@ | |
| "turn_on": { | ||
| "service": "mdi:lightbulb-on" | ||
| } | ||
| }, | ||
| "triggers": { | ||
| "state": { | ||
| "trigger": "mdi:state-machine" | ||
| } | ||
| } | ||
| } | ||
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,165 @@ | ||
| """Provides triggers for lights.""" | ||
|
|
||
| from typing import Final, cast, override | ||
|
|
||
| import voluptuous as vol | ||
|
|
||
| from homeassistant.const import ( | ||
| ATTR_ENTITY_ID, | ||
| CONF_PLATFORM, | ||
| CONF_STATE, | ||
| CONF_TARGET, | ||
| STATE_OFF, | ||
| STATE_ON, | ||
| ) | ||
| from homeassistant.core import ( | ||
| CALLBACK_TYPE, | ||
| HassJob, | ||
| HomeAssistant, | ||
| callback, | ||
| split_entity_id, | ||
| ) | ||
| from homeassistant.helpers import config_validation as cv | ||
| from homeassistant.helpers.event import process_state_match | ||
| from homeassistant.helpers.target import ( | ||
| TargetStateChangedData, | ||
| async_track_target_selector_state_change_event, | ||
| ) | ||
| from homeassistant.helpers.trigger import Trigger, TriggerActionType, TriggerInfo | ||
| from homeassistant.helpers.typing import ConfigType | ||
|
|
||
| from .const import DOMAIN | ||
|
|
||
| # remove when #151314 is merged | ||
| CONF_OPTIONS: Final = "options" | ||
|
|
||
| ATTR_BEHAVIOR: Final = "behavior" | ||
| BEHAVIOR_FIRST: Final = "first" | ||
| BEHAVIOR_LAST: Final = "last" | ||
| BEHAVIOR_ANY: Final = "any" | ||
|
|
||
| STATE_PLATFORM_TYPE: Final = "state" | ||
| STATE_TRIGGER_SCHEMA = vol.Schema( | ||
| { | ||
| vol.Required(CONF_OPTIONS): { | ||
| vol.Required(CONF_STATE): vol.In([STATE_ON, STATE_OFF]), | ||
| vol.Required(ATTR_BEHAVIOR, default=BEHAVIOR_ANY): vol.In( | ||
| [BEHAVIOR_FIRST, BEHAVIOR_LAST, BEHAVIOR_ANY] | ||
| ), | ||
| }, | ||
| vol.Required(CONF_TARGET): cv.TARGET_FIELDS, | ||
| } | ||
| ) | ||
|
|
||
|
|
||
| class StateTrigger(Trigger): | ||
| """Trigger for state changes.""" | ||
|
|
||
| @override | ||
| @classmethod | ||
| async def async_validate_config( | ||
| cls, hass: HomeAssistant, config: ConfigType | ||
| ) -> ConfigType: | ||
| """Validate config.""" | ||
| return cast(ConfigType, STATE_TRIGGER_SCHEMA(config)) | ||
|
arturpragacz marked this conversation as resolved.
|
||
|
|
||
| def __init__(self, hass: HomeAssistant, config: dict) -> None: | ||
| """Initialize the state trigger.""" | ||
| self.hass = hass | ||
| self.config = config | ||
|
|
||
| @override | ||
| async def async_attach( | ||
| self, action: TriggerActionType, trigger_info: TriggerInfo | ||
| ) -> CALLBACK_TYPE: | ||
| """Attach the trigger.""" | ||
| job = HassJob(action, f"light state trigger {trigger_info}") | ||
| trigger_data = trigger_info["trigger_data"] | ||
| config_options = self.config[CONF_OPTIONS] | ||
|
|
||
| match_config_state = process_state_match(config_options.get(CONF_STATE)) | ||
|
|
||
| def check_all_match(entity_ids: set[str]) -> bool: | ||
| """Check if all entity states match.""" | ||
| return all( | ||
| match_config_state(state.state) | ||
| for entity_id in entity_ids | ||
| if (state := self.hass.states.get(entity_id)) is not None | ||
| ) | ||
|
|
||
| def check_one_match(entity_ids: set[str]) -> bool: | ||
| """Check that only one entity state matches.""" | ||
| return ( | ||
| sum( | ||
| match_config_state(state.state) | ||
| for entity_id in entity_ids | ||
| if (state := self.hass.states.get(entity_id)) is not None | ||
| ) | ||
| == 1 | ||
| ) | ||
|
|
||
| behavior = config_options.get(ATTR_BEHAVIOR) | ||
|
|
||
| @callback | ||
| def state_change_listener( | ||
| target_state_change_data: TargetStateChangedData, | ||
| ) -> None: | ||
| """Listen for state changes and call action.""" | ||
| event = target_state_change_data.state_change_event | ||
| entity_id = event.data["entity_id"] | ||
| from_state = event.data["old_state"] | ||
| to_state = event.data["new_state"] | ||
|
|
||
| if to_state is None: | ||
| return | ||
|
|
||
| # This check is required for "first" behavior, to check that it went from zero | ||
| # entities matching the state to one. Otherwise, if previously there were two | ||
| # entities on CONF_STATE and one changed, this would trigger. | ||
| # For "last" behavior it is not required, but serves as a quicker fail check. | ||
| if not match_config_state(to_state.state): | ||
| return | ||
| if behavior == BEHAVIOR_LAST: | ||
| if not check_all_match(target_state_change_data.targeted_entity_ids): | ||
| return | ||
| elif behavior == BEHAVIOR_FIRST: | ||
| if not check_one_match(target_state_change_data.targeted_entity_ids): | ||
| return | ||
|
|
||
| self.hass.async_run_hass_job( | ||
| job, | ||
| { | ||
| "trigger": { | ||
| **trigger_data, | ||
| CONF_PLATFORM: self.config[CONF_PLATFORM], | ||
| ATTR_ENTITY_ID: entity_id, | ||
| "from_state": from_state, | ||
| "to_state": to_state, | ||
| "description": f"state of {entity_id}", | ||
|
arturpragacz marked this conversation as resolved.
|
||
| } | ||
| }, | ||
| event.context, | ||
| ) | ||
|
|
||
| def entity_filter(entities: set[str]) -> set[str]: | ||
| """Filter entities of this domain.""" | ||
| return { | ||
| entity_id | ||
| for entity_id in entities | ||
| if split_entity_id(entity_id)[0] == DOMAIN | ||
| } | ||
|
|
||
| target_config = self.config[CONF_TARGET] | ||
| return async_track_target_selector_state_change_event( | ||
| self.hass, target_config, state_change_listener, entity_filter | ||
| ) | ||
|
|
||
|
|
||
| TRIGGERS: dict[str, type[Trigger]] = { | ||
| STATE_PLATFORM_TYPE: StateTrigger, | ||
| } | ||
|
|
||
|
|
||
| async def async_get_triggers(hass: HomeAssistant) -> dict[str, type[Trigger]]: | ||
| """Return the triggers for lights.""" | ||
| return TRIGGERS | ||
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,22 @@ | ||
| state: | ||
| target: | ||
| entity: | ||
| domain: light | ||
| fields: | ||
| state: | ||
| required: true | ||
| default: "on" | ||
| selector: | ||
| select: | ||
| options: | ||
| - "off" | ||
| - "on" | ||
| behavior: | ||
| required: true | ||
| default: any | ||
| selector: | ||
| select: | ||
| options: | ||
| - first | ||
| - last | ||
| - any |
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.
Uh oh!
There was an error while loading. Please reload this page.