import machine
import time
import dht
from hcsr04 import HCSR04
from machine import Pin, ADC, SoftI2C
from ssd1306 import SSD1306_I2C
import network
from umqtt.simple import MQTTClient
from time import ticks_ms
# ====================== 配置部分 ======================
SECRET_KEY = "a019001c4fee4049a0e55087d01bfc91"
MQTT_SERVER = "bemfa.com" # 使用短域名
MQTT_PORT = 9501
MQTT_CLIENT_ID = SECRET_KEY # 直接使用秘钥作为客户端ID
# 主题配置
TOPICS = {
'temp': 'mytemp',
'humi': 'myhumi',
'dist': 'mydistance',
'gas': 'mq2value',
'gas_status': 'mq2status',
'status': 'status' # 在线状态主题
}
# 状态标识
ONLINE_STATUS = "on"
OFFLINE_STATUS = "off"
# 硬件引脚配置
PIN_CONFIG = {
'dht': 5,
'trig': 4,
'echo': 27,
'gas': 34,
'sda': 21,
'scl': 22
}
# 连接管理参数
ONLINE_PUBLISH_INTERVAL = 60000 # 60秒发送一次在线状态
INITIAL_RECONNECT_DELAY = 5000 # 初始重连等待5秒
MAX_RECONNECT_DELAY = 60000 # 最大重连等待60秒
# ====================== 初始化硬件 ======================
dht_sensor = dht.DHT22(Pin(PIN_CONFIG['dht']))
ultrasonic = HCSR04(trigger_pin=PIN_CONFIG['trig'], echo_pin=PIN_CONFIG['echo'])
gas_sensor = ADC(Pin(PIN_CONFIG['gas']))
gas_sensor.atten(ADC.ATTN_11DB)
# 使用SoftI2C
i2c = SoftI2C(scl=Pin(PIN_CONFIG['scl']), sda=Pin(PIN_CONFIG['sda']))
oled = SSD1306_I2C(128, 64, i2c)
# 全局变量
mqtt_client = None
wifi_connected = False
last_online_publish = 0
reconnect_delay = INITIAL_RECONNECT_DELAY
last_connection_attempt = 0
# ====================== 网络连接 ======================
def connect_wifi():
global wifi_connected
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
if not wlan.isconnected():
print('Connecting WiFi...')
wlan.connect('Wokwi-GUEST', '')
max_wait = 20 # 增加等待时间
while max_wait > 0:
if wlan.isconnected():
break
max_wait -= 1
time.sleep(0.5)
wifi_connected = wlan.isconnected()
if wifi_connected:
print('WiFi connected:', wlan.ifconfig())
else:
print('WiFi connection failed')
return wifi_connected
def publish_status(status, retain=True):
"""发布状态消息"""
if mqtt_client:
try:
mqtt_client.publish(f"{SECRET_KEY}/{TOPICS['status']}",
status,
retain=retain)
print(f"Published status: {status}")
return True
except Exception as e:
print("Publish status failed:", e)
return False
def connect_mqtt():
global mqtt_client, reconnect_delay, last_connection_attempt
current_time = ticks_ms()
# 防止过于频繁重连
if current_time - last_connection_attempt < reconnect_delay:
return False
last_connection_attempt = current_time
try:
# 清理旧连接
if mqtt_client:
try:
mqtt_client.disconnect()
except:
pass
mqtt_client = None
# 创建新连接
mqtt_client = MQTTClient(MQTT_CLIENT_ID,
MQTT_SERVER,
MQTT_PORT,
keepalive=60)
mqtt_client.connect()
print("MQTT connected")
# 发布在线状态
publish_status(ONLINE_STATUS, retain=True)
# 重置重连延迟
reconnect_delay = INITIAL_RECONNECT_DELAY
return True
except Exception as e:
print("MQTT connect failed:", e)
mqtt_client = None
# 指数退避算法增加重连延迟
reconnect_delay = min(reconnect_delay * 2, MAX_RECONNECT_DELAY)
return False
def check_connection():
"""检查并维持连接"""
global wifi_connected, last_online_publish
# 检查WiFi
if not wifi_connected or not network.WLAN(network.STA_IF).isconnected():
wifi_connected = connect_wifi()
if not wifi_connected:
return False
# 检查MQTT
if mqtt_client is None:
return connect_mqtt()
try:
# 检查MQTT连接状态
mqtt_client.ping()
# 定期发布在线状态
current_time = ticks_ms()
if current_time - last_online_publish > ONLINE_PUBLISH_INTERVAL:
if publish_status(ONLINE_STATUS):
last_online_publish = current_time
return True
except Exception as e:
print("MQTT connection lost:", e)
publish_status(OFFLINE_STATUS) # 尝试发布离线状态
mqtt_client = None
return False
# ====================== 主程序 ======================
def main():
# 初始显示
oled.fill(0)
oled.text("Initializing...", 0, 0)
oled.show()
# 初始连接
connect_wifi()
connect_mqtt()
last_send = 0
SEND_INTERVAL = 2000 # 2秒发送间隔
while True:
try:
current_time = ticks_ms()
# 维持连接
connection_ok = check_connection()
# 读取传感器数据
dht_sensor.measure()
temp = dht_sensor.temperature()
humi = dht_sensor.humidity()
dist = ultrasonic.distance_cm()
gas = gas_sensor.read()
# OLED显示
oled.fill(0)
oled.text(f"T:{temp:.1f}C H:{humi:.1f}%", 0, 0)
oled.text(f"D:{dist:.1f}cm", 0, 16)
oled.text(f"G:{gas}", 0, 32)
oled.text(f"WiFi: {'ON' if wifi_connected else 'OFF'}", 0, 48)
oled.text(f"MQTT: {'ON' if mqtt_client else 'OFF'}", 0, 56)
oled.show()
# 发送传感器数据
if connection_ok and (current_time - last_send > SEND_INTERVAL):
try:
mqtt_client.publish(TOPICS['temp'], str(temp))
mqtt_client.publish(TOPICS['humi'], str(humi))
mqtt_client.publish(TOPICS['dist'], str(dist))
mqtt_client.publish(TOPICS['gas'], str(gas))
# 气体状态判断
status = "SAFE"
if gas > 2000: status = "WARNING"
if gas > 2500: status = "DANGER"
mqtt_client.publish(TOPICS['gas_status'], status)
print("Sensor data published")
last_send = current_time
except Exception as e:
print("Publish failed:", e)
mqtt_client = None
time.sleep(0.5)
except Exception as e:
print("Main loop error:", e)
oled.fill(0)
oled.text("Error:" + str(e)[:20], 0, 0)
oled.show()
time.sleep(2)
if __name__ == "__main__":
try:
main()
finally:
# 程序结束时发布离线状态
if mqtt_client:
publish_status(OFFLINE_STATUS)
try:
mqtt_client.disconnect()
except:
pass