from hcsr04 import HCSR04
from machine import Pin
from time import sleep

#declaracion de sensores
pir = Pin(27, Pin.IN, Pin.PULL_UP) #sensor de movimiento
sensor = HCSR04(trigger_pin=12, echo_pin=14) #sensor de distancia

#luces
ledVerde = Pin(19, Pin.OUT)
ledAmarillo = Pin(18, Pin.OUT)
ledRojo = Pin(5, Pin.OUT)

#constantes
portonT = 10 #tiempo(en segundos) que tarda el porton a abrir (forzado a 10 para fines practicos durante pruebas)
estaticoT = 10 #tiempo(en segundos) de espera para confirmar la detencion del vehiculo

allow = 1 #variable que contiene la confirmacion de ingreso correcto de contraseña (forzada a 1 para pruebas)
estadoactual = 0 #variable que contiene el estado actual en la operacion
contadorT = 0 #variable que cuenta el tiempo a apertura de porton
contadorEst = 0 #variable que cuenta el tiempo hasta confirmar que el vehiculo se detuvo

def operacion_Verde(estadoluz): #funcion que ejecuta una "operacion" con el led designado por su color segun el estado enviado
    if(estadoluz == 0): #apagar el led
        ledVerde.value(0)
    if(estadoluz == 1): #encender el led
        ledVerde.value(1)
    if(estadoluz == 2): #hacer parpadear el led
        ledVerde.value(1)
        sleep(1)
        ledVerde.value(0)
        sleep(1)

def operacion_Amarillo(estadoluz): #misma funcion que el anterior pero solo apaga/hace parpadear
    if(estadoluz == 0):
        ledAmarillo.value(0)
    if(estadoluz == 1):
        ledAmarillo.value(1)
        sleep(0.5)
        ledAmarillo.value(0)
        sleep(0.5)

def operacion_Rojo(estadoluz): #misma funcion que el anterior pero solo apaga/hace parpadear
    if(estadoluz == 0):
        ledRojo.value(0)
    if(estadoluz == 1):
        ledRojo.value(1)
        sleep(0.2)
        ledRojo.value(0)
        sleep(0.2)

def estado_luces(estado): #funcion que determina la operacion a realizar por cada led segun el estado actual
    if(estado == 0):
        operacion_Verde(0)
        operacion_Amarillo(0)
        operacion_Rojo(0)
    if(estado == 1):
        operacion_Verde(2)
    if(estado == 2):
        operacion_Verde(1)
    if(estado == 3):
        operacion_Verde(0)
        operacion_Amarillo(1)
    if(estado == 4):
        operacion_Amarillo(0)
        operacion_Rojo(1)

while True:
    estado_luces(estadoactual) #la funcion determina la operacion a ejecutar para cada led segun el estado actual (estado '0' por default)
    distance = sensor.distance_cm() #variable que guarda la distancia medida por el sensor (sensor mide en un rango de 400cms-2cm aproximado en ambos extremos)
    
    if(allow == 1 and estadoactual == 0): #si el estado actual es '0' y la contraseña es la correcta...
        estadoactual = 1 #...se pasa al estado '1' (el porton comienza a abrirse mientras que el led verde parpadea)
        print("estado actual:", estadoactual)

    if(estadoactual == 1):
        contadorT += 2 #se comienza a contar (de a dos por el intervalo de tiempo de cada parpadeo) hasta finalizar la apertura del porton
        print("seg:", contadorT)

    if(contadorT == portonT): #una vez finalizado la apertura del porton (determinado por el tiempo establecido) se pasa a estado '2'(led verde queda encendido para indicar que se puede ingresar a la cochera)
        contadorT = 0
        estadoactual = 2
        print("estado actual:", estadoactual)

    if(estadoactual == 2 and pir.value() == 1): #al alcanzar el estado '2', el sistema queda a la espera de detectar el ingreso del auto a traves del sensor laser
        estadoactual = 3 #el sensor laser se encuentra sobre la linea de la superficie y una vez accionado lleva al sistema al estado '3'(led verde se apaga, led amarillo comienza a parpadear hasta alcanzar la distancia x1)
        print("estado actual:", estadoactual)

    if(estadoactual == 3 and distance < 400): #cuando el auto llega a la distancia de deteccion del sensor y la atraviesa (distancia x1) el sistema pasa al estado '4'(led amarillo se apaga, led rojo comienza a parpadear hasta distancia final)
        estadoactual = 4
        distancia_ant = distance #en esta instancia, se guarda la distancia alcanzada para uso posterior
        print("estado actual:", estadoactual)

    if(estadoactual == 4):
        print("distancia actual:", distance)

    #si el vehiculo "retrocede" y sale por fuera del rango del sensor,
        #se vuelve al estado anterior
    if(estadoactual == 4 and distance >= 400):
        estadoactual = 3

    #dentro del estado '4' se controla si el auto se ha detenido
    #si la distancia actual se encuentra dentro un rango aproximado a la
        #distancia anterior, el contador se inicia. si se alcanza el limite
        #establecido entonces se confirma la detencion del vehiculo
    #si la distancia actual esta por fuera del rango, se guarda la nueva distancia
        #y se reinicia el contador
    if(estadoactual == 4 and distance < (distancia_ant + 0.2) and distance > (distancia_ant - 0.2)):
        contadorEst += 1
        print("distancia ant:", distancia_ant, "con aprox max:", (distancia_ant + 0.2), "con aprox min", (distancia_ant - 0.2))
        print("contador estatico:", contadorEst)
    else:
        contadorEst = 0
        distancia_ant = distance

    #el proceso termina cuando se alcanza el extremo inferior del sensor
        #o cuando el auto ha estado detenido durante una cierta cantidad de tiempo
    if((estadoactual == 4 and distance <= 3) or (contadorEst == estaticoT)):
        estadoactual = 0
        print("estado actual:", estadoactual)
        estado_luces(estadoactual)
        break