import time
from machine import Pin, ADC, SoftI2C
from ssd1306 import SSD1306_I2C
from umqtt.simple import MQTTClient
import network
# WiFi配置 - Wokwi-GUEST是Wokwi仿真环境的默认网络
WIFI_SSID = "Wokwi-GUEST"
WIFI_PASSWORD = ""
# 巴法云 MQTT 配置
MQTT_SERVER = "bemfa.com"
MQTT_PORT = 9501
MQTT_CLIENT_ID = "3e74bc9a643481be57b70de123a7e419"
MQTT_TOPIC = "MQ2"
# 硬件配置
mq2_pin = ADC(Pin(34)) # MQ2传感器连接到ADC引脚34
mq2_pin.atten(ADC.ATTN_11DB) # 设置为11dB衰减,测量范围0-3.3V
# 继电器和LED控制
relay_pin = Pin(15, Pin.OUT) # 继电器控制引脚
relay_pin.on() # 默认关闭继电器
# 初始化OLED屏 -
i2c = SoftI2C(scl=Pin(22), sda=Pin(21)) # 使用SoftI2C替代旧版I2C
oled = SSD1306_I2C(128, 64, i2c)
# 系统参数
smoke_threshold = 500 # 默认烟雾阈值
current_mode = "AUTO" # 工作模式
alarm_triggered = False # 报警状态
# 映射MQ2模拟值到烟雾浓度百分比
def map_smoke_value(raw_value):
raw_value = max(0, min(raw_value, 4095)) # 确保值在有效范围内
return (raw_value / 4095) * 100
# 连接WiFi - 增强版,带超时和重试(去掉等待提示打印)
def connect_wifi():
sta_if = network.WLAN(network.STA_IF)
if sta_if.isconnected():
print("已连接到WiFi")
return True
print(f'正在连接到网络... SSID={WIFI_SSID}')
sta_if.active(True)
sta_if.connect(WIFI_SSID, WIFI_PASSWORD)
# 带超时的连接等待(15秒),但不打印等待剩余时间
timeout = 15
while not sta_if.isconnected() and timeout > 0:
time.sleep(1)
timeout -= 1
if sta_if.isconnected():
print('网络配置:', sta_if.ifconfig())
return True
else:
print("WiFi连接超时")
return False
# 连接MQTT服务器
def connect_mqtt():
client = MQTTClient(MQTT_CLIENT_ID, MQTT_SERVER, MQTT_PORT, MQTT_USER, MQTT_PASSWORD)
try:
client.connect()
print('已连接到MQTT服务器!')
return client
except Exception as e:
print(f'MQTT连接失败: {e}')
return None
# 处理MQTT消息
def sub_cb(topic, msg):
global smoke_threshold, current_mode, alarm_triggered
msg_str = msg.decode()
if topic.decode() == MQTT_TOPIC:
try:
# 设置烟雾阈值命令
if msg_str.startswith("THRESHOLD:"):
try:
new_threshold = int(msg_str.split(":")[1])
if 100 <= new_threshold <= 4000:
smoke_threshold = new_threshold
print(f"烟雾阈值已更新为 {smoke_threshold}")
update_display()
else:
print("无效的阈值,必须在100-4000之间")
except:
print("无效的阈值格式")
# 模式切换命令
elif msg_str in ["AUTO", "MANUAL"]:
current_mode = msg_str
print(f"工作模式已切换为 {current_mode}")
alarm_triggered = False # 切换模式时重置报警状态
relay_pin.on() # 关闭继电器
update_display()
# 手动控制继电器
elif msg_str in ["RELAY_ON", "RELAY_OFF"]:
if current_mode == "MANUAL":
if msg_str == "RELAY_ON":
relay_pin.off() # 打开继电器(LED亮起)
alarm_triggered = True
print("手动打开继电器")
else:
relay_pin.on() # 关闭继电器(LED熄灭)
alarm_triggered = False
print("手动关闭继电器")
update_display()
else:
print("自动模式下不允许手动控制")
# 状态查询命令
elif msg_str == "STATUS":
smoke_value = mq2_pin.read()
status_msg = f"{smoke_value}"
mqtt_client.publish(MQTT_TOPIC, status_msg)
print(f"状态查询,烟雾值={smoke_value}")
except ValueError:
print("收到无效的消息格式")
# 更新OLED显示
def update_display():
try:
oled.fill(0)
smoke_value = mq2_pin.read()
oled.text(f"烟雾: {smoke_value}", 0, 10)
oled.text(f"阈值: {smoke_threshold}", 0, 25)
oled.text(f"模式: {current_mode}", 0, 40)
oled.text(f"报警: {'开' if alarm_triggered else '关'}", 0, 55)
oled.show()
except Exception as e:
print(f"OLED更新错误: {e}")
# 主程序
if __name__ == "__main__":
print("MQ2烟雾监测系统启动")
# 初始化显示
try:
oled.fill(0)
oled.text("系统初始化中...", 0, 32)
oled.show()
except Exception as e:
print(f"OLED初始化错误: {e}")
# 连接WiFi - 关键修改:使用增强的连接函数(无等待提示)
wifi_connected = connect_wifi()
if not wifi_connected:
print("致命错误: 无法连接到WiFi")
try:
oled.fill(0)
oled.text("WiFi错误", 0, 20)
oled.text("请检查网络", 0, 40)
oled.show()
except:
pass
# 进入错误循环
while True:
time.sleep(1)
# 连接MQTT服务器
mqtt_client = connect_mqtt()
if not mqtt_client:
print("致命错误: 无法连接到MQTT")
try:
oled.fill(0)
oled.text("MQTT错误", 0, 20)
oled.text("请检查设置", 0, 40)
oled.show()
except:
pass
while True:
time.sleep(1)
print("系统初始化完成")
try:
oled.fill(0)
oled.text("系统已启动", 0, 20)
oled.text("等待数据...", 0, 40)
oled.show()
except:
pass
# 主循环
last_publish_time = 0
publish_interval = 2 # 发布间隔(秒)
while True:
try:
if mqtt_client:
mqtt_client.check_msg()
# 立即读取烟雾值
smoke_value = mq2_pin.read()
# 仅在自动模式下进行报警判断
if current_mode == "AUTO":
if smoke_value > smoke_threshold and not alarm_triggered:
alarm_triggered = True
print(f"报警触发! 烟雾值: {smoke_value}")
# 触发报警时立即控制继电器闪烁
relay_pin.value(not relay_pin.value()) # 闪烁效果
elif smoke_value <= smoke_threshold and alarm_triggered:
alarm_triggered = False
print(f"报警解除. 烟雾值: {smoke_value}")
relay_pin.on() # 确保继电器关闭(LED熄灭)
# 如果已经触发报警,持续闪烁
if alarm_triggered:
time.sleep(0.2) # 闪烁频率
relay_pin.value(not relay_pin.value())
# 更新显示
update_display()
# 定期发布传感器数据
current_time = time.time()
if current_time - last_publish_time >= publish_interval:
mqtt_client.publish(MQTT_TOPIC, f"{smoke_value}")
last_publish_time = current_time
except Exception as e:
print(f"主循环错误: {e}")
try:
oled.fill(0)
oled.text("错误:", 0, 20)
oled.text(str(e)[:16], 0, 40)
oled.show()
except:
pass
time.sleep(1)