From 33109b35a4477b2b5b4a85dac366b70c727322aa Mon Sep 17 00:00:00 2001 From: Joseph Abbey Date: Sun, 16 Jun 2024 13:48:23 +0100 Subject: [PATCH 1/5] Add RandomNumber and CurrentTime intents --- custom_components/custom_sentences/intent.py | 67 ++++++++++++++++++++ custom_sentences/en/custom_sentences.yaml | 23 ++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/custom_components/custom_sentences/intent.py b/custom_components/custom_sentences/intent.py index 0863969..7a96886 100644 --- a/custom_components/custom_sentences/intent.py +++ b/custom_components/custom_sentences/intent.py @@ -1,8 +1,12 @@ """Intent handlers.""" +import datetime +import random import typing import homeassistant.helpers.config_validation as cv +import pytz +import voluptuous as vol from homeassistant.core import HomeAssistant from homeassistant.helpers import intent @@ -10,6 +14,8 @@ async def async_setup_intents(hass: HomeAssistant) -> None: """Set up the custom intent handlers.""" intent.async_register(hass, ConversationProcessIntentHandler()) + intent.async_register(hass, RandomNumberIntentHandler()) + intent.async_register(hass, CurrentTimeIntentHandler()) class ConversationProcessIntentHandler(intent.IntentHandler): @@ -74,3 +80,64 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse response = intent_obj.create_response() response.async_set_speech(f"{name} says '{response_text}'") return response + + +class RandomNumberIntentHandler(intent.IntentHandler): + """Handle RandomNumber intents.""" + + # Type of intent to handle + intent_type = "RandomNumber" + + description = "Generate a random number in a range." + + # Optional. A validation schema for slots + slot_schema: typing.ClassVar[dict] = { + "from": vol.All(vol.Coerce(int), vol.Range(min=0, max=999999999)), + "to": vol.All(vol.Coerce(int), vol.Range(min=0, max=999999999)), + } + + async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: + """Handle the intent.""" + # Extract the slot values + slots = intent_obj.slots + from_value = int(slots["from"]["value"]) + to_value = int(slots["to"]["value"]) + + # Generate a random number + result = random.randint(from_value, to_value) # noqa: S311 + + # Create and return a response + response = intent_obj.create_response() + response.async_set_speech(f"{result}") + return response + + +class CurrentTimeIntentHandler(intent.IntentHandler): + """Handle CurrentTime intents.""" + + # Type of intent to handle + intent_type = "CurrentTime" + + description = "Get the current time." + + async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: + """Handle the intent.""" + # Retrieve the user's timezone from Home Assistant configuration + user_timezone = intent_obj.hass.config.time_zone + + # Create a timezone object using pytz + timezone = pytz.timezone(user_timezone) + + # Get the current time in UTC + utc_now = datetime.datetime.now(datetime.UTC) + + # Convert the current UTC time to the user's timezone + user_time = utc_now.astimezone(timezone) + + # Format the time as a string + result = user_time.strftime("%H:%M") + + # Create and return a response + response = intent_obj.create_response() + response.async_set_speech(f"The time is {result}") + return response diff --git a/custom_sentences/en/custom_sentences.yaml b/custom_sentences/en/custom_sentences.yaml index 76b126d..55ea30a 100644 --- a/custom_sentences/en/custom_sentences.yaml +++ b/custom_sentences/en/custom_sentences.yaml @@ -1,11 +1,30 @@ -language: "en" +language: 'en' intents: ConversationProcess: data: - sentences: - - "(Ask | Tell) {name} [to] {text}" + - '(Ask | Tell) {name} [to] {text}' requires_context: domain: conversation + RandomNumber: + data: + - sentences: + - '(Pick|Generate) a [random] number between {random_range:from} and {random_range:to}' + - '(Pick|Generate) a [random] number [from] {random_range:from} (through | to) {random_range:to}' + - sentences: + - '(Pick|Generate) a [random] number (below | up to) {random_range:to}' + slots: + from: 1 + CurrentTime: + data: + - sentences: + - "What's the time" + - 'What is the time' + - 'What time is it' lists: text: wildcard: true + random_range: + range: + from: 0 + to: 999999999 From 20fc3cecf0e47331df970fa9904a9cba0cb65184 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 16 Jun 2024 12:49:09 +0000 Subject: [PATCH 2/5] Restyled by prettier-yaml --- custom_sentences/en/custom_sentences.yaml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/custom_sentences/en/custom_sentences.yaml b/custom_sentences/en/custom_sentences.yaml index 55ea30a..99869c6 100644 --- a/custom_sentences/en/custom_sentences.yaml +++ b/custom_sentences/en/custom_sentences.yaml @@ -1,26 +1,26 @@ -language: 'en' +language: "en" intents: ConversationProcess: data: - sentences: - - '(Ask | Tell) {name} [to] {text}' + - "(Ask | Tell) {name} [to] {text}" requires_context: domain: conversation RandomNumber: data: - sentences: - - '(Pick|Generate) a [random] number between {random_range:from} and {random_range:to}' - - '(Pick|Generate) a [random] number [from] {random_range:from} (through | to) {random_range:to}' + - "(Pick|Generate) a [random] number between {random_range:from} and {random_range:to}" + - "(Pick|Generate) a [random] number [from] {random_range:from} (through | to) {random_range:to}" - sentences: - - '(Pick|Generate) a [random] number (below | up to) {random_range:to}' + - "(Pick|Generate) a [random] number (below | up to) {random_range:to}" slots: from: 1 CurrentTime: data: - sentences: - "What's the time" - - 'What is the time' - - 'What time is it' + - "What is the time" + - "What time is it" lists: text: wildcard: true From a8ed3c82d3ea588a55281a7ed4de8461121d1246 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 16 Jun 2024 12:49:15 +0000 Subject: [PATCH 3/5] Restyled by reorder-python-imports --- custom_components/custom_sentences/intent.py | 1 - 1 file changed, 1 deletion(-) diff --git a/custom_components/custom_sentences/intent.py b/custom_components/custom_sentences/intent.py index 7a96886..8f9154c 100644 --- a/custom_components/custom_sentences/intent.py +++ b/custom_components/custom_sentences/intent.py @@ -1,5 +1,4 @@ """Intent handlers.""" - import datetime import random import typing From a45e3dc2a6d4819cb12498e9bf0bbab22df2ee75 Mon Sep 17 00:00:00 2001 From: "Restyled.io" Date: Sun, 16 Jun 2024 12:49:20 +0000 Subject: [PATCH 4/5] Restyled by yapf --- custom_components/custom_sentences/intent.py | 29 ++++++++++++-------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/custom_components/custom_sentences/intent.py b/custom_components/custom_sentences/intent.py index 8f9154c..7a26c8a 100644 --- a/custom_components/custom_sentences/intent.py +++ b/custom_components/custom_sentences/intent.py @@ -30,7 +30,8 @@ class ConversationProcessIntentHandler(intent.IntentHandler): # Optional. A validation schema for slots slot_schema: typing.ClassVar[dict] = {"name": cv.string, "text": cv.string} - async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: + async def async_handle(self, + intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" # Extract the slot values slots = intent_obj.slots @@ -39,8 +40,9 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse # Define the constraints for matching the target entity constraints = intent.MatchTargetsConstraints( - name=name, domains=["conversation"], assistant=intent_obj.assistant - ) + name=name, + domains=["conversation"], + assistant=intent_obj.assistant) # Match the target entity match_result = intent.async_match_targets(intent_obj.hass, constraints) @@ -62,18 +64,19 @@ async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse result = await intent_obj.hass.services.async_call( "conversation", "process", - {"text": text, "agent_id": matched_entity_id}, + { + "text": text, + "agent_id": matched_entity_id + }, blocking=True, return_response=True, ) # Extract the response text - response_text = ( - result.get("response", {}) - .get("speech", {}) - .get("plain", {}) - .get("speech", "") - ) + response_text = (result.get("response", + {}).get("speech", + {}).get("plain", + {}).get("speech", "")) # Create and return a response response = intent_obj.create_response() @@ -95,7 +98,8 @@ class RandomNumberIntentHandler(intent.IntentHandler): "to": vol.All(vol.Coerce(int), vol.Range(min=0, max=999999999)), } - async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: + async def async_handle(self, + intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" # Extract the slot values slots = intent_obj.slots @@ -119,7 +123,8 @@ class CurrentTimeIntentHandler(intent.IntentHandler): description = "Get the current time." - async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: + async def async_handle(self, + intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" # Retrieve the user's timezone from Home Assistant configuration user_timezone = intent_obj.hass.config.time_zone From 97f9e0ef7d63909abe25478f98809e35deaa4b37 Mon Sep 17 00:00:00 2001 From: Joseph Abbey Date: Sun, 16 Jun 2024 14:00:38 +0100 Subject: [PATCH 5/5] Revert "Restyle Add RandomNumber and CurrentTime intents" --- custom_components/custom_sentences/intent.py | 30 +++++++++----------- custom_sentences/en/custom_sentences.yaml | 14 ++++----- 2 files changed, 20 insertions(+), 24 deletions(-) diff --git a/custom_components/custom_sentences/intent.py b/custom_components/custom_sentences/intent.py index 7a26c8a..7a96886 100644 --- a/custom_components/custom_sentences/intent.py +++ b/custom_components/custom_sentences/intent.py @@ -1,4 +1,5 @@ """Intent handlers.""" + import datetime import random import typing @@ -30,8 +31,7 @@ class ConversationProcessIntentHandler(intent.IntentHandler): # Optional. A validation schema for slots slot_schema: typing.ClassVar[dict] = {"name": cv.string, "text": cv.string} - async def async_handle(self, - intent_obj: intent.Intent) -> intent.IntentResponse: + async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" # Extract the slot values slots = intent_obj.slots @@ -40,9 +40,8 @@ async def async_handle(self, # Define the constraints for matching the target entity constraints = intent.MatchTargetsConstraints( - name=name, - domains=["conversation"], - assistant=intent_obj.assistant) + name=name, domains=["conversation"], assistant=intent_obj.assistant + ) # Match the target entity match_result = intent.async_match_targets(intent_obj.hass, constraints) @@ -64,19 +63,18 @@ async def async_handle(self, result = await intent_obj.hass.services.async_call( "conversation", "process", - { - "text": text, - "agent_id": matched_entity_id - }, + {"text": text, "agent_id": matched_entity_id}, blocking=True, return_response=True, ) # Extract the response text - response_text = (result.get("response", - {}).get("speech", - {}).get("plain", - {}).get("speech", "")) + response_text = ( + result.get("response", {}) + .get("speech", {}) + .get("plain", {}) + .get("speech", "") + ) # Create and return a response response = intent_obj.create_response() @@ -98,8 +96,7 @@ class RandomNumberIntentHandler(intent.IntentHandler): "to": vol.All(vol.Coerce(int), vol.Range(min=0, max=999999999)), } - async def async_handle(self, - intent_obj: intent.Intent) -> intent.IntentResponse: + async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" # Extract the slot values slots = intent_obj.slots @@ -123,8 +120,7 @@ class CurrentTimeIntentHandler(intent.IntentHandler): description = "Get the current time." - async def async_handle(self, - intent_obj: intent.Intent) -> intent.IntentResponse: + async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse: """Handle the intent.""" # Retrieve the user's timezone from Home Assistant configuration user_timezone = intent_obj.hass.config.time_zone diff --git a/custom_sentences/en/custom_sentences.yaml b/custom_sentences/en/custom_sentences.yaml index 99869c6..55ea30a 100644 --- a/custom_sentences/en/custom_sentences.yaml +++ b/custom_sentences/en/custom_sentences.yaml @@ -1,26 +1,26 @@ -language: "en" +language: 'en' intents: ConversationProcess: data: - sentences: - - "(Ask | Tell) {name} [to] {text}" + - '(Ask | Tell) {name} [to] {text}' requires_context: domain: conversation RandomNumber: data: - sentences: - - "(Pick|Generate) a [random] number between {random_range:from} and {random_range:to}" - - "(Pick|Generate) a [random] number [from] {random_range:from} (through | to) {random_range:to}" + - '(Pick|Generate) a [random] number between {random_range:from} and {random_range:to}' + - '(Pick|Generate) a [random] number [from] {random_range:from} (through | to) {random_range:to}' - sentences: - - "(Pick|Generate) a [random] number (below | up to) {random_range:to}" + - '(Pick|Generate) a [random] number (below | up to) {random_range:to}' slots: from: 1 CurrentTime: data: - sentences: - "What's the time" - - "What is the time" - - "What time is it" + - 'What is the time' + - 'What time is it' lists: text: wildcard: true