44# CellarTracker for Home Assistant
55
66Brings your [ CellarTracker] ( https://cellartracker.com ) wine cellar into Home Assistant: summary
7- sensors for bottle count and cellar value, plus a searchable, sortable dashboard of every bottle.
7+ sensors for bottle count, cellar value and drinking windows, plus a dashboard that filters every
8+ bottle down to the ones you can drink tonight.
89
910> ** Disclaimer**
1011> This is a personal project. It is not affiliated with, connected to, or endorsed by
@@ -45,11 +46,14 @@ and error semantics; its own `requests`-based transport sets no timeout and is n
4546
4647- Two summary sensors — total bottle count and total cellar value — with proper device classes,
4748 units and state classes, so both feed Home Assistant's long-term statistics.
49+ - Two drink-window sensors — how many bottles are ready to drink, and how many are past their
50+ window — derived at poll time, so they cost nothing and add no entity per bottle.
4851- A selectable currency, so the value sensor is denominated correctly.
49- - A diagnostic status sensor.
52+ - A diagnostic sensor reporting when the cellar last synchronised .
5053- A REST endpoint exposing full per-bottle detail, and a self-contained dashboard page that
51- renders it as a searchable, sortable table with drink-window highlighting. The page ships with
52- the integration and is served from it, so there is nothing to copy into ` <config>/www ` .
54+ filters it by drinking window, searches it across five fields and shows each bottle's position
55+ in its window. The page ships with the integration and is served from it, so there is nothing
56+ to copy into ` <config>/www ` .
5357- Reauthentication: if your password changes, Home Assistant prompts you to re-enter it rather
5458 than silently failing.
5559- One account per installation, enforced by the config flow, so there is no ambiguity
@@ -108,7 +112,7 @@ state attributes:
108112
109113```
110114GET /api/cellartracker/inventory # every bottle, as JSON
111- GET /api/cellartracker/inventory?view=compact # the same bottles, nine columns
115+ GET /api/cellartracker/inventory?view=compact # the same bottles, ten columns
112116GET /api/cellartracker/settings # the configured currency and its symbol
113117```
114118
@@ -127,6 +131,7 @@ Each bottle in the response carries CellarTracker's own column names. The ones t
127131| ` Vintage ` | Vintage year, ` 0 ` for non-vintage |
128132| ` Producer ` | Producer name |
129133| ` Location ` / ` Bin ` | Where the bottle is stored |
134+ | ` Barcode ` | The bottle's barcode, if you have scanned one |
130135| ` Size ` | Bottle size, e.g. ` 750ml ` |
131136| ` Valuation ` | Current value, coerced to a float (` 0.0 ` if unparseable) |
132137| ` Price ` | What you paid |
@@ -269,9 +274,41 @@ title: My Wine Collection
269274The page reads your live Home Assistant session from the parent frame, so it needs no token or
270275credential of its own. Open it embedded in a dashboard, not as a standalone browser tab.
271276
272- It gives you search across wine name, location and bin; sortable columns; bottle values formatted
273- in your configured currency; links to each wine on CellarTracker; drink-window colouring (green =
274- ready, red = too early or past); and light/dark theme following your Home Assistant theme.
277+ ### What it gives you
278+
279+ **Four filter chips**, each carrying its count, so a 150-bottle cellar becomes a short list:
280+
281+ | Chip | Shows |
282+ |---|---|
283+ | **All wines** | Everything, including bottles with no recorded window |
284+ | **Ready to drink** | The current year falls inside the drinking window |
285+ | **Past window** | The window ended before this year |
286+ | **Needs aging** | The window has not opened yet |
287+
288+ The Ready and Past counts are the same numbers the sensors report — they are checked against each
289+ other by the test suite, so the chip and the sensor card beside it cannot disagree.
290+
291+ **Search** across wine name, vintage, location, bin and barcode. Every word has to match, so
292+ ` chianti 2023` narrows rather than finding nothing.
293+
294+ **Sort** by wine, vintage, value, drink-by year, bin or location, in either direction. Bottles
295+ with nothing recorded for the chosen column sort last rather than heading the list.
296+
297+ **Each bottle** shows its name, vintage, location and bin, its value in your configured currency,
298+ and a bar showing where this year sits inside its drinking window :
299+
300+ | Label | Meaning |
301+ |---|---|
302+ | **Ready** (green) | Inside the drinking window |
303+ | **Drink this year** (amber) | The final year of the window — urgent, not expired |
304+ | **Past window** (red) | The window ended before this year |
305+ | **Needs aging** (blue) | Not open yet |
306+ | **No window** (grey) | CellarTracker has no recommendation for this bottle |
307+
308+ Tapping a bottle opens a drawer with its barcode, full window, value, a **Copy bin** button and a
309+ link to the wine on CellarTracker.
310+
311+ The page follows your Home Assistant light/dark theme, and every control is sized for a thumb.
275312
276313The card needs no account parameter — one account is supported per installation, so the
277314endpoints have nothing to disambiguate. A stale `?entry_id=...` left over from a card configured
@@ -300,8 +337,10 @@ entities:
300337 name: Bottles
301338 - entity: sensor.<account>_total_value
302339 name: Cellar value
303- - entity: sensor.<account>_status
304- name: Connection
340+ - entity: sensor.<account>_ready_to_drink
341+ name: Ready to drink
342+ - entity: sensor.<account>_last_synchronised
343+ name: Last synchronised
305344` ` `
306345
307346# ## Markdown card with an average
@@ -419,13 +458,18 @@ window. **That is not possible with the entities this integration creates**, bec
419458per-bottle entities to filter — `auto-entities` works over the entity registry, and bottles are
420459not in it.
421460
422- Drink-window filtering happens in the dashboard page instead, which colours `BeginConsume` and
423- `EndConsume` per bottle : green when the year is in range, red when the bottle is too young or
424- past its window. Sort by either column to bring the relevant bottles together.
461+ There are two answers that do not need per-bottle entities.
462+
463+ **For a count**, use the sensors: `sensor.<account>_ready_to_drink` and
464+ ` sensor.<account>_past_drinking_window` are ordinary numeric entities, so they work in any card,
465+ template or automation.
425466
426- If you want drink-window data in Lovelace proper, the missing piece is per-bottle entities — see
427- [Bottle-level data](#bottle-level-data) for why they are not created by default. Please open an
428- issue if this matters to you; it is a reasonable feature to add behind an opt-in, given the
467+ **For the actual list**, use the dashboard page and its **Ready to drink** chip. That is what the
468+ chips are for, and the counts match the sensors exactly.
469+
470+ If you want the bottles themselves in Lovelace proper, the missing piece is per-bottle entities —
471+ see [Bottle-level data](#bottle-level-data) for why they are not created by default. Please open
472+ an issue if this matters to you; it is a reasonable feature to add behind an opt-in, given the
429473recorder cost is the user's to accept.
430474
431475---
@@ -519,16 +563,28 @@ logger:
519563
520564` ` ` bash
521565pip install -r requirements_test.txt
522- python -m pytest # 149 tests
566+ python -m pytest
523567ruff check .
524568` ` `
525569
526570The test suite stubs the handful of `homeassistant` symbols the integration imports rather than
527- depending on `pytest-homeassistant-custom-component`, so it installs in seconds and runs in under
528- a second. The dashboard tests execute `cellar.html`'s real script under Node, so install Node to
529- run them — they skip if it is absent.
571+ depending on `pytest-homeassistant-custom-component`, so it installs in seconds and runs in a few.
572+ The dashboard tests execute `cellar.html`'s real script under Node, so install Node to run them —
573+ they skip if it is absent.
574+
575+ Type checking needs Home Assistant itself, which the test suite deliberately does not install :
576+
577+ ` ` ` bash
578+ python3.13 -m venv .typecheck
579+ .typecheck/bin/pip install -r requirements_mypy.txt
580+ .typecheck/bin/python -m mypy
581+ ` ` `
582+
583+ Running `mypy` against an interpreter without Home Assistant is worse than not running it : every
584+ ` homeassistant.*` import resolves to `Any`, and the check passes over code it never looked at.
585+ The configuration refuses to do that, so it will fail loudly rather than mislead you.
530586
531- CI runs the suite on Python 3.12 and 3.13, plus `ruff`, `hassfest` and HACS validation.
587+ CI runs the suite on Python 3.12 and 3.13, plus `ruff`, `mypy`, ` hassfest` and HACS validation.
532588
533589# ## Cutting a release
534590
0 commit comments