import time
import machine
import micropython
import network
from machine import Pin,PWM
from umqtt.simple import MQTTClient
#Indicamos red WIFI y clave
ssid = 'Wokwi-GUEST'
wifipassword = ''
#Datos Server MQTT (Broker)
#Indicamos datos MQTT Broker (server y puerto)
mqtt_server = 'io.adafruit.com'
port = 1883
user = 'joelrueda' #definido en adafruit
password = 'aio_YmmY86wdTJDgGXR6pGLD1CPYjt5L' #key adafruit
#Indicamos ID(unico) y topicos
client_id = 'MiAlarma3'
topic_PIR = 'joelrueda/feeds/SensorPIR3'
topic_ALARMA = 'joelrueda/feeds/ALARMA3'
#Usamos una variable para definir si la alarma esta activa
ALARMA_ACTIVA=False
LEDESTADO = Pin(14,Pin.OUT)

#Definimos modo Station (conectarse a Access Point remoto)
sta_if = network.WLAN(network.STA_IF)
sta_if.active(True)
#Conectamos al wifi
sta_if.connect(ssid, wifipassword)
print("Conectando")
while not sta_if.isconnected():
  print(".", end="")
  time.sleep(0.1)
print("Conectado a Wifi!")
#Vemos cuales son las IP
print(sta_if.ifconfig())

#Antes de conectarnos al broker, vamos a definir una funcion
#que sera llamada cada vez que se produzca un publish sobre
#un topico donde estamos suscriptos
def callback_alarma(topic, msg):
    global ALARMA_ACTIVA,LEDESTADO
    #Cuando se ejecuta esta funcion quere decir que
    #hubo un mensaje nuevo en algun topico, verificamos esto
    #Dado que lo que llega viene en UTF-8, lo decodificamos
    #para que sea una cadena de texto regular
    dato = msg.decode('utf-8')
    topicrec = topic.decode('utf-8')
    print("Cambio en: "+topicrec+":"+dato)
    #Nos fijamos si es el topico esperado y el valor del dato
    if topicrec == topic_ALARMA and "OFF" in dato:
        ALARMA_ACTIVA=False
    else:
        ALARMA_ACTIVA=True  
    LEDESTADO.value(ALARMA_ACTIVA)

#Intentamos conectarnos al broker MQTT
try:
    conexionMQTT = MQTTClient(client_id, mqtt_server,user=user,password=password,port=int(port))
    conexionMQTT.set_callback(callback_alarma)
    conexionMQTT.connect()
    conexionMQTT.subscribe(topic_ALARMA)
    print("Conectado con Broker MQTT")
except OSError as e:
    #Si fallo la conexion, reiniciamos todo
    print("Fallo la conexion al Broker, reiniciando...")
    time.sleep(5)
    machine.reset()


#Armamos un loop infinito que chequea por mensajes nuevos
#y verifica el estado del PIR
PIR = Pin(13,Pin.IN)
LEDPIR = Pin(12,Pin.OUT)
SIRENA = PWM(Pin(5), freq=1200, duty_u16=32768)
SIRENA.duty(0)
estadoPIR = PIR.value()
print("Comenzando monitoreo de PIR")
SONANDO=False #Estado de la sirena
while True:
    #Si se produce una excepcion, por ejemplo se corta el wifi
    #o perdemos la conexion MQTT, simplemente vamos a reiniciar
    #el micro para que comience la secuencia nuevamente, asi que
    #usamos un bloque Try+Except
    try:
        #Tenemos que verificar si hay mensajes nuevos publicados por el broker
        conexionMQTT.check_msg()
        time.sleep_ms(500)
        #actualizamos el LED
        estadoPIRNuevo = PIR.value()
        LEDPIR.value(estadoPIRNuevo)
        #Si la ALARMA esta activa...
        if ALARMA_ACTIVA:
            #Y el PIR detecta movimiento
            if estadoPIRNuevo:
                #Entonces tiene que sonar
                SONANDO=True
                #Si el estado anterior del PIR era 0, entonces notificamos
                #ya que el PIR estaba apagado y ahora encendido, o sea que acaba
                #de detectar movimiento
                if not estadoPIR:
                    #enviamos al server el cambio
                    print("PIR Activo durante estado de alarma activa")
                    conexionMQTT.publish(topic_PIR,str(1))
            else:
                #Si el PIR no detecta movimiento pero lo hizo anterior mente
                #Entonces notificamos
                if estadoPIR:
                    conexionMQTT.publish(topic_PIR,str(0))
        else:
            #Si la alarma no esta activa, no deberia sonar
            SONANDO=False
            
        #Siempre actualizamos el estado del PIR
        estadoPIR = estadoPIRNuevo
        if SONANDO:
            SIRENA.duty(512)
        else:
            SIRENA.duty(0)
    except OSError as e:
        print("Error ",e)
        time.sleep(5)
        machine.reset()