from machine import Pin, I2C
import network
import time
from ultrasonic import Ultrasonic # 自訂模組,用來操作超音波感測器
from umqtt.simple import MQTTClient # 用來進行 MQTT 通訊
from lcd_api import LcdApi # LCD 控制 API
from i2c_lcd import I2cLcd # I2C LCD 類別
# --- WiFi 連線 ---
sta = network.WLAN(network.STA_IF) # 啟用 WiFi (STA 模式)
sta.active(True)
sta.connect("Wokwi-GUEST", "") # 連線到 WiFi(Wokwi 無密碼)
while not sta.isconnected(): # 等待 WiFi 成功連線
time.sleep(0.1)
print("WiFi connected!") # 成功連線後顯示訊息
# --- LCD 初始化 ---
i2c = I2C(0, scl=Pin(22), sda=Pin(21)) # 設定 I2C 使用的腳位
lcd = I2cLcd(i2c, 0x27, 2, 16) # 初始化 LCD,2 列 16 字
lcd.clear()
lcd.putstr("Under Detection") # 初始顯示狀態
time.sleep(1)
# --- 超音波感測器初始化 ---
sensor_left = Ultrasonic(trig_pin=12, echo_pin=13) # 左側超音波感測器
sensor_right = Ultrasonic(trig_pin=16, echo_pin=17) # 右側超音波感測器
# --- LED 設定 ---
led_red = Pin(26, Pin.OUT) # 設定紅色 LED 腳位為輸出
led_red.off() # 預設關閉紅燈
# --- MQTT 設定 ---
MQTT_BROKER = "mqtt3.thingspeak.com" # ThingSpeak MQTT 伺服器
MQTT_CLIENT_ID = "MysnAQEPLD0RIiEBNB8MNzY"
MQTT_USER = "MysnAQEPLD0RIiEBNB8MNzY"
MQTT_PASSWORD = "IkTFjR7D6bqxFw/XS6Fme+fq"
MQTT_TOPIC = "channels/2992248/publish" # 發佈主題(通道)
client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, user=MQTT_USER, password=MQTT_PASSWORD)
client.connect() # 連接到 MQTT
print("MQTT connected!") # 成功連線後顯示訊息
# --- 警報狀態變數 ---
alarm_triggered = False # 判斷目前是否進入警報狀態
# --- 中斷處理函式 ---
def handle_intr(sensor):
global alarm_triggered
distance = sensor.distance_cm() # 讀取超音波感測距離
print("[Interrupt] Distance: {:.1f} cm".format(distance)) # 顯示測量距離,幫助調試
if distance < 100: # 若距離小於 100 公分
alarm_triggered = True # 啟動警報狀態
led_red.on() # 亮起紅色 LED
lcd.clear()
lcd.putstr("Alert!") # LCD 顯示警報
payload = "field3=1" # MQTT 傳送警報為 1(有人)
client.publish(MQTT_TOPIC, payload)
print("Alarm ON ")
else:
alarm_triggered = False # 解除警報
led_red.off() # 熄滅紅燈
lcd.clear()
lcd.putstr("Alarm OFF") # 恢復正常顯示
payload = "field3=0" # MQTT 傳送警報為 0(無人)
client.publish(MQTT_TOPIC, payload)
print("Alarm OFF ")
# --- 左右中斷觸發函式 ---
def left_intr(pin):
handle_intr(sensor_left)
def right_intr(pin):
handle_intr(sensor_right)
# --- 中斷腳位設定 ---
pir_left = Pin(33, Pin.IN) # 左側 PIR 感測器輸入腳位
pir_right = Pin(19, Pin.IN) # 右側 PIR 感測器輸入腳位
pir_left.irq(trigger=Pin.IRQ_RISING, handler=left_intr) # 偵測上升緣觸發
pir_right.irq(trigger=Pin.IRQ_RISING, handler=right_intr)
# --- 主程式迴圈 ---
while True:
# 取得左右超音波感測距離
left = sensor_left.distance_cm()
right = sensor_right.distance_cm()
# 顯示距離資訊於 Shell
print("Left: {:.1f} cm".format(left))
print("Right: {:.1f} cm".format(right))
# 組成 MQTT 傳送內容(field1: 左距離, field2: 右距離, field3: 警報狀態)
payload = "field1={:.1f}&field2={:.1f}&field3={}".format(
left, right, 1 if alarm_triggered else 0)
client.publish(MQTT_TOPIC, payload)
print("Published to MQTT:", payload)
# 若非警報狀態,顯示距離在 LCD 上
if not alarm_triggered:
lcd.clear()
lcd.move_to(0, 0)
lcd.putstr("Left: {:.1f} cm".format(left))
lcd.move_to(0, 1)
lcd.putstr("Right: {:.1f} cm".format(right))
# 自動清除警報:若左右距離皆大於等於 100 公分
if alarm_triggered and left >= 100 and right >= 100:
alarm_triggered = False
led_red.off() # 熄滅紅燈
lcd.clear()
lcd.putstr("Under Detection")
client.publish(MQTT_TOPIC, "field3=0")
print("Alarm auto cleared")
time.sleep(5) # 每 5 秒更新一次