# SmartGuard ESP32 - Multi-Sensor Alarm System
# Author: Santiago Pinedo
from machine import Pin, PWM, SoftI2C
from dht import DHT22
import time
import utime
dht_sensor = DHT22(Pin(4))
trig = Pin(5, Pin.OUT)
echo = Pin(18, Pin.IN)
pir = Pin(19, Pin.IN)
btn_mute = Pin(32, Pin.IN, Pin.PULL_UP)
led_green = Pin(25, Pin.OUT)
led_red = Pin(26, Pin.OUT)
led_yellow = Pin(27, Pin.OUT)
buzzer = PWM(Pin(23), freq=1000, duty=0)
i2c = SoftI2C(scl=Pin(22), sda=Pin(21))
# LCD I2C
I2C_ADDR = 0x27
def lcd_send(data, mode):
high = (data & 0xF0) | 0x08 | mode
low = ((data << 4) & 0xF0) | 0x08 | mode
for nibble in [high, low]:
i2c.writeto(I2C_ADDR, bytes([nibble | 0x04]))
utime.sleep_us(1)
i2c.writeto(I2C_ADDR, bytes([nibble & ~0x04]))
utime.sleep_us(50)
def lcd_init():
utime.sleep_ms(50)
for cmd in [0x33, 0x32, 0x28, 0x0C, 0x06, 0x01]:
lcd_send(cmd, 0)
utime.sleep_ms(5)
def lcd_clear():
lcd_send(0x01, 0)
utime.sleep_ms(5)
def lcd_write(text, row=0, col=0):
offsets = [0x00, 0x40]
lcd_send(0x80 | (offsets[row] + col), 0)
for ch in text:
lcd_send(ord(ch), 1)
def lcd_print(line1="", line2=""):
lcd_clear()
lcd_write(line1[:16], 0)
lcd_write(line2[:16], 1)
# Ultrasonic sensor
def get_distance():
trig.off()
utime.sleep_us(2)
trig.on()
utime.sleep_us(10)
trig.off()
timeout = utime.ticks_us()
while echo.value() == 0:
if utime.ticks_diff(utime.ticks_us(), timeout) > 30000:
return 999
start = utime.ticks_us()
while echo.value() == 1:
if utime.ticks_diff(utime.ticks_us(), start) > 30000:
return 999
end = utime.ticks_us()
return (utime.ticks_diff(end, start) * 0.0343) / 2
# Buzzer
def beep(freq=1000, duration=200, times=1, muted=False):
if muted:
return
for _ in range(times):
buzzer.freq(freq)
buzzer.duty(512)
time.sleep_ms(duration)
buzzer.duty(0)
time.sleep_ms(100)
# LEDs off
def leds_off():
led_green.off()
led_red.off()
led_yellow.off()
event_log = []
def log_event(msg):
timestamp = utime.ticks_ms() // 1000
entry = f"[{timestamp}s] {msg}"
event_log.append(entry)
if len(event_log) > 5:
event_log.pop(0)
print(entry)
def print_log():
print("\n===== EVENT LOG =====")
for e in event_log:
print(e)
print("=====================\n")
# Button mute
muted = False
mute_pressed = False
def check_mute_button():
global muted, mute_pressed
if btn_mute.value() == 0:
if not mute_pressed:
mute_pressed = True
muted = not muted
state = "MUTED" if muted else "UNMUTED"
log_event(f"Buzzer {state} by button")
lcd_print("Buzzer:", state)
time.sleep_ms(500)
else:
mute_pressed = False
# Wilson beeps
def wilson_panic():
if muted:
return
for _ in range(5):
buzzer.freq(3000)
buzzer.duty(512)
time.sleep_ms(80)
buzzer.duty(0)
time.sleep_ms(50)
buzzer.freq(500)
buzzer.duty(512)
time.sleep_ms(80)
buzzer.duty(0)
time.sleep_ms(50)
def wilson_warning():
if muted:
return
for _ in range(3):
buzzer.freq(800)
buzzer.duty(512)
time.sleep_ms(300)
buzzer.duty(0)
time.sleep_ms(400)
lcd_init()
lcd_print("SmartGuard ESP32", "Starting...")
time.sleep(2)
beep(500, 100, 2)
log_event("System started")
alert_level = 0
cycle = 0
print("=== SmartGuard ESP32 - Multi-Sensor Alarm System ===")
while True:
cycle += 1
alert_level = 0
reasons = []
check_mute_button()
# Read temperature & humidity
try:
dht_sensor.measure()
temp = dht_sensor.temperature()
hum = dht_sensor.humidity()
except:
temp = 0
hum = 0
dist = get_distance()
motion = pir.value()
if temp > 35:
alert_level = 2
reasons.append(f"HIGH TEMP {temp}C")
elif temp > 28:
alert_level = max(alert_level, 1)
reasons.append(f"WARM {temp}C")
if dist < 20:
alert_level = 2
reasons.append(f"TOO CLOSE {dist:.0f}cm")
print("WILSON IS RIGHT HERE!!!")
lcd_print("!! WILSON !!", "GET AWAY FROM ME")
wilson_panic()
elif dist < 50:
alert_level = max(alert_level, 1)
reasons.append(f"NEAR {dist:.0f}cm")
print("Wilson is getting closer...")
lcd_print("Wilson is coming", f"Dist:{dist:.0f}cm !!!")
wilson_warning()
if motion:
alert_level = max(alert_level, 1)
reasons.append("MOTION DETECTED")
leds_off()
if alert_level == 0:
led_green.on()
lcd_print(f"T:{temp}C H:{hum}%", f"Dist:{dist:.0f}cm OK")
if cycle % 10 == 0:
log_event(f"OK | T:{temp}C D:{dist:.0f}cm")
elif alert_level == 1:
led_yellow.on()
beep(800, 150, 1, muted)
reason_str = " | ".join(reasons)
lcd_print("!! CAUTION !!", reason_str[:16])
log_event(f"CAUTION: {reason_str}")
elif alert_level == 2:
led_red.on()
beep(2000, 300, 3, muted)
reason_str = " | ".join(reasons)
lcd_print("!!! DANGER !!!", reason_str[:16])
log_event(f"DANGER: {reason_str}")
if cycle % 20 == 0:
print_log()
if cycle % 5 == 0:
mute_status = "MUTED" if muted else "ACTIVE"
print(f"[Cycle {cycle}] Buzzer: {mute_status} | Alert level: {alert_level}")
check_mute_button()
time.sleep(1)