mirror of
https://github.com/home-assistant/core.git
synced 2025-07-03 11:27:05 +00:00
Add complete intent function for shopping list component (#128565)
* add intent * add tests * raise IntentHandleError * add check for non completed * Prefer completing non complete items * cleanup * cleanup tests * rename test Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com> * remove duplicated test * update test * complete all items * fix event * remove type def * return speech slots --------- Co-authored-by: Abílio Costa <abmantis@users.noreply.github.com>
This commit is contained in:
parent
4fcebf18dc
commit
c20ad5fde1
@ -92,13 +92,10 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b
|
||||
"""Mark the first item with matching `name` as completed."""
|
||||
data = hass.data[DOMAIN]
|
||||
name = call.data[ATTR_NAME]
|
||||
|
||||
try:
|
||||
item = [item for item in data.items if item["name"] == name][0]
|
||||
except IndexError:
|
||||
_LOGGER.error("Updating of item failed: %s cannot be found", name)
|
||||
else:
|
||||
await data.async_update(item["id"], {"name": name, "complete": True})
|
||||
await data.async_complete(name)
|
||||
except NoMatchingShoppingListItem:
|
||||
_LOGGER.error("Completing of item failed: %s cannot be found", name)
|
||||
|
||||
async def incomplete_item_service(call: ServiceCall) -> None:
|
||||
"""Mark the first item with matching `name` as incomplete."""
|
||||
@ -258,6 +255,30 @@ class ShoppingData:
|
||||
)
|
||||
return removed
|
||||
|
||||
async def async_complete(
|
||||
self, name: str, context: Context | None = None
|
||||
) -> list[dict[str, JsonValueType]]:
|
||||
"""Mark all shopping list items with the given name as complete."""
|
||||
complete_items = [
|
||||
item for item in self.items if item["name"] == name and not item["complete"]
|
||||
]
|
||||
|
||||
if len(complete_items) == 0:
|
||||
raise NoMatchingShoppingListItem
|
||||
|
||||
for item in complete_items:
|
||||
_LOGGER.debug("Completing %s", item)
|
||||
item["complete"] = True
|
||||
await self.hass.async_add_executor_job(self.save)
|
||||
self._async_notify()
|
||||
for item in complete_items:
|
||||
self.hass.bus.async_fire(
|
||||
EVENT_SHOPPING_LIST_UPDATED,
|
||||
{"action": "complete", "item": item},
|
||||
context=context,
|
||||
)
|
||||
return complete_items
|
||||
|
||||
async def async_update(
|
||||
self, item_id: str | None, info: dict[str, Any], context: Context | None = None
|
||||
) -> dict[str, JsonValueType]:
|
||||
|
@ -5,15 +5,17 @@ from __future__ import annotations
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import config_validation as cv, intent
|
||||
|
||||
from . import DOMAIN, EVENT_SHOPPING_LIST_UPDATED
|
||||
from . import DOMAIN, EVENT_SHOPPING_LIST_UPDATED, NoMatchingShoppingListItem
|
||||
|
||||
INTENT_ADD_ITEM = "HassShoppingListAddItem"
|
||||
INTENT_COMPLETE_ITEM = "HassShoppingListCompleteItem"
|
||||
INTENT_LAST_ITEMS = "HassShoppingListLastItems"
|
||||
|
||||
|
||||
async def async_setup_intents(hass: HomeAssistant) -> None:
|
||||
"""Set up the Shopping List intents."""
|
||||
intent.async_register(hass, AddItemIntent())
|
||||
intent.async_register(hass, CompleteItemIntent())
|
||||
intent.async_register(hass, ListTopItemsIntent())
|
||||
|
||||
|
||||
@ -36,6 +38,33 @@ class AddItemIntent(intent.IntentHandler):
|
||||
return response
|
||||
|
||||
|
||||
class CompleteItemIntent(intent.IntentHandler):
|
||||
"""Handle CompleteItem intents."""
|
||||
|
||||
intent_type = INTENT_COMPLETE_ITEM
|
||||
description = "Marks an item as completed on the shopping list"
|
||||
slot_schema = {"item": cv.string}
|
||||
platforms = {DOMAIN}
|
||||
|
||||
async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
|
||||
"""Handle the intent."""
|
||||
slots = self.async_validate_slots(intent_obj.slots)
|
||||
item = slots["item"]["value"].strip()
|
||||
|
||||
try:
|
||||
complete_items = await intent_obj.hass.data[DOMAIN].async_complete(item)
|
||||
except NoMatchingShoppingListItem:
|
||||
complete_items = []
|
||||
|
||||
intent_obj.hass.bus.async_fire(EVENT_SHOPPING_LIST_UPDATED)
|
||||
|
||||
response = intent_obj.create_response()
|
||||
response.async_set_speech_slots({"completed_items": complete_items})
|
||||
response.response_type = intent.IntentResponseType.ACTION_DONE
|
||||
|
||||
return response
|
||||
|
||||
|
||||
class ListTopItemsIntent(intent.IntentHandler):
|
||||
"""Handle AddItem intents."""
|
||||
|
||||
@ -47,7 +76,7 @@ class ListTopItemsIntent(intent.IntentHandler):
|
||||
async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
|
||||
"""Handle the intent."""
|
||||
items = intent_obj.hass.data[DOMAIN].items[-5:]
|
||||
response = intent_obj.create_response()
|
||||
response: intent.IntentResponse = intent_obj.create_response()
|
||||
|
||||
if not items:
|
||||
response.async_set_speech("There are no items on your shopping list")
|
||||
|
@ -4,6 +4,52 @@ from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers import intent
|
||||
|
||||
|
||||
async def test_complete_item_intent(hass: HomeAssistant, sl_setup) -> None:
|
||||
"""Test complete item."""
|
||||
await intent.async_handle(
|
||||
hass, "test", "HassShoppingListAddItem", {"item": {"value": "soda"}}
|
||||
)
|
||||
await intent.async_handle(
|
||||
hass, "test", "HassShoppingListAddItem", {"item": {"value": "beer"}}
|
||||
)
|
||||
await intent.async_handle(
|
||||
hass, "test", "HassShoppingListAddItem", {"item": {"value": "beer"}}
|
||||
)
|
||||
await intent.async_handle(
|
||||
hass, "test", "HassShoppingListAddItem", {"item": {"value": "wine"}}
|
||||
)
|
||||
|
||||
response = await intent.async_handle(
|
||||
hass, "test", "HassShoppingListCompleteItem", {"item": {"value": "beer"}}
|
||||
)
|
||||
|
||||
assert response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||
completed_items = response.speech_slots.get("completed_items")
|
||||
assert len(completed_items) == 2
|
||||
assert completed_items[0]["name"] == "beer"
|
||||
assert hass.data["shopping_list"].items[1]["complete"]
|
||||
assert hass.data["shopping_list"].items[2]["complete"]
|
||||
|
||||
# Complete again
|
||||
response = await intent.async_handle(
|
||||
hass, "test", "HassShoppingListCompleteItem", {"item": {"value": "beer"}}
|
||||
)
|
||||
|
||||
assert response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||
assert response.speech_slots.get("completed_items") == []
|
||||
assert hass.data["shopping_list"].items[1]["complete"]
|
||||
assert hass.data["shopping_list"].items[2]["complete"]
|
||||
|
||||
|
||||
async def test_complete_item_intent_not_found(hass: HomeAssistant, sl_setup) -> None:
|
||||
"""Test completing a missing item."""
|
||||
response = await intent.async_handle(
|
||||
hass, "test", "HassShoppingListCompleteItem", {"item": {"value": "beer"}}
|
||||
)
|
||||
assert response.response_type == intent.IntentResponseType.ACTION_DONE
|
||||
assert response.speech_slots.get("completed_items") == []
|
||||
|
||||
|
||||
async def test_recent_items_intent(hass: HomeAssistant, sl_setup) -> None:
|
||||
"""Test recent items."""
|
||||
await intent.async_handle(
|
||||
|
Loading…
x
Reference in New Issue
Block a user