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 = "b2e3961e73fe4064b831d9b4b821d965" # 必须唯一
MQTT_USER = ""
MQTT_PASSWORD = ""
MQTT_TOPIC = "mydht" # 主题名称
MQTT_CONTROL_TOPIC = "light002" # 控制主题
# 硬件配置
dht_pin = Pin(4)
sensor = dht.DHT22(dht_pin)
led_pin = Pin(15, Pin.OUT)
led_pin.value(0) # 初始关闭LED
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)
# 系统状态
system_mode = "auto" # 初始为自动模式
temp_threshold = 30.0 # 默认温度阈值
hum_threshold = 70.0 # 默认湿度阈值
last_alert_time = 0
alert_interval = 1 # 报警闪烁间隔(秒)
led_status = 0 # LED当前状态
last_sensor_time = 0 # 上次读取传感器时间
sensor_interval = 2 # 传感器读取间隔(秒)
# 连接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():
time.sleep(0.1)
print('Network config:', wlan.ifconfig())
return wlan
# 订阅消息回调函数
def sub_cb(topic, msg):
global system_mode, temp_threshold, hum_threshold
topic = topic.decode('utf-8')
msg = msg.decode('utf-8')
print(f"Received message on topic {topic}: {msg}")
try:
# 解析控制命令
if topic == MQTT_CONTROL_TOPIC:
if msg.startswith("mode:"):
mode = msg.split(":")[1]
if mode in ["auto", "manual"]:
system_mode = mode
print(f"Changed to {system_mode} mode")
log_event(f"System mode changed to {system_mode}")
else:
print(f"Invalid mode: {mode}")
elif msg.startswith("temp_threshold:"):
temp_threshold = float(msg.split(":")[1])
print(f"Temperature threshold set to: {temp_threshold}°C")
log_event(f"Temperature threshold set to {temp_threshold}°C")
elif msg.startswith("hum_threshold:"):
hum_threshold = float(msg.split(":")[1])
print(f"Humidity threshold set to: {hum_threshold}%")
log_event(f"Humidity threshold set to {hum_threshold}%")
elif msg.startswith("led:"):
if system_mode == "manual":
led_state = int(msg.split(":")[1])
led_pin.value(led_state)
led_status = led_state # 更新LED状态
print(f"LED set to: {led_state}")
log_event(f"LED manually set to {led_state}")
else:
print("Cannot manually control LED in auto mode")
except Exception as e:
print(f"Error processing message: {e}")
# 连接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_CONTROL_TOPIC)
print(f"Subscribed to control topic: {MQTT_CONTROL_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 update_console(temp, hum):
if temp is not None and hum is not None:
print(f"Temperature: {temp:.1f}°C | Humidity: {hum:.1f}% | Mode: {system_mode}")
print(f"Thresholds: Temp={temp_threshold}°C, Hum={hum_threshold}%")
else:
print("Sensor read failed")
# 更新OLED屏幕显示 - 增强报警显示效果
def update_oled(temp, hum, mqtt_connected=False):
oled.fill(0) # 清屏
# 显示标题
oled.text("DHT22 Monitoring", 0, 0)
# 检查是否有报警情况
has_alarm = False
if temp is not None and temp > temp_threshold:
has_alarm = True
if hum is not None and hum > hum_threshold:
has_alarm = True
# 报警状态下的特殊显示
if has_alarm and (time.time() % 2 < 1): # 每秒切换一次
oled.fill(1) # 全屏反色
oled.text("ALARM!", 40, 25, 0) # 黑色文字
if temp is not None and hum is not None:
# 显示温度和阈值
temp_text = f"Temp: {temp:.1f}°C"
temp_color = 0 if (temp > temp_threshold and has_alarm) else 1
oled.text(temp_text, 10, 20, temp_color)
# 显示湿度和阈值
hum_text = f"Hum: {hum:.1f}%"
hum_color = 0 if (hum > hum_threshold and has_alarm) else 1
oled.text(hum_text, 10, 40, hum_color)
# 显示模式
oled.text(f"Mode: {system_mode}", 0, 52)
# 显示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() # 更新显示
# 处理报警逻辑 - 增强LED闪烁效果
def handle_alarm(temp, hum):
global last_alert_time, led_status, led_pin
# 检查是否需要报警
need_alarm = False
if temp is not None and temp > temp_threshold:
need_alarm = True
if hum is not None and hum > hum_threshold:
need_alarm = True
# 处理报警状态
current_time = time.time()
if need_alarm:
# 闪烁LED - 不同报警级别不同频率
flash_interval = alert_interval
if (temp is not None and temp > temp_threshold + 5) or (hum is not None and hum > hum_threshold + 10):
flash_interval = alert_interval / 2 # 紧急情况加快闪烁频率
if current_time - last_alert_time >= flash_interval:
led_status = 1 - led_status # 切换LED状态
led_pin.value(led_status)
last_alert_time = current_time
else:
# 关闭报警
if led_status != 0:
led_status = 0
led_pin.value(led_status)
# 记录事件日志
def log_event(message):
timestamp = time.localtime()
log_msg = f"{timestamp[0]}-{timestamp[1]:02d}-{timestamp[2]:02d} {timestamp[3]:02d}:{timestamp[4]:02d}:{timestamp[5]:02d} - {message}"
print(f"LOG: {log_msg}")
# 可以扩展将日志发布到MQTT
# mqtt_client.publish("DHT22_LOG", log_msg)
# 主函数
def main():
print("Starting DHT22 Monitoring System...")
oled.text("Initializing...", 10, 30)
oled.show()
mqtt_client = None # 初始化 MQTT 客户端变量
# 连接 WiFi
wlan = connect_wifi()
# 连接 MQTT
mqtt_client = connect_mqtt()
# 记录上次发布时间
last_publish_time = 0
publish_interval = 5 # 每 5 秒发布一次数据
# 记录启动事件
log_event("System started")
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)
# 更新 OLED 显示
update_oled(temperature, humidity, mqtt_client is not None)
# 处理报警逻辑
handle_alarm(temperature, humidity)
# 发布数据到 MQTT 主题
if temperature is not None and humidity is not None:
data = f"temp:{temperature:.1f},hum:{humidity:.1f},mode:{system_mode},temp_threshold:{temp_threshold},hum_threshold:{hum_threshold},led:{led_status}"
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()
led_pin.value(0) # 关闭 LED
oled.fill(0)
oled.show() # 清屏
if __name__ == "__main__":
main()