# ============================================================
# TRAM QUAN TRAC THOI TIET & CHAT LUONG KHONG KHI THONG MINH
# Hardware : ESP32 + BMP180 + DHT22 + MQ-135 + Rain Sensor
# Language : MicroPython
# ============================================================
import network
import BlynkLib
from machine import SoftI2C, Pin, ADC
from time import sleep, ticks_ms, ticks_diff
import dht
from bmp180 import BMP180
# ─────────────────────────────────────────────────────────────
# CẤU HÌNH
# ─────────────────────────────────────────────────────────────
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASS = ""
BLYNK_TOKEN = "TFOMy_PaZIzIgQfbdb_mae5OtwUQBEuh"
AQI_THRESHOLD = 150
TEMP_MAX = 38.0
HUMIDITY_MIN = 30.0
RAIN_THRESHOLD = 500
V_TEMP_BMP = 0
V_PRESSURE = 1
V_ALTITUDE = 2
V_TEMP_DHT = 3
V_HUMIDITY = 4
V_AQI = 5
V_RAIN = 6
V_ALERT = 7
# ─────────────────────────────────────────────────────────────
# KẾT NỐI WiFi (Giới hạn thời gian chờ để tránh treo mạch)
# ─────────────────────────────────────────────────────────────
def connect_wifi():
print("[WiFi] Dang khoi dong cau hinh mang...")
sta = network.WLAN(network.STA_IF)
sta.active(True)
if not sta.isconnected():
print("[WiFi] Dang ket noi toi", WIFI_SSID)
sta.connect(WIFI_SSID, WIFI_PASS)
timeout = 2
while not sta.isconnected() and timeout > 0:
sleep(1)
timeout -= 1
print(" ...", end="")
if sta.isconnected():
print("\n[WiFi] Ket noi thanh cong! IP:", sta.ifconfig()[0])
return True
print("\n[WiFi] Khong the ket noi. Chuyển sang chay OFFLINE.")
return False
# ─────────────────────────────────────────────────────────────
# KHỞI TẠO CẢM BIẾN
# ─────────────────────────────────────────────────────────────
print("\n[HE THONG] Dang nap cau hinh thiet bi...")
i2c = SoftI2C(scl=Pin(22), sda=Pin(21))
try:
devices = i2c.scan()
print("[I2C] Da quet thay thiet bi:", [hex(d) for d in devices])
bmp = BMP180(i2c)
bmp.oversample_setting = 2
bmp.baseline = 101325
except Exception:
print("[I2C] Khong thay BMP180 phan cung. Su dung du lieu gia lap.")
bmp = None
dht_sensor = dht.DHT22(Pin(4))
mq135 = ADC(Pin(34))
mq135.atten(ADC.ATTN_11DB)
rain_adc = ADC(Pin(35))
rain_adc.atten(ADC.ATTN_11DB)
# ─────────────────────────────────────────────────────────────
# HÀM ĐỌC CẢM BIẾN AN TOÀN
# ─────────────────────────────────────────────────────────────
def read_bmp180():
if bmp is None: return 26.5, 1011.2, 120.0
try: return bmp.temperature, (bmp.pressure / 100.0), bmp.altitude
except Exception: return 26.5, 1011.2, 120.0
def read_dht22():
try:
dht_sensor.measure()
return dht_sensor.temperature(), dht_sensor.humidity()
except Exception: return 28.0, 62.0
def read_mq135():
try:
raw = mq135.read()
return int((raw / 4095.0) * 500), raw
except Exception: return 0, 0
def read_rain():
try:
raw = rain_adc.read()
return (1 if raw < RAIN_THRESHOLD else 0), raw
except Exception: return 0, 4095
def build_alert(temp_dht, humidity, aqi, is_raining):
alerts = []
if temp_dht > TEMP_MAX: alerts.append("Nhiet do cao")
if humidity < HUMIDITY_MIN: alerts.append("Do am thap")
if aqi > AQI_THRESHOLD: alerts.append("Khong khi o nhiem")
if is_raining: alerts.append("Dang co mua")
return " | ".join(alerts) if alerts else "An toan"
def print_data(temp_bmp, pressure, altitude, temp_dht, humidity, aqi, raw_mq, is_raining, raw_rain):
print("\n" + "="*45)
print(" BMP180 | Temp: {:.1f} C | Ap suat: {:.1f} hPa".format(temp_bmp, pressure))
print(" DHT22 | Temp: {:.1f} C | Do am : {:.1f} %".format(temp_dht, humidity))
print(" MQ-135 | AQI : {} | (Raw ADC: {})".format(aqi, raw_mq))
print(" Mua | Trang thai: {} | (Raw ADC: {})".format("CO" if is_raining else "KHONG", raw_rain))
print("="*45)
# ─────────────────────────────────────────────────────────────
# CHƯƠNG TRÌNH CHÍNH
# ─────────────────────────────────────────────────────────────
is_online = connect_wifi()
blynk = None
if is_online:
try:
blynk = BlynkLib.Blynk(BLYNK_TOKEN, insecure=True)
print("[Blynk] Da khoi tao ket noi.")
except Exception:
blynk = None
print("[HE THONG] Bat dau quet du lieu...")
SEND_INTERVAL_MS = 2000
last_send = ticks_ms() - SEND_INTERVAL_MS
while True:
# Chạy lệnh Blynk nền (nếu có kết nối)
if blynk is not None:
try:
blynk.run()
except Exception:
pass
# Đoạn xử lý đọc và IN DỮ LIỆU ĐÃ ĐƯỢC ĐƯA RA NGOÀI (Không bị phụ thuộc vào Blynk)
now = ticks_ms()
if ticks_diff(now, last_send) >= SEND_INTERVAL_MS:
last_send = now
# Đọc cảm biến
temp_bmp, pressure, altitude = read_bmp180()
temp_dht, humidity = read_dht22()
aqi, raw_mq = read_mq135()
is_raining, raw_rain = read_rain()
# In thẳng dữ liệu lên màn hình Console Wokwi bất chấp trạng thái mạng
print_data(temp_bmp, pressure, altitude, temp_dht, humidity, aqi, raw_mq, is_raining, raw_rain)
alert_msg = build_alert(temp_dht, humidity, aqi, is_raining)
print("[Canh bao]:", alert_msg)
# Chỉ đẩy lên cloud nếu blynk hoạt động tốt
if blynk is not None and blynk._connected:
try:
blynk.virtual_write(V_TEMP_BMP, round(temp_bmp, 1))
blynk.virtual_write(V_PRESSURE, round(pressure, 1))
blynk.virtual_write(V_TEMP_DHT, round(temp_dht, 1))
blynk.virtual_write(V_HUMIDITY, round(humidity, 1))
blynk.virtual_write(V_AQI, aqi)
blynk.virtual_write(V_RAIN, is_raining)
blynk.virtual_write(V_ALERT, alert_msg)
except Exception:
pass