from machine import Pin, PWM, Timer, time_pulse_us
import time
# ======================
# Settings
# ======================
DISTANCE_THRESHOLD = 20 # cm
ANGLE_OPEN = 90
ANGLE_CLOSED = 0
DEBOUNCE_MS = 200
TRIG_PIN = 5
ECHO_PIN = 18
SERVO_PIN = 27
# ======================
# Hardware
# ======================
trig = Pin(TRIG_PIN, Pin.OUT)
echo = Pin(ECHO_PIN, Pin.IN)
servo = PWM(Pin(SERVO_PIN), freq=50, duty=0)
# ======================
# State (Interrupt style)
# ======================
last_irq_time = 0
request_open = False
request_close = False
door_is_open = False
# ======================
# Servo control
# ======================
def servo_angle(deg):
duty = int((((deg) / 180.0) * 2.0 + 0.5) / 20.0 * 1023)
servo.duty(duty)
# ======================
# Ultrasonic read
# ======================
def get_distance():
trig.off()
time.sleep_us(2)
trig.on()
time.sleep_us(10)
trig.off()
duration = time_pulse_us(echo, 1, 30000)
if duration < 0:
return 999
return (duration * 0.0343) / 2
# ------------------1---------------------
# ======================
# "Interrupt" handler (edge trigger simulation)
# ======================
def Ultrasonic_irq_open():
global last_irq_time, request_open
now = time.ticks_ms()
if time.ticks_diff(now, last_irq_time) > DEBOUNCE_MS:
request_open = True
last_irq_time = now
def Ultrasonic_irq_close():
global last_irq_time, request_close
now = time.ticks_ms()
if time.ticks_diff(now, last_irq_time) > DEBOUNCE_MS:
request_close = True
last_irq_time = now
# ------------------2---------------------
# ======================
# Actions
# ======================
def open_water():
global door_is_open
servo_angle(ANGLE_OPEN)
door_is_open = True
print("Water is on")
def close_water():
global door_is_open
servo_angle(ANGLE_CLOSED)
door_is_open = False
print("Water is off")
# ======================
# Init
# ======================
servo_angle(ANGLE_CLOSED)
print("System Ready 🚰")
# ======================
# Previous state (IMPORTANT for edge detection)
# ======================
was_close = False
# ------------------3---------------------
# ======================
# Main loop
# ======================
while True:
distance = get_distance()
print("Distance = ", distance)
# ======================
# EDGE DETECTION (this is the key idea)
# ======================
# Entering range → OPEN interrupt
if distance < DISTANCE_THRESHOLD and not was_close :
Ultrasonic_irq_open()
was_close = True
# Leaving range → CLOSE interrupt
elif distance >= DISTANCE_THRESHOLD and was_close:
Ultrasonic_irq_close()
was_close = False
# ======================
# Handle interrupts (like button IRQ)
# ======================
if request_open:
request_open = False
if not door_is_open:
open_water()
if request_close:
request_close = False
if door_is_open:
close_water()
time.sleep_ms(20)