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
Methode 3 klingt ja schon gut. Erst mal zur Kontrolle und zum Verständnis ein Beispiel gerechnet, klappt. Also rein damit in das Python Script.
Leider keine Verbesserung. Es könnte sein, dass das Script zu langsam reagiert zwischen Trigger und Echo. Ich habe kontrolliert, dass das Script nicht zu langsam ist, zwischen Trigger und Echo dreht das Script ein paar Runden in der while-Schleife.
Ich werde noch einen anderen Modus der Platine testen und einen 120K Ohm Widerstand einlöten um ein serielles Signal zu bekommen. Fortsetzung folgt…
Weiter gehts:
Widerstand eingelötet mit einem kleinen Kabel, da ein „normaler“ Widerstand mit Beinchen viel zu groß ist.
apt-get install python-serial
Disable the login shell on the serial port in the interfacing options of „sudo raspi-config“, and reboot. For B+ that may be all that is required.
Später…
Mit dem 120kOhm Widerstand habe ich es nicht geschafft die Platine zum laufen zu bringen, vorerst.
Also 47kOhm Widerstand besorgt, damit startet die Platine sofort an und sendet ununterbrochen Signale. Damit konnte ich die Verdrahtung für das Auslesen kontrollieren, Signale kommen an.
Aber es sind nicht alle Messungen richtig, darum kümmere ich mich später.
Wieder den 120kOhm Widerstand eingebaut, und endlich das Geheimnis um das 0X55 Kommando mit viel probieren gelöst. Und dann noch mehr probiert, denn nirgends ist dokumentiert, dass man noch einmal ein Kommando senden muss um die Platine wieder zu deaktivieren.
Dann einen Codeblock gebaut, der Werte die zu weit außer dem Mittelwert sind verwirft und noch einmal einen neuen Mittelwert bildet.
Dann ein Codeblock der die komplette Messreihe verwirft wenn das Ergebnis nicht plausiebel ist, also außerhalb der Größe des Tanks.
Dann ein Code der vom Abstand umrechnet auf die Füllmenge des Tanks. Mein Tank sieht wie eine liegende Tonne aus, also sind Füllstand und Volumen nicht linear.
Dann das Ergebnis in eine Datenbank schreiben. Endlich fertig.
Und hier der komplette Code:
</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: