diff --git a/homeassistant/components/keyboard_remote.py b/homeassistant/components/keyboard_remote.py index 992f9390124..69151043276 100644 --- a/homeassistant/components/keyboard_remote.py +++ b/homeassistant/components/keyboard_remote.py @@ -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: