from machine import Pin, SoftI2C
import time
from dht import DHT22 # 导入DHT22模块
from ssd1306 import SSD1306_I2C # I2C的oled驱动
import network
from umqtt.simple import MQTTClient
# 硬件配置
DHT_PIN = 2 # DHT22数据引脚
OLED_SDA_PIN = 23 # OLED SDA引脚
OLED_SCL_PIN = 18 # OLED SCL引脚
# 网络配置 - 请修改为你的网络信息
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
# 巴法云MQTT配置
MQTT_PROFILE_NAME = "yanqi-巴法云平台MQTT"
MQTT_BROKER = "bemfa.com"
MQTT_PORT = 9501
MQTT_CLIENT_ID = "eac294c0d54f24e87948fe5831d0d4f6"
MQTT_TOPIC = "mydht" # 要订阅和发布的主题
# 全局变量,用于保存 MQTT 客户端
mqtt_client = None
def connect_wifi():
"""连接WiFi网络"""
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print("正在连接WiFi...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
# 等待连接
max_wait = 10
while max_wait > 0:
if wlan.isconnected():
break
max_wait -= 1
print("等待连接...")
time.sleep(1)
if wlan.isconnected():
print(f"WiFi连接成功,网络配置: {wlan.ifconfig()}")
return True
else:
print("WiFi连接失败")
return False
else:
print(f"已连接WiFi,网络配置: {wlan.ifconfig()}")
return True
def setup_hardware():
"""初始化硬件组件"""
# 创建软件I2C对象
i2c = SoftI2C(sda=Pin(OLED_SDA_PIN), scl=Pin(OLED_SCL_PIN))
# 创建OLED对象
oled = SSD1306_I2C(128, 64, i2c)
# 初始化DHT22传感器
dht_sensor = DHT22(Pin(DHT_PIN))
return oled, dht_sensor
def display_sensor_data(oled, temperature, humidity, wifi_connected):
"""在OLED上显示传感器数据"""
oled.fill(0) # 清空屏幕
# 显示标题
oled.text("DHT22 senor", 0, 0, 1)
# 显示温度数据
temp_text = f"temp: {temperature:.1f} °C"
oled.text(temp_text, 10, 20, 1)
# 显示湿度数据
hum_text = f"humi: {humidity:.1f} %"
oled.text(hum_text, 10, 40, 1)
# 显示WiFi状态
wifi_text = "WiFi: success" if wifi_connected else "WiFi: 未连接"
oled.text(wifi_text, 0, 56, 1)
oled.show() # 刷新屏幕显示
def read_sensor_data(dht_sensor):
"""读取DHT22传感器数据"""
try:
dht_sensor.measure()
temperature = dht_sensor.temperature()
humidity = dht_sensor.humidity()
return temperature, humidity
except Exception as e:
raise RuntimeError(f"读取传感器失败: {e}")
def connect_mqtt():
"""连接MQTT服务器并订阅主题"""
global mqtt_client
try:
mqtt_client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, MQTT_PORT)
# 定义回调函数,用于处理订阅主题收到的消息
mqtt_client.set_callback(sub_callback)
mqtt_client.connect()
# 订阅主题
mqtt_client.subscribe(MQTT_TOPIC)
print(f"已连接到MQTT服务器并订阅主题: {MQTT_TOPIC}")
return mqtt_client
except Exception as e:
print(f"连接MQTT服务器或订阅失败: {e}")
return None
def sub_callback(topic, msg):
"""订阅主题的回调函数,当收到消息时会被调用"""
print(f"收到订阅消息,主题: {topic.decode()}, 内容: {msg.decode()}")
# 这里可以根据收到的消息进行相应处理,比如控制硬件、修改显示等
# 示例:如果收到特定指令,可在此处扩展逻辑
def publish_data(client, temperature, humidity):
"""发布温湿度数据到MQTT主题"""
try:
data = f"temp={temperature:.1f}&hum={humidity:.1f}"
client.publish(MQTT_TOPIC, data)
print(f"已发布数据: {data}")
except Exception as e:
print(f"发布数据失败: {e}")
def main():
"""主程序入口"""
try:
# 连接WiFi
wifi_connected = connect_wifi()
# 初始化硬件
oled, dht_sensor = setup_hardware()
# 显示初始化信息
oled.fill(0)
oled.text("系统初始化中...", 15, 20, 1)
oled.text(f"WiFi: {'已连接' if wifi_connected else '未连接'}", 15, 40, 1)
oled.show()
time.sleep(3) # 等待传感器稳定
print("DHT22温湿度监测系统已启动")
print("-" * 30)
# 连接MQTT服务器并订阅主题
client = connect_mqtt()
if client is None:
return
while True:
try:
# 读取传感器数据
temperature, humidity = read_sensor_data(dht_sensor)
# 显示数据
display_sensor_data(oled, temperature, humidity, wifi_connected)
# 发布数据到MQTT主题
publish_data(client, temperature, humidity)
# 检查是否有订阅消息(非阻塞方式,需定期调用)
if client is not None:
client.check_msg()
# 等待5秒再进行下一次读取(DHT22建议采样间隔至少2秒,这里设置为5秒更保险)
time.sleep(5)
except RuntimeError as e:
# 处理传感器读取错误
oled.fill(0)
oled.text("传感器错误!", 20, 20, 1)
oled.text(str(e), 10, 40, 1)
oled.show()
print(f"运行时错误: {e}")
time.sleep(5) # 错误发生后等待更长时间
except KeyboardInterrupt:
# 清理资源
oled.fill(0)
oled.text("程序已停止", 25, 30, 1)
oled.show()
time.sleep(1)
oled.fill(0)
oled.show()
print("\n程序已停止")
if mqtt_client is not None:
mqtt_client.disconnect()
except Exception as e:
print(f"发生未知错误: {e}")
if 'oled' in locals():
oled.fill(0)
oled.text("致命错误!", 20, 20, 1)
oled.text(str(e), 10, 40, 1)
oled.show()
if mqtt_client is not None:
mqtt_client.disconnect()
if __name__ == "__main__":
main()