Update keyboard_remote.py (#5535)
* Update keyboard_remote.py I added a couple of events: keyboard_remote_connected and keyboard_remote_disconnected, useful to trigger some action (for example: play a sound) I changed the way the component refers to the keyboard: not by "descriptor", but by name. The fact is that the udev system doesn't always give a name link in /dev/input/by-id folder and the actual /dev/input/eventX file changes automatically. For example, if I had my keyboard on /dev/input/event13 and then it disconnected, if something else connects to the system it will get the first input file available, that is /dev/input/event13. If the keyboard then reconnects, it will get /dev/input/event14, thus breaking the configuration. Now it searches every time for the right input file. The problem might be that, in case of ha upgrade, the pre-existing configuration won't work. I thing there are some guidelines here, but I am not sure. I think it's inevitable: the initial idea to use a /dev/input/by-id/ symbolic link was good, but unfortunately it doesn't seem to work with bluetooth devices. I haven't updated the documentation yet: I'm waiting for some ok about the change in configuration key names. * Update keyboard_remote.py That should do the trick. You are right: device names can be duplicated, thus they're not reliable in case of multiple devices. Unfortunately, the only other information available is the physical address, even more complicated. But in case you have just one keyboard remote of same model, the name works just fine. I'll put it in the documentation which, once the code is approved, I will promptly update. * Update keyboard_remote.py * Update keyboard_remote.py * Update keyboard_remote.py * Unwrap logger errorpull/5555/head
parent
c3a55e7d82
commit
9cad9c19f8
|
@ -1,32 +1,8 @@
|
|||
"""
|
||||
Receive signals from a keyboard and use it as a remote control.
|
||||
|
||||
This component allows to use a keyboard as remote control. It will
|
||||
fire ´keyboard_remote_command_received´ events witch can then be used
|
||||
in automation rules.
|
||||
|
||||
The `evdev` package is used to interface with the keyboard and thus this
|
||||
is Linux only. It also means you can't use your normal keyboard for this,
|
||||
because `evdev` will block it.
|
||||
|
||||
Example:
|
||||
keyboard_remote:
|
||||
device_descriptor: '/dev/input/by-id/foo'
|
||||
type: 'key_up' # optional alternaive 'key_down' and 'key_hold'
|
||||
# be carefull, 'key_hold' fires a lot of events
|
||||
|
||||
and an automation rule to bring breath live into it.
|
||||
|
||||
automation:
|
||||
alias: Keyboard All light on
|
||||
trigger:
|
||||
platform: event
|
||||
event_type: keyboard_remote_command_received
|
||||
event_data:
|
||||
key_code: 107 # inspect log to obtain desired keycode
|
||||
action:
|
||||
service: light.turn_on
|
||||
entity_id: light.all
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/keyboard_remote/
|
||||
"""
|
||||
|
||||
# pylint: disable=import-error
|
||||
|
@ -54,10 +30,14 @@ KEY_CODE = 'key_code'
|
|||
KEY_VALUE = {'key_up': 0, 'key_down': 1, 'key_hold': 2}
|
||||
TYPE = 'type'
|
||||
DEVICE_DESCRIPTOR = 'device_descriptor'
|
||||
DEVICE_NAME = 'device_name'
|
||||
DEVICE_ID_GROUP = 'Device descriptor or name'
|
||||
|
||||
|
||||
CONFIG_SCHEMA = vol.Schema({
|
||||
DOMAIN: vol.Schema({
|
||||
vol.Required(DEVICE_DESCRIPTOR): cv.string,
|
||||
vol.Exclusive(DEVICE_DESCRIPTOR, DEVICE_ID_GROUP): cv.string,
|
||||
vol.Exclusive(DEVICE_NAME, DEVICE_ID_GROUP): cv.string,
|
||||
vol.Optional(TYPE, default='key_up'):
|
||||
vol.All(cv.string, vol.Any('key_up', 'key_down', 'key_hold')),
|
||||
}),
|
||||
|
@ -67,22 +47,15 @@ CONFIG_SCHEMA = vol.Schema({
|
|||
def setup(hass, config):
|
||||
"""Setup keyboard_remote."""
|
||||
config = config.get(DOMAIN)
|
||||
device_descriptor = config.get(DEVICE_DESCRIPTOR)
|
||||
if not device_descriptor:
|
||||
id_folder = '/dev/input/'
|
||||
_LOGGER.error(
|
||||
'A device_descriptor must be defined. '
|
||||
'Possible descriptors are %s:\n%s',
|
||||
id_folder, os.listdir(id_folder)
|
||||
)
|
||||
return
|
||||
|
||||
key_value = KEY_VALUE.get(config.get(TYPE, 'key_up'))
|
||||
if not config.get(DEVICE_DESCRIPTOR) and\
|
||||
not config.get(DEVICE_NAME):
|
||||
_LOGGER.error('No device_descriptor or device_name found.')
|
||||
return
|
||||
|
||||
keyboard_remote = KeyboardRemote(
|
||||
hass,
|
||||
device_descriptor,
|
||||
key_value
|
||||
config
|
||||
)
|
||||
|
||||
def _start_keyboard_remote(_event):
|
||||
|
@ -106,66 +79,93 @@ def setup(hass, config):
|
|||
class KeyboardRemote(threading.Thread):
|
||||
"""This interfaces with the inputdevice using evdev."""
|
||||
|
||||
def __init__(self, hass, device_descriptor, key_value):
|
||||
def __init__(self, hass, config):
|
||||
"""Construct a KeyboardRemote interface object."""
|
||||
from evdev import InputDevice
|
||||
from evdev import InputDevice, list_devices
|
||||
|
||||
self.device_descriptor = device_descriptor
|
||||
try:
|
||||
self.dev = InputDevice(device_descriptor)
|
||||
except OSError: # Keyboard not present
|
||||
_LOGGER.debug(
|
||||
'KeyboardRemote: keyboard not connected, %s',
|
||||
self.device_descriptor)
|
||||
self.keyboard_connected = False
|
||||
self.device_descriptor = config.get(DEVICE_DESCRIPTOR)
|
||||
self.device_name = config.get(DEVICE_NAME)
|
||||
if self.device_descriptor:
|
||||
self.device_id = self.device_descriptor
|
||||
else:
|
||||
self.keyboard_connected = True
|
||||
self.device_id = self.device_name
|
||||
self.dev = self._get_keyboard_device()
|
||||
if self.dev is not None:
|
||||
_LOGGER.debug(
|
||||
'KeyboardRemote: keyboard connected, %s',
|
||||
self.dev)
|
||||
'Keyboard connected, %s',
|
||||
self.device_id
|
||||
)
|
||||
else:
|
||||
id_folder = '/dev/input/by-id/'
|
||||
device_names = [InputDevice(file_name).name
|
||||
for file_name in list_devices()]
|
||||
_LOGGER.debug(
|
||||
'Keyboard not connected, %s.\n\
|
||||
Check /dev/input/event* permissions.\
|
||||
Possible device names are:\n %s.\n \
|
||||
Possible device descriptors are %s:\n %s',
|
||||
self.device_id,
|
||||
device_names,
|
||||
id_folder,
|
||||
os.listdir(id_folder)
|
||||
)
|
||||
|
||||
threading.Thread.__init__(self)
|
||||
self.stopped = threading.Event()
|
||||
self.hass = hass
|
||||
self.key_value = key_value
|
||||
self.key_value = KEY_VALUE.get(config.get(TYPE, 'key_up'))
|
||||
|
||||
def _get_keyboard_device(self):
|
||||
from evdev import InputDevice, list_devices
|
||||
if self.device_name:
|
||||
devices = [InputDevice(file_name) for file_name in list_devices()]
|
||||
for device in devices:
|
||||
if self.device_name == device.name:
|
||||
return device
|
||||
elif self.device_descriptor:
|
||||
try:
|
||||
device = InputDevice(self.device_descriptor)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
return device
|
||||
return None
|
||||
|
||||
def run(self):
|
||||
"""Main loop of the KeyboardRemote."""
|
||||
from evdev import categorize, ecodes, InputDevice
|
||||
from evdev import categorize, ecodes
|
||||
|
||||
if self.keyboard_connected:
|
||||
if self.dev is not None:
|
||||
self.dev.grab()
|
||||
_LOGGER.debug(
|
||||
'KeyboardRemote interface started for %s',
|
||||
'Interface started for %s',
|
||||
self.dev)
|
||||
|
||||
while not self.stopped.isSet():
|
||||
# Sleeps to ease load on processor
|
||||
time.sleep(.1)
|
||||
|
||||
if not self.keyboard_connected:
|
||||
try:
|
||||
self.dev = InputDevice(self.device_descriptor)
|
||||
except OSError: # still disconnected
|
||||
continue
|
||||
else:
|
||||
if self.dev is None:
|
||||
self.dev = self._get_keyboard_device()
|
||||
if self.dev is not None:
|
||||
self.dev.grab()
|
||||
self.keyboard_connected = True
|
||||
_LOGGER.debug('KeyboardRemote: keyboard re-connected, %s',
|
||||
self.device_descriptor)
|
||||
self.hass.bus.fire(
|
||||
KEYBOARD_REMOTE_CONNECTED
|
||||
)
|
||||
_LOGGER.debug('Keyboard re-connected, %s',
|
||||
self.device_id)
|
||||
else:
|
||||
continue
|
||||
|
||||
try:
|
||||
event = self.dev.read_one()
|
||||
except IOError: # Keyboard Disconnected
|
||||
self.keyboard_connected = False
|
||||
_LOGGER.debug('KeyboardRemote: keyboard disconnected, %s',
|
||||
self.device_descriptor)
|
||||
self.dev = None
|
||||
self.hass.bus.fire(
|
||||
KEYBOARD_REMOTE_DISCONNECTED
|
||||
)
|
||||
_LOGGER.debug('Keyboard disconnected, %s',
|
||||
self.device_id)
|
||||
continue
|
||||
|
||||
if not event:
|
||||
|
|
Loading…
Reference in New Issue