esp32 MQTTX

import network
import time
from umqtt.simple import MQTTClient
import machine
import json
import gc
# 配置 WiFi
WIFI_SSID = "TonyMagic6"
WIFI_PASSWORD = "12345678"
# 全局变量
led = None
client = None
last_publish_time = 0
PUBLISH_INTERVAL = 15 # 发布间隔(秒)
WIFI_RETRY_INTERVAL = 5 # WiFi重试间隔(秒)
MQTT_RETRY_INTERVAL = 5 # MQTT重试间隔(秒)
# 初始化内置温度传感器
def init_temperature_sensor():
"""初始化ESP32内置温度传感器"""
try:
# 对于ESP32,内置温度传感器通常是ADC1的通道8
# 不同型号的ESP32可能有不同的实现方式
from machine import ADC
# 尝试不同的初始化方法
try:
# 方法1:直接使用通道4(常见于ESP32)
adc = ADC(4)
# 尝试设置衰减器,如果失败则使用默认设置
try:
adc.atten(ADC.ATTN_11DB) # 设置衰减器为11dB
except:
print("Using default ADC attenuation")
adc.width(ADC.WIDTH_12BIT) # 12位精度
return adc
except:
# 方法2:尝试使用ADC1通道8
try:
adc = ADC(machine.Pin(32)) # 尝试使用GPIO32(ADC1通道4)
return adc
except:
print("Alternative ADC method failed")
return None
except Exception as e:
print(f"Temperature sensor init failed: {e}")
return None
def read_temperature(adc):
"""读取ESP32内置温度传感器值并转换为摄氏度"""
try:
if adc is None:
return None
# 读取多个样本并取平均值以提高精度
samples = 10
total = 0
for i in range(samples):
total += adc.read()
time.sleep(0.01)
adc_value = total / samples
print(f"ADC raw value: {adc_value}")
# 将ADC值转换为电压(mV)
# ESP32 ADC参考电压通常为1100mV
voltage = adc_value * 1100 / 4095 # 12位ADC,最大值为4095
print(f"Voltage: {voltage:.2f} mV")
# 使用更精确的温度转换公式
# 这个公式适用于大多数ESP32型号
temperature = 27 - (voltage - 500) / 10
# 限制温度范围在合理范围内
temperature = max(min(temperature, 85), -40)
return round(temperature, 1)
except Exception as e:
print(f"Temperature read error: {e}")
return None
# 改进的 WiFi 连接函数
def connect_wifi():
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
# 如果已经连接,先断开
if wlan.isconnected():
print("Already connected to WiFi, disconnecting first...")
wlan.disconnect()
time.sleep(1)
# 扫描可用的 WiFi 网络
print("Scanning for WiFi networks...")
networks = wlan.scan()
found_networks = []
for net in networks:
try:
ssid = net[0].decode('utf-8')
found_networks.append(ssid)
print(f"Found: {ssid}")
except:
continue
if WIFI_SSID not in found_networks:
print(f"Warning: Target network '{WIFI_SSID}' not found in scan results")
print(f"Connecting to {WIFI_SSID}...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)
# 增加等待时间和重试机制
max_wait = 20
for i in range(max_wait):
if wlan.isconnected():
break
print(f'Waiting for connection... ({i+1}/{max_wait})')
time.sleep(1)
if wlan.isconnected():
print("WiFi connected!")
print("IP address:", wlan.ifconfig()[0])
return True
else:
print("WiFi connection failed")
wlan.disconnect()
return False
# 重试连接 WiFi
def ensure_wifi_connection(max_retries=3):
for attempt in range(max_retries):
print(f"WiFi connection attempt {attempt + 1}/{max_retries}")
if connect_wifi():
return True
if attempt < max_retries - 1:
print(f"Retrying in {WIFI_RETRY_INTERVAL} seconds...")
time.sleep(WIFI_RETRY_INTERVAL)
return False
# MQTT 配置
MQTT_BROKER = "broker.emqx.io"
MQTT_PORT = 1883
MQTT_CLIENT_ID = "esp32_client_%s" % machine.unique_id()
MQTT_TOPIC_SUB = "esp32/led_tony_123"
MQTT_TOPIC_SUB1 = "esp32/sub1"
MQTT_TOPIC_PUB = "esp32/led_tony_123"
MQTT_TOPIC_TEMP = "esp32/temperature"
def mqtt_callback(topic, msg):
try:
# 解码字节为字符串
topic_str = topic.decode('utf-8') if isinstance(topic, bytes) else topic
msg_str = msg.decode('utf-8') if isinstance(msg, bytes) else msg
print(f"Received message: '{msg_str}' on topic: '{topic_str}'")
# 尝试解析JSON
try:
data = json.loads(msg_str)
print("Parsed JSON:", data)
return
except ValueError:
pass
# 处理普通文本消息
if topic_str == MQTT_TOPIC_SUB:
msg_lower = msg_str.lower().strip()
if msg_lower == "on":
led.on()
print("LED已打开")
elif msg_lower == "off":
led.off()
print("LED已关闭")
elif msg_lower == "toggle":
led.value(not led.value())
print("LED已切换状态")
elif msg_lower == "temperature" or msg_lower == "temp":
# 立即读取并发布温度
temp = read_temperature(temp_sensor)
if temp is not None:
temp_msg = {"temperature": temp, "timestamp": time.time()}
client.publish(MQTT_TOPIC_TEMP, json.dumps(temp_msg))
print(f"Temperature published: {temp}°C")
else:
print("Temperature sensor not available")
elif msg_lower == "debug":
# 调试命令:读取ADC原始值
if temp_sensor:
raw_value = temp_sensor.read()
print(f"ADC raw value: {raw_value}")
client.publish(MQTT_TOPIC_PUB, json.dumps({"debug": "adc_read", "value": raw_value}))
else:
print(f"Unknown command: {msg_str}")
except Exception as e:
print(f"Error in callback: {e}")
def connect_mqtt():
global client
try:
client = MQTTClient(
client_id=MQTT_CLIENT_ID,
server=MQTT_BROKER,
port=MQTT_PORT,
keepalive=60
)
client.set_callback(mqtt_callback)
client.connect()
client.subscribe(MQTT_TOPIC_SUB)
client.subscribe(MQTT_TOPIC_SUB1)
print("Connected to MQTT and subscribed to topics")
return client
except Exception as e:
print(f"MQTT connection failed: {e}")
return None
def reconnect_mqtt():
"""重新连接MQTT"""
global client
print("Attempting MQTT reconnection...")
try:
if client:
client.disconnect()
except:
pass
time.sleep(2)
return connect_mqtt()
def publish_status(client, temp_sensor):
"""发布状态信息(包含温度)"""
try:
# 读取温度
temperature = read_temperature(temp_sensor)
message = {
"device": "ESP32",
"client_id": MQTT_CLIENT_ID,
"timestamp": time.time(),
"free_memory": gc.mem_free(),
"status": "online",
"led_status": "on" if (led.value() )else "off",
"temperature": temperature if temperature is not None else "N/A"
}
client.publish(MQTT_TOPIC_PUB, json.dumps(message))
if temperature is not None:
print(f"Status message published, temperature: {temperature}°C")
else:
print("Status message published (temperature sensor not available)")
return True
except Exception as e:
print(f"Publish failed: {e}")
return False
def main():
global led, client, last_publish_time
# 初始化 LED
led = machine.Pin(2, machine.Pin.OUT)
led.off() # 初始状态关闭
# 初始化温度传感器
temp_sensor = init_temperature_sensor()
if temp_sensor:
print("Temperature sensor initialized")
# 测试读取一次温度
temp = read_temperature(temp_sensor)
if temp is not None:
print(f"Initial temperature: {temp}°C")
else:
print("Failed to read initial temperature")
else:
print("Temperature sensor not available - using fallback mode")
print("ESP32 MQTT Client Starting...")
print("Free memory:", gc.mem_free())
# 连接 WiFi
if not ensure_wifi_connection():
print("Failed to connect to WiFi after multiple attempts")
return
# 连接 MQTT
client = connect_mqtt()
if not client:
print("Failed to connect to MQTT")
return
print("ESP32 MQTT client started successfully")
last_publish_time = time.time()
try:
while True:
# 检查MQTT消息
try:
client.check_msg()
except Exception as e:
print(f"MQTT error: {e}, attempting reconnect...")
client = reconnect_mqtt()
if not client:
print("Reconnection failed, waiting before retry...")
time.sleep(MQTT_RETRY_INTERVAL)
continue
# 定期发布状态(包含温度)
current_time = time.time()
if current_time - last_publish_time >= PUBLISH_INTERVAL:
if publish_status(client, temp_sensor):
last_publish_time = current_time
# 闪烁LED指示活动状态
led.value(not led.value())
time.sleep(0.1)
led.value(not led.value())
# 短暂延迟以减少CPU使用
time.sleep(0.1)
except KeyboardInterrupt:
print("Program interrupted by user")
except Exception as e:
print(f"Unexpected error: {e}")
finally:
# 清理资源
print("Cleaning up resources...")
try:
if client:
client.disconnect()
print("MQTT disconnected")
except:
pass
led.off()
print("Program ended")
# 运行程序
if __name__ == "__main__":
gc.collect()
print("Initial free memory:", gc.mem_free())
main()
浙公网安备 33010602011771号