Home Assistant Unofficial Reference 2024.12.1
services.py
Go to the documentation of this file.
1 """Define services for the Mealie integration."""
2 
3 from dataclasses import asdict
4 from datetime import date
5 from typing import cast
6 
7 from aiomealie import (
8  MealieConnectionError,
9  MealieNotFoundError,
10  MealieValidationError,
11  MealplanEntryType,
12 )
13 import voluptuous as vol
14 
15 from homeassistant.config_entries import ConfigEntryState
16 from homeassistant.const import ATTR_DATE
17 from homeassistant.core import (
18  HomeAssistant,
19  ServiceCall,
20  ServiceResponse,
21  SupportsResponse,
22 )
23 from homeassistant.exceptions import HomeAssistantError, ServiceValidationError
24 from homeassistant.helpers import config_validation as cv
25 
26 from .const import (
27  ATTR_CONFIG_ENTRY_ID,
28  ATTR_END_DATE,
29  ATTR_ENTRY_TYPE,
30  ATTR_INCLUDE_TAGS,
31  ATTR_NOTE_TEXT,
32  ATTR_NOTE_TITLE,
33  ATTR_RECIPE_ID,
34  ATTR_START_DATE,
35  ATTR_URL,
36  DOMAIN,
37 )
38 from .coordinator import MealieConfigEntry
39 
40 SERVICE_GET_MEALPLAN = "get_mealplan"
41 SERVICE_GET_MEALPLAN_SCHEMA = vol.Schema(
42  {
43  vol.Required(ATTR_CONFIG_ENTRY_ID): str,
44  vol.Optional(ATTR_START_DATE): cv.date,
45  vol.Optional(ATTR_END_DATE): cv.date,
46  }
47 )
48 
49 SERVICE_GET_RECIPE = "get_recipe"
50 SERVICE_GET_RECIPE_SCHEMA = vol.Schema(
51  {
52  vol.Required(ATTR_CONFIG_ENTRY_ID): str,
53  vol.Required(ATTR_RECIPE_ID): str,
54  }
55 )
56 
57 SERVICE_IMPORT_RECIPE = "import_recipe"
58 SERVICE_IMPORT_RECIPE_SCHEMA = vol.Schema(
59  {
60  vol.Required(ATTR_CONFIG_ENTRY_ID): str,
61  vol.Required(ATTR_URL): str,
62  vol.Optional(ATTR_INCLUDE_TAGS): bool,
63  }
64 )
65 
66 SERVICE_SET_RANDOM_MEALPLAN = "set_random_mealplan"
67 SERVICE_SET_RANDOM_MEALPLAN_SCHEMA = vol.Schema(
68  {
69  vol.Required(ATTR_CONFIG_ENTRY_ID): str,
70  vol.Required(ATTR_DATE): cv.date,
71  vol.Required(ATTR_ENTRY_TYPE): vol.In([x.lower() for x in MealplanEntryType]),
72  }
73 )
74 
75 SERVICE_SET_MEALPLAN = "set_mealplan"
76 SERVICE_SET_MEALPLAN_SCHEMA = vol.Any(
77  vol.Schema(
78  {
79  vol.Required(ATTR_CONFIG_ENTRY_ID): str,
80  vol.Required(ATTR_DATE): cv.date,
81  vol.Required(ATTR_ENTRY_TYPE): vol.In(
82  [x.lower() for x in MealplanEntryType]
83  ),
84  vol.Required(ATTR_RECIPE_ID): str,
85  }
86  ),
87  vol.Schema(
88  {
89  vol.Required(ATTR_CONFIG_ENTRY_ID): str,
90  vol.Required(ATTR_DATE): cv.date,
91  vol.Required(ATTR_ENTRY_TYPE): vol.In(
92  [x.lower() for x in MealplanEntryType]
93  ),
94  vol.Required(ATTR_NOTE_TITLE): str,
95  vol.Required(ATTR_NOTE_TEXT): str,
96  }
97  ),
98 )
99 
100 
101 def async_get_entry(hass: HomeAssistant, config_entry_id: str) -> MealieConfigEntry:
102  """Get the Mealie config entry."""
103  if not (entry := hass.config_entries.async_get_entry(config_entry_id)):
105  translation_domain=DOMAIN,
106  translation_key="integration_not_found",
107  translation_placeholders={"target": DOMAIN},
108  )
109  if entry.state is not ConfigEntryState.LOADED:
111  translation_domain=DOMAIN,
112  translation_key="not_loaded",
113  translation_placeholders={"target": entry.title},
114  )
115  return cast(MealieConfigEntry, entry)
116 
117 
118 def setup_services(hass: HomeAssistant) -> None:
119  """Set up the services for the Mealie integration."""
120 
121  async def async_get_mealplan(call: ServiceCall) -> ServiceResponse:
122  """Get the mealplan for a specific range."""
123  entry = async_get_entry(hass, call.data[ATTR_CONFIG_ENTRY_ID])
124  start_date = call.data.get(ATTR_START_DATE, date.today())
125  end_date = call.data.get(ATTR_END_DATE, date.today())
126  if end_date < start_date:
128  translation_domain=DOMAIN,
129  translation_key="end_date_before_start_date",
130  )
131  client = cast(MealieConfigEntry, entry).runtime_data.client
132  try:
133  mealplans = await client.get_mealplans(start_date, end_date)
134  except MealieConnectionError as err:
135  raise HomeAssistantError(
136  translation_domain=DOMAIN,
137  translation_key="connection_error",
138  ) from err
139  return {"mealplan": [asdict(x) for x in mealplans.items]}
140 
141  async def async_get_recipe(call: ServiceCall) -> ServiceResponse:
142  """Get a recipe."""
143  entry = async_get_entry(hass, call.data[ATTR_CONFIG_ENTRY_ID])
144  recipe_id = call.data[ATTR_RECIPE_ID]
145  client = entry.runtime_data.client
146  try:
147  recipe = await client.get_recipe(recipe_id)
148  except MealieConnectionError as err:
149  raise HomeAssistantError(
150  translation_domain=DOMAIN,
151  translation_key="connection_error",
152  ) from err
153  except MealieNotFoundError as err:
155  translation_domain=DOMAIN,
156  translation_key="recipe_not_found",
157  translation_placeholders={"recipe_id": recipe_id},
158  ) from err
159  return {"recipe": asdict(recipe)}
160 
161  async def async_import_recipe(call: ServiceCall) -> ServiceResponse:
162  """Import a recipe."""
163  entry = async_get_entry(hass, call.data[ATTR_CONFIG_ENTRY_ID])
164  url = call.data[ATTR_URL]
165  include_tags = call.data.get(ATTR_INCLUDE_TAGS, False)
166  client = entry.runtime_data.client
167  try:
168  recipe = await client.import_recipe(url, include_tags)
169  except MealieValidationError as err:
171  translation_domain=DOMAIN,
172  translation_key="could_not_import_recipe",
173  ) from err
174  except MealieConnectionError as err:
175  raise HomeAssistantError(
176  translation_domain=DOMAIN,
177  translation_key="connection_error",
178  ) from err
179  if call.return_response:
180  return {"recipe": asdict(recipe)}
181  return None
182 
183  async def async_set_random_mealplan(call: ServiceCall) -> ServiceResponse:
184  """Set a random mealplan."""
185  entry = async_get_entry(hass, call.data[ATTR_CONFIG_ENTRY_ID])
186  mealplan_date = call.data[ATTR_DATE]
187  entry_type = MealplanEntryType(call.data[ATTR_ENTRY_TYPE])
188  client = entry.runtime_data.client
189  try:
190  mealplan = await client.random_mealplan(mealplan_date, entry_type)
191  except MealieConnectionError as err:
192  raise HomeAssistantError(
193  translation_domain=DOMAIN,
194  translation_key="connection_error",
195  ) from err
196  if call.return_response:
197  return {"mealplan": asdict(mealplan)}
198  return None
199 
200  async def async_set_mealplan(call: ServiceCall) -> ServiceResponse:
201  """Set a mealplan."""
202  entry = async_get_entry(hass, call.data[ATTR_CONFIG_ENTRY_ID])
203  mealplan_date = call.data[ATTR_DATE]
204  entry_type = MealplanEntryType(call.data[ATTR_ENTRY_TYPE])
205  client = entry.runtime_data.client
206  try:
207  mealplan = await client.set_mealplan(
208  mealplan_date,
209  entry_type,
210  recipe_id=call.data.get(ATTR_RECIPE_ID),
211  note_title=call.data.get(ATTR_NOTE_TITLE),
212  note_text=call.data.get(ATTR_NOTE_TEXT),
213  )
214  except MealieConnectionError as err:
215  raise HomeAssistantError(
216  translation_domain=DOMAIN,
217  translation_key="connection_error",
218  ) from err
219  if call.return_response:
220  return {"mealplan": asdict(mealplan)}
221  return None
222 
223  hass.services.async_register(
224  DOMAIN,
225  SERVICE_GET_MEALPLAN,
226  async_get_mealplan,
227  schema=SERVICE_GET_MEALPLAN_SCHEMA,
228  supports_response=SupportsResponse.ONLY,
229  )
230  hass.services.async_register(
231  DOMAIN,
232  SERVICE_GET_RECIPE,
233  async_get_recipe,
234  schema=SERVICE_GET_RECIPE_SCHEMA,
235  supports_response=SupportsResponse.ONLY,
236  )
237  hass.services.async_register(
238  DOMAIN,
239  SERVICE_IMPORT_RECIPE,
240  async_import_recipe,
241  schema=SERVICE_IMPORT_RECIPE_SCHEMA,
242  supports_response=SupportsResponse.OPTIONAL,
243  )
244  hass.services.async_register(
245  DOMAIN,
246  SERVICE_SET_RANDOM_MEALPLAN,
247  async_set_random_mealplan,
248  schema=SERVICE_SET_RANDOM_MEALPLAN_SCHEMA,
249  supports_response=SupportsResponse.OPTIONAL,
250  )
251  hass.services.async_register(
252  DOMAIN,
253  SERVICE_SET_MEALPLAN,
254  async_set_mealplan,
255  schema=SERVICE_SET_MEALPLAN_SCHEMA,
256  supports_response=SupportsResponse.OPTIONAL,
257  )
None setup_services(HomeAssistant hass)
Definition: services.py:118
MealieConfigEntry async_get_entry(HomeAssistant hass, str config_entry_id)
Definition: services.py:101