You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本移植到ESP8266的MicroPython遇错误求排查

问题排查与移植修复方案

核心问题定位

你遇到的OSError 2在MicroPython环境中通常对应DNS解析失败、目标主机不可达或网络连接超时,同时移植代码存在几处逻辑错误,导致异常无法准确定位且功能失效:

1. 异常捕获过于宽泛,无法定位具体问题

当前代码仅用except:捕获所有异常,只打印固定字符串,完全无法获取异常类型和具体信息。需要修改捕获逻辑,打印异常详情:

except Exception as e:
    print(f"异常类型: {type(e).__name__}, 详情: {e}")

2. 函数返回值不匹配导致数据处理错误

login()函数返回(response.json(), response)元组,但check_status()中仅用json_data = login()接收,导致json_data是包含JSON数据和响应对象的元组而非纯JSON字典。后续调用get_relay_status(json_data)时,会因元组无法通过键取值触发错误。

3. get_relay_status无返回值,状态对比逻辑失效

原Python代码中该函数返回继电器状态,但移植后仅控制LED却未返回状态值,导致current_status始终为None,状态变化的对比逻辑完全无法执行。

4. mDNS域名解析问题

apex.local是本地mDNS域名,多数ESP8266的MicroPython固件默认不支持mDNS解析,会导致无法解析主机地址,触发OSError 2。建议直接使用Apex控制器的静态IP地址替代域名。

5. urequests资源未释放

urequests的响应对象如果不手动关闭,会导致ESP8266内存泄漏,长期运行可能引发其他异常。


修正后的完整代码

import machine
import time
import urequests
import ubinascii
import network

# Wi-Fi credentials
WIFI_SSID = "CREDS"
WIFI_PASSWORD = "CREDS"

# Apex controller credentials - 替换为静态IP
url = "http://192.168.x.x/cgi-bin/status.json"  # 替换成你的Apex实际IP
username = "admin"
password = "1234"
previous_status = None

# LED pin
LED_PIN = 2

# Connect to Wi-Fi network
station = network.WLAN(network.STA_IF)
station.active(True)
station.connect(WIFI_SSID, WIFI_PASSWORD)
while not station.isconnected():
    time.sleep(1)
print(f'Wi-Fi连接成功,网络信息: {station.ifconfig()}')

# Define LED pin as output
led = machine.Pin(LED_PIN, machine.Pin.OUT)

def login():
    credentials = '{}:{}'.format(username, password)
    encoded_credentials = ubinascii.b2a_base64(credentials.encode())[:-1].decode()
    headers = {'Authorization': 'Basic {}'.format(encoded_credentials)}

    try:
        response = urequests.get(url, headers=headers, timeout=5)  # 添加超时
        if response.status_code != 200:
            raise Exception(f"请求失败,状态码: {response.status_code}")
        json_data = response.json()
        response.close()  # 释放资源
        return json_data
    except Exception as e:
        if 'response' in locals():
            response.close()
        raise e  # 抛出异常让上层处理

# Fetch relay status and toggle LED accordingly
def get_relay_status(json_data):
    for output in json_data['istat']['outputs']:
        if output['name'] == 'Relay_1':
            status = output['status'][0]
            # 控制LED
            led.value(1 if status == 'ON' else 0)
            return status  # 返回状态值用于对比
    return None  # 未找到Relay_1时返回None

def check_status():
    global previous_status
    
    try:
        json_data = login()
        current_status = get_relay_status(json_data)
        
        if current_status is None:
            print("未找到Relay_1设备")
            return
            
        if previous_status is not None and previous_status != current_status:
            print(f"继电器状态变更为: {current_status}")

        previous_status = current_status
    except Exception as e:
        print(f"异常类型: {type(e).__name__}, 详情: {e}")
    finally:
        time.sleep(5)  # 添加延迟,避免频繁请求占用资源
      
while True:
    check_status()

额外排查建议

  1. 验证网络连通性:在ESP8266的REPL中执行import socket; socket.getaddrinfo("192.168.x.x", 80)(替换为Apex的IP),如果报错则说明网络不通,检查Wi-Fi是否在同一网段、Apex控制器是否在线。
  2. 检查Apex接口权限:确保使用的账号密码有权限访问/cgi-bin/status.json接口,可先用浏览器访问该地址验证。
  3. 固件兼容性:如果仍有问题,尝试更新ESP8266的MicroPython固件到最新稳定版,部分旧固件存在网络模块bug。

内容的提问来源于stack exchange,提问作者DATTO MOTORSPORTS

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 08:47:33