![](/img/trans.png)
[英]How can I control a fan with GPIO on a Raspberry Pi 3 using Python?
[英]Using Python, can I send a Raspberry Pi GPIO input as a HID keypress or command?
我正在修改现有代码,将 Raspberry Pi 用作蓝牙 HID 键盘和鼠标。 现有代码可以很好地通过蓝牙将按键发送到我的 Macbook。
我正在苦苦挣扎的是将来自 Raspberry Pi 的 GPIO 输入转换为通过蓝牙发送的命令或按键。 我可以让按键在本地工作,但我不知道如何更改代码以适应 GPIO 输入。
理想情况下,我想使用一个按钮来按“Command+向右箭头”或使用 AppleScript 向 Macbook 上的 Spotify 发送下一首曲目命令。 这是我唯一需要编码的按键。
我想我需要导入 GPIO 并将其设置为 BCM,然后让它将输入从引脚 4 转换为发送的 AppleScript 命令。 我只是想不出在哪里做。
现有代码如下:
#!/usr/bin/python3
#
# Thanhle Bluetooth keyboard emulation service
# keyboard copy client.
# Reads local key events and forwards them to the btk_server DBUS service
#
import os # used to all external commands
import sys # used to exit the script
import dbus
import dbus.service
import dbus.mainloop.glib
import time
import evdev # used to get input from the keyboard
from evdev import *
import keymap # used to map evdev input to hid keodes
# Define a client to listen to local key events
class Keyboard():
def __init__(self):
# the structure for a bt keyboard input report (size is 10 bytes)
self.state = [
0xA1, # this is an input report
0x01, # Usage report = Keyboard
# Bit array for Modifier keys
[0, # Right GUI - Windows Key
0, # Right ALT
0, # Right Shift
0, # Right Control
0, # Left GUI
0, # Left ALT
0, # Left Shift
0], # Left Control
0x00, # Vendor reserved
0x00, # rest is space for 6 keys
0x00,
0x00,
0x00,
0x00,
0x00]
print("setting up DBus Client")
self.bus = dbus.SystemBus()
self.btkservice = self.bus.get_object(
'org.thanhle.btkbservice', '/org/thanhle/btkbservice')
self.iface = dbus.Interface(self.btkservice, 'org.thanhle.btkbservice')
print("waiting for keyboard")
# keep trying to key a keyboard
have_dev = False
while have_dev == False:
try:
# try and get a keyboard - should always be event0 as
# we're only plugging one thing in
self.dev = InputDevice("/dev/input/event0")
have_dev = True
except OSError:
print("Keyboard not found, waiting 3 seconds and retrying")
time.sleep(3)
print("found a keyboard")
def change_state(self, event):
evdev_code = ecodes.KEY[event.code]
modkey_element = keymap.modkey(evdev_code)
if modkey_element > 0:
if self.state[2][modkey_element] == 0:
self.state[2][modkey_element] = 1
else:
self.state[2][modkey_element] = 0
else:
# Get the keycode of the key
hex_key = keymap.convert(ecodes.KEY[event.code])
# Loop through elements 4 to 9 of the inport report structure
for i in range(4, 10):
if self.state[i] == hex_key and event.value == 0:
# Code 0 so we need to depress it
self.state[i] = 0x00
elif self.state[i] == 0x00 and event.value == 1:
# if the current space if empty and the key is being pressed
self.state[i] = hex_key
break
# poll for keyboard events
def event_loop(self):
for event in self.dev.read_loop():
# only bother if we hit a key and its an up or down event
if event.type == ecodes.EV_KEY and event.value < 2:
self.change_state(event)
self.send_input()
# forward keyboard events to the dbus service
def send_input(self):
bin_str = ""
element = self.state[2]
for bit in element:
bin_str += str(bit)
a = self.state
print(*a)
self.iface.send_keys(int(bin_str, 2), self.state[4:10])
if __name__ == "__main__":
print("Setting up keyboard")
kb = Keyboard()
print("starting event loop")
kb.event_loop()
当我使用 Retrogame 或其他代码将 Raspberry Pi 设置为从 GPIO 读取按键时,它会读取按键,但不会将它们转换为键盘 python 程序中的按键。 似乎需要在代码中完成。
编辑以添加更多信息:
该代码还包括这个名为“send_string.py”的 Python 文件。
#!/usr/bin/python3
import os # used to all external commands
import sys # used to exit the script
import dbus
import dbus.service
import dbus.mainloop.glib
import time
# import thread
import keymap
class BtkStringClient():
# constants
KEY_DOWN_TIME = 0.01
KEY_DELAY = 0.01
def __init__(self):
# the structure for a bt keyboard input report (size is 10 bytes)
self.state = [
0xA1, # this is an input report
0x01, # Usage report = Keyboard
# Bit array for Modifier keys
[0, # Right GUI - Windows Key
0, # Right ALT
0, # Right Shift
0, # Right Control
0, # Left GUI
0, # Left ALT
0, # Left Shift
0], # Left Control
0x00, # Vendor reserved
0x00, # rest is space for 6 keys
0x00,
0x00,
0x00,
0x00,
0x00]
self.scancodes = {
"-": "KEY_MINUS",
"=": "KEY_EQUAL",
";": "KEY_SEMICOLON",
"'": "KEY_APOSTROPHE",
"`": "KEY_GRAVE",
"\\": "KEY_BACKSLASH",
",": "KEY_COMMA",
".": "KEY_DOT",
"/": "KEY_SLASH",
"_": "key_minus",
"+": "key_equal",
":": "key_semicolon",
"\"": "key_apostrophe",
"~": "key_grave",
"|": "key_backslash",
"<": "key_comma",
">": "key_dot",
"?": "key_slash",
" ": "KEY_SPACE",
}
# connect with the Bluetooth keyboard server
print("setting up DBus Client")
self.bus = dbus.SystemBus()
self.btkservice = self.bus.get_object(
'org.thanhle.btkbservice', '/org/thanhle/btkbservice')
self.iface = dbus.Interface(self.btkservice, 'org.thanhle.btkbservice')
def send_key_state(self):
"""sends a single frame of the current key state to the emulator server"""
bin_str = ""
element = self.state[2]
for bit in element:
bin_str += str(bit)
self.iface.send_keys(int(bin_str, 2), self.state[4:10])
def send_key_down(self, scancode, modifiers):
"""sends a key down event to the server"""
self.state[2] = modifiers
self.state[4] = scancode
self.send_key_state()
def send_key_up(self):
"""sends a key up event to the server"""
self.state[4] = 0
self.send_key_state()
def send_string(self, string_to_send):
for c in string_to_send:
cu = c.upper()
modifiers = [ 0, 0, 0, 0, 0, 0, 0, 0 ]
if cu in self.scancodes:
scantablekey = self.scancodes[cu]
if scantablekey.islower():
modifiers = [ 0, 0, 0, 0, 0, 0, 1, 0 ]
scantablekey = scantablekey.upper()
else:
if c.isupper():
modifiers = [ 0, 0, 0, 0, 0, 0, 1, 0 ]
scantablekey = "KEY_" + cu
scancode = keymap.keytable[scantablekey]
self.send_key_down(scancode, modifiers)
time.sleep(BtkStringClient.KEY_DOWN_TIME)
self.send_key_up()
time.sleep(BtkStringClient.KEY_DELAY)
if __name__ == "__main__":
if(len(sys.argv) < 2):
print("Usage: send_string <string to send>")
exit()
dc = BtkStringClient()
string_to_send = sys.argv[1]
print("Sending " + string_to_send)
dc.send_string(string_to_send)
print("Done.")
编辑#2:
这是否接近轮询 GPIO 事件的方法?
# poll for keyboard events
def event_loop(self):
global cmd
for event in self.dev.read_loop():
# only bother if we hit a key and its an up or down event
if event.type == ecodes.EV_KEY and event.value < 2:
self.change_state(event)
self.send_input()
while True:
if event.type == GPIO.input(4):
self.change_state(event)
cmd = """osascript -e 'tell app "Spotify" next track'"""
self.nextrack(self)
time.sleep(.25)
# forward keyboard events to the dbus service
def nextrack(self):
global cmd
bin_str = ""
element = self.state[2]
for bit in element:
bin_str += str(bit)
a = self.state
print("Play next track")
cmd = """osascript -e 'tell app "Spotify" next track'"""
self.iface.send_keys(os.system(cmd))
是这样的:
def gpioThread():
state = GPIO.input(4)
while True:
now = GPIO.input(4)
if now != state:
# Take action here based on whether "now" is 0 or 1.
state = now
time.sleep(0.25)
那么你将不得不使用
t = Threading.thread(target=gpioThread)
t.run()
创建和运行线程。 确保将引脚设置为“输入”模式。 GPIO 引脚可以是其中之一,但一次只能是一个。
这是典型的 Rpi 程序——许多小线程全职运行以执行微小任务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.