UPDATE: neuere Version des Beitrags unter: Regenwassertank Füllstand messen mit Raspberry Pi; Version 2020
Hardware:
Raspberry Pi
DYP-ME007Y
Software:
Am Ende wurde es: python und mysql
Vorwort zum DYP-ME007Y: hier gibt es wohl verschiedene Versionen, die beste Erklärung dazu habe ich hier gefunden: JSN-SR04T-2.0.pdf
Ich verwende die Variante ohne Widerstand, also die simple Variante.
Dazu habe ich mal ein Script zum antesten gesucht und auch gleich was gefunden.
http://town-und-country.taunustörtchen.de/ueberwachung-der-zisterne-mit-dem-raspberry-pi/
ABER: die Berechnung gilt für einen Tank der über die gesamte Tiefe einen konstanten Querschnitt hat. Mein Tank ist aber ein liegender Zylinder, was bedeutet, dass 10 cm Unterschied im Wasserstand viel mehr Volumen hat als der selbe Unterschied ganz oben oder ganz unten.
Also mal auf die Suche gemacht nach einer verwendbar einfachen Formel.
Der zweite Treffer in der Online-Suche war
</pre>
#!/usr/bin/python
# coding=utf8
import time
import math
import sys
import RPi.GPIO as GPIO
#################### select mode ######################
# mode 1 = analog (R27 empty)
# mode 2 = serial, running continuous (R27 = 47kOhm)
# mode 3 = serial with trigger from script (R27 = 120kOhm)
mode=3
#################### Tank settings ####################
voll=70 # 70 cm von Sensor bis Wasseroberfläche = voll
leer=230 # 230 cm von Sensor bis Wasseroberfläche= leer
laenge=230 #230 cm Länge des Tanks
radius=90 #90 Radius Tank
korr= 0 # 20 wird zur Entfernung addiert
echo_time = 2 # delay between measurements in seconds ### make sure no echo is left
allowed_dev = 0.1 # filter out wrong measurements
#################### serial settings ####################
if (mode == 3) or (mode == 2):
import serial
#seriellen Port einstellen
ser = serial.Serial("/dev/ttyAMA0", baudrate=9600) #, timeout=3.0
ser = serial.Serial(
port='/dev/ttyAMA0',
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1
)
#################### analog settings ####################
elif (mode == 1):
GPIO.setmode(GPIO.BOARD)
trig=13
echo=15
GPIO.setup(echo,GPIO.IN)
GPIO.setup(trig,GPIO.OUT)
else:
print "Mode falsch."
print >> sys.stderr, "Mode falsch."
GPIO.cleanup()
sys.exit(1)
###### main ###############
entfernung=0
gesamt=0
entf_array = {}
for i in range(0,10):
if (mode == 1): ### analog
GPIO.output(trig,True)
time.sleep(0.00001)
GPIO.output(trig,False)
j = 0
while GPIO.input(echo) == 0:
pass
start=time.time();
while GPIO.input(echo) == 1:
pass
ende = time.time();
entfernung=(((ende - start) * 34300) / 2)+korr
elif (mode == 2): ### serial cont.
ser.flushInput()
#import pdb
#pdb.set_trace()
#ser.write(bytes([0x55]))
#startbyte = ord(ser.read(1))
startbyte = 1
while startbyte != 255:
read = ser.read(1)
print read
if len(read) == 0:
continue
else:
startbyte = ord(read)
hbyte = ord(ser.read(1))
lbyte = ord(ser.read(1))
sbyte = ord(ser.read(1))
entfernung = (hbyte * 256 + lbyte)/10 + korr
summe = startbyte + hbyte + lbyte
summe = summe - (int(summe/256) * 256)
if summe != sbyte:
entfernung = 0
print(startbyte, hbyte, lbyte, sbyte, entfernung)
elif (mode == 3): ### serial standby
ser.flushInput()
ser.write(chr(0X55))
#startbyte = ord(ser.read(1))
#import pdb
#pdb.set_trace()
startbyte = None
while startbyte != 255:
read = ser.read(1)
if len(read) == 0:
ser.flushInput()
continue
else:
startbyte = ord(read)
hbyte = ord(ser.read(1))
lbyte = ord(ser.read(1))
sbyte = ord(ser.read(1))
ser.flushInput()
ser.write(chr(0X55))
ser.write(chr(0X55))
entfernung = (hbyte * 256 + lbyte)/10 + korr
summe = startbyte + hbyte + lbyte
summe = summe - (int(summe/256) * 256)
if summe != sbyte:
entfernung = 0
#print (i)
#print(startbyte, hbyte, lbyte, sbyte, entfernung)
print entfernung
entf_array[i] = entfernung
gesamt=gesamt+entfernung
time.sleep(echo_time)
mittelwert=gesamt/(i+1)
##### filter mismatching measurements
i = 0
gesamt = 0
for entf in entf_array:
if entf_array[entf] < mittelwert*(1+allowed_dev) and entf_array[entf] > mittelwert*(1-allowed_dev):
gesamt=gesamt+entf_array[entf]
i=i+1
mittelwert=gesamt/(i)
##### discard if median is outside full or empty
if (mittelwert < voll or mittelwert > leer):
print "Messung ausserhalb Bereich: " + str(mittelwert)
print >> sys.stderr, "Messung ausserhalb Bereich: " + str(mittelwert)
mittelwert = None
volumen = None
#if (mode == 1):
# GPIO.cleanup()
#sys.exit(1)
else:
##### convert distance to round tank volume
print "Entfernung: ", mittelwert, " cm"
hoehe = (leer - mittelwert)
acosval = (radius - hoehe)/float(radius) # float needed else python rounds to int
alpha = 2*math.acos(acosval)
volumen = int(round(laenge * radius*radius/2*(alpha -math.sin(alpha))))
check = False
if check:
print "leer: ", leer, " cm"
print "radius: ", radius, " cm"
print "laenge: ", laenge, " cm"
print "hoehe: ", hoehe, " cm"
print "acosval: ", acosval, ""
print "alpha: ", alpha, " rad"
print "Volumen: ", volumen, " cm³"
print "Volumen: ", volumen/1000, " Liter"
print "- - - - - - - - - - - - - - - - - - - - - "
#f1=open('/var/scripts/regentank_check/entfernung.txt','w')
#print >> f1, '%d' % (mittelwert)
#f1.close()
#f2=open('/var/scripts/regentank_check/volumen.txt','w')
#print >> f2, '%d' %(volumen)
#f2.close()
#f1l=open('/var/scripts/regentank_check/entfernung.txt','r')
#f2l=open('/var/scripts/regentank_check/volumen.txt','r')
#serverftp = ftplib.FTP('ftp.server.de', 'user', 'pass')
#serverftp.storbinary('Stor entfernung.txt', f1l)
#serverftp.storbinary('Stor volumen.txt', f2l)
#serverftp.quit()
import MySQLdb
db = MySQLdb.connect(host="localhost", # your host, usually localhost
user="regenwasseruser", # your username
passwd="password", # your password
db="regenwasser") # name of the data base
# you must create a Cursor object. It will let
# you execute all the queries you need
cur = db.cursor()
# Use all the SQL you like
if volumen:
vol_string = str(int(round(volumen/1000,0)))
else:
vol_string = "Null"
cur.execute("INSERT INTO volumen (`datetime`,`volume`) VALUES (now()," + vol_string + ")")
db.commit()
db.close()
#### clean up after using GPIO mode
if (mode == 1):
GPIO.cleanup()
<pre>
Und zu guter letzt, noch meine Skizzen von der Verkabelung, für Modus 1, 2 und 3:
Modus 1, analog, kein Widerstand:

Modus 2, seriell Dauer, 47kOhm Widerstand:

Modus 3, seriell Standby, 120kOhm Widerstand:

Und noch eine Warnung: ich hatte einen Schlauch quer durch den Tank liegen von der Wasserpumpe. Der Sensor hat, als der Wassertand viel, den Schlauch erfasst. Unbedingt darauf achten, dass die Richtung in die der Sensor misst auch wirklich frei ist.
Ich lasse das script jetzt einmal pro Tag per crontab laufen.
Hier gehts zum Setup des Systems: http://bitsnbites.astrids.bplaced.net/?p=145
Oder weiterlesen beim erstellen der Anzeige des Füllstands mit html und php:
