Skip to content

Repository files navigation

Fridge Assistant

Know what's in your fridge, freezer and pantry โ€” since when, and what to eat first.

License: MIT HACS Custom Repository Home Assistant


Fridge Assistant is a Home Assistant custom integration that turns your fridge, freezer and pantry into a searchable inventory. Every item gets a short code and a printable sticker, expiry dates are estimated automatically from a 99-recipe database (or an LLM), and a mobile-first panel lets you add, scan, and finish items right from your phone โ€” standing in front of the open door.

It's built to be genuinely useful for a household with more than one person: every item remembers who put it in, finishing an item (eaten / tossed) is logged with who and when, and there's a full undo. It works completely offline; AI estimates and the printer add-on are both optional.

Table of contents

Features

  • ๐Ÿ“‹ Inventory across fridge, freezer and pantry, with search and per-location filters.
  • ๐Ÿ—“๏ธ Automatic expiry dates from a built-in database of 99 common products & dishes (Dutch, i18n-ready), matched conservatively โ€” it will ask rather than guess wrong.
  • โœจ AI estimates for anything not in the database, via your existing Home Assistant conversation agent or a direct OpenAI key.
  • ๐Ÿ“š Templates manager โ€” view, edit, hide/restore built-ins, or add your own (with or without AI).
  • ๐Ÿท๏ธ Unique item codes (AB12-style) with an optional printed sticker (barcode included) via the companion label printer add-on.
  • ๐Ÿฑ Portions โ€” split a batch (say, a big pan of lasagne) into up to 24 portions on one item. Each portion gets its own sub-code and sticker (AB12-1, AB12-2, โ€ฆ); scanning one marks exactly that portion eaten, and the last portion completes the item automatically.
  • ๐Ÿ—‚๏ธ Inspector drawer โ€” on desktop an item opens in a side drawer (the list stays visible and clickable); on mobile everything remains a bottom sheet. History and the templates manager use the same drawer.
  • ๐Ÿ“ท Barcode scanning โ€” scan your own sticker to instantly find an item, or scan a retail barcode to add a new grocery product with its name/photo/quantity pre-filled.
  • ๐Ÿ‘ค Who added what โ€” items remember who put them in, shown with their Home Assistant person avatar.
  • โœ… Finish items as eaten or tossed, logged in a paginated history with who/when โ€” with undo.
  • ๐Ÿ”” Expiry notifications โ€” a persistent notification + event fires daily (time configurable) for anything expired or expiring soon.
  • ๐Ÿงน Clean-up mode โ€” clear out everything past its date in one tap.
  • ๐Ÿ“ฑ Mobile-first panel โ€” built for using with your phone in hand, standing at the open fridge door.
  • ๐ŸŒ Fully local โ€” works with zero internet access; AI estimates, barcode lookups and the printer add-on are all optional.

Screenshots

Inventory list with location filters and expiry status

The inventory panel โ€” filter by location, see what's expiring at a glance.

Item detail view with Eaten and Tossed actions

Item detail โ€” print a sticker, edit, or finish it as eaten/tossed.

Scanning a printed fridge label with the phone camera

Scanning a Fridge Assistant label to instantly pull up that item.

Two printed stickers on food containers in the freezer

Printed stickers (DYMO 99014) on containers in the freezer.

How it works

Inventory model

Every item lives in one of three locations โ€” fridge, freezer, or pantry (room-temperature storage) โ€” and belongs to one of two kinds:

  • ๐Ÿฅ• ingredient โ€” a single product (milk, lettuce, cheese, ...)
  • ๐Ÿฒ dish โ€” something prepared (leftovers, a home-cooked meal, ...)

Kind is derived from a set of 15 finer categories (vegetables, fruit, dairy, meat, fish, breakfast, lunch, dinner, snack, bakery, sauces & spices, drinks, eggs, leftovers, other) but can always be overridden per item. Prepared meals are categorised by the meal-time they're usually eaten at, so the inventory can be filtered on e.g. "what dinners are in the freezer?".

Item codes & stickers

Every item gets a unique 4-character code โ€” two letters + two digits (e.g. AB12), with visually ambiguous letters (I/O/Q) excluded so it always reads cleanly off a small sticker. The code format (letters-first or digits-first) is configurable.

If the optional Label Printer add-on is installed, a tap on ๐Ÿท๏ธ prints a sticker sized for a DYMO 99014 label (54 ร— 101 mm) with the item name, a scannable Code 39 barcode of the item code, the storage date, a bold "eat before" date, contents, and quantity/servings.

Portions

Cooked a big batch? Set a portion count when adding the item (or later, in the inspector) and the batch stays one item in the list instead of three duplicates. Each portion gets its own sub-code (AB12-1, AB12-2, โ€ฆ) with its own sticker and barcode, plus a PORTION 1/3 line on the label. Scanning a portion sticker in eat-mode marks exactly that portion as eaten (with per-portion undo); eating or tossing the last open portion completes the whole item โ€” as tossed only when every portion was tossed, otherwise eaten. The inspector shows every portion's state (open / eaten by whom, when), lets you eat, toss or reprint per portion, and resize the batch without disturbing consumed portions.

Automatic expiry estimation

A seed database of 99 Dutch recipes/products (84 ingredients, 15 dishes) maps product names to shelf-life in days, per location. Typing a name matches conservatively โ€” an exact or near-exact match is auto-suggested, but a loose one-word overlap is not (so "pizza" won't silently become "cheese"), and negations like "macaroni zonder vlees" ("without meat") correctly exclude templates that mention the excluded word. Every suggestion can be dismissed in favour of a manual date, a different template, or an AI estimate.

The full database is editable from the ๐Ÿ“š Templates manager: built-in templates can be tweaked (creating a personal override, restorable with one tap) or hidden entirely; you can also add your own from scratch, with or without AI.

AI estimates

For anything the database doesn't know, Fridge Assistant can ask an LLM for a conservative, food-safety-minded shelf-life estimate (days in fridge / freezer / pantry), a category, an emoji, and a short storage tip โ€” all editable before you save. Two ways to run it:

  1. Your existing Home Assistant conversation agent (e.g. an OpenAI/Anthropic/Gemini/Ollama integration) โ€” auto-selected, skipping the intent-only default Assist agent.
  2. A direct OpenAI API key in the integration's options, calling the API directly (default model gpt-4o-mini).

You can save any AI estimate as a reusable template with one tap.

Barcode scanning

Tap the ๐Ÿ“ท button next to add (โž•) to open the scanner. It has two modes:

  • ๐Ÿ”Ž Search โ€” scan one of your own printed stickers and its item opens immediately.
  • ๐Ÿฝ๏ธ Eat โ€” scan your own stickers to mark each one eaten on the spot, without leaving the camera view (handy right after cooking, to clear out what you used).

Scanning a barcode that isn't one of your own labels is treated as a retail barcode (EAN/UPC): Fridge Assistant looks it up first against products you've scanned before (works offline, for repeat purchases), then against Open Food Facts (free, no API key) to pre-fill the name, category, quantity and photo of a new item โ€” you just confirm the location and date.

Three detection tiers keep it working across devices:

  1. The native BarcodeDetector API (Android / Chromium) for live camera scanning.
  2. A bundled ZXing decoder, lazy-loaded only on devices without a native detector (notably iOS) โ€” live camera and photo-capture both work.
  3. A photo-capture button and manual code entry as an always-available fallback.

Note: live camera scanning requires a secure context (HTTPS) โ€” it works over Nabu Casa or your own TLS, but falls back to photo/manual entry over plain http://.

Multi-user tracking & history

Every item remembers who added it (resolved from the Home Assistant user behind the action) and shows their avatar โ€” pulled from a linked person entity's photo, or coloured initials if there isn't one.

Finishing an item โ€” ๐Ÿฝ๏ธ Eaten or ๐Ÿ—‘๏ธ Tossed โ€” moves it into a paginated history log (who, what, when), reachable via ๐Ÿ“œ in the top bar. Every finish action can be undone, restoring the item with its original id and code so a physical sticker still matches. History is capped at the most recent 500 events (a rolling window) so storage stays bounded โ€” but your active inventory is never purged automatically; an item only leaves the fridge when you finish it yourself.

Notifications

A daily check (time configurable, default 09:00) fires an event and a persistent notification listing anything expired or expiring within your configured warning window (default 3 days) โ€” split into "past date" and "expiring soon". You can also trigger the check on demand.

Mobile-first design

The panel is built to be used one-handed with your phone in hand, standing at the open fridge:

  • A native Home Assistant hamburger menu is injected into the panel header (a full-page custom panel otherwise has no sidebar access on mobile).
  • Safe-area insets (env(safe-area-inset-*)) keep controls clear of the notch and home indicator.
  • 44px+ tap targets and 16px inputs (avoids iOS auto-zoom on focus).
  • A thumb-reachable floating add (โž•) and scan (๐Ÿ“ท) button, bottom-right.

Language

Fridge Assistant follows a simple rule everywhere โ€” panel, printed labels, AI prompts, and the daily expiry notification: Dutch if Home Assistant's language is Dutch, English for anything else. There's no third language and no silent fallback to Dutch for an unconfigured or unrecognized language โ€” only nl/en text ships, and everything else resolves to English.

The panel reads the current user's Home Assistant frontend language (so two people in the same household can each see their own language); server-rendered text (printed labels, the daily notification, AI prompts) reads Home Assistant's system-configured language, since those aren't tied to a specific browser session.

The 99-recipe shelf-life database itself (product names, storage tips) is Dutch content โ€” a different kind of project than UI translation โ€” and isn't translated by this rule.

Installation

Via HACS (custom repository)

Fridge Assistant isn't in the default HACS store, so add it as a custom repository:

  1. HACS โ†’ Integrations โ†’ โ‹ฎ โ†’ Custom repositories.
  2. Add https://github.com/MaxGramser/fridge_assistant, category Integration.
  3. Install Fridge Assistant, then restart Home Assistant.
  4. Settings โ†’ Devices & Services โ†’ Add Integration โ†’ Fridge Assistant.
  5. Open Koelkast in the sidebar.

Manual

Copy custom_components/fridge_assistant into your Home Assistant config/custom_components/ directory, restart Home Assistant, and follow steps 4โ€“5 above.

Configuration

All options live under Settings โ†’ Devices & Services โ†’ Fridge Assistant โ†’ Configure:

Option Default Description
Warn this many days before expiry 3 How many days ahead "expiring soon" starts.
Enable AI estimates on Turn AI shelf-life estimation on/off.
AI conversation agent (auto) Which conversation.* agent to use. Leave empty to auto-pick an LLM agent.
OpenAI API key (none) If set, estimates call OpenAI directly instead of a conversation agent.
OpenAI model gpt-4o-mini Model used for direct API calls.
Item code format letters-first (AB12) Or digits-first (12AB).
Enable notifications on Toggle the daily expiry notification.
Daily check time 09:00 When the daily expiry check runs.
Enable label printer off Turn on once the add-on is installed.
Label Printer add-on URL http://local-label-printer:8000 Only change if you renamed/moved the add-on.
Copies per print 1 How many stickers to print per tap.

Services

All services live under the fridge_assistant domain and can be called from automations, scripts, or Developer Tools โ†’ Actions.

Service Description Key fields
fridge_assistant.add_item Add an item. Expiry is estimated automatically from contents + location if not given. name, contents, location, added_date, expiry_date, quantity, portions
fridge_assistant.update_item Update fields on an existing item. id, (any item field)
fridge_assistant.remove_item Delete an item outright (no history entry). id
fridge_assistant.complete_item Finish an item as eaten or tossed โ€” logged to history with who/when. id, action (eaten / tossed)
fridge_assistant.eat_portion Mark one portion eaten/tossed; the last portion completes the item. id or code (AB12-2 picks that portion), portion, action
fridge_assistant.remove_expired Clear out everything past its date in one call. โ€”
fridge_assistant.estimate Ask AI to estimate shelf life for a product name. name
fridge_assistant.add_template Add or update a template in the shelf-life database. name, (template fields)
fridge_assistant.print_sticker Render and print a label via the add-on. id
fridge_assistant.run_check Run the expiry check immediately (event + notification). โ€”

Sensors

Three sensors are created per config entry:

  • Total items โ€” count of everything currently in the inventory.
  • Expiring soon โ€” count of items within the warning window (not yet past date).
  • Expired โ€” count of items already past their date.

Both expiry sensors expose the matching item list (code, name, days left, ...) as attributes.

Optional: Label Printer add-on

The integration works completely without a printer โ€” stickers are cosmetic. If you want physical labels, install the companion Label Printer add-on alongside it. It now lives in its own repository: MaxGramser/label-printer-addon. Add that URL under Settings โ†’ Add-ons โ†’ Add-on store โ†’ โ‹ฎ โ†’ Repositories, install Label Printer, and pick which label roll is loaded (by DYMO part number or Zebra size).

  • Generic by design: it accepts any PNG/PDF over HTTP and prints it via CUPS โ€” the integration does all the rendering, so the add-on itself has no Fridge Assistant-specific logic.
  • Auto-detects DYMO LabelWriter and Zebra printers over USB, side by side.
  • Tested hardware: DYMO LabelWriter 400/450/550 with 99014 labels (54 ร— 101 mm) and a Zebra ZD220D with 104 ร— 159 mm shipping labels.

After installing, set Enable label printer in this integration's options (and adjust the add-on URL if yours differs โ€” an add-on installed from the repository gets a hostname like http://xxxxxxxx-label-printer:8000, shown on the add-on's page).

Data & privacy

  • All inventory data, templates, and history are stored locally in Home Assistant's own storage โ€” nothing leaves your network for normal use.
  • AI estimates send only the product name to your chosen conversation agent or directly to OpenAI (if you've configured an API key) โ€” whichever provider you already use for that agent.
  • Retail barcode scanning sends the scanned barcode number to the free Open Food Facts API (server-side, from Home Assistant Core, not your browser) to resolve a product name/photo. This only happens when you scan a barcode that isn't one of your own labels. Nothing else about your inventory is sent.
  • The printer add-on communicates only on your local network.

Known limitations

  • Only Dutch and English exist (see Language) โ€” the 99-recipe database's product names and notes stay Dutch regardless of the UI language.
  • Live camera barcode scanning requires a secure context (HTTPS); it degrades gracefully to photo-capture or manual entry otherwise.
  • The label printer add-on has been tested against DYMO LabelWriter 400/450/550 (99014 labels) and a Zebra ZD220D (104 ร— 159 mm); other CUPS-supported label printers may work but are unverified.

Architecture (for contributors)

custom_components/fridge_assistant/
โ”œโ”€โ”€ __init__.py          # setup, static paths, panel registration, daily check scheduling
โ”œโ”€โ”€ config_flow.py        # config + options flow
โ”œโ”€โ”€ const.py               # locations, categories, kinds, option keys & defaults
โ”œโ”€โ”€ store.py                # persisted data layer: items, templates, history, matching logic
โ”œโ”€โ”€ coordinator.py          # runtime object: options, notifications, expiry checks
โ”œโ”€โ”€ services.py              # fridge_assistant.* services
โ”œโ”€โ”€ websocket_api.py          # WebSocket API backing the panel (live state, mutations)
โ”œโ”€โ”€ ai.py                       # AI shelf-life estimation (conversation agent / OpenAI)
โ”œโ”€โ”€ products.py                  # retail barcode lookup (Open Food Facts)
โ”œโ”€โ”€ codes.py                       # item code generation
โ”œโ”€โ”€ label_render.py                  # Pillow-based DYMO label rendering (no HA imports)
โ”œโ”€โ”€ brand_render.py                    # generates the icon/logo artwork in brands/
โ”œโ”€โ”€ printer.py                          # renders + posts labels to the add-on
โ”œโ”€โ”€ panel/                    # the mobile-first custom panel โ€” native ES modules, no build step
โ”‚   โ”œโ”€โ”€ fridge-assistant-panel.js  # entry: custom element, shell, list, filters
โ”‚   โ”œโ”€โ”€ strings.js                 # all nl/en UI strings + label maps
โ”‚   โ”œโ”€โ”€ styles.js                  # all CSS (injected into the shadow root)
โ”‚   โ”œโ”€โ”€ lib/                       # format helpers + modal/drawer/toast surfaces
โ”‚   โ”œโ”€โ”€ views/                     # one module per view (inspector, add, scanner, โ€ฆ)
โ”‚   โ””โ”€โ”€ vendor/zxing.min.js        # bundled barcode decoder for iOS/Safari
โ””โ”€โ”€ data/
    โ”œโ”€โ”€ seed_templates.json                   # the 99-template shelf-life database
    โ””โ”€โ”€ fonts/                                  # bundled fonts for label rendering

brands/                       # icon/logo assets (Home Assistant brands format)

The optional, generic CUPS-based print add-on lives in its own repository: MaxGramser/label-printer-addon.

Backend changes require a full Home Assistant restart (ha core restart) โ€” a config entry reload does not re-import Python modules. Frontend (panel.js) and label design changes only need a browser/app hard-refresh.

License

MIT

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages