How I almost automated grocery shopping
Tags: programming, cooking, opensource, showdev
Published: 2022-02-01 14:28:44

With the pandemic everyone's got their own challenges. For me it became particularly hard to switch to online grocery shopping. 

In my typical order I'd buy groceries for 7-10 days and it will contain 60-80 items in a cart. When I do my shopping offline I usually don't plan much and go through all the departments and pick up stuff as I go. It's rare when I forget to buy something because it catches my eye, but more often I buy something that I don't need (well, that's how supermarkets designed to work).

Online is a different story. I can't reproduce the same behaviour and go through the whole catalog. So I needed to plan my meals. I'd written down ingredients for my recipes on sticky notes and combined them to make an order.

This was really tedious. After a few orders I noticed that it was kind of repetitive. Although my wife will tell you that I just was lazy and didn't want to do boring stuff, the developer in me said that it's time to automate this and never solve the same problem again. 

That's how [Cooklang](https://cooklang.org) was born.

## About Cooklang

I though what if I store my recipes in Markdown-like text files and tag ingredients with `@` symbol? Like that:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3bk1w72fuhmd8su6r666.png)

That will make recipe files human and machine readable. 

Given these recipe files computers can create a shopping list and actually do much more: calculate nutrition values, costs or whatever given that information for ingredients provided.

And as it's stays human readable, that means I can be agile and store my recipes in git and perfect them over time (like code refactoring). 

Also because it's just a simple text format I avoid "vendor lock-in" problem and still can use my recipes the same way when I retire. My recipes are mine, forever.

## About tools

Having only a language specification isn't really helpful. Yes, I can store my recipes on GitHub and own them, but that's it. 

I imagined that it would be nice to have many small applications which can understand the language and do their own small thing very well: calculate calories, shopping, costs, smart meal planning, etc. I was really excited.

I read a wonderful book [Crafting Interpreters](http://craftinginterpreters.com) by Robert Nystrom and did a few experiments and I created a simple [parser](https://github.com/cooklang/CookInSwift) and [CLI app](https://github.com/cooklang/CookCLI). As I want to focus here on how I automated shopping I might do another post about the parser and CLI if anyone interested, so I skip all the details.

So CLI can understand Cooklang files, extract ingredients, and group them:

```
$ cook shopping-list \
> Neapolitan\ Pizza.cook \
> Root\ Vegetable\ Tray\ Bake.cook
BREADS AND BAKED GOODS
    breadcrumbs                   150 g

DRIED HERBS AND SPICES
    dried oregano                 3 tbsp
    dried sage                    1 tsp
    pepper                        1 pinch
    salt                          25 g, 2 pinches

FRUIT AND VEG
    beetroots                     300 g
    carrots                       300 g
    celeriac                      300 g
    fresh basil                   18 leaves
    garlic                        3 gloves
    lemon                         1 item
    onion                         1 large
    red onion                     2 items
    thyme                         2 springs

MEAT AND SEAFOOD
    parma ham                     3 packs

MILK AND DAIRY
    butter                        15 g
    egg                           1 item
    mozzarella                    3 packs

OILS AND DRESSINGS
    Dijon mustard                 1 tsp
    Marmite                       1 tsp
    cider                         150 ml
    olive oil                     3 tbsp

OTHER (add new items into aisle.conf)
    tipo zero flour               820 g

PACKAGED GOODS, PASTA AND SAUCES
    vegetable stock               150 ml
    water                         530 ml

TINNED GOODS AND BAKING
    cannellini beans              400 g
    chopped tomato                3 cans
    fresh yeast                   1.6 g
    redcurrant jelly              1 tsp
```

I also can set output format to `json` or `yaml` and feed this into other programs. Or just use good old plain text output manipulation and pipes in shell. It has a few more features like a web-server to explore the recipes with cooking mode and make shopping list in the browser.

I migrated a bunch of recipes from scattered sources into Cooklang format and stored them on GitHub repository https://github.com/dubadub/cookbook.

## My grocery shopping approach

Unfortunately, I haven't got far after that and fully automated shopping yet. I still need to do some manual steps because my shop doesn't provide any API access (surprise!).

That's how my process looks now:

1/ I generate a list of all ingredients. I added directories with symlinks to recipes which represent a meal plan. So it's easy to generate a list of ingredients for the whole directory like that:
```
$ cook shopping-list --only-ingredients ./Plan\ I
```

2/ I remove from the list whatever I have at home.

3/ I paste all the ingredients to a multi search input on the shop's web-site:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pr3r1gxfw1218il7hhcv.png)
 
4/ I manually go through each item and add to a cart 😓.

5/ Done!

It has a manual step, but still:
* much faster than before;
* has less cognitive load to my brain;
* more precise. 

I'm really happy with this precision part. I noticed that I now cover all my needs but not over consume. Eco-sufficiency in some way.

## What's next

I solved only 80% of my problem and I want to do more. I'm thinking to create a mapping between ingredients from my recipes and links to them at my shop's web-site. That will allow me to use `curl` or Selenium to complete the problem.


## Links

[Cooklang web-site](https://cooklang.org)
[Parser](https://github.com/cooklang/CookInSwift)
[CLI](https://github.com/cooklang/CookCLI)
[My recipes](https://github.com/dubadub/cookbook)