Blog/Software Development

How We Built Smart Scales for Our Office Coffee Drawer

Coffee beans and a white cup filled with coffee beans

We love automation! It does repeating tasks for us automatically and helps us avoid making mistakes, for example – forgetting to do something. Automation easily fits in where tasks repeat regularly. However, it’s also possible to automate irregular tasks. Here’s one example!

As we are heavy coffee drinkers, we ran into a problem with the coffee bean supply in our offices. We store coffee bean bags in drawers and sometimes forget to order it in a timely fashion. Coffee in our offices is consumed randomly and our office administrator has to check daily if we have enough of it or more must be ordered. It’s not that easy to get it delivered the same day and the mood in the office is not so great when we run out of coffee. We needed to find a solution!

So we started looking for some solutions to get notifications when supplies of these precious seeds run low. Unfortunately, we couldn’t find anything suitable and decided to weigh coffee beans with smart scales that we built ourselves. We are engineers and we love building new stuff!

Kitchen drawer with two bags of coffee beans on top of the smart scales developed by TestDevLab

We created a platform that can be put in a drawer and put coffee bean bags on top of it. The platform has 4 weight sensors (compression load cells), connected to HX711 chip (analog to digital converter) which is connected to a Raspberry Pi mini-computer through its GPIO pins.

When we looked for scales/sensors that can be connected to Raspberry Pi we found a few options, but picked the ones that would be delivered to us in the shortest period of time.

Smart scale weight sensor developed by TestDevLab

On Raspberry Pi, we installed Raspbian OS and used Python script which sends a signal to sensors and gets resistance value as a response. Then we calculated weight value out of these resistance values. If measured weight is less than the weight of two coffee bean bags, we repeat measuring weight 20 more times. If the average weight stays less than the weight of two full bags, we send a notification to Discord chat that we use internally.

Here is our main logic for reading data from HX711 chips:

try:
    print("Connecting to HX711...")
    hx711 = HX711(
            dout_pin=23,
            pd_sck_pin=24,
            channel='A',
            gain=64
        )
    result = hx711.reset() # Reset before start
    if result:
        print("Successful HX711 reset")
    else:
        print("HX711 reset failed")
        raise ValueError()
    print("Connected to HX711")

    while(repeatMeasurements):
        measures = hx711.get_raw_data()
        processMeasurement(int(sorted(measures)[1]/1000))
except Exception as e:
    logging.error("Exception", exc_info=True)
finally:
    GPIO.cleanup()

For sending a message to Discord we used simple webhook:

def sendToDiscord(message):
    url = <Your webhook url>
    formdata = "------:::BOUNDARY:::\r\nContent-Disposition: form-data; name=\"content\"\r\n\r\n" + message + "\r\n------:::BOUNDARY:::--"
    connection = http.client.HTTPSConnection("discordapp.com")
    connection.request(
        "POST", url, formdata, {
            'Content-Type': "multipart/form-data; boundary=----:::BOUNDARY:::",
            'cache-control': "no-cache"
        }
    )
    response = connection.getresponse().read()
    return response.decode("utf-8")

And we also created a CRON job that runs scale script every 10 minutes during the working days 9:00 – 17:00 (Monday – Friday).

0 9-17 * * 1-5 /usr/bin/python3 /home/pi/Desktop/scale.py
10 9-16 * * 1-5 /usr/bin/python3 /home/pi/Desktop/scale.py
20 9-16 * * 1-5 /usr/bin/python3 /home/pi/Desktop/scale.py
30 9-16 * * 1-5 /usr/bin/python3 /home/pi/Desktop/scale.py
40 9-16 * * 1-5 /usr/bin/python3 /home/pi/Desktop/scale.py
50 9-16 * * 1-5 /usr/bin/python3 /home/pi/Desktop/scale.py

We really didn’t want it to spam the chat, so we made sure that only one notification can be sent daily by saving the date after notification is sent and checking it before sending the next one. This way there will be only one notification per day about coffee bean supply running low.

def saveLastMessageSentTimeToFile():
    with open("scalescript_save.txt", mode='a') as file:
        file.write("%s" % (datetime.date.now()))       

def lastMessageSentDateFromFile():
    dateString = ""
    with open(dateSaveFile, "r") as file:
        dateString = file.read()
    if dateString == "":
        logging.warning("Could not read last send date from file: " + dateSaveFile)
    else:
        lastSentDatetime = datetime.datetime.strptime(dateString, '%Y-%m-%d %H:%M:%S.%f')
        dateString = lastSentDatetime.date()
    return dateString

And that’s it! We automated our coffee drawer and it will send us a notification once it’s time for new coffee delivery.

Notification that coffee supply is running low

You can find a full python script here.

Struggles?

Max load for one weight sensor is 50 kg so in total we can weigh 200 kg of coffee and that is a lot! This was one thing that was worrying us – we were not sure if these weight sensors would be precise enough for smaller weights of around 1-2 kg. But it turned out that they have a precision of roughly 0.01 kg and it is enough for this project.

Connecting all sensors was not hard at all and creating a platform was fun. Not to mention it was easy to find how to schedule scripts with CRON and use the HX711 chip on Raspbian with all the resources we have available today.

Below you can find some pictures from the process of building the platform and connecting everything together.

Picture showing how the weight sensor was built
Different equipment needed to build the weight sensor
Wires connected to the weight sensor
Wires connected and taped to the weight sensor
QA engineer having a video call with 5-start rating graphic displayed above

Deliver a product made to impress

Build a product that stands out by implementing best software QA practices.

Get started today