import network
import time
from machine import Pin, I2C, PWM, ADC
import ssd1306
import dht
from umqtt.simple import MQTTClient
import ubinascii
import machine
# ตัวแปรสำหรับเก็บสถานะระบบ
wifi_connected = False
mqtt_connected = False
current_angle = 0
last_pot_val = 0
# --- การตั้งค่า MQTT ---
MQTT_BROKER = "broker.emqx.io"
# สร้าง Client ID แบบไม่ซ้ำกันโดยใช้ ID ของบอร์ด
MQTT_CLIENT_ID = b"pico-w-mqtt-08"
MQTT_TOPIC_PUB = b"student08/pico/status" # Topic สำหรับส่งข้อมูล
MQTT_TOPIC_SUB = b"pico/servo_cmd" # Topic สำหรับรับคำสั่งควบคุมมอเตอร์
client = None
# 1. ตั้งค่า Pin สำหรับหลอด LED สองสี
led_blue = Pin(18, Pin.OUT)
led_red = Pin(19, Pin.OUT)
led_red.value(1)
led_blue.value(0)
# 2. ตั้งค่า I2C สำหรับจอ OLED (SDA=GP16, SCL=GP17)
i2c = I2C(0, sda=Pin(16), scl=Pin(17))
oled = ssd1306.SSD1306_I2C(128, 64, i2c)
# 3. ตั้งค่าเซ็นเซอร์ DHT22 (GP20)
sensor = dht.DHT22(Pin(20))
# 4. ตั้งค่า Servo Motor (GP14)
servo = PWM(Pin(14))
servo.freq(50)
def set_servo_angle(angle, source="ระบบ"):
global current_angle
current_angle = angle
min_duty = 1638
max_duty = 8192
duty = int(min_duty + (max_duty - min_duty) * (angle / 180))
servo.duty_u16(duty)
print(">> Servo หมุนไปที่: {} องศา (สั่งจาก: {})".format(angle, source))
# เมื่อมอเตอร์หมุน ให้ส่งสถานะล่าสุดขึ้น MQTT ด้วย
if mqtt_connected:
try:
msg = "Servo: {} deg".format(angle)
client.publish(MQTT_TOPIC_PUB, msg.encode())
except:
pass
# ฟังก์ชัน Callback สำหรับรับคำสั่งจาก MQTT
def mqtt_callback(topic, msg):
print("\n[MQTT] ได้รับข้อความจาก Topic {}: {}".format(topic.decode(), msg.decode()))
if topic == MQTT_TOPIC_SUB:
try:
# แปลงข้อความที่ได้รับเป็นตัวเลของศา
angle = int(msg.decode())
if 0 <= angle <= 180:
set_servo_angle(angle, "MQTT")
global last_pot_val
last_pot_val = pot.read_u16() # รีเซ็ตค่า Volumn
else:
print(">> องศาต้องอยู่ระหว่าง 0 - 180")
except ValueError:
print(">> รูปแบบคำสั่ง MQTT ไม่ถูกต้อง (ต้องเป็นตัวเลข)")
# 5. ตั้งค่าปุ่มกด (GP27, GP22, GP21)
sw_yellow = Pin(27, Pin.IN, Pin.PULL_DOWN)
sw_red_btn = Pin(22, Pin.IN, Pin.PULL_DOWN)
sw_green = Pin(21, Pin.IN, Pin.PULL_DOWN)
# 6. ตั้งค่า Potentiometer (GP26)
pot = ADC(Pin(26))
# ข้อมูล Wi-Fi
ssid = "Wokwi-GUEST"
password = ""
def connect_wifi():
global wifi_connected, last_pot_val
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
oled.fill(0)
oled.text("Connecting to", 0, 0)
oled.text("WiFi...", 0, 15)
oled.show()
print("กำลังเชื่อมต่อ Wi-Fi...")
while not wlan.isconnected():
time.sleep(0.5)
ip_address = wlan.ifconfig()[0]
print("เชื่อมต่อ Wi-Fi สำเร็จ! IP:", ip_address)
led_red.value(0)
led_blue.value(1)
wifi_connected = True
last_pot_val = pot.read_u16()
return ip_address
def connect_mqtt():
global client, mqtt_connected
try:
print("กำลังเชื่อมต่อ MQTT Broker: {} ...".format(MQTT_BROKER))
client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, keepalive=60)
client.set_callback(mqtt_callback)
client.connect()
client.subscribe(MQTT_TOPIC_SUB)
print("เชื่อมต่อ MQTT สำเร็จ! รอรับคำสั่งที่ Topic:", MQTT_TOPIC_SUB.decode())
mqtt_connected = True
except OSError as e:
print("ไม่สามารถเชื่อมต่อ MQTT ได้:", e)
mqtt_connected = False
# เริ่มต้นระบบ
ip = connect_wifi()
connect_mqtt()
set_servo_angle(0, "เริ่มต้นระบบ")
# จัดการเวลา
dht_interval = 5 * 60 * 1000 # 5 นาที
last_dht_read = time.ticks_ms() - dht_interval
temp = 0.0
hum = 0.0
# ลูปการทำงานหลัก
while True:
current_time = time.ticks_ms()
# เช็คข้อความเข้าจาก MQTT
if mqtt_connected:
try:
client.check_msg()
except OSError:
pass # ป้องกันโปรแกรมค้างหากเน็ตหลุดชั่วคราว
# 1. ตรวจสอบการกดปุ่ม (Polling)
if wifi_connected:
if sw_yellow.value() == 1:
set_servo_angle(0, "ปุ่มเหลือง")
last_pot_val = pot.read_u16()
time.sleep(0.1)
elif sw_red_btn.value() == 1:
set_servo_angle(90, "ปุ่มแดง")
last_pot_val = pot.read_u16()
time.sleep(0.1)
elif sw_green.value() == 1:
set_servo_angle(176, "ปุ่มเขียว")
last_pot_val = pot.read_u16()
time.sleep(0.1)
# 2. ตรวจสอบและอ่านค่า DHT22 ทุกๆ 5 นาที พร้อมส่งขึ้น MQTT
if time.ticks_diff(current_time, last_dht_read) >= dht_interval:
try:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
print("อัปเดต DHT22 -> Temp: {:.1f} C, Hum: {:.1f} %".format(temp, hum))
# ส่งข้อมูลขึ้น MQTT
if mqtt_connected:
msg = "Temp:{:.1f}, Hum:{:.1f}".format(temp, hum)
client.publish(MQTT_TOPIC_PUB, msg.encode())
except OSError as e:
print("อ่านค่าเซ็นเซอร์ล้มเหลว")
last_dht_read = current_time
# 3. ตรวจสอบการหมุน Potentiometer
if wifi_connected:
current_pot = pot.read_u16()
if abs(current_pot - last_pot_val) > 800:
angle = int((current_pot / 65535) * 180)
set_servo_angle(angle, "วอลลุ่ม")
last_pot_val = current_pot
# 4. อัปเดตหน้าจอ OLED
oled.fill(0)
oled.text("IP: {}".format(ip), 0, 0)
oled.text("Temp: {:.1f} C".format(temp), 0, 15)
oled.text("Hum: {:.1f} %".format(hum), 0, 30)
oled.text("Servo: {} deg".format(current_angle), 0, 45)
oled.show()
time.sleep(0.1)