樹莓派與紅外線遙控器
利用樹莓派接收紅外線訊息、發射紅外線訊息是相當常用的遠端控制技巧
一、利用remote-ssh extension打造遠端開發環境
先前有介紹使用VS Code遠端開發Django,當時使用的方法有點土法練鋼,現在微軟提供非常簡易的remote-ssh擴充套件,可以讓VS Code很方便的與遠端樹莓派整合在一起,利用前端電腦的強大處理能力去協同開發後端樹莓派的Python應用。
在介紹紅外線的接收與發射前,讓我們先來打造一個Python遠端開發的樹莓派環境。
二、打開支援核心
現今的Linux核心已可直接支援紅外線遙控器的收發,只要將它打開即可,非常方便使用。
三、萬碼奔騰,自製編碼對應表
紅外線使用的編碼表按鍵名稱列表:https://peppe8o.com/download/txt/ir-keytable%20available%20keycodes.txt
由於遙控器的廠牌太多種類,甚至是同廠牌也有不同型號的遙控器,其編碼也不一定會完全一致,因此,學習自製編碼對應表,是常遇到的課題。
四、控制VLC播放音樂及LED閃爍
有了前面的基礎後,就可以利用python-evdev模組,來讀取遙控器資料並判斷是哪個按鈕被按下,進行相對應的程式處理。同時,由於VLC於背景播放,可使用psutil模組,來處理結束播放事宜。這二個模組功能是相當強大的,值得好好研究與學習。官網說明文件如下:
# ir_read_nomessage.py
from evdev import InputDevice, list_devices, categorize, ecodes
def get_ir_device():
devices = [InputDevice(path) for path in list_devices()]
for device in devices:
print(device.path, device.name, device.phys)
if 'ir_recv' in device.name:
return device
else:
device.close()
dev = get_ir_device()
try:
for event in dev.read_loop():
if event.type == ecodes.EV_KEY:
if event.value == 1:
if ecodes.KEY[event.code] == 'KEY_1':
print('press 1')
elif ecodes.KEY[event.code] == 'KEY_2':
print('press 2')
elif ecodes.KEY[event.code] == 'KEY_3':
print('press 3')
dev.close()
quit()
except KeyboardInterrupt:
print('press ctrl-c')
dev.close()
quit()
# vlc_id.py
import psutil
# 方法一:先取得所有的process id (PID),再找出vlc的PID,找到就kill離開
# process_ids = psutil.pids()
# for pid in process_ids:
# p = psutil.Process(pid)
# if 'vlc' in p.name():
# print(p.name())
# print(p.pid)
# p.kill()
# break
# 方法二:透過iter的方式,一個個找,找到就kill離開
for proc in psutil.process_iter(['pid', 'name']):
if 'vlc' in proc.info['name']:
print(proc.info['pid'])
p = psutil.Process(proc.info['pid'])
p.kill()
break
from evdev import InputDevice, list_devices, categorize, ecodes
from gpiozero import LED
import subprocess
import psutil
led = LED(27)
led_on = False
vlc_on = False
def get_ir_device():
devices = [InputDevice(path) for path in list_devices()]
for device in devices:
print(device.path, device.name, device.phys)
if 'ir_recv' in device.name:
return device
else:
device.close()
def stop_vlc():
for proc in psutil.process_iter(['pid', 'name']):
if 'vlc' in proc.info['name']:
print(proc.info['pid'])
p = psutil.Process(proc.info['pid'])
p.kill()
return
dev = get_ir_device()
try:
for event in dev.read_loop():
if event.type == ecodes.EV_KEY and event.value == 1:
if ecodes.KEY[event.code] == 'KEY_1':
# 控制VLC播放音樂
if vlc_on:
# 利用PID停止播放
print('停止播放音樂')
stop_vlc()
else:
print('開始播放音樂')
subprocess.run(["cvlc", "-LZ", "/home/pi/Music"])
vlc_on = not vlc_on
elif ecodes.KEY[event.code] == 'KEY_2':
# 控制LED亮與暗
if led_on:
led.off()
else:
led.blink()
led_on = not led_on
elif ecodes.KEY[event.code] == 'KEY_3':
print('離開程式')
dev.close()
quit()
except KeyboardInterrupt:
print('按鍵Ctrl+c中斷程式')
dev.close()
quit()
五、發射紅外線訊號
先利用evtest來檢視鍵盤訊號值,再利用ir_ctl測試,依據scancode發射紅外線訊號給接收器,最後撰寫程式來完成工作。
from evdev import InputDevice, list_devices, categorize, ecodes
from configparser import ConfigParser
from collections import defaultdict
from time import sleep
import os
config = ConfigParser()
config.read(os.path.expanduser('~/lien.toml'))
# 列出所有的設定section
# print(keymap.sections())
scancodes = config['protocols.scancodes']
keymaps = defaultdict()
# 原先格式是
# [protocols.scancodes]
# 0x41ba09 = "KEY_1"
# 轉成 "KEY_1" = 0x41ba09
# 並且將 " 字符除去(利用replace),如此才可以使用keymaps['KEY_1']
# 如果不去除,就必須要用keymaps['"KEY_1"'],此用法容易混淆
for s in scancodes:
keymaps[scancodes[s].replace('"','')] = s
dev = InputDevice('/dev/input/event0')
try:
for event in dev.read_loop():
if event.type == ecodes.EV_KEY and event.value == 1:
if event.code == ecodes.KEY_A:
print('按鍵 A')
command = f"ir-ctl -S necx:{keymaps['KEY_1']} -d /dev/lirc0"
os.system(command)
elif event.code == ecodes.KEY_B:
print('按鍵 B')
command = f"ir-ctl -S necx:{keymaps['KEY_2']} -d /dev/lirc0"
os.system(command)
elif event.code == ecodes.KEY_C:
print('結束程式')
dev.close()
break
except KeyboardInterrupt:
dev.close()
quit()
Last updated
Was this helpful?