from machine import Pin, Timer, lightsleep, SLEEP, PWM
from esp32 import wake_on_ext0, WAKEUP_ALL_LOW, WAKEUP_ANY_HIGH
from time import sleep_ms

class Switch:

    def __init__(self, pin):
        self.switch = Pin(pin, Pin.IN, Pin.PULL_DOWN)
        self.last_status = self.status = self.switch.value()
        self.timer = Timer(-1)
        self.switch.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=self._isr, wake=SLEEP)

    def _isr(self, pin):
        # start one shot timer for 20 ms
        self.timer.init(period=20, mode=Timer.ONE_SHOT, callback=self._tsr)
        # disable interrupt
        self.switch.irq(trigger=0)

    def _tsr(self, pin):
        # read switch status
        self.status = self.switch.value()
        # enable interrupt
        self.switch.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING, handler=self._isr, wake=SLEEP)

    def read(self):
        return self.status

class LED:
    def __init__(self, pin):
        self.me = Pin(pin, Pin.OUT)
        self.me.off()

    def on(self):
        self.me.on()

    def off(self):
        self.me.off()

    def toggle(self):
        self.me.value(not self.me.value())

class Gong:
    
    def __init__(self, pin):
        self.pwm = PWM(Pin(pin))
        self.pwm.freq(440)
        self.pwm.duty(0)
        
    def strike(self, freq=440):
        self.pwm.freq(freq)
        for d in range(1, 255, 1):
            a = 1023 / d
            self.pwm.duty(int(a))
            sleep_ms(5)
        self.pwm.duty(0)

class App:
    def __init__(self):
        self.red = LED(2)
        self.green = LED(4)
        self.green.on()
        self.gong = Gong(16)
        print('If you want to abort, now is the time! (3 seconds)')
        sleep_ms(3000)
        self.last_status = 0
        self.sw = Switch(14)
        
    def run(self):
        while True:
            status = self.sw.read()
            if status != self.last_status:
                self.last_status = status
                self.red.toggle()
                self.green.toggle()
                self.gong.strike(3000)
                print(f'Status: { status }')
                sleep_ms(20)
            if status:
                wake_on_ext0(pin = 14, level = WAKEUP_ALL_LOW)
            else:
                wake_on_ext0(pin = 14, level = WAKEUP_ANY_HIGH)
            lightsleep(10000)
            # sleep_ms(3000)
            
    def check(self):
        status = self.sw.read()
        print(f'Current status is {status}.')
    
a = App()
a.run()

## lightsleep and wifi
## wifi.active(False)
## lightsleep(duration)
## wifi.active(True)
## wifi.connect()
## while not wifi.is_connected():
##  sleep_ms(200)