# 作业27-DHT22-阈值
# 在shell控制台、OLED屏、网页或小程序中上同时显示DHT22的信息
# 当温度或湿度高于某一特定值(阈值)时,连接ESP32引脚15的led闪烁,实现报警。
# 通过light002主题控制LED灯
import dht
from machine import Pin, I2C
import ssd1306
import time
import network
from umqtt.simple import MQTTClient
# 网络配置
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
# 巴法云MQTT配置
MQTT_SERVER = "bemfa.com"
MQTT_PORT = 9501
MQTT_CLIENT_ID = "e9043ebda15dd81b945cc88cccbcb3c6" # 必须唯一
MQTT_USER = ""
MQTT_PASSWORD = ""
MQTT_TOPIC = "DHT22" # 数据发布主题
MQTT_LIGHT_TOPIC = "light002" # 灯光控制主题
# 阈值配置
TEMP_THRESHOLD = 28 # 温度阈值(°C)
HUMI_THRESHOLD = 70 # 湿度阈值(%)
# 初始化硬件
dht_pin = Pin(4)
sensor = dht.DHT22(dht_pin)
i2c = I2C(0, scl=Pin(18), sda=Pin(23), freq=400000)
oled_width = 128
oled_height = 64
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)
# LED控制引脚
led_pin = Pin(15, Pin.OUT) # 控制LED灯的引脚
led_state = False # 当前LED状态
alarm_state = False # 报警状态
# 连接WiFi
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('Connecting to network...')
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
while not wlan.isconnected():
pass
print('Network config:', wlan.ifconfig())
return wlan
# 订阅消息回调函数 - 处理接收到的MQTT消息
def sub_cb(topic, msg):
global led_state
topic = topic.decode()
msg = msg.decode()
print(f"Received message on topic {topic}: {msg}")
# 处理温度/湿度数据主题
if topic == MQTT_TOPIC:
pass # 确保空代码块有pass语句
# 处理灯光控制主题
elif topic == MQTT_LIGHT_TOPIC:
if msg == 'on':
led_state = True
led_pin.on()
print("LED turned ON")
elif msg == 'off':
led_state = False
led_pin.off()
print("LED turned OFF")
elif msg == 'toggle':
led_state = not led_state
led_pin.value(led_state)
print(f"LED toggled to {'ON' if led_state else 'OFF'}")
# 连接MQTT服务器
def connect_mqtt():
client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER, MQTT_PORT)
# 设置订阅回调函数
client.set_callback(sub_cb)
try:
client.connect()
print(f"Connected to MQTT Broker: {MQTT_SERVER}")
# 订阅数据主题和灯光控制主题
client.subscribe(MQTT_TOPIC)
client.subscribe(MQTT_LIGHT_TOPIC)
print(f"Subscribed to topics: {MQTT_TOPIC}, {MQTT_LIGHT_TOPIC}")
return client
except Exception as e:
print(f"MQTT connection failed: {e}")
return None
# 读取DHT22传感器数据
def read_sensor():
try:
sensor.measure()
temp = sensor.temperature()
hum = sensor.humidity()
return temp, hum
except OSError as e:
print(f"Sensor read error: {e}")
return None, None
# 检查是否触发报警条件
def check_alarm(temp, hum):
global alarm_state
if temp is not None and hum is not None:
alarm_state = (temp > TEMP_THRESHOLD) or (hum > HUMI_THRESHOLD)
return alarm_state
return False
# 处理报警状态
def handle_alarm():
if alarm_state:
# 闪烁LED实现报警
for _ in range(3):
led_pin.on()
time.sleep(0.3)
led_pin.off()
time.sleep(0.3)
# 恢复LED到之前的状态
led_pin.value(led_state)
# 更新控制台显示
def update_console(temp, hum):
if temp is not None and hum is not None:
alarm_text = " (ALARM!)" if check_alarm(temp, hum) else ""
print(f"Temperature: {temp:.1f}°C | Humidity: {hum:.1f}% | LED: {'ON' if led_state else 'OFF'}{alarm_text}")
else:
print("Sensor read failed")
# 更新OLED屏幕显示
def update_oled(temp, hum, mqtt_connected=False):
oled.fill(0) # 清屏
if temp is not None and hum is not None:
# 显示标题
oled.text("DHT22 Monitoring", 0, 0)
# 显示温度
oled.text(f"Temp: {temp:.1f}°C", 10, 20)
# 显示湿度
oled.text(f"Hum: {hum:.1f}%", 10, 40)
# 显示LED状态
led_text = f"LED: {'ON' if led_state else 'OFF'}"
if alarm_state:
led_text += " (ALARM!)"
oled.text(led_text, 0, 50)
# 显示MQTT连接状态
status_text = "MQTT: Connected" if mqtt_connected else "MQTT: Disconnected"
oled.text(status_text, 0, 56)
else:
oled.text("Sensor Error", 20, 30)
oled.show() # 更新显示
# 主函数
def main():
print("Starting DHT22 Monitoring System...")
oled.text("Initializing...", 10, 30)
oled.show()
# 连接WiFi
wlan = connect_wifi()
# 连接MQTT
mqtt_client = connect_mqtt()
# 记录上次发布时间
last_publish_time = 0
publish_interval = 5 # 每5秒发布一次数据
try:
while True:
# 检查MQTT连接状态,若连接则处理可能收到的订阅消息
if mqtt_client:
try:
mqtt_client.check_msg()
except Exception as e:
print(f"Error checking MQTT messages: {e}")
mqtt_client = connect_mqtt() # 尝试重新连接
# 检查是否到发布数据时间
if mqtt_client and (time.time() - last_publish_time) >= publish_interval:
try:
# 读取传感器数据
temperature, humidity = read_sensor()
# 更新控制台显示
update_console(temperature, humidity)
# 检查是否触发报警
if check_alarm(temperature, humidity):
handle_alarm()
# 更新OLED显示
update_oled(temperature, humidity, mqtt_client is not None)
# 发布数据到MQTT主题
if temperature is not None and humidity is not None:
data = f"temp:{temperature:.1f},hum:{humidity:.1f},led:{led_state},alarm:{alarm_state}"
mqtt_client.publish(MQTT_TOPIC, data)
print(f"Published: {data}")
# 更新发布时间
last_publish_time = time.time()
except Exception as e:
print(f"Error in main loop: {e}")
# 尝试重新连接MQTT
mqtt_client = connect_mqtt()
update_oled(None, None, False)
# 短暂休眠,避免CPU占用过高
time.sleep(0.1)
except KeyboardInterrupt:
print("\nProgram stopped by user")
if mqtt_client:
mqtt_client.disconnect()
oled.fill(0)
oled.show() # 清屏
if __name__ == "__main__":
main()