1 """Todo platform for the Bring! integration."""
3 from __future__
import annotations
5 from typing
import TYPE_CHECKING
8 from bring_api
import (
11 BringNotificationType,
12 BringRequestException,
14 import voluptuous
as vol
20 TodoListEntityFeature,
27 from .
import BringConfigEntry
30 ATTR_NOTIFICATION_TYPE,
32 SERVICE_PUSH_NOTIFICATION,
34 from .coordinator
import BringData, BringDataUpdateCoordinator
35 from .entity
import BringBaseEntity
40 config_entry: BringConfigEntry,
41 async_add_entities: AddEntitiesCallback,
43 """Set up the sensor from a config entry created in the integrations UI."""
44 coordinator = config_entry.runtime_data
49 bring_list=bring_list,
51 for bring_list
in coordinator.data.values()
54 platform = entity_platform.async_get_current_platform()
56 platform.async_register_entity_service(
57 SERVICE_PUSH_NOTIFICATION,
59 vol.Required(ATTR_NOTIFICATION_TYPE): vol.All(
60 vol.Upper, cv.enum(BringNotificationType)
62 vol.Optional(ATTR_ITEM_NAME): cv.string,
69 """A To-do List representation of the Bring! Shopping List."""
71 _attr_translation_key =
"shopping_list"
73 _attr_supported_features = (
74 TodoListEntityFeature.CREATE_TODO_ITEM
75 | TodoListEntityFeature.UPDATE_TODO_ITEM
76 | TodoListEntityFeature.DELETE_TODO_ITEM
77 | TodoListEntityFeature.SET_DESCRIPTION_ON_ITEM
81 self, coordinator: BringDataUpdateCoordinator, bring_list: BringData
83 """Initialize the entity."""
84 super().
__init__(coordinator, bring_list)
85 self.
_attr_unique_id_attr_unique_id = f
"{coordinator.config_entry.unique_id}_{self._list_uuid}"
89 """Return the todo items."""
94 summary=item[
"itemId"],
95 description=item[
"specification"]
or "",
96 status=TodoItemStatus.NEEDS_ACTION,
98 for item
in self.
bring_listbring_list[
"purchase"]
103 summary=item[
"itemId"],
104 description=item[
"specification"]
or "",
105 status=TodoItemStatus.COMPLETED,
107 for item
in self.
bring_listbring_list[
"recently"]
113 """Return the bring list."""
114 return self.coordinator.data[self.
_list_uuid_list_uuid]
117 """Add an item to the To-do list."""
119 await self.coordinator.bring.save_item(
122 item.description
or "",
125 except BringRequestException
as e:
127 translation_domain=DOMAIN,
128 translation_key=
"todo_save_item_failed",
129 translation_placeholders={
"name": item.summary
or ""},
135 """Update an item to the To-do list.
137 Bring has an internal 'recent' list which we want to use instead of a todo list
138 status, therefore completed todo list items are matched to the recent list and
139 pending items to the purchase list.
141 This results in following behaviour:
143 - Completed items will move to the "completed" section in home assistant todo
144 list and get moved to the recently list in bring
145 - Bring shows some odd behaviour when renaming items. This is because Bring
146 did not have unique identifiers for items in the past and this is still
147 a relic from it. Therefore the name is not to be changed! Should a name
148 be changed anyway, the item will be deleted and a new item will be created
149 instead and no update for this item is performed and on the next cloud pull
150 update, it will get cleared and replaced seamlessly.
155 bring_purchase_item = next(
156 (i
for i
in bring_list[
"purchase"]
if i[
"uuid"] == item.uid),
160 bring_recently_item = next(
161 (i
for i
in bring_list[
"recently"]
if i[
"uuid"] == item.uid),
165 current_item = bring_purchase_item
or bring_recently_item
171 if item.summary == current_item[
"itemId"]:
173 await self.coordinator.bring.batch_update_list(
174 bring_list[
"listUuid"],
176 itemId=item.summary
or "",
177 spec=item.description
or "",
180 BringItemOperation.ADD
181 if item.status == TodoItemStatus.NEEDS_ACTION
182 else BringItemOperation.COMPLETE,
184 except BringRequestException
as e:
186 translation_domain=DOMAIN,
187 translation_key=
"todo_update_item_failed",
188 translation_placeholders={
"name": item.summary
or ""},
192 await self.coordinator.bring.batch_update_list(
193 bring_list[
"listUuid"],
196 itemId=current_item[
"itemId"],
197 spec=item.description
or "",
199 operation=BringItemOperation.REMOVE,
202 itemId=item.summary
or "",
203 spec=item.description
or "",
204 uuid=
str(uuid.uuid4()),
205 operation=BringItemOperation.ADD
206 if item.status == TodoItemStatus.NEEDS_ACTION
207 else BringItemOperation.COMPLETE,
212 except BringRequestException
as e:
214 translation_domain=DOMAIN,
215 translation_key=
"todo_rename_item_failed",
216 translation_placeholders={
"name": item.summary
or ""},
222 """Delete an item from the To-do list."""
225 await self.coordinator.bring.batch_update_list(
235 BringItemOperation.REMOVE,
237 except BringRequestException
as e:
239 translation_domain=DOMAIN,
240 translation_key=
"todo_delete_item_failed",
241 translation_placeholders={
"count":
str(len(uids))},
248 message: BringNotificationType,
249 item: str |
None =
None,
251 """Send a push notification to members of a shared bring list."""
254 await self.coordinator.bring.notify(self.
_list_uuid_list_uuid, message, item
or None)
255 except BringRequestException
as e:
257 translation_domain=DOMAIN,
258 translation_key=
"notify_request_failed",
260 except ValueError
as e:
262 translation_domain=DOMAIN,
263 translation_key=
"notify_missing_argument_item",
264 translation_placeholders={
265 "service": f
"{DOMAIN}.{SERVICE_PUSH_NOTIFICATION}",
None async_update_todo_item(self, TodoItem item)
list[TodoItem] todo_items(self)
None async_delete_todo_items(self, list[str] uids)
None __init__(self, BringDataUpdateCoordinator coordinator, BringData bring_list)
None async_send_message(self, BringNotificationType message, str|None item=None)
None async_create_todo_item(self, TodoItem item)
BringData bring_list(self)
None async_setup_entry(HomeAssistant hass, BringConfigEntry config_entry, AddEntitiesCallback async_add_entities)