KegMon Electronics

If I’m entertaining even a few friends Murphy’s law always expresses itself as “If guests are counting on beer, the keg will run out”. Clearly more data (and more beer) is the solution to this problem: today we build a device to monitor the quantity of beer left in my Kegerator.


Simply stated, I need a way to determine the amount of beer left inside a keg. As an average beer is 16ounces I’d like to be able to measure differences of less than an ounce. One could weigh the keg to determine the quantity left; however, I initially dismissed using weight as I assumed available sensors were too inaccurate. One could count pours using a simple switch on the tap handle, but this does not account for partial pours or top-offs and seems far too inaccurate. Alternatively, one can monitor the quantity of beer as it is poured to determine what is left.


The Swissflow800 inline flow monitor is incredibly accurate: it measures around .164mL increments with little calibration or optimization. It covers flow velocities of 0.5 to 20 liter per minute at temperatures of -20 to +90 °C and an operating pressure of up to 230psi (16bar or 1.6MPa) – it seemed perfect. Sadly, the accuracy comes with tradeoffs. First and foremost the sensor is expensive at around $150. There are more prohibitive drawbacks: for each 0.164mL of fluid, the Swissflow sends a pulse which the micro controller must track and count. At the flow rate of beer even my ArduinoMega couldn’t keep up. I let the Arduino count every 10 ticks (1.64mL) before running some math, then 100 (16.4mL) but no luck. There are ways of making this work but with the price tag on the SwissFlow I decided this path was not optimal.

How to get an accurate weight of an object as it varies from 160lbs to 30lbs? Fortunately, MeasSpec recently released the FX1901 load cell, touted as a “1% load cell device with full scale ranges of 10, 25, 50 or 100 and 200lbf compression” with “breakthrough price/performance value”. I picked one up from for about $30 and tested it out: at the initial setup, it detected smaller than half-ounce differences, far better than I had hoped, and far better than the spec sheet indicates!


Parts List

    1. Particle Photon the WiFi enabled Arduino-ish microcontroller
    2. Load cell FX1901 from MeasSpec, purchased from
    3. Burr-Brown INA125P instrumentation amplifier, available from Mouser (necessary because load cells only produce a very small change in voltage) Amplifier amplification is set via a simple resistor across pins 8 and 9. I started with 1kΩ, it gave me good results so I didn’t try to optimize any further.
    4. Electronics enclosure, 3d printed
    5. Some stainless steel framing angles from McMaster-Carr to build the stand
    6. Audio jack. Not required, I like to wire into a three connection audio jack for easy assembly and disassembly.

Electronics assembly is easy. Follow the data sheets on the load cell and instrumentation amplifier, or mimic this Fritzing diagram:

KegMon Fritzing

The stand is very simple; a better stand will be a future exercise, for now this one is functional. An average keg weighs 160lbs when full and around 30lbs when empty. To use a 100lbf sensor we need to relieve some of that load, but still apply a proportional amount. A quick triangular frame built with framing angles left over from a previous project will balance the load nicely across three feet – one of which is the load sensor. In the event there is more force (such as during installation) the load cell can handle a 250% overload, so just try not to drop it more than a couple inches onto the stand.

KegMon Loadcell

The load must be directly applied to the nub in the middle of the load sensor. While not glamorous, the same 5/16″ bolt used for assembly fit nicely onto the center tip without touching any edges. There isn’t a lot of lateral movement of a keg after installation so there isn’t a big need to secure the sensor at this time.


Once the hardware is hooked up, a very simple program reads the load cell’s amplified analog signal from the Photon’s pin 0. The response from the load cell is linear, linear interpolation can be used to get a value using two known loads (I used empty and full):

 float newReading = analogRead(A0); // Read the voltage from the amplified load cell on pin A0
 float load = ((bLoad - aLoad)/(bReading - aReading))*(newReading - aReading) + aLoad; // Using our predefined calibration values (empty and full) interpolate the load reading to get a value.

aLoad and bLoad are known loads, 30lbs and 160lbs respectively, while aReading and bReading are pre-recorded sensor readings at those loadings.

Unfortunately, the load sensor’s output is noisy. For now, I query the analog pin almost continuously then average those readings to get a representative value. Eventually I want to use a Kalman filter for better accuracy. After removing noise, the final value is posted to a web service every ‘interval’ seconds using Particle’s TCPClient function:

if (millis() > mytime + interval) {
      weight = weight/count; // Average the readings taken over the last interval
      sprintf(url, "/postdata.php?user=0001&weight=%2.2f", weight);
      getrequest(); //send to server

      mytime = millis(); //reset all the values for the next post interval
      count = 0;
      weight = 0;

The php script records all the data posted to a database or flat file. From here, the data can be manipulated in some fun ways – an exercise I’ll leave to the reader. My guests always enjoy knowing their average ounces per hour consumed, how much the flow rate spikes at halftime versus in the middle of a big play, or beers per month consumed. ‘Estimated time until empty’ is one of my favorite metrics for parties and judging how popular a particular home-brew recipe is.

A sample graph of a few pourings is below, in which you can see the accuracy of the load cell:

Each large drop is about a beer, each small drop is smaller portions of a beer.

Final Considerations

I’ll be making some improvements. The stand needs some work, as does the algorithm to remove noise. I’ve also noticed a slight drift over time, generally upwards, by about 4-6 ounces over an evening. I want to figure out if this is caused by temperature or settling or some other factor, and see if I can filter it out.

More photos are available here:

Email or tweet me if you have questions.

See it running live on our kegerator: