From 154859ef597d15423cbae5dd1aa1048521e94426 Mon Sep 17 00:00:00 2001 From: Tudor Sandu Date: Thu, 13 Jun 2024 12:55:15 +0000 Subject: [PATCH 1/3] Add alternate_state response This is used for confirming ambiguous state values which could be rephrased/reinterpreted --- responses/en/HassGetState.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/responses/en/HassGetState.yaml b/responses/en/HassGetState.yaml index 1c817690a4..484124b309 100644 --- a/responses/en/HassGetState.yaml +++ b/responses/en/HassGetState.yaml @@ -9,6 +9,14 @@ responses: one: | {{ slots.name | capitalize }} is {{ state.state_with_unit }} + alternate_state: | + {{ slots.name | capitalize }} is {{ slots.actual_state }}, but it is + {% if state.state in slots.alternate_state %} + {{ slots.alternate_state[state.state] }} + {% else %} + {{ state.state }} + {% endif %} + one_yesno: | {% if query.matched %} Yes From 87868bacdc5cb417363d64c2169ec4ddeb30d20e Mon Sep 17 00:00:00 2001 From: Tudor Sandu Date: Thu, 13 Jun 2024 12:56:25 +0000 Subject: [PATCH 2/3] Add clearer HassGetState sentences for media_player --- sentences/en/_common.yaml | 11 ++ sentences/en/homeassistant_HassGetState.yaml | 1 + sentences/en/media_player_HassGetState.yaml | 75 +++++++++++ tests/en/media_player_HassGetState.yaml | 125 +++++++++++++++++++ 4 files changed, 212 insertions(+) create mode 100644 sentences/en/media_player_HassGetState.yaml create mode 100644 tests/en/media_player_HassGetState.yaml diff --git a/sentences/en/_common.yaml b/sentences/en/_common.yaml index 9fadc52499..893c485eaf 100644 --- a/sentences/en/_common.yaml +++ b/sentences/en/_common.yaml @@ -128,6 +128,16 @@ lists: out: "locked" - in: "unlocked" out: "unlocked" + media_player_states: + values: + - in: "[turned ]off" + out: "off" + - in: "(idle|standing by)" + out: ["on", "idle", "standby", "buffering"] + - in: "(playing|[turned ]on)" + out: "playing" + - in: "paused" + out: "paused" # binary_sensor bs_battery_states: @@ -372,6 +382,7 @@ expansion_rules: in: "(in|on|at|of)" position: "{position}[[ ]%| percent]" volume: "{volume:volume_level}[[ ]%| percent]" + media_players: "([media ]player[s]|speaker[s]stereo[s]|tv[s])" # Context awareness expansion rules all: "(all|all of|every|every single|each|each and every)" diff --git a/sentences/en/homeassistant_HassGetState.yaml b/sentences/en/homeassistant_HassGetState.yaml index f0924c5b2b..1d0730da8e 100644 --- a/sentences/en/homeassistant_HassGetState.yaml +++ b/sentences/en/homeassistant_HassGetState.yaml @@ -15,6 +15,7 @@ intents: excludes_context: domain: - cover + - media_player - sentences: - (is|are) [there] any {on_off_domains:domain} {on_off_states:state} [in ] diff --git a/sentences/en/media_player_HassGetState.yaml b/sentences/en/media_player_HassGetState.yaml new file mode 100644 index 0000000000..6183a95c84 --- /dev/null +++ b/sentences/en/media_player_HassGetState.yaml @@ -0,0 +1,75 @@ +language: en +intents: + HassGetState: + data: + - sentences: + - is [the ][state of ] [turned ]on[ in ] + slots: + actual_state: "on" + alternate_state: + "on": "in an unknown state" + idle: "not playing" + standby: "in standby" + response: alternate_state + requires_context: + domain: media_player + excludes_context: + state: + - "playing" + - "off" + + - sentences: + - is [the ][state of ] [turned ]off[ in ] + slots: + state: + - "on" + - "idle" + - "paused" + - "standby" + - "buffering" + actual_state: "not off" + alternate_state: + "on": "in an unknown state" + idle: "not playing anything" + standby: "in standby" + response: alternate_state + requires_context: + domain: media_player + + - sentences: + - is [the] [state of] {media_player_states:state} [in ] + response: one_yesno + requires_context: + domain: media_player + + - sentences: + - (is|are) [there] any {media_player_states:state} [in ] + - (do you know|tell me) if there are any {media_player_states:state} [in ] + slots: + domain: media_player + response: any + - sentences: + - (is|are) [there] any {media_player_states:state} [in ] + - (do you know|tell me) if there are any {media_player_states:state} [in ] + slots: + domain: media_player + response: any + + - sentences: + - are all [the] {media_player_states:state} [in ] + - are all [the] in {media_player_states:state} + slots: + domain: media_player + response: all + + - sentences: + - "[do you know] (which|what) (is|are) {media_player_states:state} [in ]" + slots: + domain: media_player + response: which + + - sentences: + - "[tell me] how many (is|are) {media_player_states:state} [in ]" + slots: + domain: media_player + response: how_many diff --git a/tests/en/media_player_HassGetState.yaml b/tests/en/media_player_HassGetState.yaml new file mode 100644 index 0000000000..11893df5de --- /dev/null +++ b/tests/en/media_player_HassGetState.yaml @@ -0,0 +1,125 @@ +language: en +tests: + - sentences: + - "is the TV on?" + intent: + name: HassGetState + slots: + name: "TV" + actual_state: "on" + alternate_state: + "on": "in an unknown state" + idle: "not playing" + standby: "in standby" + context: + domain: media_player + volume_level: "50" + response: "Tv is on, but it is not playing" + + - sentences: + - "is the TV off?" + intent: + name: HassGetState + slots: + name: "TV" + state: + - "on" + - "idle" + - "paused" + - "standby" + - "buffering" + actual_state: "not off" + alternate_state: + "on": "in an unknown state" + idle: "not playing anything" + standby: "in standby" + context: + domain: media_player + volume_level: "50" + response: "Tv is not off, but it is not playing anything" + + - sentences: + - "is the TV playing?" + intent: + name: HassGetState + slots: + name: "TV" + state: "playing" + context: + domain: media_player + volume_level: "50" + response: "No, idle" + + - sentences: + - "is the TV standing by?" + intent: + name: HassGetState + slots: + name: "TV" + state: + - "on" + - "idle" + - "standby" + - "buffering" + context: + domain: media_player + volume_level: "50" + response: "Yes" + + - sentences: + - "are any media players on in the kitchen?" + intent: + name: HassGetState + slots: + area: "Kitchen" + domain: "media_player" + state: "playing" + response: "No" + + - sentences: + - "are all media players on?" + intent: + name: HassGetState + slots: + domain: "media_player" + state: "playing" + response: "No, TV is not on" + + - sentences: + - "are all media players off?" + intent: + name: HassGetState + slots: + domain: "media_player" + state: "off" + response: "No, TV is not off" + + - sentences: + - "which media players are on?" + intent: + name: HassGetState + slots: + domain: "media_player" + state: "playing" + response: "Not any" + + - sentences: + - "how many media players are on?" + intent: + name: HassGetState + slots: + domain: "media_player" + state: "playing" + response: "0" + + - sentences: + - "are all the media players on in the living room" + - "are all media players on in the living room?" + - "are all media players in the living room on?" + intent: + name: HassGetState + slots: + domain: "media_player" + state: "playing" + area: "Living Room" + response: "No, TV is not on" From ce9ab25caa6d87ad2ca5240eaafe3e5a35d28a25 Mon Sep 17 00:00:00 2001 From: Tudor Sandu Date: Thu, 13 Jun 2024 12:57:46 +0000 Subject: [PATCH 3/3] Fix parser and test processor Passing the `state` slot as a list to the parser/test processor, although supported in hassil, would have not worked. --- shared/__init__.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/shared/__init__.py b/shared/__init__.py index 16258d0fa8..e891c9e0da 100644 --- a/shared/__init__.py +++ b/shared/__init__.py @@ -117,7 +117,7 @@ def get_matched_states( if device_class_entity is not None: device_class = device_class_entity.value - state_name: Optional[str] = None + state_name: Optional[str | List[str]] = None state_entity = result.entities.get("state") if state_entity is not None: state_name = state_entity.value @@ -163,7 +163,9 @@ def get_matched_states( if state_name is not None: # Match state - if state.hass_state == state_name: + if isinstance(state_name, str) and state.hass_state == state_name: + matched.append(state) + elif isinstance(state_name, list) and state.hass_state in state_name: matched.append(state) else: unmatched.append(state)