#Developed by JJ Slabbert for the PiSiphon Rain Gauge, Part of the raspberry pi open weather station.
#Python 2.7 used for testing.
#Siphoning Counter and Cylinder Level Measuring app for PiSiphon.

#Probe Pairs:
#Probe Pair 1 (lowest water level), Pin 26 and 20)
#Probe Pair 2, Pin 19 and 16
#Probe Pair 3, Pin 6 and 12
#Probe Pair 4, Pin 0 and 1
#Probe Pair 5, Pin 11 and 8

#Althought gpiozero is very usefull, the number of times that a pin can be re-used (switch between input and output, using the close() function), is limited.
#It seems like a new thread is generated by gpiozeroo, each time the the pins are switch between input/output.
#Therefore, The RPi.GPIO module will be used instead of gpiozero.

#WARNING: Electricity is dangerous. Water and high voltage/current should always be avoided. The rasperri pi use low voltage and current, making this project save.

import time
import RPi.GPIO as GPIO
t=0.0 #Total rainfall
rs=0.95 #Rainfall between siphonings. You need to calculate this with calibration.
sc=0 #Siphoning Counts
l=0 #Siphon Cylinder water level. 0,1....5
old_l=0 #Previous Siphon Cylinder water level. 0,1....5

print("Siphoning Counter and Cylinder Level Measuring app for PiSiphon.")

n=0.0 
while True:
    GPIO.setmode(GPIO.BCM)
    n=n+1
    if n/2==int(n/2): #Case for even n. The direction of current is changed on each alteration of the loop to reduce electrolysis        
        GPIO.setup(26,GPIO.OUT)
        GPIO.output(26, GPIO.HIGH)
        GPIO.setup(19,GPIO.OUT)
        GPIO.output(19, GPIO.HIGH)
        GPIO.setup(6,GPIO.OUT)
        GPIO.output(6, GPIO.HIGH)
        GPIO.setup(0,GPIO.OUT)
        GPIO.output(0, GPIO.HIGH)
        GPIO.setup(11,GPIO.OUT)
        GPIO.output(11, GPIO.HIGH)

        GPIO.setup(20,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(16,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(12,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(1,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(8,GPIO.IN,GPIO.PUD_DOWN)
        
        p1=GPIO.input(20)
        p2=GPIO.input(16)
        p3=GPIO.input(12)
        p4=GPIO.input(1)
        p5=GPIO.input(8)        
    else: #Case for odd n. The direction of current is changed on each alteration of the loop to reduce electrolysis        
        GPIO.setup(20,GPIO.OUT)
        GPIO.output(20, GPIO.HIGH)
        GPIO.setup(16,GPIO.OUT)
        GPIO.output(16, GPIO.HIGH)
        GPIO.setup(12,GPIO.OUT)
        GPIO.output(12, GPIO.HIGH)
        GPIO.setup(1,GPIO.OUT)
        GPIO.output(1, GPIO.HIGH)
        GPIO.setup(8,GPIO.OUT)
        GPIO.output(8, GPIO.HIGH)

        GPIO.setup(26,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(19,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(6,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(0,GPIO.IN,GPIO.PUD_DOWN)
        GPIO.setup(11,GPIO.IN,GPIO.PUD_DOWN)
        
        p1=GPIO.input(26)
        p2=GPIO.input(19)
        p3=GPIO.input(6)
        p4=GPIO.input(0)
        p5=GPIO.input(11)

    GPIO.cleanup() #Cleanup is needed to switch input/output (direction of current) pins
    status_bin=str(p1)+str(p2)+str(p3)+str(p4)+str(p5)
    status_int=int(status_bin,2)
    if status_int==0:
        l=0.0
    elif status_int==16:
        l=1.0
    elif status_int==24:
        l=2.0
    elif status_int==28:
        l=3.0
    elif status_int==30:
        l=4.0
    elif status_int==31:
        l=5.0
    else:
        l=old_l #error. You need to clean the probes.
        print("An unlogical Cylinder level was detected. This may hapen while Siphoning, when probes are dirty or in case of bad probe connection.")
    
    if l<old_l-2: #This indicates an siphon event
        sc=sc+1
    t=sc*rs+(l/5)*rs
    localtime = time.asctime( time.localtime(time.time()))
    f=open("rain_log_PiSiphon.txt", "a+")
    time.sleep(0.2)
    f.write(localtime+", "+str(sc)+", "+str(l)+", "+str(t)+"\n")
    time.sleep(0.2)
    f.close()    
    print ("Siphoning Counts: "+str(sc)+", Current Siphon Cylinder Level: "+str(int(l))+", Total Rainfall: "+str(t))
    old_l=l
    if n==10000: # prevent n from taking up to much memory. My experience: "python can create memory leaks"
        n=0
    time.sleep(10)
