#python #python-3.x #shell #command-line #raspberry-pi
#python #python-3.x #оболочка #командная строка #малина-пи
Вопрос:
Я создаю простую автоматизацию для своего стереоусилителя с использованием Raspberry Pi, и у меня возникли некоторые проблемы с выполнением команд оболочки из python. Предполагается, что мой скрипт прослушивает события от клиента spotify и изменяет выбранный источник на моем усилителе. У меня есть IR blaster, подключенный к моему Raspberry Pi, которым я управляю с помощью ir-ctl
инструмента. Это отлично работает из командной строки, например, когда я запускаю это:
ir-ctl -d /dev/lirc0 -S necx:0x856a24
Источник на моем усилителе изменен на AUX. Тогда я могу запустить:
ir-ctl -d /dev/lirc0 -S necx:0x856a8c
Чтобы изменить его обратно на CD. Это работает на 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:
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'')
Однако исходный код не обновляется на моем усилителе. Это меня очень смущает, почему это работает в 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.
Комментарии:
1. Я был бы более склонен винить
ir-ctl
, если у вас есть журналы с указанием нулевого кода выхода. Возможно, добавьте какой-нибудь код для повторного запроса, если/dev/lirc0
действительно установлено новое значение. Если это неправильная переменная, попробуйте установить ее снова.2. Я не уверен, возможно ли это. Устройство позволяет мне только передавать, могу ли я каким-то образом прочитать из файла устройства? У меня не так уж много знаний в этой области. От
ir-ctl -f -d /dev/lirc0
: Функции приема / dev /lirc0: — Устройство не может получить функции отправки / dev / lirc0: — Устройство может отправлять необработанный IR — кодировщик ИК-сканирования — Установить несущую — Установить рабочий цикл. ——- Кроме того, возможно ли, что использование virtualenv (и, следовательно, python 3 вместо системного python 2.7 по умолчанию) что-то нарушает внутри ir-ctl?3. Хм, инструмент, похоже, написан на C, поэтому, я думаю, вряд ли на него повлияет версия python github.com/cz172638/v4l-utils/blob/master/utils/ir-ctl/ir-ctl.c
4. У вас это работает иногда, но не всегда? есть ли какие-то обстоятельства, при которых, по вашему мнению, это срабатывает чаще, чем у других? Каково соотношение между тем, что работает, и тем, что не работает?
5. В общем, кажется, что это работает в течение нескольких запусков команды, затем она прерывается, затем она снова работает. В зависимости от варианта это примерно 50% времени, когда все в порядке или ниже.
Ответ №1:
Возможно, проблема не в коде Python, а в характере обработки ИК-сигналов вашим приемником (стереоусилителем). Может быть недостаточно отправить только одну команду, и вам нужно отправить несколько одновременно. Вместо
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 Отправляет IR-scancode в указанном протоколе. Протокол должен соответствовать одному из протоколов, перечисленных ниже, за которым следует двоеточие и номер scancode. Если этот параметр указан несколько раз, отправьте все scancodes по порядку с интервалом в 125 мс между ними.Длину промежутка можно изменить с помощью —gap.