-
-
Notifications
You must be signed in to change notification settings - Fork 38.2k
Allow using more than one keyboard remote #11061
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
balloob
merged 3 commits into
home-assistant:dev
from
BryanJacobs:multiple_keyboard_remotes
Dec 14, 2017
Merged
Changes from 1 commit
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,8 +21,9 @@ | |
| _LOGGER = logging.getLogger(__name__) | ||
|
|
||
| DEVICE_DESCRIPTOR = 'device_descriptor' | ||
| DEVICE_ID_GROUP = 'Device descriptor or name' | ||
| DEVICE_ID_GROUP = 'Device description' | ||
| DEVICE_NAME = 'device_name' | ||
| DEVICES = 'devices' | ||
| DOMAIN = 'keyboard_remote' | ||
|
|
||
| ICON = 'mdi:remote' | ||
|
|
@@ -40,7 +41,15 @@ | |
| 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')), | ||
| vol.All(cv.string, vol.Any('key_up', 'key_down', 'key_hold')), | ||
| vol.Exclusive(DEVICES, DEVICE_ID_GROUP): vol.All(cv.ensure_list, [ | ||
| vol.Schema({ | ||
| 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')) | ||
| }) | ||
| ]), | ||
| }), | ||
| }, extra=vol.ALLOW_EXTRA) | ||
|
|
||
|
|
@@ -50,8 +59,9 @@ def setup(hass, config): | |
| config = config.get(DOMAIN) | ||
|
|
||
| if not config.get(DEVICE_DESCRIPTOR) and\ | ||
| not config.get(DEVICE_NAME): | ||
| _LOGGER.error("No device_descriptor or device_name found") | ||
| not config.get(DEVICE_NAME) and\ | ||
| not config.get(DEVICES): | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. undefined name 'DEVICES' |
||
| _LOGGER.error("No device_descriptor, device_name, or dev block found") | ||
| return | ||
|
|
||
| keyboard_remote = KeyboardRemote( | ||
|
|
@@ -63,7 +73,7 @@ def _start_keyboard_remote(_event): | |
| keyboard_remote.run() | ||
|
|
||
| def _stop_keyboard_remote(_event): | ||
| keyboard_remote.stopped.set() | ||
| keyboard_remote.stop() | ||
|
|
||
| hass.bus.listen_once( | ||
| EVENT_HOMEASSISTANT_START, | ||
|
|
@@ -77,19 +87,21 @@ def _stop_keyboard_remote(_event): | |
| return True | ||
|
|
||
|
|
||
| class KeyboardRemote(threading.Thread): | ||
| class KeyboardRemoteThread(threading.Thread): | ||
| """This interfaces with the inputdevice using evdev.""" | ||
|
|
||
| def __init__(self, hass, config): | ||
| """Construct a KeyboardRemote interface object.""" | ||
| from evdev import InputDevice, list_devices | ||
| def __init__(self, hass, device_name, device_descriptor, key_value): | ||
| """Construct a thread listening for events on one device.""" | ||
| self.hass = hass | ||
| self.device_name = device_name | ||
| self.device_descriptor = device_descriptor | ||
| self.key_value = key_value | ||
|
|
||
| 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.device_id = self.device_name | ||
|
|
||
| self.dev = self._get_keyboard_device() | ||
| if self.dev is not None: | ||
| _LOGGER.debug("Keyboard connected, %s", self.device_id) | ||
|
|
@@ -103,6 +115,7 @@ def __init__(self, hass, config): | |
| id_folder = '/dev/input/by-id/' | ||
|
|
||
| if os.path.isdir(id_folder): | ||
| from evdev import InputDevice, list_devices | ||
| device_names = [InputDevice(file_name).name | ||
| for file_name in list_devices()] | ||
| _LOGGER.debug( | ||
|
|
@@ -116,7 +129,6 @@ def __init__(self, hass, config): | |
| threading.Thread.__init__(self) | ||
| self.stopped = threading.Event() | ||
| self.hass = hass | ||
| self.key_value = KEY_VALUE.get(config.get(TYPE, 'key_up')) | ||
|
|
||
| def _get_keyboard_device(self): | ||
| """Get the keyboard device.""" | ||
|
|
@@ -145,7 +157,7 @@ def run(self): | |
|
|
||
| while not self.stopped.isSet(): | ||
| # Sleeps to ease load on processor | ||
| time.sleep(.1) | ||
| time.sleep(.05) | ||
|
|
||
| if self.dev is None: | ||
| self.dev = self._get_keyboard_device() | ||
|
|
@@ -178,3 +190,32 @@ def run(self): | |
| KEYBOARD_REMOTE_COMMAND_RECEIVED, | ||
| {KEY_CODE: event.code} | ||
| ) | ||
|
|
||
|
|
||
| class KeyboardRemote(object): | ||
| """Sets up one thread per device.""" | ||
|
|
||
| def __init__(self, hass, config): | ||
| """Construct a KeyboardRemote interface object.""" | ||
| self.threads = [] | ||
| for dev_block in config.get(DEVICES, []) + [config]: | ||
| device_descriptor = dev_block.get(DEVICE_DESCRIPTOR) | ||
| device_name = dev_block.get(DEVICE_NAME) | ||
| key_value = KEY_VALUE.get(dev_block.get(TYPE, 'key_up')) | ||
|
|
||
| if device_descriptor is not None\ | ||
| or device_name is not None: | ||
| thread = KeyboardRemoteThread(hass, device_name, | ||
| device_descriptor, | ||
| key_value) | ||
| self.threads.append(thread) | ||
|
|
||
| def run(self): | ||
| """Run all event listener threads.""" | ||
| for thread in self.threads: | ||
| thread.start() | ||
|
|
||
| def stop(self): | ||
| """Stop all event listener threads.""" | ||
| for thread in self.threads: | ||
| thread.stopped.set() | ||
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of adding
ensure_listhere, you can just wrap the whole DOMAIN config as an ensure list. No need to specify the schema twice.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have done so. Be aware this means you can never backwards-compatibly add module-level (not keyboard-level) configuration options in the future.