from machine import UART, Pin, SoftI2C, Timer
import time
import network
from ssd1306 import SSD1306_I2C
from umqtt.simple import MQTTClient
import dht
# 硬件配置
# OLED 引脚
OLED_SDA_PIN = 23
OLED_SCL_PIN = 18
# DHT22 引脚
DHT22_PIN = 4
# 串口配置(使用串口1,TX: GPIO1, RX: GPIO3 ,根据实际硬件确认)
UART_PORT = 1
UART_BAUDRATE = 115200
UART_TX_PIN = 1
UART_RX_PIN = 3
# LED 引脚(状态指示)
LED_PIN = 15
# 网络配置(需替换为实际 WiFi 信息)
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
# 巴法云 MQTT 配置
MQTT_BROKER = "bemfa.com"
MQTT_PORT = 9501
MQTT_CLIENT_ID = "531335e94ce44795a9834be0a956119a"
MQTT_TEMP_TOPIC = "temp"
MQTT_HUMI_TOPIC = "humity"
ONLINE_STATUS = "on"
OFFLINE_STATUS = "off"
# 全局变量
dht_sensor = None
oled = None # OLED显示屏
uart = None # 串口对象
led = None # LED对象
wifi_connected = False # WiFi连接状态
mqtt_client = None # MQTT客户端
timer = None # 定时器对象
last_online_publish = 0 # 上次发布在线状态的时间
online_publish_interval = 60 # 在线状态发布间隔(秒)
last_connection_attempt = 0 # 上次连接尝试时间
connection_backoff = 5 # 初始重连等待时间(秒)
max_connection_backoff = 60 # 最大重连等待时间(秒)
last_dht_read = 0 # 上次读取DHT22的时间
dht_read_interval = 2 # DHT22读取间隔(秒)
temperature = 0.0 # 温度值
humidity = 0.0 # 湿度值
def connect_wifi():
"""连接WiFi网络"""
global wifi_connected
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
time.sleep(1)
if wlan.isconnected():
print(f"WiFi连接成功,网络配置: {wlan.ifconfig()}")
wifi_connected = True
return True
else:
print("WiFi连接失败")
wifi_connected = False
return False
else:
print(f"已连接WiFi,网络配置: {wlan.ifconfig()}")
wifi_connected = True
return True
def setup_hardware():
"""初始化硬件组件:OLED、DHT22、串口、LED"""
global oled, uart, led, dht_sensor
# 初始化OLED
i2c = SoftI2C(sda=Pin(OLED_SDA_PIN), scl=Pin(OLED_SCL_PIN))
oled = SSD1306_I2C(128, 64, i2c)
# 初始化DHT22传感器
dht_sensor = dht.DHT22(Pin(DHT22_PIN))
# 初始化串口
uart = UART(UART_PORT, baudrate=UART_BAUDRATE, tx=Pin(UART_TX_PIN), rx=Pin(UART_RX_PIN))
# 初始化LED
led = Pin(LED_PIN, Pin.OUT)
led.value(0) # 默认关闭LED
return oled, uart, led, dht_sensor
def display_status():
"""在OLED上显示温湿度、WiFi连接状态和MQTT连接状态"""
global oled, temperature, humidity, wifi_connected, mqtt_client
oled.fill(0) # 清屏
# 显示温湿度
oled.text("Temp: {:.1f} C".format(temperature), 0, 0, 1)
oled.text("Humi: {:.1f} %".format(humidity), 0, 15, 1)
# 显示WiFi状态
wifi_text = "WiFi: Connected" if wifi_connected else "WiFi: Disconnected"
oled.text(wifi_text, 0, 30, 1)
# 显示MQTT状态
mqtt_text = "MQTT: Connected" if mqtt_client else "MQTT: Disconnected"
oled.text(mqtt_text, 0, 45, 1)
oled.show() # 更新显示
def read_dht_sensor():
"""读取DHT22传感器数据"""
global dht_sensor, temperature, humidity, last_dht_read
current_time = time.time()
# 检查是否到了读取时间
if current_time - last_dht_read < dht_read_interval:
return False
last_dht_read = current_time
try:
dht_sensor.measure()
temperature = dht_sensor.temperature()
humidity = dht_sensor.humidity()
print(f"读取DHT22: 温度={temperature}°C, 湿度={humidity}%")
# 在串口显示
uart.write(f"\r温度: {temperature}°C, 湿度: {humidity}%\n")
return True
except Exception as e:
print(f"读取DHT22失败: {e}")
return False
def connect_mqtt():
"""连接巴法云MQTT服务器"""
global mqtt_client, last_connection_attempt, connection_backoff
current_time = time.time()
# 避免过于频繁地尝试连接
if current_time - last_connection_attempt < connection_backoff:
time.sleep(connection_backoff)
return False
last_connection_attempt = current_time
try:
# 如果已有客户端,先断开
if mqtt_client:
try:
mqtt_client.disconnect()
except:
pass
mqtt_client = None
# 创建新的MQTT客户端连接
mqtt_client = MQTTClient(MQTT_CLIENT_ID, MQTT_BROKER, MQTT_PORT)
mqtt_client.connect()
print("已连接到巴法云MQTT服务器")
# 重置重连等待时间
connection_backoff = 5
return True
except Exception as e:
print(f"连接MQTT服务器失败: {e}")
mqtt_client = None
# 增加重连等待时间,但不超过最大值
connection_backoff = min(connection_backoff * 2, max_connection_backoff)
return False
def publish_sensor_data():
"""发布传感器数据到巴法云MQTT服务器"""
global mqtt_client, temperature, humidity
if not mqtt_client:
return False
try:
# 发布温度数据
mqtt_client.publish(MQTT_TEMP_TOPIC, "{:.1f}".format(temperature))
print(f"已发布温度: {temperature}°C 到主题: {MQTT_TEMP_TOPIC}")
# 发布湿度数据
mqtt_client.publish(MQTT_HUMI_TOPIC, "{:.1f}".format(humidity))
print(f"已发布湿度: {humidity}% 到主题: {MQTT_HUMI_TOPIC}")
return True
except Exception as e:
print(f"发布传感器数据失败: {e}")
return False
def check_mqtt_connection():
"""检查MQTT连接状态,如果断开则重新连接"""
global mqtt_client, wifi_connected
if not wifi_connected:
wifi_connected = connect_wifi()
if not wifi_connected:
return False
if mqtt_client is None:
print("MQTT客户端未初始化,尝试连接...")
return connect_mqtt()
try:
# 使用ping检查连接是否活跃
mqtt_client.ping()
return True
except Exception as e:
print(f"MQTT ping失败,连接已断开: {e}")
mqtt_client = None
return connect_mqtt()
def main():
"""主程序逻辑:读取DHT22数据、OLED显示、MQTT上传数据"""
global wifi_connected, mqtt_client, timer
# 连接WiFi
wifi_connected = connect_wifi()
if not wifi_connected:
print("WiFi连接失败,程序退出")
return
# 初始化硬件
oled, uart, led, dht_sensor = setup_hardware()
# 连接MQTT服务器
if not connect_mqtt():
print("MQTT连接失败,程序退出")
return
# 欢迎信息
uart.write(b"\rDHT22温湿度监控系统已启动\n")
uart.write(b"------------------------\n")
try:
while True:
# 检查MQTT连接
if not check_mqtt_connection():
time.sleep(5) # 连接失败后等待一段时间再重试
continue
# 读取DHT22传感器数据
if read_dht_sensor():
# 发布传感器数据到MQTT
publish_sensor_data()
# 更新OLED显示
display_status()
# 处理串口数据
if uart.any():
data = uart.read()
print("串口收到:", data)
if data == b'?':
uart.write(b"\r可用命令:\n")
uart.write(b" ? - 显示帮助信息\n")
uart.write(b" r - 立即读取传感器数据\n")
uart.write(b" s - 显示当前状态\n")
elif data == b'r':
if read_dht_sensor():
publish_sensor_data()
display_status()
elif data == b's':
display_status()
time.sleep(0.1) # 适当延时,减少CPU使用率
except KeyboardInterrupt:
print("程序被用户中断")
finally:
# 清理资源
if mqtt_client:
try:
mqtt_client.disconnect()
except:
pass
print("程序已停止")
if __name__ == "__main__":
main()