Automatic Shopping List: DIY smart shelf using strain gauges
Wouldn’t it be great if your shopping list would write itself? Wouldn’t it be great to have automated statistics about your grocery buying/consumption?
Reducing Shopping / Starting Stocking
When Corona hit about one year ago, there were empty shelves in stores everywhere. No matter where you looked: Shanghai, Moscow, Berlin, Paris, New York - panic buying everywhere.
In an effort to become resilient against such fluctuations in food (and more importantly toilet paper) availability, I started implementing the (german) government recommendations for crisis preparation. This includes stocking food for 14 days.
To keep this 14 day stock as well as reduce the number of times I go shopping, I started generating an inventory and shop only once a week (as opposed to daily). I now track around 150 different items that we keep on stock. This means that every week I spend around half an hour updating the inventory. A simple Google Sheet then diffs this against a list of items I want to stock and creates a shopping list.
To help with this I built a smart shelf that calculates it’s contents using four strain gauges. For every item added to the shelf, the center of mass can be determined in 2D by how the load is distributed across the four strain gauges.
Using the center of mass, as well as the different weight of the items, the shelf can be densely packed with many different items.
The ESP calculates the weight distribution many times a second. Weight shifts are ignored (pushing around stock on the shelf). Whenever there is a significant change in weight, the delta is sent out via MQTT:
This delta includes the delta weight as well as X and Y component as 0-1 (or rather -0.1 to 1.1 for the Y axis as the sensors are not placed at the rim of the shelf). A server application listens on the MQTT topic, does the matching of the delta weight distribution to configured items in a database and updates them with the new quantity.
The server application exposes the inventory as CSV over HTTPS.
Google Sheets periodically fetches the CSV via
=IMPORTDATA(...) and updates the inventory accordingly.
Bill of Materials
- 4x strain gauges 10KG
- 4x HX711 modules (which contain a 24bit ADC)
- 1x ESP8266 module LOLIN D1 mini
- 1x breadboard for power distribution (incl. 100µF capacitor to decouple the HX711 from the ripples of the ESP8266)
- (planned) 1x 80cm RGB addressable LED strip for feedback / UX
80Hz HX711 module
One of my goals was that the shelf becomes immediately responsive. Unfortunately the HX711 module that I picked only supports an update rate of 10Hz. Ultimately I want the LED strip in the background to show the location of newly added items without perceptible delay. I know from experience that my reaction time is as low as 100ms (at least used to be a decade ago), so the perception has to be faster. this is why I am aiming for <25ms latency. The next shelf will be built with a HX711 module with 80Hz update frequency.
User feedback via addressable LEDs
When adding items to the shelf, currently there is no feedback at all. In the future an addressable LED strip should:
- show the current position of newly added/removed items that are still pending the expiry of a debounce timer in real-time. This should even allow to let a ball roll over the shelf with the LED lights lighting up at the exact same place.
- show when the debounce timer expired and the MQTT message was sent
- Show the success / error of the server processing as well as how many items were added/removed. This LED pattern should also indicate which category of product was detected (e.g. by lighting up the entire valid X-range for this item)
Statistics / Dashboards
It will be trivial to not only expose this inventory as CSV, but also as prometheus endpoint. This will allow me to make dashboards about the state of the inventory and consumption over time.
Also I thought about adding more sensors that monitor storage conditions especially temperature and humidity. This first shelf includes a TMP36GZ, but it seems to give results off by a couple of °C (more than the datasheet permits). So I will probably go for a DHT22 in the next iteration.
The (very hacky) source is available at: https://gitlab.com/nielsole/logistics-board