import time
import math
from machine import Pin, ADC, I2C, PWM
from ssd1306 import SSD1306_I2C # แก้ไข: เปลี่ยนการ Import ให้ตรงกับชื่อคลาส
# --- [1. I2C OLED Setup] ---
# ใช้ I2C0: SDA=GP0, SCL=GP1
i2c = I2C(0, scl=Pin(1), sda=Pin(0), freq=400000)
# ตรวจสอบว่าเจอ OLED ที่ address ไหน
devices = i2c.scan()
oled_address = devices[0] if devices else 0x3C
print(f"พบ I2C address: {hex(oled_address)}")
# แก้ไข: เรียกใช้คลาส SSD1306_I2C โดยตรง (เนื่องจากใช้ from...import)
oled = SSD1306_I2C(128, 64, i2c, addr=oled_address)
# --- [2. Analog Inputs (ADC)] ---
# กำหนดขา ADC สำหรับเซนเซอร์ Analog
temp_adc = ADC(26) # NTC Thermistor (GP26 -> ADC0)
pot_adc = ADC(27) # Potentiometer (GP27 -> ADC1)
gas_adc = ADC(28) # MQ-2 Gas Sensor (GP28 -> ADC2)
# --- [3. Digital LDR Input] ---
ldr_digital = Pin(22, Pin.IN) # LDR Digital Out (GP22)
# --- [4. RGB LED Setup (PWM)] ---
# ใช้ PWM สำหรับการควบคุมความสว่างและผสมสี
red_pin = PWM(Pin(16))
green_pin = PWM(Pin(17))
blue_pin = PWM(Pin(18))
# ตั้งค่าความถี่ (1000 Hz)
red_pin.freq(1000)
green_pin.freq(1000)
blue_pin.freq(1000)
# --- [5. NTC Thermistor Constants] ---
# ค่าคงที่สำหรับคำนวณอุณหภูมิ (B-Parameter Model)
VREF = 3.3 # แรงดันอ้างอิงของ Pico W
MAX_ADC = 65535 # ค่าสูงสุดของ ADC 16-bit
R_FIXED = 10000 # ความต้านทานคงที่ในวงจรแบ่งแรงดัน (เช่น 10k Ohm)
R_NOMINAL = 10000 # ความต้านทาน NTC ที่ T_NOMINAL
T_NOMINAL = 25 # อุณหภูมิปกติ (25C)
B_VALUE = 3950 # B-Parameter (ใช้ค่าประมาณ 3950K)
# --- [6. Functions] ---
def read_temperature_c(adc_value):
"""คำนวณอุณหภูมิจากค่า ADC ของ NTC โดยใช้ B-Parameter Model"""
# 1. คำนวณแรงดันไฟฟ้าที่ขา ADC
voltage = adc_value * VREF / MAX_ADC
# 2. คำนวณความต้านทานของ NTC (จากวงจรแบ่งแรงดัน: R_therm = R_fixed * (V_ref / V_in - 1))
# ป้องกันการหารด้วยค่าที่ใกล้ศูนย์
if voltage < 0.0001:
return -273.15 # อุณหภูมิต่ำสุดที่เป็นไปได้
R_thermistor = R_FIXED * (VREF / voltage - 1.0)
# 3. คำนวณอุณหภูมิ (C)
steinhart = R_thermistor / R_NOMINAL
steinhart = math.log(steinhart)
steinhart /= B_VALUE
steinhart += 1.0 / (T_NOMINAL + 273.15) # แปลง T_NOMINAL เป็น K
steinhart = 1.0 / steinhart
temp_c = steinhart - 273.15
return temp_c
def set_rgb_led_status(temp_c):
"""ควบคุม RGB LED ตามอุณหภูมิ"""
duty_on = 65535
# ปิดทุกสีก่อน
red_pin.duty_u16(0)
green_pin.duty_u16(0)
blue_pin.duty_u16(0)
if temp_c < 20:
blue_pin.duty_u16(duty_on) # เย็นมาก (น้ำเงิน)
elif temp_c > 32:
red_pin.duty_u16(duty_on) # ร้อน (แดง)
elif 20 <= temp_c <= 32:
green_pin.duty_u16(duty_on) # อุณหภูมิปกติ (เขียว)
# --- [7. Main Loop] ---
print("--- เริ่มการทำงานของระบบตรวจสอบสภาพแวดล้อม ---")
while True:
# 1. อ่านค่าเซนเซอร์ Analog (NTC, Pot, Gas)
temp_raw = temp_adc.read_u16()
gas_raw = gas_adc.read_u16()
pot_raw = pot_adc.read_u16()
# 2. ประมวลผล NTC (อุณหภูมิ)
temp_c = read_temperature_c(temp_raw)
# 3. ประมวลผล Gas และ Threshold (Potentiometer)
MAX_ADC_INT = 65535 # เพื่อให้โค้ดสะอาดขึ้น
# แปลงค่าเป็น % โดยประมาณ
gas_pct = gas_raw * 100 // MAX_ADC_INT
pot_pct = pot_raw * 100 // MAX_ADC_INT # Pot เป็นตัวกำหนด Threshold
# 4. ประมวลผล LDR (แสง)
light_status = "Bright" if ldr_digital.value() == 1 else "Dark"
# 5. ตรวจจับสถานะอันตราย (ระดับแก๊สสูงกว่าค่า Threshold ที่กำหนดโดย Pot)
alert = gas_pct > pot_pct
# 6. ควบคุม RGB LED ตามอุณหภูมิ
set_rgb_led_status(temp_c)
# 7. แสดงผลบน OLED
oled.fill(0)
oled.text("Temp: {:.1f} C".format(temp_c), 0, 0)
oled.text("Gas: {}%".format(gas_pct), 0, 12)
oled.text("Thresh: {}%".format(pot_pct), 0, 24)
oled.text("Light: {}".format(light_status), 0, 36)
oled.text("STATUS: {}".format("DANGER" if alert else "SAFE"), 0, 48)
oled.show()
time.sleep(1)