When I originally thought about this project, I was thinking of having the Raspberry Pi interface with another micro-controller which would take the actual measurements. The majority of the sensors are essentially designed to generate pulses. The frequency of these pulses corresponds to a certain value. For example, the rain gauge operates using a reed switch with a 100 Ohm resistor in series with it. When a hundredth of an inch of water passes through it, it momentarily closed the reed switch. Depending on how you hook it up, it can be either active low or active high. I prefer working with active high signals, so that is the design I went with.
However, after thinking about it for awhile I decided to use the GPIOs on the Raspberry PI and to use the interrupt library. In hind sight, that may not have been the best idea. I originally connected the rain gauge to the first GPIO pin (board pin 3). Unfortunately, the only place where it is documented that board pin 3 has pull up resistor on the Raspberry Pi board itself is in the code for the library. So when I first did my integration, it was throwing all kinds of errors and warnings. So, I ended up switching it to board pin 8. The schematic below is the updated schematic I am currently using.
The code is relatively simple. Rather than having locks, I use a counter. Due to the GIL in Python, the counter is essentially atomic (not that it matters much for this implementation anyway). Every hour, I calculate what the difference is in the current count from the previous hour’s count. I multiply by 0.01″ because every rising edge should be a hundredth of an inch and write it to the database.
#!/usr/bin/python3 import RPi.GPIO as GPIO import time import psycopg2 GPIO.setmode(GPIO.BOARD) GPIO.setup(8, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) c = 0 o = 0 def my_callback(channel): global c c = c + 1 print("Rain Gauge Trigger %i" % (c,)) GPIO.add_event_detect(8, GPIO.RISING, callback=my_callback) while 1==1: time.sleep(3600) t = c #read c once in case it changes r = (c-o)*0.01 o = t # now do the database update conn = psycopg2.connect("dbname=weather user=grafana password=[PASSWORD] host=[HOST]") cur = conn.cursor() cur.execute("INSERT INTO rain (time, amount) VALUES ('now', %s)", (r, )) conn.commit() cur.close() conn.close()
I run the program using screen so that I can disconnect from the Raspberry Pi. At some point, I plan on using systemd to run it as a daemon which is restartable and will run at boot. From, there I use Grafana to generate a nice display.
Unfortunately, one of the problems I do have is that there are a lot of “phantom” interrupts as in there are interrupts when it is not raining. I get a few of these an hour. I believe it has something to do with the logic level thresholds, so I am going to play with the pull down resistor to see if I can get them to go away.