Skip to content

Instantly share code, notes, and snippets.

@supaeasy
Created March 27, 2026 20:28
Show Gist options
  • Select an option

  • Save supaeasy/a5ee63eaa26277004e127a4adb3fa8d6 to your computer and use it in GitHub Desktop.

Select an option

Save supaeasy/a5ee63eaa26277004e127a4adb3fa8d6 to your computer and use it in GitHub Desktop.
Tandoor 2.5.x Shopping List to Bring! Importer via Home Assistant (uses HA Bring! Integration and HACS pyscript)
import requests
from decimal import Decimal
@pyscript_compile
def make_request(url, headers, method='GET', data=None):
if method == 'GET':
response = requests.get(url, headers=headers)
elif method == 'PATCH':
response = requests.patch(url, headers=headers, json=data)
elif method == 'POST':
response = requests.post(url, headers=headers, json=data)
return response.json() if response.status_code != 204 else None
@service
def get_tandoor_list_v2():
api_url = "https://tandoor.domain.tld/api/shopping-list-entry/"
headers = {
"Authorization": "Bearer tda_YOURBEARERTOKEN",
"Content-Type": "application/json"
}
# Ab v2.5.x: Antwort ist paginiert -> alle Seiten abrufen (max. 200 pro Seite)
all_items = []
url = f"{api_url}?page_size=200"
while url:
response_data = task.executor(make_request, url, headers)
if not response_data:
break
all_items.extend(response_data.get("results", []))
url = response_data.get("next")
# Liste der Einheiten ohne Leerzeichen
no_space_units = ['ml', 'l', 'g', 'kg', 'lb', 'fl oz', 'oz']
checked_ids = []
for item in all_items:
# Überspringe Einträge, die bereits als checked markiert sind
if item["checked"]:
continue
description_parts = []
# amount als Decimal parsen (CustomDecimalField gibt String/Decimal zurück)
raw_amount = item.get("amount")
amount = Decimal(str(raw_amount)) if raw_amount else None
if amount == 0:
amount = None
has_unit = item["unit"] and item["unit"]["name"] and item["unit"]["name"] != "-"
# Bestimme den korrekten Namen basierend auf Menge und Einheit
if amount and amount > 1 and not has_unit and item["food"].get("plural_name"):
name = item["food"]["plural_name"]
else:
name = item["food"]["name"]
if amount:
if amount == int(amount):
description_parts.append(str(int(amount)))
else:
description_parts.append(str(amount))
if has_unit:
unit = item["unit"]["name"]
unit_name = item["unit"].get("plural_name") if amount and amount > 1 else unit
if unit.lower() in no_space_units:
description_parts[-1] += unit_name
else:
description_parts.append(unit_name)
if description_parts:
description = " ".join(description_parts)
description_parts = [description]
# Ab v2.5.x: list_recipe_data statt recipe_mealplan
list_recipe_data = item.get("list_recipe_data")
if list_recipe_data:
recipe_data = list_recipe_data.get("recipe_data")
if recipe_data and recipe_data.get("name"):
description_parts.append(f"Für: {recipe_data['name']}")
description = " ".join(description_parts)
# Eintrag zur Bring!-Liste (todo.zuhause) hinzufügen
service.call("todo", "add_item", entity_id="todo.zuhause", item=name, description=description)
checked_ids.append(item["id"])
# Ab v2.5.x: Alle Einträge auf einmal als checked markieren (Bulk-Endpoint)
if checked_ids:
bulk_url = f"{api_url}bulk/"
bulk_data = {"ids": checked_ids, "checked": True}
bulk_response = task.executor(make_request, bulk_url, headers, method='POST', data=bulk_data)
if bulk_response is not None:
log.info(f"Erfolgreich {len(checked_ids)} Einträge als checked markiert in Tandoor API")
else:
log.error(f"Fehler beim Bulk-Markieren. Response: {bulk_response}")
log.info(f"Tandoor-Liste aktualisiert: {len(checked_ids)} Einträge zu todo.zuhause hinzugefügt")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment