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

Orange Pi 5 Debian下Python Web应用启动权限与Xlib连接问题

Orange Pi 5 Debian系统Python应用启动异常解决方案

问题1:普通用户运行触发PermissionError(GPIO权限不足)

报错信息

orangepi@orangepi5:~$ python3 /home/orangepi/v-link/V-Link.py
Initializing backend...
Traceback (most recent call last):
File "/hone/orangeps/v-Link/V-Link.py", line 9, in
from backend.adc import ADCThread
File "/home/orangepi/v-Link/backend/adc.py", line 9, in
import board
...
PermissionError: [Errno 13] Permission denied
...

解决方案

  • 将当前用户加入gpio用户组,永久获取GPIO设备访问权限:
    sudo usermod -aG gpio $USER
    
  • 注销当前用户重新登录,使组权限生效
  • 验证权限:登录后执行groups命令,确认输出包含gpio

问题2:root用户运行触发Xlib.error.DisplayConnectionError

报错信息

Xlib.error.DisplayConnectionError: Can't connect to display ":0" : b'No protocol specified\n'

解决方案

xhost+是临时生效的方法,重启后会失效,推荐以下更安全或永久的方式:

方法1:临时允许root访问当前用户的X显示(重启后失效)

在普通用户终端执行:

xhost +si:localuser:root

之后切换到root用户运行应用即可

方法2:永久配置root访问X显示

  1. 编辑X服务器权限配置文件:
    sudo nano /etc/X11/Xwrapper.config
    
  2. 将allowed_users=console修改为allowed_users=anybody
  3. 添加一行needs_root_rights=yes
  4. 保存退出,重启系统后生效

方法3:运行应用时指定DISPLAY环境变量

在root用户下执行应用时,手动指定显示变量:

DISPLAY=:0 python3 /home/orangepi/v-link/V-Link.py

应用代码(供参考)

import threading
import time
import sys
import os

sys.path.append(os.path.dirname(os.path.abspath(__file__)))

from backend.server              import ServerThread
from backend.adc                 import ADCThread
from backend.canbus              import CanBusThread
from backend.linbus              import LinBusThread
from backend.browser             import BrowserThread

from backend.dev.vcan            import VCanThread
from backend.shared.shared_state import shared_state

class VLINK:
    def __init__(self):
        self.exit_event = shared_state.exit_event
        self.threads = {
            "VCan":     VCanThread(),
            "Browser":  BrowserThread(),
            "Server":   ServerThread(),
            "Canbus":   CanBusThread(),
            #"Linbus":  LinBusThread(),
            "ADC":      ADCThread(),
        }


    def start_thread(self, thread_name):
        thread_class = self.threads[thread_name].__class__

        if not self.threads[thread_name].is_alive():
            self.threads[thread_name] = thread_class()
            thread = self.threads[thread_name]
            thread.daemon = True
            thread.start()
            shared_state.THREAD_STATES[thread_name] = True
            print(f"{thread_name} thread started.")
        else:
            print(f"{thread_name} thread is already running.")


    def stop_thread(self, thread_name):
        thread = self.threads[thread_name]
        if thread.is_alive():
            print(f"Stopping {thread_name} thread.")
            thread.stop_thread()
            thread.join()
            shared_state.THREAD_STATES[thread_name] = False
            print(f"{thread_name} thread stopped.")

    def toggle_thread(self, thread_name):
        if shared_state.THREAD_STATES[thread_name]:
            self.stop_thread(thread_name)
        else:
            self.start_thread(thread_name)

        self.print_thread_states()

    def join_threads(self):
        for thread_name in self.threads:
            self.stop_thread(thread_name)

        for thread_name, thread in self.threads.items():
            if thread.is_alive():
                thread.join()
                shared_state.THREAD_STATES[thread_name] = False
        print("Done.")

    def process_toggle_event(self):
        if shared_state.toggle_can.is_set():
            self.toggle_thread("Canbus")
            shared_state.toggle_can.clear()
            
        if shared_state.toggle_adc.is_set():
            self.toggle_thread("ADC")
            shared_state.toggle_adc.clear()

        if shared_state.toggle_browser.is_set():
            self.toggle_thread("Browser")
            shared_state.toggle_browser.clear()


    def process_exit_event(self):
        if self.exit_event.is_set():
            self.exit_event.clear()
            shared_state.toggle_browser.set()
            time.sleep(1)
            sys.exit(0)

    def print_thread_states(self):
        if(shared_state.isDev):
            for thread_name, thread in self.threads.items():
                state = "Alive" if thread.is_alive() else "Not Alive"
                print(f"{thread_name} Thread: {state}")



def clear_screen():
    if os.name == 'nt':
        os.system('cls')
    else:
        os.system('clear')

def non_blocking_input(prompt):
    try:
        return input(prompt)
    except EOFError:
        return None


if __name__ == "__main__":
    vlink = VLINK()

    vlink.start_thread("Server")

    if len(sys.argv) > 1 and sys.argv[1] == "dev":
        shared_state.isDev = True
        choice = non_blocking_input("Simulate CAN-Bus? (Y/N): ")
        if choice.lower() == 'y':
            shared_state.vCan = True
            print("Starting VCAN...")
            vlink.toggle_thread("VCan")

        choice = non_blocking_input("Start on Vite-Port 5173? (Y/N): ")
        if choice.lower() == 'y':
            shared_state.isFlask = False

        choice = non_blocking_input("Start in Kiosk mode? (Y/N): ")
        if choice.lower() == 'n':
            shared_state.isKiosk = False

    vlink.start_thread("Canbus")
    time.sleep(.1)
    vlink.start_thread("ADC")
    time.sleep(3)
    vlink.start_thread("Browser")

    vlink.print_thread_states()

    try:
        while(True):
            vlink.process_toggle_event()
            vlink.process_exit_event()
            time.sleep(.1)
    except KeyboardInterrupt:
            print("\nExiting... Stopping threads.")
            #vlink.join_threads()
            sys.exit(0)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 13:34:59