esp32 MQTTX

 

 e64016259fb321b4a0ccddbf12a1e47d

 

 

 

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()

  

posted @ 2025-09-17 10:42  多多和羊羊  阅读(10)  评论(0)    收藏  举报