import utime import ujson import network import urequests import machine from machine import Pin threshold = 15 # cm sound_speed = 340 * 100 # m/s * centi = cm/s # TODO: add if open for more than 1 minute, send alert class App: ssid: str password: str server: str token: str opened: bool = False previously_opened: bool = False ultra_opened_counter: int = 0 ultra_opened_threshold: int = 3 led = Pin(15, Pin.OUT) trigger = Pin(2, Pin.OUT) echo = Pin(3, Pin.IN) def __init__(self): print("Loading .env.json...") with open(".env.json") as stream: data = ujson.load(stream) network = data.get("network") if network is None: print("'network' missing in env") exit(1) server = data.get("server") if server is None: print("'server' missing in env") exit(1) self.ssid = network.get("ssid") self.password = network.get("password") self.server = server.get("address") self.token = server.get("token") if self.ssid is None or \ self.password is None or \ self.server is None or \ self.token is None: print("missing properties in env") exit(1) def connect(self): print("Connecting to wifi...") wlan = network.WLAN(network.STA_IF) wlan.active(False) utime.sleep_ms(250) wlan.active(True) utime.sleep_ms(250) wlan.connect(self.ssid, self.password) utime.sleep_ms(100) i = 0 while not wlan.isconnected(): print(f"Waiting for connection{(i % 3 + 1) * "."}{3 * " "}", end="\r") i += 1 for _ in range(4): self.led.toggle() utime.sleep_ms(250) if i % 10 == 0: print("Attempting to restart connection...") wlan.connect(self.ssid, self.password) for i in range(10): self.led.toggle() utime.sleep_ms(50) print(f"Connected with IP {wlan.ifconfig()[0]}") self.update_server() def update_server(self): print("Updating state...", end="\r") data = {"opened": self.opened} raw = ujson.dumps(data) try: r = urequests.post(f"{self.server}/open", headers={"Authorization": self.token, "Content-Type": "application/json"}, data=raw) print(f"State updated [{r.status_code}]") except Exception as e: print(f"Error occurred: {e}") def ultra(self): self.trigger.low() utime.sleep_us(2) self.trigger.high() utime.sleep_us(10) self.trigger.low() # echo goes high as soon as sound wave is sent # and returns to low once sound gets back sent_time = utime.ticks_us() while self.echo.value() == 0: sent_time = utime.ticks_us() # us received_time = utime.ticks_us() while self.echo.value() == 1: received_time = utime.ticks_us() # us delta_time = received_time - sent_time # us distance = delta_time / 1_000_000 * sound_speed / 2 print(f"distance: {distance} cm") if distance < threshold: # door closed self.led.low() self.ultra_opened_counter = 0 # was it closed just now? if self.previously_opened: self.update_server() self.previously_opened = False else: # door opened self.led.high() self.ultra_opened_counter += 1 # was it opened just now? if not self.previously_opened: self.update_server() self.previously_opened = True def run(self): print("Starting door alarm...") self.connect() i = 0 # T = 500ms f = 2 Hz while True: try: self.ultra() if i >= 20: # every 10 seconds, blink for 100ms self.led.toggle() utime.sleep_ms(100) self.led.toggle() utime.sleep_ms(400) i = 0 else: utime.sleep_ms(500) except Exception as e: print(f"Fatal exception occurred: {e}") i += 1 if __name__ == "__main__": App().run()