RasPi Flow Meter In A Pinch – Part 2

META: Part 1 describes the problem I’m trying to solve here.

I need a way to monitor water flow through my water filter over several days, and I don’t want to sit and watch it.

So – I took a Raspberry Pi I’ve got and a little Python and hacked a solution together.  The basic idea was that I’d position a plastic cup below the output stream of the waste water, I’d put two wires into the cup, I’d put a voltage on one wire and attempt to see the voltage on the other.  I’d use the Raspberry Pi to check for the voltage once per minute and log the status to a file with a timestamp.  Later, I could graph the state of the voltage – DETECTED or NOT DETECTED – over time, and produce a graph showing when the waste water was running.  With that I could even get an approximate flow rate waste water, if I wanted, by measuring how long it takes to output a liter of waste water and multiplying by run time.

First – the cup.  The simple flow meter.  I poked a hole in the bottom so water drains out slowly, and poked a couple holes through the sides to hold wires in position close to each other without touching.  When water covers the wires current should be able to flow between them, when the water drains out current should stop flowing.  If the waste water overflows the cup it will just run over and down the drain as it usually does.  It takes about 30 seconds for water to drain from overflow until the wires are not conducting, and I was hoping to measure conductivity every minute, so my initial cup holes were close enough.  The waste water runs quickly enough that the cup fills up in about a minute.  This means that polling every minute should produce a graph that closely represents reality.

Cup with two wires hooked up, water running into the top, and water overflowing down the side.  Cup is sitting in a laundry room slop sink.

Next – the Raspberry Pi.  I got Adafruit’s Pi Cobbler along with the Pi, which is a cleverly-named pinout that’s easy to plug into a breadboard.  That plus this handy tutorial from Make made it really easy to write a little voltage tester.  Here’s the code.

#!/usr/bin/env python3

import RPi.GPIO as GPIO
from time import sleep, ctime
import atexit

INPUT_PIN=21
POLL_PERIOD=60
LOG_FILE="/home/username/waterLog.csv"

def resetGPIO():
 GPIO.cleanup()

def setupGPIO():
 GPIO.setmode(GPIO.BCM)
 """ Set INPUT_PIN to pull-up, so the signal will be when it goes low
  That way, we won't potentially source a lot of current to ground with
  a positive voltage, and also just the ground of water might pull it down,
  which would indicate there's water in the cup (and therefore, is what we
  want)
  """
 GPIO.setup(INPUT_PIN, GPIO.IN, pull_up_down = GPIO.PUD_UP)
 
def pollForWater():
 with open(LOG_FILE, "a") as f:
  f.write(",".join((ctime(), str(GPIO.input(INPUT_PIN) == 0)))+"\n")

if __name__ == "__main__":
 atexit.register(resetGPIO)
 setupGPIO()
 while True:
  pollForWater()
  sleep(POLL_PERIOD)

So, now I connect the Pi to a ribbon cable, to a Pi Cobbler, to a breadboard, to two wires on pin 21 and a ground pin respectively.  The other ends of the wires are not touching and are in the cup.  A couple design choices – I could make the pin I’m using for input (pin 21) connect to the Pi via a pull-up or a pull-down resistor.  These options, and the resistors, are built-in to the Pi and selectable in code.

I told pin 21 to use a pull-up resistor, but if instead I told pin 21 to use a pull-down resistor, it would normally rest at 0 V and I would detect a voltage (and thereby detect water) by connecting 3.3 V to the other wire.  There’s a problem with that – I’m putting these wires in water and that will potentially introduce another “ground” connection.  When the wires touch water, the 3.3 V wire would essentially be connected directly to ground, and then the Pi would try to provide a bunch of current, and that could be bad for the Pi.

I told pin 21 to use a pull-up resistor, so that means it normally rests at 3.3 V.  It is connected through a good-sized resistor to 3.3 V, so when nothing is connecting the pin to ground or some other voltage, that resistor “pulls” the voltage on pin 21 up to 3.3 V.  If something connects the pin to ground, the Pi will try to provide current again, just like before.  However, in this case the good-sized resistor is in the way, between 3.3 V and ground, so the Pi won’t have to provide too much current to get everything to equilibrium.  Some folks call this “current limiting” – the Pi is limited to how much current it can provide.  A voltage source simply provides enough current to raise the voltage at its output to its set level.  When that happens, all the currents and voltages balance out and everything reaches equilibrium and stays the same until some other thing happens to the circuit to throw everything out-of-balance.  With pin 21 set as “pull-up”, even if the water introduces another ground, nothing bad should happen to the Pi.

Another design choice – I used Python’s “atexit” to cleanup the Pi’s GPIO port.  The example website I linked to above simply put it after the “while True” polling loop.  The problem with putting the GPIO cleanup after the infinite loop is that if you kill the program by pressing ctrl+c (or by any other means I can think of) the cleanup code never runs.  Python just exits the program immediately.  By registering the cleanup code with “atexit”, Python will run that cleanup code as the last thing it does whenever it possibly can.  There are ways to kill the program where Python will bypass atexit, but all the common methods will let Python exit cleanly and cleanup the port.  Port cleanup isn’t critical in my case – I’ve already got the simple ground protection setup I described above, but it can’t hurt, and if I ever just copy my old code into a new project I’ll be glad I did it correctly.

Raspberry Pi connected via ribbon cable to breadboard.  Breadboard has several circuits on it, and is sitting on a table.  Two wires run from breadboard to slop sink to the right.

Um, that’s pretty much it.  There’s some other stuff on the breadboard but it’s just an old circuit and is irrelevant here.

Waste water hose draining into cup (the cup with the two wires, sitting in the slop sink).

So, that’s what the setup in the sink looks like.  The water is running out of the output here, it’s hard to see in the photo but there’s the shadow.

Photo of a command prompt terminal displaying sample output.  Sample output is date stamp on the left followed by a true or false value, separated by a comma.  The time stamps are a second apart, and true/false values vary through the data.

And here’s a photo of the screen.  Because no screenshots for you.  Just gonna take a photo and pretend like that’s cool.  See how some say true and some say false?  This was a test run, polling every second.  When the wires are less than half-submerged they don’t provide a clean on/off signal to the Pi.  That’s ok, this was a hack.  When I poll only every minute the on/off signal gets much sharper.

Screenshot of terminal data taken once a minute, timestamp comma true/false.  All of the early time stamps are true, then about halfway through they switch to all-false.

Actual data – a screenshot this time because we’re not savages.  I filled up some containers at around 17:20, that caused the filter to start filtering and the waste water to start running, then the water ran until about 18:31, so about an hour.  I would expect that the water doesn’t run again until late tomorrow at the earliest…  We’ll see!

RasPi Flow Meter In A Pinch – Part 1

META: This first part is about the problem that caused me to build the solution.  Part 2 is about the solution.

My new place has an awesome feature that was disabled when I moved in – a reverse osmosis water filter!  It’s not a whole-house hookup, it’s just for the refrigerator and a dedicated tap on the sink.  We definitely wanted to use this thing!  At first, I just turned it on and it seemed to work fine.  However, with a little time, I noticed that the output water from the filter never seemed to stop, and there was a small leak on the “filtered water” side…

A marketing image of a reverse osmosis filter.  There's a storage tank that holds about four gallons on the left, there's a five stage filtering system on the right.  The first three stages are long tubes along the bottom, they filter out sediment and shit.  The fourth stage is the reverse osmosis membrane.  It's the branes of the operation, but it's hidden behind the fifth stage and sitting on a small platform just above those first three cylinders.  Stage four and five are squat horizontal cylinders.  Stage five modifies water flavor.

So – reverse osmosis filtering – it uses water flowing past a membrane to pull impurities out of the water on the other side of the membrane…  It uses water to filter water…  Pretty crazy.  That water that did the pulling, however, has to get dumped down the drain.  The filtering system wastes about 5 times as much water as we drink.  Not great, I know, but maybe I’ll rig the thing up to water the plants later, or something.  It’s not like the waste water got very dirty.

Anyway – that waste water never stopped running.  It was very wasteful.  The parts didn’t really have numbers on them so I couldn’t lookup the system to figure out what was wrong…  I just called some dude who knew.

And he wanted $340 to fix the thing!  Crazy.  I can figure this out.

I decided to start by fixing the small leak.  Start small!  I figured out how the hoses worked, then figured out how to look the system and spare parts up online, then rejiggered the output hose, and the leak stopped.  Score!

The waste water output is controlled by two valves.  One valve prevents backflow – when this is broken it frequently causes the waste water output to never stop.  The other valve is a pressure balance thing, so when the filtered water side pressure is close-enough to the input water pressure the valve closes off and it stops water from flowing through the filter.  Pretty slick!  When the pressure balance is broken it frequently causes the waste water output to never stop.  A little troubleshooting indicated that the pressure-balance valve was the real culprit.  Perhaps it was broken, or dirty, or just out of balance?

It was at about this point in the troubleshooting that I realized the output water was not continuously running anymore – the entire system seemed to be working properly.  I think solving the small output leak caused the pressure on the filtered size to raise enough that it closed the pressure-balance valve.

Problem solved!  Maybe…  I’m never very confident when problems with systems I don’t understand very well seem to solve themselves…  It’s nice, but not ideal.  Plus, it’s hard to tell if the output water is really running a sensible amount.  The system has this tank built in to store up water, so even after we dispense a normal amount, the pressure in the filtered side is still pretty high – it’s still high enough that the system doesn’t need to filter more water right away.  That sets up this very nice natural hysteresis, which is great for the system but not great for troubleshooting.

To be confident everything is working, I need to monitor the waste water output for several days.  I do not want to watch the output valve for several days.  I need a data-recording flow meter.  Time to get nerdy!