Grocy: get specific item from sensor.stock_grocy

Hi everybody,

I use the grocy custom component with an external instance of grocy. It is connected and works fine, there are these sensors by default

  • binary_sensor.grocy_expired_products
  • binary_sensor.grocy_expiring_producs
  • binary_sensor.grocy_missing_products
  • sensor.grocy_chores
  • sensor.grocy_shopping_list
  • sensor.grocy_stock

The sensor.grocy_stock entity provides attributes like these

attribution: Data from this is provided by grocy.
items: 
- _product_id: 3
  _available_amount: 3
  _best_before_date: '2999-12-31T00:00:00+00:00'
  _name: Test1
  _barcodes:
    - ''
  _product_group_id: null
- _product_id: 4
  _available_amount: 17
  _best_before_date: '2999-12-31T00:00:00+00:00'
  _name: '[BAT] CR1632'
  _barcodes:
    - '6972646746335'
  _product_group_id: 1
- _product_id: 5
  _available_amount: 8
  _best_before_date: '2999-12-31T00:00:00+00:00'
  _name: '[BAT] CR2025'
  _barcodes:
    - '4891199001130'
  _product_group_id: 1
- _product_id: 6
  _available_amount: 48
  _best_before_date: '2999-12-31T00:00:00+00:00'
  _name: '[BAT] AG10'
  _barcodes:
    - '6998817810100'
  _product_group_id: 1

unit_of_measurement: Product(s)
friendly_name: grocy.stock
icon: mdi:format-quote-close

When I use {{ states.sensor.grocy_stock.attributes }} in templates, I get this

{'attribution': 'Data from this is provided by grocy.', 'items': [{'_product_id': 3, '_available_amount': 3.0, '_best_before_date': datetime.datetime(2999, 12, 31, 0, 0, tzinfo=datetime.timezone.utc), '_name': 'Test1', '_barcodes': [''], '_product_group_id': None}, {'_product_id': 4, '_available_amount': 17.0, '_best_before_date': datetime.datetime(2999, 12, 31, 0, 0, tzinfo=datetime.timezone.utc), '_name': '[BAT] CR1632', '_barcodes': ['6972646746335'], '_product_group_id': 1}, {'_product_id': 5, '_available_amount': 8.0, '_best_before_date': datetime.datetime(2999, 12, 31, 0, 0, tzinfo=datetime.timezone.utc), '_name': '[BAT] CR2025', '_barcodes': ['4891199001130'], '_product_group_id': 1}, {'_product_id': 6, '_available_amount': 48.0, '_best_before_date': datetime.datetime(2999, 12, 31, 0, 0, tzinfo=datetime.timezone.utc), '_name': '[BAT] AG10', '_barcodes': ['6998817810100'], '_product_group_id': 1}], 'unit_of_measurement': 'Product(s)', 'friendly_name': 'grocy.stock', 'icon': 'mdi:format-quote-close'}

How can I pick a particular item from here? Let’s say I want the item with {'_product_id': 5}; I tried {{ states.sensor.grocy_stock.attributes.items }}, and wanted to break it down further from there, but this will just return <built-in method items of mappingproxy object at 0x7f732be53fd0>.

A different approach is this

sensor:
  - platform: rest
    resource: http://<grocy-ip>:9283/api/stock/products/4
    headers:
      GROCY-API-KEY: !secret grocy_api_key
    name: "[V] (BAT) CR1632"
    value_template: "{{ value_json.stock_amount }}"
    unit_of_measurement: "Stück"
    scan_interval: 3600
    json_attributes:
      - last_purchased
      - last_used

This works fine, but requires me to create an individual rest sensor per item! I currently only have 3 items, because I just started with grocy again and wanted to see how well I can integrate it in Home Assistant. However, I plan to have all kinds of items I can automate (dish tabs, dryer towels, laundry detergent, etc.) in grocy to automatically update their states whenever one of them has been used.

Can this be done by parsing the sensor.grocy_stock instead of creating countless individual sensors? Since there are

  • grocy.add_product
  • grocy.consume_product
  • grocy.execute_chore

services, I could easily achieve the consumption part of this. But I’d like to display the current stock of each relevant item in a dedicated tab within Home Assistant (rather than in grocy). To be precise, I’d like to somehow display "stock of <item-3>: {{ <whatever goes here to display available stock for item 3> }}".

Thank you for your ideas :slight_smile:

1 Like

There are several ways but one way would be

{{ state_attr('sensor.grocy_stock', 'items')[2]['_name'] }}

This would return the name of the third item (_product _id: 5). The template is Jinja (Google it) which is basically python code between the curly braces. You can use the Developer tools/Templates in the HA UI to try this out real time and help you get your syntax right. Give it a try.

1 Like

Thank you. This worked. I can use {{ state_attr('sensor.grocy_stock', 'items')[2]['_name'] }}: {{ state_attr('sensor.grocy_stock', 'items')[2]['_available_amount'] | int }} to get the name and value for each sensor like this.

Correct, have fun!

1 Like

Hi. Is there a way to create sensors for all items in the attributes? I have 240 items

The short answer is yes… but, you will need to give us more information about what your goal is. Do you want an individual sensor for each item? What data should the state of the sensor represent?

Here’s an example of using the Template editor tools to build out a set of sensors:

You then just copy/paste everything from the result into wherever you keep your template sensors in your configuration.


template:
  - sensor:
{%- for item in state_attr('sensor.grocy_stock', 'products') %}
    - name: {{ item.name }} Grocy Stock
      state: {{'{{ '-}} 
      {{ "state_attr('sensor.grocy_stock', 'products')[" ~ (loop.index -1) ~ "].available_amount" }} 
      {{-' | int(0) }}' }}
{% endfor %}

Thanks. Now, i can stop to create them one by one.
Yes, I want an individual sensor for each item and the available amount should be the state. It’s really difficult for a newbie like me but Im learning more and more.

Hello! Trying this code and it makes this after i have put it throug Template:

template:
  - sensor:
    - name: Frokostegg Grocy Stock
      state: {{ state_attr('sensor.grocy_stock', 'products')[0].available_amount | int(0) }}

    - name: Cola Grocy Stock
      state: {{ state_attr('sensor.grocy_stock', 'products')[1].available_amount | int(0) }}`

When i put that in my sensors.yaml i got this error when checking configurations:

Configuration errors
Error loading /config/configuration.yaml: while parsing a flow mapping
  in "/config/sensors.yaml", line 4, column 15
expected ',' or '}', but got '<scalar>'
  in "/config/sensors.yaml", line 4, column 60

Any ideas what im doing wrong?

The file, sensors.yaml, is set up for the Sensor integration, not the Template integration. You need to put it directly in configuration.yaml or a file that is properly included/merged and setup with the template top-level key.

Thank you.

This is now my configuration.yaml:


# Loads default set of integrations. Do not remove.
default_config:

# Load frontend themes from the themes folder
frontend:
  themes: !include_dir_merge_named themes

automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - x
    
#Sensors from Grocy

template:
  - sensor:
    - name: Tine Laktosefri Lettmelk 0,5 % fett Grocy Stock
      state: {{ state_attr('sensor.grocy_stock', 'products')[0].available_amount | int(0) }}

    - name: Frokostegg Grocy Stock
      state: {{ state_attr('sensor.grocy_stock', 'products')[1].available_amount | int(0) }}

    - name: Cola Grocy Stock
      state: {{ state_attr('sensor.grocy_stock', 'products')[2].available_amount | int(0) }}

Then i got this following error:

missed comma between flow collection entries (23:60)

 20 |  ... 
 21 |  ... 
 22 |  ... ettmelk 0,5 % fett Grocy Stock
 23 |  ... ensor.grocy_stock', 'products')[0].available_amount | int(0) }}
-----------------------------------------^
 24 |  ... 
 25 |  ... Stock

Then i did some googling and found out that i could use " before and after state. So now my code looks like this:

template:
  - sensor:
    - name: Tine Laktosefri Lettmelk 0,5 % fett Grocy Stock
      state: "{{ state_attr('sensor.grocy_stock', 'products')[0].available_amount | int(0) }}"

    - name: Frokostegg Grocy Stock
      state: "{{ state_attr('sensor.grocy_stock', 'products')[1].available_amount | int(0) }}"

    - name: Cola Grocy Stock
      state: "{{ state_attr('sensor.grocy_stock', 'products')[2].available_amount | int(0) }}"

I am not a programmer, but now it looks like it working. Is that a ok way to do it, or would you do something else?
The code i am now running in my template to make the output is now this:

template:
  - sensor:
{%- for item in state_attr('sensor.grocy_stock', 'products') %}
    - name: {{ item.name }} Grocy Stock
      state: "{{'{{ '-}} 
      {{ "state_attr('sensor.grocy_stock', 'products')[" ~ (loop.index -1) ~ "].available_amount" }} 
      {{-' | int(0) }}' }}"
{% endfor %}

That depends on what your actual goal is… if you specifically want a quantity sensor for each individual stock item, then that’s okay. If your goal is something else, then it’s likely unnecessary to set up all those intermediate sensor entities.

Hi,

I’m new to Python. {{ state_attr('sensor.grocy_stock', 'products')[2]['name'] }}
works perfect for me. But I need a specific Item filtered by ‘id’ how do I get this into the […].
Thanks!

I had the same problem; my issue with the examples above is that the array index can change if you delete something from grocy so I wanted to find a way to pull it out by id. This is what I came up with:

## Select an individual product based off its grocy id (23 in this case)
{{ state_attr('sensor.grocy_stock', 'products')|selectattr('id', 'equalto', 23)|list|first}}

## Get the name of a specific grocy product
{{ (state_attr('sensor.grocy_stock', 'products')|selectattr('id', 'equalto', 23)|list|first).name }}

## Get the available amount of a specific grocy product
{{ (state_attr('sensor.grocy_stock', 'products')|selectattr('id', 'equalto', 23)|list|first).available_amount }}

## Get the available amount of a specific grocy product
{{ (state_attr('sensor.grocy_stock', 'products')|selectattr('id', 'equalto', 23)|list|first).best_before_date }}

The 23 in each example line is the id of the product according to grocy. Use whatever id you want.

There’s probably a better way to get all that info in one call, but I’m not great with templates.

EDIT:

I figured out the “Better” way. This code gives the same output as above, but is a lot more readable. You can use this when making fancy buttons or whatever:

# Pull all details of a product into a single variable called "product"
{% set product = state_attr('sensor.grocy_stock', 'products')|selectattr('id', 'equalto', 23)|list|first %}

# Name
{{ product.name }}

# Amount
{{ product.available_amount }}

# Due
{{ product.best_before_date }}

Thank you! I‘ll give this a try!