Add Mealie service to get mealplan (#120824)

Co-authored-by: Robert Resch <robert@resch.dev>
This commit is contained in:
Joost Lekkerkerker 2024-07-07 21:19:20 +02:00 committed by GitHub
parent 833ac4db49
commit f126360c67
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 572 additions and 2 deletions

View file

@ -7,15 +7,25 @@ from aiomealie import MealieAuthenticationError, MealieClient, MealieConnectionE
from homeassistant.const import CONF_API_TOKEN, CONF_HOST, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryError, ConfigEntryNotReady
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers import config_validation as cv, device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.typing import ConfigType
from .const import DOMAIN
from .coordinator import MealieConfigEntry, MealieCoordinator
from .services import setup_services
PLATFORMS: list[Platform] = [Platform.CALENDAR]
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Mealie component."""
setup_services(hass)
return True
async def async_setup_entry(hass: HomeAssistant, entry: MealieConfigEntry) -> bool:
"""Set up Mealie from a config entry."""

View file

@ -10,7 +10,7 @@ from homeassistant.components.calendar import CalendarEntity, CalendarEvent
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from . import MealieConfigEntry, MealieCoordinator
from .coordinator import MealieConfigEntry, MealieCoordinator
from .entity import MealieEntity

View file

@ -5,3 +5,7 @@ import logging
DOMAIN = "mealie"
LOGGER = logging.getLogger(__package__)
ATTR_CONFIG_ENTRY_ID = "config_entry_id"
ATTR_START_DATE = "start_date"
ATTR_END_DATE = "end_date"

View file

@ -0,0 +1,5 @@
{
"services": {
"get_mealplan": "mdi:food"
}
}

View file

@ -0,0 +1,69 @@
"""Define services for the Mealie integration."""
from dataclasses import asdict
from datetime import date
from typing import cast
import voluptuous as vol
from homeassistant.config_entries import ConfigEntryState
from homeassistant.core import (
HomeAssistant,
ServiceCall,
ServiceResponse,
SupportsResponse,
)
from homeassistant.exceptions import ServiceValidationError
from .const import ATTR_CONFIG_ENTRY_ID, ATTR_END_DATE, ATTR_START_DATE, DOMAIN
from .coordinator import MealieConfigEntry
SERVICE_GET_MEALPLAN = "get_mealplan"
SERVICE_GET_MEALPLAN_SCHEMA = vol.Schema(
{
vol.Required(ATTR_CONFIG_ENTRY_ID): str,
vol.Optional(ATTR_START_DATE): date,
vol.Optional(ATTR_END_DATE): date,
}
)
def setup_services(hass: HomeAssistant) -> None:
"""Set up the services for the Mealie integration."""
async def async_get_mealplan(call: ServiceCall) -> ServiceResponse:
"""Get the mealplan for a specific range."""
if not (
entry := hass.config_entries.async_get_entry(
call.data[ATTR_CONFIG_ENTRY_ID]
)
):
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="integration_not_found",
translation_placeholders={"target": DOMAIN},
)
if entry.state is not ConfigEntryState.LOADED:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="not_loaded",
translation_placeholders={"target": entry.title},
)
start_date = call.data.get(ATTR_START_DATE, date.today())
end_date = call.data.get(ATTR_END_DATE, date.today())
if end_date < start_date:
raise ServiceValidationError(
translation_domain=DOMAIN,
translation_key="end_date_before_start_date",
)
client = cast(MealieConfigEntry, entry).runtime_data.client
mealplans = await client.get_mealplans(start_date, end_date)
return {"mealplan": [asdict(x) for x in mealplans.items]}
hass.services.async_register(
DOMAIN,
SERVICE_GET_MEALPLAN,
async_get_mealplan,
schema=SERVICE_GET_MEALPLAN_SCHEMA,
supports_response=SupportsResponse.ONLY,
)

View file

@ -0,0 +1,13 @@
get_mealplan:
fields:
config_entry_id:
required: true
selector:
config_entry:
integration: mealie
start_date:
selector:
date:
end_date:
selector:
date:

View file

@ -35,5 +35,36 @@
"name": "Side"
}
}
},
"exceptions": {
"not_loaded": {
"message": "{target} is not loaded."
},
"integration_not_found": {
"message": "Integration \"{target}\" not found in registry."
},
"end_date_before_start_date": {
"message": "End date must be after start date."
}
},
"services": {
"get_mealplan": {
"name": "Get mealplan",
"description": "Get meaplan from Mealie",
"fields": {
"config_entry_id": {
"name": "Mealie instance",
"description": "Select the Mealie instance to get mealplan from"
},
"start_date": {
"name": "Start date",
"description": "The startdate of the data to get (default: today)."
},
"end_date": {
"name": "End date",
"description": "The enddate of the data to get (default: today)."
}
}
}
}
}

View file

@ -0,0 +1,297 @@
# serializer version: 1
# name: test_service_mealplan
dict({
'mealplan': list([
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 22),
'mealplan_id': 230,
'recipe': dict({
'description': "Een traybake is eigenlijk altijd een goed idee. Deze zoete aardappel curry traybake dus ook. Waarom? Omdat je alleen maar wat groenten - en in dit geval kip - op een bakplaat (traybake dus) legt, hier wat kruiden aan toevoegt en deze in de oven schuift. Ideaal dus als je geen zin hebt om lang in de keuken te staan. Maar gewoon lekker op de bank wil ploffen om te wachten tot de oven klaar is. Joe! That\\'s what we like. Deze zoete aardappel curry traybake bevat behalve zoete aardappel en curry ook kikkererwten, kippendijfilet en bloemkoolroosjes. Je gebruikt yoghurt en limoen als een soort dressing. En je serveert deze heerlijke traybake met naanbrood. Je kunt natuurljk ook voor deze traybake met chipolataworstjes gaan. Wil je graag meer ovengerechten? Dan moet je eigenlijk even kijken naar onze Ovenbijbel. Onmisbaar in je keuken! We willen je deze zoete aardappelstamppot met prei ook niet onthouden. Megalekker bordje comfortfood als je \\'t ons vraagt.",
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'AiIo',
'name': 'Zoete aardappel curry traybake',
'original_url': 'https://chickslovefood.com/recept/zoete-aardappel-curry-traybake/',
'recipe_id': 'c5f00a93-71a2-4e48-900f-d9ad0bb9de93',
'recipe_yield': '2 servings',
'slug': 'zoete-aardappel-curry-traybake',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.BREAKFAST: 'breakfast'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 229,
'recipe': dict({
'description': 'The BEST Roast Chicken recipe is simple, budget friendly, and gives you a tender, mouth-watering chicken full of flavor! Served with roasted vegetables, this recipe is simple enough for any cook!',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'JeQ2',
'name': 'Roast Chicken',
'original_url': 'https://tastesbetterfromscratch.com/roast-chicken/',
'recipe_id': '5b055066-d57d-4fd0-8dfd-a2c2f07b36f1',
'recipe_yield': '6 servings',
'slug': 'roast-chicken',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.LUNCH: 'lunch'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 226,
'recipe': dict({
'description': 'Te explicamos paso a paso, de manera sencilla, la elaboración de la receta de pollo al curry con leche de coco en 10 minutos. Ingredientes, tiempo de...',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'INQz',
'name': 'Receta de pollo al curry en 10 minutos (con vídeo incluido)',
'original_url': 'https://www.directoalpaladar.com/recetas-de-carnes-y-aves/receta-de-pollo-al-curry-en-10-minutos',
'recipe_id': 'e360a0cc-18b0-4a84-a91b-8aa59e2451c9',
'recipe_yield': '2 servings',
'slug': 'receta-de-pollo-al-curry-en-10-minutos-con-video-incluido',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.LUNCH: 'lunch'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 224,
'recipe': dict({
'description': 'bourguignon, oignon, carotte, bouquet garni, vin rouge, beurre, sel, poivre',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'nj5M',
'name': 'Boeuf bourguignon : la vraie recette (2)',
'original_url': 'https://www.marmiton.org/recettes/recette_boeuf-bourguignon_18889.aspx',
'recipe_id': '9c7b8aee-c93c-4b1b-ab48-2625d444743a',
'recipe_yield': '4 servings',
'slug': 'boeuf-bourguignon-la-vraie-recette-2',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 222,
'recipe': dict({
'description': 'Εύκολη μακαρονάδα με κεφτεδάκια στον φούρνο από τον Άκη Πετρετζίκη. Φτιάξτε την πιο εύκολη μακαρονάδα με κεφτεδάκια σε μόνο ένα σκεύος.',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'En9o',
'name': 'Εύκολη μακαρονάδα με κεφτεδάκια στον φούρνο (1)',
'original_url': 'https://akispetretzikis.com/recipe/7959/efkolh-makaronada-me-keftedakia-ston-fourno',
'recipe_id': 'f79f7e9d-4b58-4930-a586-2b127f16ee34',
'recipe_yield': '6 servings',
'slug': 'eukole-makaronada-me-kephtedakia-ston-phourno-1',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 221,
'recipe': dict({
'description': 'Delicious Greek turkey meatballs with lemon orzo, tender veggies, and a creamy feta yogurt sauce. These healthy baked Greek turkey meatballs are filled with tons of wonderful herbs and make the perfect protein-packed weeknight meal!',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'Kn62',
'name': 'Greek Turkey Meatballs with Lemon Orzo & Creamy Feta Yogurt Sauce',
'original_url': 'https://www.ambitiouskitchen.com/greek-turkey-meatballs/',
'recipe_id': '47595e4c-52bc-441d-b273-3edf4258806d',
'recipe_yield': '4 servings',
'slug': 'greek-turkey-meatballs-with-lemon-orzo-creamy-feta-yogurt-sauce',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.SIDE: 'side'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 220,
'recipe': dict({
'description': 'Einfacher Nudelauflauf mit Brokkoli, Sahnesauce und extra Käse. Dieses vegetarische 5 Zutaten Rezept ist super schnell gemacht und SO gut!',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'nOPT',
'name': 'Einfacher Nudelauflauf mit Brokkoli',
'original_url': 'https://kochkarussell.com/einfacher-nudelauflauf-brokkoli/',
'recipe_id': '9d553779-607e-471b-acf3-84e6be27b159',
'recipe_yield': '4 servings',
'slug': 'einfacher-nudelauflauf-mit-brokkoli',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 219,
'recipe': dict({
'description': 'This is a modified Pampered Chef recipe. You can use a trifle bowl or large glass punch/salad bowl to show it off. It is really easy to make and I never have any leftovers. Cook time includes chill time.',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'ibL6',
'name': 'Pampered Chef Double Chocolate Mocha Trifle',
'original_url': 'https://www.food.com/recipe/pampered-chef-double-chocolate-mocha-trifle-74963',
'recipe_id': '92635fd0-f2dc-4e78-a6e4-ecd556ad361f',
'recipe_yield': '12 servings',
'slug': 'pampered-chef-double-chocolate-mocha-trifle',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 22),
'mealplan_id': 217,
'recipe': dict({
'description': 'Cheeseburger Sliders are juicy, cheesy and beefy - everything we love about classic burgers! These sliders are quick and easy plus they are make-ahead and reheat really well.',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'beGq',
'name': 'Cheeseburger Sliders (Easy, 30-min Recipe)',
'original_url': 'https://natashaskitchen.com/cheeseburger-sliders/',
'recipe_id': '8bdd3656-5e7e-45d3-a3c4-557390846a22',
'recipe_yield': '24 servings',
'slug': 'cheeseburger-sliders-easy-30-min-recipe',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.LUNCH: 'lunch'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 22),
'mealplan_id': 216,
'recipe': dict({
'description': 'This All-American beef stew recipe includes tender beef coated in a rich, intense sauce and vegetables that bring complementary texture and flavor.',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': '356X',
'name': 'All-American Beef Stew Recipe',
'original_url': 'https://www.seriouseats.com/all-american-beef-stew-recipe',
'recipe_id': '48f39d27-4b8e-4c14-bf36-4e1e6497e75e',
'recipe_yield': '6 servings',
'slug': 'all-american-beef-stew-recipe',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 212,
'recipe': dict({
'description': 'This All-American beef stew recipe includes tender beef coated in a rich, intense sauce and vegetables that bring complementary texture and flavor.',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': '356X',
'name': 'All-American Beef Stew Recipe',
'original_url': 'https://www.seriouseats.com/all-american-beef-stew-recipe',
'recipe_id': '48f39d27-4b8e-4c14-bf36-4e1e6497e75e',
'recipe_yield': '6 servings',
'slug': 'all-american-beef-stew-recipe',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 22),
'mealplan_id': 211,
'recipe': dict({
'description': 'Einfacher Nudelauflauf mit Brokkoli, Sahnesauce und extra Käse. Dieses vegetarische 5 Zutaten Rezept ist super schnell gemacht und SO gut!',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'nOPT',
'name': 'Einfacher Nudelauflauf mit Brokkoli',
'original_url': 'https://kochkarussell.com/einfacher-nudelauflauf-brokkoli/',
'recipe_id': '9d553779-607e-471b-acf3-84e6be27b159',
'recipe_yield': '4 servings',
'slug': 'einfacher-nudelauflauf-mit-brokkoli',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 23),
'mealplan_id': 196,
'recipe': dict({
'description': 'Simple to prepare and ready in 25 minutes, this vegetarian miso noodle recipe can be eaten on its own or served as a side.',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': '5G1v',
'name': 'Miso Udon Noodles with Spinach and Tofu',
'original_url': 'https://www.allrecipes.com/recipe/284039/miso-udon-noodles-with-spinach-and-tofu/',
'recipe_id': '25b814f2-d9bf-4df0-b40d-d2f2457b4317',
'recipe_yield': '2 servings',
'slug': 'miso-udon-noodles-with-spinach-and-tofu',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': None,
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'mealplan_date': FakeDate(2024, 1, 22),
'mealplan_id': 195,
'recipe': dict({
'description': 'Avis aux nostalgiques des années 1980, la mousse de saumon est de retour dans une présentation adaptée au goût du jour. On utilise une technique sans faille : un saumon frais cuit au micro-ondes et mélangé au robot avec du fromage à la crème et de la crème sure. On obtient ainsi une texture onctueuse à tartiner, qui na rien à envier aux préparations gélatineuses dantan !',
'group_id': '0bf60b2e-ca89-42a9-94d4-8f67ca72b157',
'image': 'rrNL',
'name': 'Mousse de saumon',
'original_url': 'https://www.ricardocuisine.com/recettes/8919-mousse-de-saumon',
'recipe_id': '55c88810-4cf1-4d86-ae50-63b15fd173fb',
'recipe_yield': '12 servings',
'slug': 'mousse-de-saumon',
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
'title': None,
'user_id': '1ce8b5fe-04e8-4b80-aab1-d92c94685c6d',
}),
dict({
'description': 'Dineren met de boys',
'entry_type': <MealplanEntryType.DINNER: 'dinner'>,
'group_id': '3931df86-0679-4579-8c63-4bedc9ca9a85',
'mealplan_date': FakeDate(2024, 1, 21),
'mealplan_id': 1,
'recipe': None,
'title': 'Aquavite',
'user_id': '6caa6e4d-521f-4ef4-9ed7-388bdd63f47d',
}),
]),
})
# ---

View file

@ -0,0 +1,141 @@
"""Tests for the Mealie services."""
from datetime import date
from unittest.mock import AsyncMock
from freezegun.api import FrozenDateTimeFactory
import pytest
from syrupy import SnapshotAssertion
from homeassistant.components.mealie.const import (
ATTR_CONFIG_ENTRY_ID,
ATTR_END_DATE,
ATTR_START_DATE,
DOMAIN,
)
from homeassistant.components.mealie.services import SERVICE_GET_MEALPLAN
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ServiceValidationError
from . import setup_integration
from tests.common import MockConfigEntry
async def test_service_mealplan(
hass: HomeAssistant,
mock_mealie_client: AsyncMock,
mock_config_entry: MockConfigEntry,
snapshot: SnapshotAssertion,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test the get_mealplan service."""
await setup_integration(hass, mock_config_entry)
freezer.move_to("2023-10-21")
response = await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id},
blocking=True,
return_response=True,
)
assert mock_mealie_client.get_mealplans.call_args_list[1][0] == (
date(2023, 10, 21),
date(2023, 10, 21),
)
assert response == snapshot
response = await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{
ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id,
ATTR_START_DATE: date(2023, 10, 22),
ATTR_END_DATE: date(2023, 10, 25),
},
blocking=True,
return_response=True,
)
assert response
assert mock_mealie_client.get_mealplans.call_args_list[2][0] == (
date(2023, 10, 22),
date(2023, 10, 25),
)
response = await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{
ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id,
ATTR_START_DATE: date(2023, 10, 19),
},
blocking=True,
return_response=True,
)
assert response
assert mock_mealie_client.get_mealplans.call_args_list[3][0] == (
date(2023, 10, 19),
date(2023, 10, 21),
)
response = await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{
ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id,
ATTR_END_DATE: date(2023, 10, 22),
},
blocking=True,
return_response=True,
)
assert response
assert mock_mealie_client.get_mealplans.call_args_list[4][0] == (
date(2023, 10, 21),
date(2023, 10, 22),
)
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{
ATTR_CONFIG_ENTRY_ID: mock_config_entry.entry_id,
ATTR_START_DATE: date(2023, 10, 22),
ATTR_END_DATE: date(2023, 10, 19),
},
blocking=True,
return_response=True,
)
async def test_service_mealplan_without_entry(
hass: HomeAssistant,
mock_config_entry: MockConfigEntry,
) -> None:
"""Test the get_mealplan service without entry."""
mock_config_entry.add_to_hass(hass)
mock_config_entry2 = MockConfigEntry(domain=DOMAIN)
mock_config_entry2.add_to_hass(hass)
await hass.config_entries.async_setup(mock_config_entry.entry_id)
await hass.async_block_till_done()
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{ATTR_CONFIG_ENTRY_ID: mock_config_entry2.entry_id},
blocking=True,
return_response=True,
)
with pytest.raises(ServiceValidationError):
await hass.services.async_call(
DOMAIN,
SERVICE_GET_MEALPLAN,
{ATTR_CONFIG_ENTRY_ID: "bad-config_id"},
blocking=True,
return_response=True,
)