Today I’m going to show you some of the ways I’m using Home Assistant and Grocy to automate our shopping list. Using Home Assistant with Grocy allows our smart home to tell us when we need to purchase something, as opposed to adding things to a shopping list when it’s already too late.



What is Grocy?

If you’re running HASS IO, you may have seen an add-on from Franck called Grocy. This little gem is a stock management system for the home. Grocy allows you to know how much of a product you have at home, and to track when items are due to expire. For example how many litres of milk you have at home, and when it will expire.

The recipes feature of Grocy is where it all comes together. Once you put in the ingredients required for a meal, Grocy can tell you what ingredients you have on hand to make that meal, or allow you to add missing items to the shopping list. When you cook a recipe, by the click of a button, Grocy will reduce the stock levels of those products and keep track of your remaining stock.

For those times when you don’t use a fixed recipe, there is also the ability to “consume” items in Grocy. This is where you can tell Grocy you just drank a can of Fosters, so it knows how much you have left in stock.

For the most part this is great, but if you want to take full advantage of Grocy it does require you to login and track your usage of items regularly. This can get quite annoying if you need to open your phone each time you use an egg from the fridge or wake up in the night for a glass of milk. This is where we can leverage our smart home controller, in my case Home Assistant, to automate the consumption of items in Grocy.

Setting up Home Assistant

One of the things I love about Home Assistant is its flexibility to integrate with other systems and software. There’s a whole bunch of ways to integrate things, from HTTP with REST sensors and switches, to MQTT.

To make things easier, I’m going to use a Shell Command, which will make a cURL request to the Grocy REST API to consume an item. I want to be able to re-use as much code as possible, so I’m going to use template data to dynamically send data to this cURL request. This will come in handy later.

To begin, lets start with our shell command, and I’ll explain what this is doing.

grocy.yaml shell_command: grocy_consume_item: "curl -X POST http://{{server_ip}}:9283/api/stock/products/{{product_id}}/consume -H 'Accept: application/json' -H 'Content-Type: application/json' -H 'GROCY-API-KEY: {{grocy_key}}' -H 'cache-control: no-cache' -d '{ \"amount\": {{amount}}, \"transaction_type\": \"consume\", \"spoiled\": false }'" 1 2 3 4 shell _ command : grocy _ consume _ item : "curl -X POST http :// { { server _ ip } } :9283/api/stock/products/ { { product _ id } } /consume -H 'Accept: application/json' -H 'Content-Type: application/json' -H 'GROCY-API-KEY: {{grocy_key}}' -H 'cache-control: no-cache' -d '{ \"amount\": {{amount}}, \"transaction_type\": \"consume\", \"spoiled\": false }' "

In this command, I’ve got some parameters wrapped in {{brackets}}. These will allow us to use the same shell command in our scripts and automations moving forward. Let’s break down these parameters.

{{server_ip}} The IP address of the server where Grocy is running. If running on the same machine as Home Assistant, this could be 127.0.0.1 {{PRODUCT_ID}} The Grocy ID of the product to be consumed. You can get this from the URL of the edit product page inside Grocy. {{grocy_key}} The API key for your Grocy install. Get this from your Grocy settings page. {{AMOUNT}} The amount you wish to consume. This depends on the product.

We’ll use this shell command throughout the next few scenarios.

The Latest In Your Inbox Enter your email address below to receive my latest blog posts and videos about Home Automation in your Inbox

Dishwashing Tablets

If you’ve previously read my blog on making dishwashers and washing machines smart, you’ll know that my smart home knows the state of my dishwasher. This means that my home also knows when we start the dishwasher.

With this information, we can get Home Assistant to tell Grocy when we have used a dishwashing tablet.

Setting up Grocy

First we need to create a product in Grocy for dishwashing tablets. For this I’ve created a new Quantity Unit called tablet. Once I’ve created a product in Grocy, I then use the inventory to record how many dishwashing tablets I have in the house.

There’s a couple of things going on in this screenshot, so let me explain.

The minimum stock amount is defined when you create your item in Grocy. Once I have less than 60 dishwashing tablets in stock, Grocy will mark the item as low in stock and prompt me to add this to my shopping list.

Next up is the QU Purchase or Quantity Purchase. Here you’ll notice I’ve created a Quantity Unit in Grocy called 80pk Box. This is because you don’t go to the supermarket and ask for 1 dishwashing tablet. You buy them in packs. For me, the brand I like to use always comes in an 80pk box. For this reason, the QU Factor is set to 80. This means when I purchase 1 box of dishwashing tablets, Grocy will automatically add 80 tablets in stock.

Finally the Product Group is handy for the shopping list feature. Items will be grouped together nicely, so when you’re in the supermarket you can have your shopping list arranged into the aisles.

Once we’ve created the product we can use the Inventory feature of Grocy to tell Grocy how many tablets we have in stock already. Once Grocy knows how many dishwashing tablets are in the house, its time to tell Home Assistant to consume (remove 1 tablet from stock) each time the dishwasher starts.

Home Assistant

To start off simple, each time my dishwasher goes into the Running state, I want Home Assistant to remove 1 tablet from Grocy. To do that, I’ll use the following automation.

dishwasher.yaml - alias: Dishwasher consume tablet running trigger: - platform: state entity_id: sensor.dishwasher_status to: 'Running' action: - service: shell_command.grocy_consume_item data: server_ip: 127.0.0.1 grocy_key: GROCY123APIKEY product_id: 59 amount: 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 - alias : Dishwasher consume tablet running trigger : - platform : state entity _ id : sensor.dishwasher_status to : 'Running' action : - service : shell_command.grocy_consume_item data : server _ ip : 127.0.0.1 grocy _ key : GROCY123APIKEY product _ id : 59 amount : 1

Pretty basic, right? Using those template variables in the shell command, we can also use Home Assistant secrets as variables. This way if your product ID for dishwashing tablets changes in the future, you’ve just got one place to update.

Although now I have a problem. Let’s take a look at the diagram from my Dishwasher state automation.

In this diagram, we can see that the state can go back to Running in the middle of a cycle. This means each time the power drops and comes back up, Home Assistant will remove a dishwashing tablet from my stock, even though I haven’t put another tablet in the dishwasher.

I need to stop this from happening. So let’s go ahead and make a small change to our automation above.

dishwasher.yaml - alias: Dishwasher consume tablet running trigger: - platform: state entity_id: sensor.dishwasher_status to: 'Running' action: - service: shell_command.grocy_consume_item data: server_ip: 127.0.0.1 grocy_key: GROCY product_id: 59 amount: 1 - service: homeassistant.turn_off entity_id: automation.dishwasher_consume_tablet_running 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - alias : Dishwasher consume tablet running trigger : - platform : state entity _ id : sensor.dishwasher_status to : 'Running' action : - service : shell_command.grocy_consume_item data : server _ ip : 127.0.0.1 grocy _ key : GROCY product _ id : 59 amount : 1 - service : homeassistant.turn_off entity _ id : automation.dishwasher_consume_tablet_running

This will turn the automation off once it has been run. Now we need another automation to turn this back on once the dishwasher door has been opened.

dishwasher.yaml - alias: Dishwasher consume tablet enable trigger: - platform: state entity_id: sensor.dishwasher_status to: Dirty condition: condition: and conditions: - condition: state entity_id: sensor.dishwasher_status state: Dirty - condition: state entity_id: automation.dishwasher_consume_tablet_running state: 'off' action: - service: homeassistant.turn_on entity_id: automation.dishwasher_consume_tablet_running 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - alias : Dishwasher consume tablet enable trigger : - platform : state entity _ id : sensor.dishwasher_status to : Dirty condition : condition : and conditions : - condition : state entity _ id : sensor.dishwasher_status state : Dirty - condition : state entity _ id : automation.dishwasher_consume_tablet_running state : 'off' action : - service : homeassistant.turn_on entity _ id : automation.dishwasher_consume_tablet_running

Now Home Assistant will automatically remove a dishwashing tablet from my stock levels when the dishwasher is run. Grocy will prompt me to buy tablets when stock levels get below my set threshold.

Washing Machine

So the dishwasher was pretty simple. But what about something a tiny bit more complicated? The washing machine needs to manage two items. Washing Powder and Fabric Softener. However unlike the dIshwasher, these are different amounts. Washing powder is measured in weight, whilst the Fabric Softener is measured in litres.

This makes things slightly tricky. For my washing powder, I can easily use a kitchen scale to weigh how much a scoop of powder consumes. Luckily for the liquid, it mentions there are 25 washes in the bottle. Using this, we can do some maths to work out how much Home Assistant should subtract each time the washing machine is turned on.

2000ml / 25 washes = 80ml per wash

From there, we can then plug these into our Home Assistant automations.

washing.yaml - alias: Washing Machine Powder Consume trigger: - platform: state entity_id: sensor.washing_machine_status to: 'Running' action: # Consume washing detergent / fabric softener - service: shell_command.grocy_consume_item data: server_ip: 127.0.0.1 grocy_key: GROCYKEY product_id: 24 amount: 80 # Consume washing powder - service: shell_command.grocy_consume_item data: server_ip: 127.0.0.1 grocy_key: GROCYKEY product_id: 23 amount: 45 - service: homeassistant.turn_off entity_id: automation.washing_machine_powder_consume 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 - alias : Washing Machine Powder Consume trigger : - platform : state entity _ id : sensor.washing_machine_status to : 'Running' action : # Consume washing detergent / fabric softener - service : shell_command.grocy_consume_item data : server _ ip : 127.0.0.1 grocy _ key : GROCYKEY product _ id : 24 amount : 80 # Consume washing powder - service : shell_command.grocy_consume_item data : server _ ip : 127.0.0.1 grocy _ key : GROCYKEY product _ id : 23 amount : 45 - service : homeassistant.turn_off entity _ id : automation.washing_machine_powder_consume

In Grocy I’ve set these items up with the right purchase and consumption units like the dishwashing tablets.

Regular Consumables

So far we’ve automated things where Home Assistant can “see” them being consumed. But what about other things that Home Assistant can’t see via sensors?

For daily things, we can setup timed automations to execute at a certain time. For example every day at 9am, remove a breakfast bar from stock, but only if it is a workday.

grocy.yaml - alias: Consume breakfast bar on Work Day trigger: - platform: time at: '08:00:00' condition: condition: and conditions: - condition: state entity_id: binary_sensor.workday_sensor state: 'on' action: - service: shell_command.grocy_consume_item data_template: server_ip: 127.0.0.1 grocy_key: GROCYKEY product_id: 32 amount: 1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 - alias : Consume breakfast bar on Work Day trigger : - platform : time at : '08 :00 :00' condition : condition : and conditions : - condition : state entity _ id : binary_sensor.workday_sensor state : 'on' action : - service : shell_command.grocy_consume_item data _ template : server _ ip : 127.0.0.1 grocy _ key : GROCYKEY product _ id : 32 amount : 1

For items consumed on an ad-hoc basis, we can use the Home Assistant interface. This would be particularly helpful for a tablet like an Amazon Fire Tablet mounted to a wall in the kitchen.

We can easily create scripts, which can be used to tell Grocy to consume items when called. Here’s a script which will remove 100ml of Milk from stock when executed.

grocy.yaml script: grocy_consume_milk: alias: Consume Glass of Milk sequence: - service: shell_command.grocy_consume_single_item data: server_ip: 127.0.0.1 grocy_key: GROCYKEY product_id: 4 amount: 0.1 #Grocy tracks Milk in litres, so mark 0.1 litres as consumed 1 2 3 4 5 6 7 8 9 10 11 12 script : grocy _ consume _ milk : alias : Consume Glass of Milk sequence : - service : shell_command.grocy_consume_single_item data : server _ ip : 127.0.0.1 grocy _ key : GROCYKEY product _ id : 4 amount : 0.1 #Grocy tracks Milk in litres , so mark 0 . 1 litres as consumed

Which can appear in Lovelace with an entity card like:

Alerting when item below threshold

Grocy has the ability to mark items in its interface when they are below a threshold. However this requires you to open the Grocy interface. It would be better if Home Assistant could send you a notification when your stock levels have reached a certain point.

We can easily do this with a REST Sensor, and some automations. We’ll need to use a full URL to the Grocy API for this.

grocy.yaml sensor: - platform: rest resource: http://127.0.0.1:9283/api/stock/products/52 headers: GROCY-API-KEY: GROCYKEY name: Dishwashing Tablets value_template: '{{ value_json.stock_amount }}' scan_interval: 3600 json_attributes: - last_purchased 1 2 3 4 5 6 7 8 9 10 11 12 sensor : - platform : rest resource : http : //127.0.0.1:9283/api/stock/products/52 headers : GROCY - API - KEY : GROCYKEY name : Dishwashing Tablets value_template : '{{ value_json.stock_amount }}' scan_interval : 3600 json_attributes : - last_purchased

Now we’ll setup an automation to send a notification at 9:30pm if there are less than 10 dIshwashing tablets in stock.

grocy.yaml automation: - alias: Alert when Dishwashing tablets below threshold trigger: - platform: time at: '21:30:00' condition: condition: and conditions: - condition: numeric_state entity_id: sensor.dishwashing_tablets below: 10 - condition: time before: '23:00:00' after: '20:00:00' action: - service: notify.phil data: message: Oh no you need to buy Dishwashing tablets! title: Dishwashing Tablets 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 automation : - alias : Alert when Dishwashing tablets below threshold trigger : - platform : time at : '21 :30 :00' condition : condition : and conditions : - condition : numeric_state entity _ id : sensor.dishwashing_tablets below : 10 - condition : time before : '23 :00 :00' after : '20 :00 :00' action : - service : notify.phil data : message : Oh no you need to buy Dishwashing tablets! title : Dishwashing Tablets

Maybe instead of bugging me at 9:30pm when the grocery store is closed, Home Assistant could just add the item to my shopping list once. There are several different systems Home Assistant can integrate with for this. For example you may choose to send an email to Todoist. For the sake of simplicity, I’m going to use the Home Assistant shopping list for this example.

dishwashing.yaml automation: - alias: Dishwashing tablets shopping list add trigger: - platform: state entity_id: sensor.dishwashing_tablets state: 10 condition: condition: and conditions: - condition: state entity_id: sensor.dishwashing_tablets state: 10 action: - service: shopping_list.add_item data: name: Dishwashing Tablets 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 automation : - alias : Dishwashing tablets shopping list add trigger : - platform : state entity _ id : sensor.dishwashing_tablets state : 10 condition : condition : and conditions : - condition : state entity _ id : sensor.dishwashing_tablets state : 10 action : - service : shopping_list.add_item data : name : Dishwashing Tablets

You can also automate marking the items as done once the stock amount returns to a normal threshold

dishwashing.yaml automation: - alias: Dishwashing tablets shopping list complete trigger: - platform: numeric_state entity_id: sensor.dishwashing_tablets above: 40 condition: condition: and conditions: - condition: numeric_state entity_id: sensor.dishwashing_tablets above: 40 action: - service: shopping_list.complete_item data: name: Dishwashing Tablets 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 automation : - alias : Dishwashing tablets shopping list complete trigger : - platform : numeric_state entity _ id : sensor.dishwashing_tablets above : 40 condition : condition : and conditions : - condition : numeric_state entity _ id : sensor.dishwashing_tablets above : 40 action : - service : shopping_list.complete_item data : name : Dishwashing Tablets

The only problem with marking things off the Home Assistant shopping list automatically is that there is no way to check if an item exists in the Shopping List. This means each time you use a dishwashing tablet, and it goes down from 50 -> 49, 49 -> 48 this automation will get called and may throw some errors.

We can simply turn the automation off so that once the Dishwashing tablets have been marked as complete, we won’t try again.

dishwasher.yaml automation: - alias: Dishwashing tablets shopping list complete trigger: - platform: numeric_state entity_id: sensor.dishwashing_tablets above: 40 condition: condition: and conditions: - condition: numeric_state entity_id: sensor.dishwashing_tablets above: 40 action: - service: shopping_list.complete_item data: name: Dishwashing Tablets - service: automation.turn_off data: entity_id: automation.dishwashing_tablets_shopping_list_complete 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 automation : - alias : Dishwashing tablets shopping list complete trigger : - platform : numeric_state entity _ id : sensor.dishwashing_tablets above : 40 condition : condition : and conditions : - condition : numeric_state entity _ id : sensor.dishwashing_tablets above : 40 action : - service : shopping_list.complete_item data : name : Dishwashing Tablets - service : automation.turn_off data : entity _ id : automation.dishwashing_tablets_shopping_list_complete

For good measure we should also turn that automation back on, once we have added the item to the shopping list.

dishwashing.yaml automation: - alias: Dishwashing tablets shopping list add trigger: - platform: state entity_id: sensor.dishwashing_tablets state: 10 condition: condition: and conditions: - condition: state entity_id: sensor.dishwashing_tablets state: 10 action: - service: shopping_list.add_item data: name: Dishwashing Tablets - service: automation.turn_on data: entity_id: automation.dishwashing_tablets_shopping_list_complete 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 automation : - alias : Dishwashing tablets shopping list add trigger : - platform : state entity _ id : sensor.dishwashing_tablets state : 10 condition : condition : and conditions : - condition : state entity _ id : sensor.dishwashing_tablets state : 10 action : - service : shopping_list.add_item data : name : Dishwashing Tablets - service : automation.turn_on data : entity _ id : automation.dishwashing_tablets_shopping_list_complete

Making it simple with the Grocy custom component

The examples I’ve given so far will work for any Home Assistant installation, because they’re using core components to talk directly with the Grocy API.

There is also a custom component for Home Assistant from Sebastian Rutofski. Using the custom component, you could instead use service calls and sensors instead of relying on shell commands and REST sensors. If you’re interested, you can check out that component on GitHub.

The Grocy custom component is also available for one-click install via the Home Assistant Community Store (HACS).

Going Further

So far we’ve got the the shopping list automated based on time, and when devices change state. However there’s some other cool use cases you could use with Home Assistant. Here’s some ideas…