#!/usr/bin/python

import sys, signal, logging, time, RPi.GPIO as GPIO

FLOATSW_HIGH_WL = 26                                  # high water level float switch
WATER_VALVE = 10                                      # GPIO port for the Water Electo valve, High by default after boot
VALVE_CHGSTATE_TIMER = 25                             # Electro valve needs roughly 20 seconds to switch from open to close and vice versa
logger = None

def Setup():
    global logger
    logger = logging.getLogger(__name__)
    logger.setLevel(logging.INFO)
    handler = logging.FileHandler('/var/log/rodi.log')
    handler.setLevel(logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(message)s',"%Y-%m-%d %H:%M:%S")
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    GPIO.setwarnings(False)
    GPIO.setmode(GPIO.BCM)
    GPIO.setup(WATER_VALVE, GPIO.OUT)
    GPIO.setup(FLOATSW_HIGH_WL, GPIO.IN, pull_up_down=GPIO.PUD_UP)      #, initial = GPIO.HIGH)
    if not sys.stdout.isatty():
        sys.stderr = open('/var/log/rodi_stderr.log', 'a')
        sys.stdout = open('/var/log/rodi_stdout.log', 'a')
        
def Alert(message):
    global logger
    logger.info(message)                                                # log the event
    print(message)
    logger.handlers[0].flush()

def Close_valve():
    GPIO.output(WATER_VALVE, False)
    Alert("Closing the RO/DI valve")
   
def Open_valve():
    if GPIO.input(WATER_VALVE) == True:
        Alert("RO/DI Valve already opened")
        sys.exit(5)
    else:
        Alert("Opening the RO/DI valve")
        GPIO.output(WATER_VALVE, True)
        time.sleep(VALVE_CHGSTATE_TIMER)

def Refilling():
   if GPIO.input(WATER_VALVE) == True:
       return True   
   else:
       return False

class GracefulKiller:
     kill_now = False
     def __init__(self):
         signal.signal(signal.SIGINT, self.exit_gracefully)
         signal.signal(signal.SIGTERM, self.exit_gracefully)
     def exit_gracefully(self,signum, frame):
         self.kill_now = True
           
if not len(sys.argv) > 1:
    print("You must provide one numerical argument to this function (duration in seconds). Exiting.")
    sys.exit(1)

if sys.argv[1] != "close" and sys.argv[1] != "stop" and not sys.argv[1].isdigit():
    print("Value is neither 'close', 'stop' or a refill duration expressed in seconds")
    sys.exit(1)

i = 0
killer = GracefulKiller()
Setup()

if sys.argv[1] == "close" or  sys.argv[1] == "stop":
    Close_valve()

if str.count(subprocess.check_output(["ps", "aux"]), "rodi") > 1:
    Alert("Warning, we were called while another instance of rodi.py was already in Memory")
    sys.exit(1)
    
if GPIO.input(FLOATSW_HIGH_WL) == 0:
    Alert("Water level in sump already high, refilling would be dangerous, exiting")
    if GPIO.input(WATER_VALVE) == True:
        Alert("RO/DI Valve already opened while high water in the sump, closing.")
        Close_valve()
        sys.exit(3)

if sys.argv[1].isdigit():
    Alert("Not already refilling, sump water level normal, proceeding.")
    Alert("Refilling for " + sys.argv[1] + " seconds")
    try:
        Open_valve()
        while i<VALVE_CHGSTATE_TIMER+int(sys.argv[1]):
            time.sleep(1)
            i=i+1
            if GPIO.input(FLOATSW_HIGH_WL) == 0:
                Alert("Water level in sump is now high, stopping the refill")
                Close_valve()
                sys.exit(3)
                break
            if killer.kill_now:
                Alert("Caught a Sigterm, Sigkill or CTRL+C, exiting.")
                Close_valve()
                sys.exit(2)
                break
        Alert("Refill done, exiting.")
        Close_valve()
        sys.exit(0)
    except (RuntimeError, IOError):        
        Alert("Caught an exception, exiting.")
        Close_valve()
        sys.exit(4)

# Exit code :
# 5 : already refilling or cannot create lock file
# 4 : Caught an exception
# 3 : water is high either at start or during the refill
# 2 : a sigkill, sigterm or keyboard CTRL+C signal was received
# 1 : incorrect parameter received
# 0 : all went fine