Skip to content

About

Home Assistant integration for managing stockpiles with expiry warnings, supply range and shopping lists

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

PrepAssistent

Home Assistant integration for creating and managing stockpiles: food, drinks, first aid supplies, toiletries and more – with expiry warnings, a dashboard, and templates that automatically calculate shopping lists for any number of people and days.

Features

  • Multiple stock lists (e.g. "Basement", "Medicine cabinet", "Emergency supply")
  • Items with category, quantity, target quantity, unit, storage location, notes, purchase date and expiry date
  • Barcode scan: scan a product with the camera and add it directly – product data from Open Food Facts & co., see Barcode scan
  • Batches: the same item several times with different expiry dates ("Duplicate")
  • Opened on: mark one unit as opened – it is split off as its own batch; with "use within after opening (days)" the earlier expiry date applies
  • Supply range: how many days will food (kcal) and drinking water last for your household? Shown as a card in the overview, per list and as a sensor
  • Shopping list in HA: missing items as a to-do list – checking an item off records it as bought, items can be added via voice assistant
  • Bulk selection: record several items as bought at once, move them, set category/location or delete them
  • Manage: custom categories (name, icon, order) and storage locations (rename, delete, use as filter)
  • Lovelace card custom:prep-assistent-card for your own dashboards
  • Expiry warnings: daily check at the configured time → HA notification, optional push message (notify.*) and event prep_assistent_expiry for your own automations
  • Dashboard in the sidebar: key figures, "Expiry at a glance", categories, lists with fill level
  • Templates (JSON/YAML): choose people and days → quantities are calculated → apply as a shopping list
  • Shopping list filter: show missing quantities only; "Record as purchased" sets quantity, purchase date and expiry date (from "shelf life after purchase"; without it the old expiry date is cleared)
  • Sensors for your own dashboards/automations
  • Services for automations and voice assistants
  • Multilingual: German, English, French, Spanish, Italian, Russian, Danish, Norwegian, Swedish, Hungarian, Greek

Languages

Area Language
Panel (UI, date and number format) Language of the logged-in HA user
Template preview and applied items Language of the user applying the template
Notifications, name of the first list, service errors Home Assistant system language
Setup, sensors, services HA translations (translations/)

Unsupported languages fall back to English. Existing items and lists keep their names. When a template is applied again, its items are recognised even after a language change – as long as the template defines names as language objects ({de: …, en: …}); plain-string names only match exactly.

Panel and backend texts live in custom_components/prep_assistent/frontend/i18n/<language>.json. To add a language:

  1. Copy frontend/i18n/en.json, translate it and add the language code to i18n.py (LANGUAGES) and to frontend/prep-common.js (LANGUAGES).
  2. Copy translations/en.json to translations/<language>.json and translate it (setup, sensors, services).
  3. Plural forms are objects with the CLDR categories (one, few, many, other). The panel uses Intl.PluralRules, but the backend (plural_category in i18n.py) only knows special rules for Russian and French – every other language uses one/other. For languages with more forms (e.g. Polish, Czech), add a rule there.

Installation

HACS (custom repository)

Open in HACS

Or add it manually:

  1. HACS → Integrations → ⋮ → Custom repositories → enter https://github.com/anderlin/PrepAssistent, type Integration
  2. Install "PrepAssistent", restart Home Assistant
  3. Settings → Devices & services → Add integration → PrepAssistent

Manual

Copy the folder custom_components/prep_assistent to <config>/custom_components/, restart HA and add the integration.

Requirement: Home Assistant 2025.2 or newer.

Options

Option Meaning Default
Warning lead time How many days before expiry an item counts as "expiring soon" 30
Time of daily check When warnings are sent 08:00
Home Assistant notification Persistent notification in the HA UI on
Push notify service e.g. notify.mobile_app_my_phone empty
People in household Basis for the supply range (can be changed temporarily in the panel) 2
Energy need per person and day For the food supply range 2200 kcal
Drinking water per person and day For the water supply range 2 l

Shopping list (to-do)

The entity todo.prepassistent_shopping_list (name depends on the system language) contains every item whose quantity is below its target quantity, e.g. "Rice (2 kg)", with list and storage location as description. It appears in the To-do lists panel in the sidebar, in the HA app, and can be shown on dashboards with the to-do card.

Action Effect
Check off Recorded as purchased: quantity is raised to the target quantity (never lowered), purchase date today; the expiry date is recalculated from "shelf life after purchase" – if that is not set, the old expiry date is cleared
Add (also via Assist: "Add coffee to the PrepAssistent shopping list") Known item: target quantity +1 (starting from the higher of target and stock). New item: created in the first list with quantity 0 and target 1
Remove Only the need is removed (target = stock), the item itself is kept

Supply range

For each item you can enter kcal per unit and litres of drinking water per unit under More details (example: rice in kg → 3500 kcal, mineral water in l → 1). The emergency supply templates include these values.

Food range  = Σ quantity × kcal per unit ÷ (people × kcal per day)
Water range = Σ quantity × litres per unit ÷ (people × litres per day)
Range       = minimum of both (if one of them has no data, only the other counts)

Expired items are not counted. The overview shows the range for the configured household size; you can change the number of people there to try out scenarios.

Lovelace card

The card is loaded automatically (no resource needed) and appears as "PrepAssistent" in the card picker. All options can be set in the visual editor:

type: custom:prep-assistent-card
title: Pantry            # optional
list: Basement           # optional: name or ID of a list, empty = all lists
show_stats: true         # key figures
show_range: true         # supply range
show_attention: true     # expiry at a glance
show_shopping: true      # shopping list with check-off
show_scan: true          # "Scan product" button (opens the panel with the scanner)
max_items: 5             # entries per section

Barcode scan

The barcode button in the panel header (and in the Stock tab and on the Lovelace card) opens the scanner. After scanning, PrepAssistent shows the product and asks where to add it:

  • Already in stock (same barcode): the stock grows by the number of packs. If you enter an expiry date that differs from the current stock, a new batch is created.
  • Matching items without a barcode, e.g. "Rice 0/5 kg" from a template: the barcode gets linked to the item. Pack sizes are converted to the item's unit, so scanning a 500 g pack adds 0.5 kg. Missing kcal values are filled in.
  • New item: the item dialog opens with name, category, unit, kcal per pack and barcode already filled in.

"Save & scan next" lets you put away a whole shopping trip in one go. "Take out" reduces the stock of the scanned item.

How the camera is used

Where How
Home Assistant Companion app (iOS/Android) the app's native scanner – also works without HTTPS
Browser over HTTPS (or localhost) live camera, detected by the browser (Chrome/Android) or by PrepAssistent's own EAN decoder (Safari, Firefox)
Browser over plain HTTP browsers block the live camera there – take a photo of the barcode or type in the number

Without the Companion app, the browser reads EAN-13, EAN-8 and UPC-A codes, which covers virtually all retail products. With the Companion app or Chrome on Android, other formats (Code 128, QR, DataMatrix …) work as well.

Product data comes from the free databases Open Food Facts, Open Beauty Facts, Open Pet Food Facts and Open Products Facts. Only the barcode is sent. Results are cached in Home Assistant (.storage/prep_assistent.products), so a barcode scanned before is recognised offline. Unknown barcodes are only looked up again after a week.

Products not in any database (e.g. medicine): enter the details once. PrepAssistent remembers name, category, unit and shelf life for that barcode, even after the item has been deleted.

Hardware scanners: USB/Bluetooth scanners that type like a keyboard can be used in the search field of the Stock tab (it also searches barcodes). For a fixed scanner station (e.g. ESPHome), call the service prep_assistent.add_barcode from an automation.

Templates

Bundled example templates live in custom_components/prep_assistent/templates/. Your own templates go into <config>/prep_assistent/templates/ (created on first start) and survive updates. A custom template with the same id replaces a bundled one. After changes, click "Reload" in the Templates tab.

Format

id: emergency_family           # optional, otherwise the file name
name: Emergency supply family  # or multilingual, see below
description: Short description
default_persons: 4             # preset in the dialog
default_days: 14
categories:                    # optional: additional categories
  - id: baby
    name: Baby supplies
    icon: mdi:baby-bottle
items:
  - name: Drinking water
    category: getraenke
    unit: l
    per_person_per_day: 2      # 2 l per person and day
    shelf_life_days: 365       # optional: suggested expiry date when buying
    water_per_unit: 1          # optional: litres of drinking water per unit (supply range)
  - name: Rice
    category: lebensmittel
    unit: kg
    per_person_per_day: 0.1
    step: 0.5                  # round up to 0.5 kg
    kcal_per_unit: 3500        # optional: kcal per unit (supply range)
  - name: First aid kit
    category: hausapotheke
    unit: pcs                  # unit code, gets translated (Stk, pcs, шт. …)
    fixed: 1                   # independent of people/days
  - name: Nappies
    category: baby
    unit: pcs
    per_day: 6
    notes: only with a toddler

Multilingual templates

name, description, notes and unit may be a language object instead of a string. The user's language is shown, otherwise English, otherwise German:

name: {de: "Notvorrat", en: "Emergency supply", fr: "Réserve d'urgence"}
items:
  - name: {de: "Trockenfleisch", en: "Dried meat", sv: "Torkat kött"}
    unit: kg
    per_person_per_day: 0.01
    notes:
      de: Vakuumverpackt kaufen
      en: Buy vacuum-packed

Unit codes (translated automatically): pcs, kg, g, l, ml, pack, can, jar, bottle, roll, tube, bar, box, pair, bag, folder, daily_dose, eur. Any other text is used as is.

Calculation

quantity = fixed + per_person × people + per_day × days + per_person_per_day × people × days

The result is then rounded to step (default 1, round: up (default) | nearest | down) and at least min is used. Positions with quantity 0 are dropped.

Examples: per_person: 0.25 with default rounding → 1 piece per started group of 4 people. fixed: 8, per_person: 4, step: 4 → batteries in packs of 4.

Further optional fields per item: opened_shelf_life_days (use within after opening, days). shelf_life_days, opened_shelf_life_days, kcal_per_unit and water_per_unit are copied into the items when applying a template; for existing items only if no value is set there yet.

Category IDs (default): lebensmittel (food), getraenke (drinks), hausapotheke (first aid), drogerie (toiletries), haushalt (household & energy), dokumente (documents & cash), tiere (pets), sonstiges (other).

When applying to an existing list, items with the same name and unit get the new target quantity; all others are created with quantity 0 as shopping positions.

Sensors

Entity Content
Items in stock Number of items with quantity > 0
Expiring soon Count, attribute items
Expired Count, attribute items
Missing items Number of items below target quantity, attribute items
Next expiry date Date, attributes of the item
Supply range Days (minimum of food and water), attributes kcal, water, persons …
Food / water supply range Days per area
Shopping list (todo) Number of missing items, see above

Expiry dates in sensors and events are the effective dates – for opened items the date "opened + use within after opening" if it is earlier (attribute opened: true).

Services

Service Purpose
prep_assistent.add_item Create an item (list by name or ID)
prep_assistent.consume_item Reduce stock – by name or barcode, the batch expiring first is used
prep_assistent.add_barcode Add by barcode without asking: known barcodes increase the stock (pack sizes converted), unknown ones are looked up online and created
prep_assistent.apply_template Calculate and apply a template
prep_assistent.check_expiry Run the expiry check immediately
prep_assistent.reload_templates Reload template files

Example automation: push on expiry warning

triggers:
  - trigger: event
    event_type: prep_assistent_expiry
actions:
  - action: notify.mobile_app_my_phone
    data:
      title: "Check your supplies"
      message: >
        {{ trigger.event.data.expired | count }} expired,
        {{ trigger.event.data.expiring | count }} expiring soon.

Development

Try it locally (Docker)

docker compose up -d          # starts HA on http://localhost:8123
docker compose restart        # after Python changes
docker compose logs -f        # logs (PrepAssistent at debug level)
docker compose down           # stop

The integration folder is mounted directly into the container; the HA configuration lives in .dev/config/. On first start, create a user, then Settings → Devices & services → Add integration → PrepAssistent. Changes to the panel (JS) only need a browser reload without cache (Cmd+Shift+R).

Tests

python3 -m venv .venv && .venv/bin/pip install -e ".[test]"
.venv/bin/pytest

The panel (frontend/prep-assistent-panel.js) and the card (frontend/prep-assistent-card.js) are web components without a build step and share helpers from frontend/prep-common.js. Data flows through the WebSocket API (prep_assistent/*); changes are pushed live to all open panels and cards.

The bundled templates are examples (based on the recommendations of the German Federal Office of Civil Protection, BBK) and do not replace individual planning.

About

Home Assistant integration for managing stockpiles with expiry warnings, supply range and shopping lists

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages