树莓派3通过Python+HTML控制GPIO LED故障排查求助
看起来你现在的问题是Web路由不匹配、Python脚本逻辑错误和Bottle稳定性这几个点交织在一起,我来一步步帮你拆解修复:
1. 先搞定Web服务器的路由问题(Bottle升级失效的原因)
你之前的Bottle路由@route("/set/<mode>/<pin>/<strip>/<color>")在升级后失效,是因为新版本的Bottle对路由参数的匹配更严格了——你的HTML按钮会生成带空参数的URL(比如/set/0///),而原来的路由要求四个参数都非空,所以直接返回404。
要处理空参数,你需要用正则匹配允许参数为空,或者设置可选参数。修改路由如下:
from bottle import route, run, response, default_app # 允许参数为空,用正则匹配任意字符(包括空) @route("/set/<mode:re:\d+>/<pin:re:.*>/<strip:re:.*>/<color:re:.*>") def set_led(mode, pin, strip, color): # 将空参数转为默认值0或None mode = int(mode) pin = int(pin) if pin.strip() else None strip = int(strip) if strip.strip() else None color = int(color) if color.strip() else None # 执行LED控制逻辑 process = Processing() # --- 这里放修复后的控制逻辑(见下文Processing类修复)--- # 返回网页内容 response.content_type = 'text/html' return webside() @route("/") @route("/led.html") def webside(): with open("led.html", "r") as file: content = file.read() response.content_type = 'text/html' return content app = default_app()
2. 修复Processing类的致命bug
你的Processing类有好几个逻辑错误,这是脚本崩溃的核心原因:
2.1 状态存储错误
state_pin = [28]完全错误,你需要存储所有GPIO引脚的状态,用字典更合适:
class Processing(): def __init__(self): # 初始化所有默认引脚的状态为0(关闭) self.state_pin = {pin: 0 for pin in self.default_settings()}
2.2 字符串拼接错误
create_string函数里new_string[-1] = ""会报错(字符串不可变),直接用','.join()更简洁安全:
def create_string(self, input_list): return ','.join(map(str, input_list)) # 转成字符串再拼接
2.3 文件操作错误
get_settings_file里print(file + " created")是错误的(不能把文件对象和字符串拼接),改成:
def get_settings_file(self): try: with open("gpio.txt", "r") as file: settings = file.read().strip().split(",") # 转成整数列表,避免空字符串 return [int(p) for p in settings if p] except OSError: default = self.default_settings() with open("gpio.txt", "w") as file: file.write(self.create_string(default)) print("gpio.txt created with default settings") return default
2.4 引脚检查和修改逻辑错误
output_check、add_pin_file、del_pin_file的逻辑都有问题,修复后:
def output_check(self, pin): settings = self.get_settings_file() return pin in settings def add_pin_file(self, pin): settings = self.get_settings_file() if pin not in settings: settings.append(pin) with open("gpio.txt", "w") as file: file.write(self.create_string(settings)) def del_pin_file(self, pin): settings = self.get_settings_file() if pin in settings: settings.remove(pin) with open("gpio.txt", "w") as file: file.write(self.create_string(settings))
3. 彻底重构main函数
你原来的main函数逻辑完全错误:它一直在循环请求同一个固定URL,根本没有处理用户的Web请求。Web服务器本身就是用来处理请求的,main只需要初始化GPIO,然后启动服务器:
import RPi.GPIO as GPIO def main(): GPIO.setwarnings(False) GPIO.setmode(GPIO.BCM) # 初始化所有默认引脚为输出模式 settings = Processing().default_settings() for pin in settings: GPIO.setup(pin, GPIO.OUT) GPIO.output(pin, 0) # 默认关闭 # 用waitress替代默认服务器提升稳定性 from waitress import serve serve(app, host="0.0.0.0", port=88) # 服务器退出后清理GPIO GPIO.cleanup() if __name__ == "__main__": main()
4. 提升Bottle稳定性的小技巧
你说Bottle长期运行不稳定,试试这些优化:
- 用
waitress作为生产服务器替代Bottle自带的开发服务器:pip install waitress - 避免在请求处理函数里做耗时操作(GPIO操作尽量快)
- 添加全局异常捕获,避免单个请求崩溃整个服务器:
from bottle import error @error(500) def error500(error): print(f"Server error: {error}") GPIO.cleanup() return "Server Error, GPIO cleaned up."
5. HTML按钮的小优化
你的按钮URL里的空参数可以用0代替,避免//,比如:
<input type=button onClick="location.href='/set/0/0/0/0'" class="button head black" value="Reset">
这样路由匹配更简单,也避免潜在的解析问题。
最后测试步骤
- 安装最新版Bottle和waitress:
pip install --upgrade bottle waitress - 替换所有修复后的代码
- 确保
led.html和脚本在同一目录 - 运行脚本:
sudo python your_script.py(GPIO需要root权限) - 在浏览器访问
http://<你的树莓派IP>:88/led.html,点击按钮测试
内容的提问来源于stack exchange,提问作者Anonymgibtsnich

