You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在ESP32的Asyncio Web服务器中获取HTML下拉框选项值并存储到Python变量

在ESP32的Asyncio Web服务器中获取HTML下拉框选项值并存储到Python变量

嘿,我来帮你解决这个问题!你现在遇到的问题主要有两个关键点需要调整:一是HTML表单的结构问题,二是在ESP32的Web服务器代码里正确解析请求参数。


第一步:修正你的HTML代码

你现在的下拉框<select>是放在<form>标签外面的,这会导致点击提交按钮时,浏览器根本不会把下拉框的参数传递给服务器!得把<select>整个包裹在<form>标签内部,同时明确指定请求方法(默认是GET,写上更清晰),调整后的代码如下:

<form action="./sendToESP" method="GET">
  <select name="dropdown" id="dropdown">
    <option value="649">McMiller</option>
    <!-- 可以根据需求添加更多选项 -->
    <option value="750">Another Option</option>
  </select>
  <br>
  <input type="submit" value="Send!">
</form>

第二步:在ESP32的Python代码中解析参数并存储值

接下来你需要在服务器端解析请求的查询参数,这里给你两种常见的实现方案,根据你的项目需求选择:

方案一:原生Asyncio服务器实现(不依赖第三方框架)

如果是用MicroPython自带的uasyncio搭建服务器,可以借助urllib.parse.parse_qs来解析URL中的查询参数,示例代码如下:

import uasyncio as asyncio
from urllib.parse import parse_qs

# 定义全局变量存储选中的值(也可以根据你的项目结构用类变量、局部变量等)
selected_value = None

async def handle_request(reader, writer):
    # 读取请求行,格式类似 b'GET /sendToESP?dropdown=649 HTTP/1.1\r\n'
    request_line = await reader.readline()
    request_path = request_line.decode().split(' ')[1]
    
    # 处理sendToESP的请求
    if '/sendToESP' in request_path:
        global selected_value
        # 拆分路径和查询参数部分
        if '?' in request_path:
            _, query_string = request_path.split('?', 1)
            # 解析查询参数,返回字典格式,键是参数名,值是参数值的列表
            query_params = parse_qs(query_string)
            
            # 提取dropdown的参数值
            if 'dropdown' in query_params:
                selected_value = query_params['dropdown'][0]
                print(f"成功获取下拉框值: {selected_value}")
                # 返回成功响应给客户端
                response = (
                    "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n"
                    f"<h1>值已接收: {selected_value}</h1><a href='/'>返回首页</a>"
                )
            else:
                # 处理缺少参数的情况
                response = (
                    "HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n\r\n"
                    "<h1>缺少dropdown参数,请先选择选项</h1>"
                )
        else:
            # 没有带参数的情况
            response = (
                "HTTP/1.1 400 Bad Request\r\nContent-Type: text/html\r\n\r\n"
                "<h1>请先选择下拉框选项再提交</h1>"
            )
        writer.write(response.encode())
        await writer.drain()
    # 处理首页请求,返回带下拉框的页面
    elif request_path == '/' or request_path == '/index.html':
        html = """
        <html>
            <body>
                <form action="./sendToESP" method="GET">
                    <select name="dropdown" id="dropdown">
                        <option value="649">McMiller</option>
                        <option value="750">Another Option</option>
                    </select>
                    <br>
                    <input type="submit" value="Send!">
                </form>
            </body>
        </html>
        """
        response = f"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: {len(html)}\r\n\r\n{html}"
        writer.write(response.encode())
        await writer.drain()
    # 处理其他无效请求
    else:
        response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<h1>页面不存在</h1>"
        writer.write(response.encode())
        await writer.drain()
    await writer.wait_closed()

# 启动服务器
async def main():
    server = await asyncio.start_server(handle_request, '0.0.0.0', 80)
    await server.serve_forever()

asyncio.run(main())

方案二:用Microdot轻量框架实现(更简洁)

如果你的ESP32已经安装了microdot框架(这是ESP32上非常流行的轻量级Web框架),代码会简洁很多,框架会自动帮你解析请求参数:

from microdot import Microdot

app = Microdot()
# 存储选中值的变量
selected_value = None

# 首页路由,返回带下拉框的页面
@app.route('/')
def index(request):
    return """
    <html>
        <body>
            <form action="/sendToESP" method="GET">
                <select name="dropdown" id="dropdown">
                    <option value="649">McMiller</option>
                    <option value="750">Another Option</option>
                </select>
                <br>
                <input type="submit" value="Send!">
            </form>
        </body>
    </html>
    """

# 处理提交请求的路由
@app.route('/sendToESP')
def handle_submit(request):
    global selected_value
    # 直接从request.args获取解析好的参数字典
    if 'dropdown' in request.args:
        selected_value = request.args['dropdown']
        return f"<h1>值已接收: {selected_value}</h1><a href='/'>返回首页</a>"
    # 参数缺失的情况
    return "<h1>请先选择下拉框选项再提交</h1>", 400

# 启动服务器
app.run(host='0.0.0.0', port=80)

几个容易踩的坑要注意

  • 千万别忘了把select放在form标签内部,不然参数根本传不到服务器
  • 解析参数时一定要处理参数不存在的情况,避免出现KeyError报错
  • 如果是多并发请求场景,全局变量可能会有覆盖问题,这种情况建议用类或者局部作用域的变量来存储值

备注:内容来源于stack exchange,提问作者DanniDeleto

火山引擎 最新活动