首页 > 解决方案 > Python - 不可靠的 shell 命令执行?运行 ir-ctl 命令时出现问题

问题描述

我正在使用 Raspberry Pi 为我的立体声放大器构建简单的自动化,我在从 python 执行 shell 命令时遇到了一些问题。我的脚本应该监听来自 spotify 客户端的事件并更改我的放大器上的选定源。我有 IR blaster 连接到我使用ir-ctl工具控制的 Raspberry Pi。它可以从命令行完美运行,例如当我运行它时:

ir-ctl -d /dev/lirc0 -S necx:0x856a24

我的放大器上的源更改为 AUX。然后我可以运行:

ir-ctl -d /dev/lirc0 -S necx:0x856a8c

把它改回CD。当从 shell 手动运行时,这可以 100% 成功运行。该设备通过以下方式配置/boot/config.txt

dtoverlay=gpio-ir-tx

现在我想在 python 脚本中使用它来监听来自我的 spotify 客户端的事件并根据在 spotify 中选择的设备更改源。这就是问题所在 - 脚本似乎执行了命令,但有时什么也没发生,源没有改变。我对此感到非常困惑,因为我可以看到标准输出确认命令执行成功。

这是我的放大器操作脚本:

def sourceCD():
    print("Changing source to CD")
    runCode('0x856a8c')

def sourceAUX():
    print("Changing source to AUX")
    runCode('0x856a24')

def runCode(code):
    necCommand = 'necx:{}'.format(code)
    #result = subprocess.run(["ir-ctl", "-d","/dev/lirc0","-S", necCommand], capture_output=True, check=True)
    result = subprocess.run(['ir-ctl -d /dev/lirc0 -S necx:{}'.format(code)], shell=True, capture_output=True, check=True)
    print(result)

这是我的监听器脚本:

def on_message(ws, message):
    event = json.loads(message)["event"]
    print('Received event: ', event)

    if event == "contextChanged":
        print("Reacting to changed context")
        sourceAUX()

    if event == "inactiveSession":
        print("reacting to inactive session")
        sourceCD()

if __name__ == "__main__":
    websocket.enableTrace(True)
    ws = websocket.WebSocketApp("ws://192.168.0.41:24879/events",
                          on_message = on_message,
                          on_error = on_error,
                          on_close = on_close)
    ws.run_forever()

我可以在控制台输出中看到每次更改 spotify 设备时都会执行 shell 脚本:

Aug 23 23:09:59 raspberrypi python[4571]: Received event:  inactiveSession
Aug 23 23:09:59 raspberrypi python[4571]: reacting to inactive session
Aug 23 23:09:59 raspberrypi python[4571]: Changing source to CD
Aug 23 23:09:59 raspberrypi python[4571]: CompletedProcess(args=['ir-ctl', '-d', '/dev/lirc0', '-S', 'necx:0x856a8c'], returncode=0, stdout=b'', stderr=b'')
Aug 23 23:10:01 raspberrypi python[4571]: Received event:  contextChanged
Aug 23 23:10:01 raspberrypi python[4571]: Reacting to changed context
Aug 23 23:10:01 raspberrypi python[4571]: Changing source to AUX
Aug 23 23:10:02 raspberrypi python[4571]: CompletedProcess(args=['ir-ctl', '-d', '/dev/lirc0', '-S', 'necx:0x856a24'], returncode=0, stdout=b'', stderr=b'')

但是,我的放大器上的源没有更新。这让我非常困惑,为什么直接在 shell 中运行时它可以 100% 工作,而从 python 运行时它会变得不稳定?

值得一提的是,交替使用这两个:

    #result = subprocess.run(["ir-ctl", "-d","/dev/lirc0","-S", necCommand], capture_output=True, check=True)
result = subprocess.run(['ir-ctl -d /dev/lirc0 -S necx:{}'.format(code)], shell=True, capture_output=True, check=True)

似乎确实会影响成功率,这只会让我更加困惑。我是一名程序员,但 python 对我来说是一门新语言,如果对这个谜语有任何帮助,我将不胜感激。

我在 virtualenv,Python 3.7.3 中运行我的脚本。

标签: pythonpython-3.xshellcommand-lineraspberry-pi

解决方案


也许问题不在于 Python 代码,而在于您的接收器(立体声放大器)处理 IR 信号的性质。仅发送一个命令可能还不够,您需要一次发送多个命令。代替

ir-ctl -d /dev/lirc0 -S necx:0x856a24

发送

ir-ctl -d /dev/lirc0 -S necx:0x856a24 -S necx:0x856a24 -S necx:0x856a24

来自ir-ctl - 一种用于处理原始 IR 和设置 lirc 选项的瑞士刀工具

-S, --scancode=PROTOCOL:SCANCODE 以指定的协议发送红外扫描码。协议必须是下面列出的协议之一,后跟冒号和扫描码编号。如果多次指定此选项,请按顺序发送所有扫描码,它们之间的间隔为 125 毫秒。可以使用--gap 修改间隙长度。


推荐阅读